Bonjour, je crée des applications pour le SGBD
Tarantool - il s'agit d'une plateforme dĂ©veloppĂ©e par Mail.ru Group qui combine un SGBD hautes performances et un serveur d'applications Ă Lua. La vitesse Ă©levĂ©e des solutions basĂ©es sur Tarantool est obtenue, en particulier, en prenant en charge le mode SGBD en mĂ©moire et la possibilitĂ© d'exĂ©cuter la logique d'application mĂ©tier dans un espace d'adressage unique avec des donnĂ©es. Cela garantit la persistance des donnĂ©es Ă l'aide des transactions ACID (un journal WAL est conservĂ© sur le disque). Tarantool a un support de rĂ©plication et de partitionnement intĂ©grĂ©. Ă partir de la version 2.1, les requĂȘtes SQL sont prises en charge. Tarantool est open source et sous licence BSD simplifiĂ©e. Il existe Ă©galement une version commerciale d'entreprise.
Ressentez le pouvoir! (... aka profitez de la performance)Tout cela fait de Tarantool une plate-forme attrayante pour créer des applications de base de données trÚs chargées. Dans de telles applications, la réplication des données devient souvent nécessaire.
Comme mentionné ci-dessus, Tarantool a une réplication de données intégrée. Le principe de son travail est l'exécution séquentielle sur des répliques de toutes les transactions contenues dans le journal de l'assistant (WAL). Typiquement, une telle réplication (nous l'appellerons
bas niveau ci
- dessous) est utilisĂ©e pour fournir une tolĂ©rance aux pannes de l'application et / ou pour rĂ©partir la charge de lecture entre les nĆuds du cluster.
Fig. 1. RĂ©plication au sein du clusterUn exemple de scĂ©nario alternatif est le transfert de donnĂ©es créées dans une base de donnĂ©es vers une autre base de donnĂ©es pour traitement / surveillance. Dans ce dernier cas, une solution plus pratique peut ĂȘtre d'utiliser la rĂ©plication de
haut niveau - rĂ©plication des donnĂ©es au niveau de la logique mĂ©tier de l'application. C'est-Ă -dire Nous n'utilisons pas de solution prĂȘte Ă l'emploi intĂ©grĂ©e au SGBD, mais nous implĂ©mentons nous-mĂȘmes la rĂ©plication dans l'application que nous dĂ©veloppons. Cette approche prĂ©sente Ă la fois des avantages et des inconvĂ©nients. Nous listons les avantages.
1. Ăconomisez du trafic:
- vous ne pouvez pas transférer toutes les données, mais seulement une partie de celles-ci (par exemple, vous ne pouvez transférer que certaines tables, certaines de leurs colonnes ou enregistrements qui répondent à un certain critÚre);
- contrairement Ă la rĂ©plication de bas niveau, qui est effectuĂ©e en continu en mode asynchrone (implĂ©mentĂ© dans la version actuelle de Tarantool - 1.10) ou synchrone (Ă implĂ©menter dans les futures versions de Tarantool), la rĂ©plication de haut niveau peut ĂȘtre effectuĂ©e par sessions (c'est-Ă -dire que l'application effectue d'abord la synchronisation des donnĂ©es - session d'Ă©change donnĂ©es, puis il y a une pause dans la rĂ©plication, aprĂšs quoi la prochaine session d'Ă©change a lieu, etc.);
- si l'enregistrement a changé plusieurs fois, vous ne pouvez transférer que sa derniÚre version (contrairement à la réplication de bas niveau, dans laquelle toutes les modifications apportées à l'assistant seront lues séquentiellement sur les répliques).
2. La mise en Ćuvre de l'Ă©change via HTTP ne pose aucune difficultĂ©, ce qui vous permet de synchroniser des bases de donnĂ©es distantes.
Fig. 2. RĂ©plication HTTP3. Les structures de base de donnĂ©es entre lesquelles les donnĂ©es sont transmises ne doivent pas ĂȘtre les mĂȘmes (en outre, dans le cas gĂ©nĂ©ral, il est mĂȘme possible d'utiliser diffĂ©rents SGBD, langages de programmation, plates-formes, etc.).
Fig. 3. Réplication dans des systÚmes hétérogÚnesL'inconvénient est qu'en moyenne, la programmation est plus compliquée / plus chÚre que la configuration, et au lieu de configurer la fonctionnalité intégrée, vous devrez implémenter la vÎtre.
Si dans votre situation, les avantages ci-dessus jouent un rÎle décisif (ou sont une condition nécessaire), il est alors judicieux d'utiliser la réplication de haut niveau. Examinons plusieurs façons d'implémenter la réplication de données de haut niveau dans le SGBD Tarantool.
Minimisation du trafic
Ainsi, l'un des avantages de la rĂ©plication de haut niveau est la rĂ©duction du trafic. Pour que cet avantage se manifeste pleinement, il est nĂ©cessaire de minimiser la quantitĂ© de donnĂ©es transmises lors de chaque session d'Ă©change. Bien entendu, il ne faut pas oublier qu'Ă la fin de la session le rĂ©cepteur de donnĂ©es doit ĂȘtre synchronisĂ© avec la source (au moins pour la partie des donnĂ©es impliquĂ©e dans la rĂ©plication).
Comment minimiser la quantitĂ© de donnĂ©es transfĂ©rĂ©es lors de la rĂ©plication de haut niveau? La solution "au front" peut ĂȘtre la sĂ©lection des donnĂ©es par date-heure. Pour ce faire, vous pouvez utiliser le champ date-heure dĂ©jĂ dans le tableau (le cas Ă©chĂ©ant). Par exemple, un document «ordre» peut avoir un champ «temps requis pour l'exĂ©cution de l'ordre» -
delivery_time
. Le problĂšme avec cette solution est que les valeurs de ce champ ne doivent pas nĂ©cessairement ĂȘtre dans la sĂ©quence correspondant Ă la crĂ©ation des commandes. Ainsi, nous ne pouvons pas nous souvenir de la valeur maximale du champ
delivery_time
transmise lors de la session d'échange précédente, et lors de la session d'échange suivante, sélectionnez tous les enregistrements avec une valeur plus élevée du champ
delivery_time
. Dans l'intervalle entre les sessions d'échange, des enregistrements avec une valeur plus petite du champ
delivery_time
peuvent ĂȘtre ajoutĂ©s. De plus, la commande pourrait subir des modifications, ce qui n'affectait nĂ©anmoins pas le champ
delivery_time
. Dans les deux cas, les modifications ne seront pas transmises de la source au récepteur. Pour résoudre ces problÚmes, nous devrons transmettre des données "en chevauchement". C'est-à -dire au cours de chaque session d'échange, nous transférerons toutes les données avec une valeur de champ
delivery_time
qui dépasse un certain point dans le passé (par exemple, N heures à partir du moment actuel). Cependant, il est évident que pour les grands systÚmes, cette approche est trÚs redondante et peut réduire les économies de trafic que nous visons. De plus, la table transmise peut ne pas avoir de champ date-heure.
Une autre solution, plus complexe en termes de mise en Ćuvre, consiste Ă accuser rĂ©ception des donnĂ©es. Dans ce cas, Ă chaque session d'Ă©change, toutes les donnĂ©es sont transmises, dont la rĂ©ception n'est pas confirmĂ©e par le destinataire. Pour l'implĂ©mentation, vous devez ajouter une colonne boolĂ©enne Ă la table source (par exemple,
is_transferred
). Si le destinataire confirme la réception de l'enregistrement, le champ correspondant est défini sur
true
, aprĂšs quoi l'enregistrement n'est plus impliquĂ© dans les Ă©changes. Cette option de mise en Ćuvre prĂ©sente les inconvĂ©nients suivants. Tout d'abord, pour chaque enregistrement transfĂ©rĂ©, il est nĂ©cessaire de gĂ©nĂ©rer et d'envoyer une confirmation. En gros, cela peut ĂȘtre comparable Ă doubler la quantitĂ© de donnĂ©es transfĂ©rĂ©es et Ă doubler le nombre de voyages aller-retour. DeuxiĂšmement, il n'est pas possible d'envoyer le mĂȘme enregistrement Ă plusieurs rĂ©cepteurs (le premier rĂ©cepteur confirmera la rĂ©ception pour lui-mĂȘme et pour tout le monde).
La mĂ©thode, dĂ©pourvue des inconvĂ©nients ci-dessus, consiste Ă ajouter des colonnes au tableau Ă transmettre pour suivre les modifications de ses lignes. Une telle colonne peut ĂȘtre de type date-heure et doit ĂȘtre dĂ©finie / mise Ă jour par l'application pour l'heure actuelle Ă chaque fois en ajoutant / changeant des enregistrements (atomiquement avec en ajoutant / changeant). Ă titre d'exemple, appelons la colonne
update_time
. AprÚs avoir enregistré la valeur maximale du champ de cette colonne pour les enregistrements transférés, nous pouvons démarrer la prochaine session d'échange à partir de cette valeur (sélectionnez les enregistrements dont la valeur du champ
update_time
dépasse la valeur précédemment enregistrée). Le problÚme avec cette derniÚre approche est que les changements de données peuvent se produire en mode batch. Par conséquent, les valeurs de champ dans la colonne
update_time
ne pas ĂȘtre uniques. Par consĂ©quent, cette colonne ne peut pas ĂȘtre utilisĂ©e pour la sortie de donnĂ©es par lots (page). Pour la sortie des donnĂ©es page par page, il sera nĂ©cessaire d'inventer des mĂ©canismes supplĂ©mentaires susceptibles d'avoir une trĂšs faible efficacitĂ© (par exemple, extraire de la base de donnĂ©es tous les enregistrements avec
update_time
au-dessus de la valeur spécifiée et émettre un certain nombre d'enregistrements, en commençant à un certain décalage par rapport au début de l'échantillon).
Vous pouvez augmenter l'efficacité du transfert de données en améliorant légÚrement l'approche précédente. Pour ce faire, nous utiliserons un type entier (entier long) comme valeurs des champs de colonne pour suivre les modifications.
row_ver
colonne
row_ver
. La valeur de champ de cette colonne doit toujours ĂȘtre dĂ©finie / mise Ă jour chaque fois qu'un enregistrement est créé / modifiĂ©. Mais dans ce cas, le champ sera attribuĂ© non pas la date-heure actuelle, mais la valeur d'un compteur augmentĂ©e d'une unitĂ©. Par consĂ©quent, la colonne
row_ver
contiendra des valeurs uniques et peut ĂȘtre utilisĂ©e non seulement pour sortir des donnĂ©es «delta» (donnĂ©es ajoutĂ©es / modifiĂ©es aprĂšs la fin de la session d'Ă©change prĂ©cĂ©dente), mais aussi pour une pagination simple et efficace.
La derniĂšre mĂ©thode proposĂ©e pour minimiser la quantitĂ© de donnĂ©es transfĂ©rĂ©es dans le cadre d'une rĂ©plication de haut niveau me semble la plus optimale et la plus universelle. ArrĂȘtons-nous dessus plus en dĂ©tail.
Transfert de données à l'aide du compteur de version de ligne
Implémentation serveur / maßtre
Dans MS SQL Server, pour implémenter cette approche, il existe un type de colonne spécial -
rowversion
. Chaque base de données a un compteur, qui augmente d'une unité chaque fois que vous ajoutez / modifiez un enregistrement dans une table qui a une colonne de type
rowversion
. La valeur de ce compteur est automatiquement affectée au champ de cette colonne dans l'enregistrement ajouté / modifié. Tarantool DBMS n'a pas de mécanisme intégré similaire. Cependant, dans Tarantool, il n'est pas difficile de l'implémenter manuellement. Considérez comment cela se fait.
Tout d'abord, un peu de terminologie: les tables de Tarantool sont appelées espace et les enregistrements sont appelés tuple. Dans Tarantool, vous pouvez créer des séquences. Les séquences ne sont rien de plus que des générateurs nommés de valeurs ordonnées d'entiers. C'est-à -dire c'est exactement ce dont nous avons besoin pour nos besoins. Ci-dessous, nous allons créer une telle séquence.
Avant d'effectuer une opération de base de données dans Tarantool, vous devez exécuter la commande suivante:
box.cfg{}
Par conséquent, Tarantool commencera à écrire des instantanés et un journal des transactions dans le répertoire actuel.
Créez une séquence
row_version
:
box.schema.sequence.create('row_version', { if_not_exists = true })
L'option
if_not_exists
permet d'exécuter le script de création plusieurs fois: si l'objet existe, Tarantool n'essaiera pas de le recréer. Cette option sera utilisée dans toutes les commandes DDL suivantes.
Créons un espace pour un exemple.
box.schema.space.create('goods', { format = { { name = 'id', type = 'unsigned' }, { name = 'name', type = 'string' }, { name = 'code', type = 'unsigned' }, { name = 'row_ver', type = 'unsigned' } }, if_not_exists = true })
Ici, nous définissons le nom de l'espace (
goods
), les noms des champs et leurs types.
Les champs d'incrémentation automatique de Tarantool sont également créés à l'aide de séquences. Créez une clé primaire à incrémentation automatique pour le champ
id
:
box.schema.sequence.create('goods_id', { if_not_exists = true }) box.space.goods:create_index('primary', { parts = { 'id' }, sequence = 'goods_id', unique = true, type = 'HASH', if_not_exists = true })
Tarantool prend en charge plusieurs types d'index. Le plus souvent, des index des types TREE et HASH sont utilisés, qui sont basés sur les structures correspondant au nom. TREE est le type d'index le plus polyvalent. Il vous permet de récupérer des données de maniÚre ordonnée. Mais pour le choix de l'égalité, HASH est plus adapté. En conséquence, il est conseillé d'utiliser HASH pour la clé primaire (ce que nous avons fait).
Pour utiliser la colonne
row_ver
pour transmettre des données modifiées, vous devez lier les valeurs de séquence
row_ver
aux champs de cette colonne. Mais contrairement à la clé primaire, la valeur du champ dans la colonne
row_ver
doit augmenter d'une
row_ver
, non seulement lors de l'ajout de nouveaux enregistrements, mais également lors de la modification des enregistrements existants. Pour ce faire, vous pouvez utiliser des déclencheurs. Tarantool a deux types de déclencheurs pour les espaces:
before_replace
et
on_replace
. Les dĂ©clencheurs sont dĂ©clenchĂ©s chaque fois que les donnĂ©es de l'espace sont modifiĂ©es (pour chaque tuple affectĂ© par les modifications, la fonction de dĂ©clenchement est dĂ©clenchĂ©e). Contrairement Ă
on_replace
, les déclencheurs
before_replace
vous permettent de modifier les données du tuple pour lequel le déclencheur est exécuté. En conséquence, le dernier type de déclencheurs nous convient.
box.space.goods:before_replace(function(old, new) return box.tuple.new({new[1], new[2], new[3], box.sequence.row_version:next()}) end)
Ce déclencheur remplace la valeur du champ
row_ver
du tuple stocké par la
row_version
séquence
row_version
suivante.
Afin de pouvoir extraire des données de l'espace
goods
sur la colonne
row_ver
, créez un index:
box.space.goods:create_index('row_ver', { parts = { 'row_ver' }, unique = true, type = 'TREE', if_not_exists = true })
Le type d'index est un arbre (
TREE
), car nous devons récupérer les données dans l'ordre croissant des valeurs dans la colonne
row_ver
.
Ajoutez des données à l'espace:
box.space.goods:insert{nil, 'pen', 123} box.space.goods:insert{nil, 'pencil', 321} box.space.goods:insert{nil, 'brush', 100} box.space.goods:insert{nil, 'watercolour', 456} box.space.goods:insert{nil, 'album', 101} box.space.goods:insert{nil, 'notebook', 800} box.space.goods:insert{nil, 'rubber', 531} box.space.goods:insert{nil, 'ruler', 135}
Parce que le premier champ est un compteur d'incrĂ©mentation automatique, nous passons nil Ă la place. Tarantool remplacera automatiquement la valeur suivante. De mĂȘme, vous pouvez passer nil comme valeur des champs dans la colonne
row_ver
- ou ne pas spécifier la valeur du tout, car cette colonne prend la derniÚre position dans l'espace.
Vérifiez le résultat de l'insert:
tarantool> box.space.goods:select()
Comme vous pouvez le voir, le premier et le dernier champ ont été remplis automatiquement. Maintenant, il sera facile d'écrire une fonction pour paginer le déchargement des
goods
:
local page_size = 5 local function get_goods(row_ver) local index = box.space.goods.index.row_ver local goods = {} local counter = 0 for _, tuple in index:pairs(row_ver, { iterator = 'GT' }) do local obj = tuple:tomap({ names_only = true }) table.insert(goods, obj) counter = counter + 1 if counter >= page_size then break end end return goods end
La fonction prend en paramĂštre la valeur
row_ver
du dernier enregistrement reçu (0 pour le premier appel) et renvoie le prochain lot de données modifiées (s'il y en a un, sinon un tableau vide).
La récupération des données dans Tarantool se fait via des index. La fonction
get_goods
utilise l'
row_ver
index
row_ver
pour récupérer les données modifiées. Le type d'itérateur est GT (supérieur à , supérieur à ). Cela signifie que l'itérateur parcourra séquentiellement les valeurs d'index à partir de la valeur suivante aprÚs la clé transmise.
L'itérateur renvoie les tuples. Afin de pouvoir ultérieurement transférer des données via HTTP, il est nécessaire de convertir les tuples en une structure pratique pour une sérialisation ultérieure. Dans l'exemple, la fonction
tomap
standard est utilisée pour cela. Au lieu d'utiliser
tomap
vous pouvez écrire votre propre fonction. Par exemple, nous pourrions vouloir renommer le champ de
name
, ne pas passer le champ de
code
et ajouter le champ de
comment
:
local function unflatten_goods(tuple) local obj = {} obj.id = tuple.id obj.goods_name = tuple.name obj.comment = 'some comment' obj.row_ver = tuple.row_ver return obj end
La taille de page des données de sortie (le nombre d'enregistrements dans une partie) est déterminée par la variable
page_size
. Dans l'exemple, la valeur de
page_size
est 5. Dans un programme rĂ©el, la taille de la page est gĂ©nĂ©ralement plus importante. Cela dĂ©pend de la taille moyenne du tuple spatial. La taille de page optimale peut ĂȘtre sĂ©lectionnĂ©e empiriquement en mesurant le temps de transfert des donnĂ©es. Plus la page est grande, plus le nombre d'allers-retours entre les cĂŽtĂ©s Ă©metteur et rĂ©cepteur est faible. Vous pouvez donc rĂ©duire le temps total de tĂ©lĂ©chargement des modifications. Cependant, si la taille de la page est trop grande, nous prendrons trop de temps au serveur pour sĂ©rialiser la sĂ©lection. Par consĂ©quent, il peut y avoir des retards dans le traitement des autres demandes qui sont parvenues au serveur. Le paramĂštre
page_size
peut ĂȘtre chargĂ© Ă partir du fichier de configuration. Pour chaque espace transmis, vous pouvez dĂ©finir votre propre valeur. Cependant, pour la plupart des espaces, la valeur par dĂ©faut (par exemple, 100) peut convenir.
get_goods
fonction
get_goods
dans le module. Créez un fichier repl.lua contenant la description de la variable
page_size
et la fonction
get_goods
. Ă la fin du fichier, ajoutez la fonction d'exportation:
return { get_goods = get_goods }
Pour charger le module, exécutez:
tarantool> repl = require('repl')
get_goods
fonction
get_goods
:
tarantool> repl.get_goods(0)
Prenez la valeur du champ
row_ver
de la derniĂšre ligne et appelez Ă nouveau la fonction:
tarantool> repl.get_goods(5)
Et encore:
tarantool> repl.get_goods(8)
Comme vous pouvez le voir, avec cette utilisation, la fonction page par page renvoie tous les enregistrements de l'espace
goods
. La derniÚre page est suivie d'une sélection vide.
Nous apporterons des modifications Ă l'espace:
box.space.goods:update(4, {{'=', 6, 'copybook'}}) box.space.goods:insert{nil, 'clip', 234} box.space.goods:insert{nil, 'folder', 432}
Nous avons modifié la valeur du champ de
name
pour un enregistrement et ajouté deux nouveaux enregistrements.
Répétez le dernier appel de fonction:
tarantool> repl.get_goods(8)
La fonction a renvoyé les enregistrements modifiés et ajoutés. Ainsi, la fonction
get_goods
permet d'obtenir des données qui ont changé depuis son dernier appel, qui est la base de la méthode de réplication considérée.
Nous laissons la sortie des résultats via HTTP sous forme de JSON au-delà de la portée de cet article. Vous pouvez en lire plus ici:
https://habr.com/ru/company/mailru/blog/272141/Réalisation de la partie client / esclave
ConsidĂ©rez Ă quoi ressemble la mise en Ćuvre du cĂŽtĂ© rĂ©cepteur. CrĂ©ez un espace cĂŽtĂ© rĂ©ception pour stocker les donnĂ©es tĂ©lĂ©chargĂ©es:
box.schema.space.create('goods', { format = { { name = 'id', type = 'unsigned' }, { name = 'name', type = 'string' }, { name = 'code', type = 'unsigned' } }, if_not_exists = true }) box.space.goods:create_index('primary', { parts = { 'id' }, sequence = 'goods_id', unique = true, type = 'HASH', if_not_exists = true })
La structure de l'espace ressemble Ă la structure de l'espace dans la source. Mais comme nous
row_ver
pas transférer les données reçues ailleurs, la colonne
row_ver
est
row_ver
dans l'espace du récepteur. Dans le champ
id
seront inscrits les identifiants de la source. Par conséquent, cÎté récepteur, il n'est pas nécessaire de l'incrémenter automatiquement.
De plus, nous avons besoin d'un espace pour enregistrer les valeurs
row_ver
:
box.schema.space.create('row_ver', { format = { { name = 'space_name', type = 'string' }, { name = 'value', type = 'string' } }, if_not_exists = true }) box.space.row_ver:create_index('primary', { parts = { 'space_name' }, unique = true, type = 'HASH', if_not_exists = true })
Pour chaque espace chargé (champ
space_name
), nous enregistrerons ici la derniÚre valeur chargée
row_ver
(
value
champ). La clé primaire est la colonne
space_name
.
Créons une fonction pour charger les données de l'espace
goods
via HTTP. Pour ce faire, nous avons besoin d'une bibliothÚque qui implémente un client HTTP. La ligne suivante charge la bibliothÚque et instancie le client HTTP:
local http_client = require('http.client').new()
Nous avons également besoin d'une bibliothÚque pour la désérialisation json:
local json = require('json')
Cela suffit pour créer une fonction de chargement des données:
local function load_data(url, row_ver) local url = ('%s?rowVer=%s'):format(url, tostring(row_ver)) local body = nil local data = http_client:request('GET', url, body, { keepalive_idle = 1, keepalive_interval = 1 }) return json.decode(data.body) end
La fonction exĂ©cute une requĂȘte HTTP Ă l'URL, lui transmet
row_ver
comme paramĂštre et renvoie le rĂ©sultat dĂ©sĂ©rialisĂ© de la requĂȘte.
La fonction de sauvegarde des données reçues est la suivante:
local function save_goods(goods) local n = #goods box.atomic(function() for i = 1, n do local obj = goods[i] box.space.goods:put( obj.id, obj.name, obj.code) end end) end
Le cycle de stockage des données dans l'espace
goods
est placé dans une transaction (la fonction
box.atomic
est utilisée pour cela) afin de réduire le nombre d'opérations sur disque.
Enfin, la fonction de synchronisation des
goods
spatiaux locaux avec la source peut ĂȘtre implĂ©mentĂ©e comme suit:
local function sync_goods() local tuple = box.space.row_ver:get('goods') local row_ver = tuple and tuple.value or 0
Tout d'abord, nous lisons la valeur
row_ver
précédemment enregistrée pour l'espace des
goods
. S'il est absent (la premiÚre session d'échange), alors nous prenons zéro comme
row_ver
. Ensuite, dans la boucle, nous paginons les données modifiées de la source vers l'URL spécifiée. à chaque itération, nous enregistrons les données reçues dans l'espace local correspondant et
row_ver
jour la valeur
row_ver
(dans l'
row_ver
row_ver et dans la variable
row_ver
) - nous prenons la valeur
row_ver
de la derniÚre ligne des données chargées.
Pour se protéger contre les boucles accidentelles (en cas d'erreur dans le programme), la
while
peut ĂȘtre remplacĂ©e par
for
:
for _ = 1, max_req do ...
GrĂące Ă la fonction
sync_goods
, les
goods
dans le récepteur contiendront les derniÚres versions de tous les enregistrements d'espace
goods
dans la source.
De toute Ă©vidence, la suppression des donnĂ©es ne peut pas ĂȘtre diffusĂ©e de cette maniĂšre. Si un tel besoin existe, vous pouvez utiliser la marque de suppression. Ajoutez le champ boolĂ©en
is_deleted
espace des
goods
et utilisez la suppression logique au lieu de supprimer physiquement l'enregistrement - définissez la valeur du champ
is_deleted
sur
true
. Parfois, au lieu du champ booléen
is_deleted
,
is_deleted
plus pratique d'utiliser le champ
deleted
, qui stocke la date-heure de la suppression logique de l'enregistrement. AprÚs avoir effectué une suppression logique, l'enregistrement marqué pour suppression sera transféré de la source au récepteur (selon la logique décrite ci-dessus).
La séquence
row_ver
peut ĂȘtre utilisĂ©e pour transfĂ©rer des donnĂ©es depuis d'autres espaces: il n'est pas nĂ©cessaire de crĂ©er une sĂ©quence distincte pour chaque espace transmis.
Nous avons examiné un moyen efficace de réplication de données de haut niveau dans les applications utilisant le SGBD Tarantool.
Conclusions
- Tarantool DBMS est un produit attrayant et prometteur pour la création d'applications trÚs chargées.
- La réplication de haut niveau offre une approche plus flexible du transfert de données par rapport à la réplication de bas niveau.
- La méthode de réplication de haut niveau envisagée dans l'article permet de minimiser la quantité de données transmises en transférant uniquement les enregistrements qui ont changé depuis la derniÚre session d'échange.