Tarantool 3.1
Release date: April 16, 2024
Releases on GitHub: 3.1.2,
3.1.1,
3.1.0
The 3.1 release of Tarantool continues the development of a new cluster configuration approach introduced in the 3.0 version and adds the following main product features and improvements for the Community and Enterprise editions:
- Community Edition (CE)
- Improved developer experience for handling errors using the
box.errormodule. - Introduced fixed-size numeric field types:
uint8,int8,uint16, and more. - Added RPC functionality for accessing custom roles from the configuration.
- Made the
ttutility used to manage instances fully compatible with the latest Tarantool version.
- Improved developer experience for handling errors using the
- Enterprise Edition (EE)
- Introduced an external coordinator for automatic and manual failover.
- Improved the stability of work with the centralized configuration stored in etcd.
This release improves the developer experience for handling errors using the box.error module. Below are listed the most notable features and changes.
With the 3.1 release, you can add a custom payload to an error. The
payload is passed as key-value pairs where a key is a string and a value
is any Lua object. In the example below, the description key is used
to keep the custom payload.
custom_error = box.error.new({ type = 'CustomInternalError',message = 'Internal server error',description = 'Some error details' -- payload})
A payload field value can be accessed using the dot syntax:
tarantool> custom_error.description---- Some error details...
The 3.1 release simplifies creating error chains. In the earlier versions, you need to set an error cause using the set_prev(error_object) method, for example:
local ok, err = pcall(my_func)if not ok thenlocal err2 = box.error.new{type = "MyAppError", message = "my_func failed"}err2:set_prev(err)err2:raise()end
Using this approach, you need to construct a new error without raising
it, then set its cause using set_prev(), and only then raise it.
Starting with the 3.1 version, you can use a new prev argument when
constructing an error:
local ok, err = pcall(my_func)if not ok thenbox.error{type = "MyAppError", message = "my_func failed", prev = err}end
The 3.1 release allows you to increase the verbosity of error serialization. Before the 3.1 release, a serialized error representation included only an error message:
tarantool> box.error.new({ type = 'CustomInternalError', message = 'Internal server error'})---- Internal server error...
Starting with the 3.1 version, a serialized error also includes other fields that might be useful for analyzing errors:
tarantool> box.error.new({ type = 'CustomInternalError', message = 'Internal server error'})---- code: 0base_type: CustomErrortype: CustomInternalErrorcustom_type: CustomInternalErrormessage: Internal server errortrace:- file: '[C]'line: 4294967295...
Logging an error using a built-in logging module prints an
error message followed by a tab space (\t) and all the payload fields
serialized as a JSON map, for example:
main/104/app.lua/tarantool I> Internal server error {"code":0,"base_type":"CustomError","type":"CustomInternalError", ... }
Given that this change may change the behavior of existing code, a new
box_error_serialize_verbose compat option is
introduced. To try out an increased verbosity of error serialization,
set this option to new:
tarantool> require('compat').box_error_serialize_verbose = 'new'---...
The 3.1 release introduces fixed-size numeric types that might be useful to store data unencoded in an array for effective scanning. The following numeric types are added:
uint8: an integer in a range[0 .. 255].int8: an integer in a range[-128 .. 127].uint16: an integer in a range[0 .. 65,535].int16: an integer in a range[-32,768 .. 32,767].uint32: an integer in a range[0 .. 4,294,967,295].int32: an integer in a range[-2,147,483,648 .. 2,147,483,647].uint64: an integer in a range[0 .. 18,446,744,073,709,551,615].int64: an integer in a range[-9,223,372,036,854,775,808 .. 9,223,372,036,854,775,807].float32: a 32-bit floating point number.float64: a 64-bit floating point number.
A new experimental.connpool module provides a set
of features for remote connections to any cluster instance or executing
remote procedure calls on an instance that meets the specified criteria.
To load the experimental.connpool module, use the require()
directive:
sharded_cluster:router-a-001> connpool = require('experimental.connpool')---...
In the 3.1 version, this module provides the following API:
-
The
connect()function accepts an instance name and returns the active connection to this instance:sharded_cluster:router-a-001> conn = connpool.connect("storage-b-002")---...Once you have a connection, you can execute requests on a remote instance, for example, select data from a space:
sharded_cluster:router-a-001> conn.space.bands:select({}, { limit = 5 })---- - [3, 804, 'Ace of Base', 1987]- [7, 693, 'The Doors', 1965]- [9, 644, 'Led Zeppelin', 1968]- [10, 569, 'Queen', 1970]... -
The
filter()function returns the names of instances that match the specified conditions. In the example below, this function returns a list of instances with thestoragerole and specified label value:sharded_cluster:router-a-001> connpool.filter({ roles = { 'storage' }, labels = { dc = 'east' }})---- - storage-b-002- storage-a-002... -
The
call()function can be used to execute a function on a remote instance. In the example below, the following conditions are specified to choose an instance to execute thevshard.storage.buckets_countfunction on:- An instance has the
storagerole. - An instance has the
dclabel set towest. - An instance is writable.
sharded_cluster:router-a-001> connpool.call('vshard.storage.buckets_count', nil, { roles = { 'storage' }, labels = { dc = 'west' }, mode = 'rw' })sharded_cluster:router-a-001> connpool.call('vshard.storage.buckets_count', nil, { roles = { 'storage' }, labels = { dc = 'west' }, mode = 'rw' })---- 500... - An instance has the
Learn more in the experimental.connpool
module reference.
In Tarantool 3.0, the config module provides the ability to work with a current instance's configuration only. Starting with the 3.1 version, you can get all the instances that constitute a cluster and obtain the configuration of any instance of this cluster.
The config:instances() function lists all instances of the cluster:
sharded_cluster:router-a-001> require('config'):instances()---- storage-a-001:group_name: storagesinstance_name: storage-a-001replicaset_name: storage-astorage-b-002:group_name: storagesinstance_name: storage-b-002replicaset_name: storage-brouter-a-001:group_name: routersinstance_name: router-a-001replicaset_name: router-astorage-a-002:group_name: storagesinstance_name: storage-a-002replicaset_name: storage-astorage-b-001:group_name: storagesinstance_name: storage-b-001replicaset_name: storage-b...
To get the specified configuration value for a certain instance, pass an
instance name as an argument to config:get():
sharded_cluster:router-a-001> require('config'):get('iproto', {instance = 'storage-b-001'})---- readahead: 16320net_msg_max: 768listen:- uri: 127.0.0.1:3304threads: 1advertise:peer:login: replicatorclient: nullsharding:login: storage...
Tarantool Enterprise Edition 3.1 introduces an external failover coordinator that monitors a Tarantool cluster and performs automatic leadership change if a current replica set leader is inaccessible.
A failover coordinator requires the
replication.failover
configuration option to be set to supervised:
replication:failover: supervised# ...
To start a failover coordinator, execute the tarantool command with
the failover option and pass a path to a
YAML configuration file:
$ tarantool --failover --config /path/to/config
A failover coordinator connects to all the instances, polls them for
their status, and controls that each replica set with
replication.failover set to supervised has only one writable
instance.
Optionally, you can configure failover timeouts and other parameters in
the failover section at the global level:
failover:call_timeout: 1lease_interval: 15renew_interval: 5stateboard:renew_interval: 1keepalive_interval: 5
The 3.1 release includes new
sharding options that provide
additional flexibility for configuring a sharded cluster. A new
sharding.weight specifies the relative amount of data that a replica
set can store. In the example below, the storage-a replica set can
store twice as much data as storage-b:
# ...replicasets:storage-a:sharding:weight: 2# ...storage-b:sharding:weight: 1# ...
The sharding.rebalancer_mode option configures whether a rebalancer is
selected manually or automatically. This option can have one of three
values:
auto(default): if there are no replica sets with therebalancersharding role (sharding.roles), a replica set with the rebalancer will be selected automatically among all replica sets.manual: one of the replica sets should have therebalancersharding role. The rebalancer will be in this replica set.off: rebalancing is turned off regardless of whether a replica set with therebalancersharding role exists or not.
With this release, the tarantoolctl utility used to administer
Tarantool instances is completely removed from Tarantool packages. The
latest version of the tt utility is fully compatible with
Tarantool 3.1 and covers all the required functionality:
- Setting up a development environment: initializing the environment and installing different Tarantool versions.
- Various capabilities for developing cluster applications: creating applications from templates, managing modules, and building and packaging applications.
- Managing cluster instances: starting and stopping instances, connecting to remote instances for administration, and so on.
- Importing and exporting data (Enterprise Edition only).
Learn how to migrate from tarantoolctl to tt in the
tarantoolctl-migration-to-tt section.