Fəsil 05 · 9 dəq oxu

Replication

Replication

Eyni data-nın bir neçə maşında surətini saxlamaq üç səbəbdən lazımdır: istifadəçiyə coğrafi cəhətdən yaxın olmaq və azaltmaq, bir node çökəndə sistemin işləməyə davam etməsi, yəni , və oxuma yükünü bir neçə maşına yaymaq, yəni read . Data dəyişməsəydi, trivial olardı: bir dəfə kopyalayıb unutmaq olardı. Bütün çətinlik dəyişikliklərdədir.

Təsəvvür edin ki, istifadəçi profilini yeniləyir və bir saniyə sonra səhifəni yeniləyəndə köhnə dəyəri görür. Yaxud iki data mərkəzi eyni sənədi fərqli cür dəyişib və hansının düz olduğunu heç kim demir. Bu fəsil dəyişiklikləri replica-lar arasında yaymağın üç əsas üsulunu, hər birinin zəif nöqtələrini və onlarla yaşamaq üçün qaydaları izah edir.

Leader-based replication

Ən geniş yayılan model leader-based və ya master-slave . Replica-lardan biri leader seçilir; bütün yazmalar yalnız ona gedir. Leader dəyişikliyi lokal storage-ə yazır və log vasitəsilə follower-lərə göndərir. Follower-lər log-u eyni sırada tətbiq edir. Oxumalar istənilən mümkündür, yazmalar isə yalnız leader-dən.

Synchronous və asynchronous

Leader yazmanı client-ə təsdiqləməzdən əvvəl follower-i gözləyirsə, synchronous-dur: follower-də data leader ilə eynidir, amma follower cavab verməyəndə yazma bloklanır. Hamısını synchronous etmək praktiki deyil, çünki bir node-un gecikməsi bütün sistemi dayandırır.

Gözləmirsə, asynchronous-dur: yazma sürətlidir və follower-in vəziyyəti leader-ə təsir etmir, amma leader çöksə, hələ replicate olunmamış yazmalar itir. Client "uğurlu" cavabı alıb, data isə yoxdur. Bu, durability-nin zəifləməsidir.

Praktik kompromis semi-synchronous-dur: bir follower synchronous, qalanları asynchronous. Synchronous follower yavaşlayanda asynchronous follower-lərdən biri onun yerinə keçir. Nəticə: ən azı iki node-da data-nın ən son surəti var.

Yeni follower qurmaq

Faylları sadəcə kopyalamaq olmaz, çünki data kopyalama zamanı dəyişir. Əvəzinə leader-in müəyyən anda snapshot-ı yeni node-a kopyalanır, sonra follower snapshot-dan sonrakı dəyişiklikləri log-dan tələb edir. Bunun üçün snapshot-ın log-dakı dəqiq mövqeyi lazımdır: PostgreSQL-də log sequence number, MySQL-də binlog coordinates.

Follower çökəndə

Follower leader-dən aldığı son transaction-ı diskində bilir və yenidən qalxanda həmin nöqtədən sonrakı dəyişiklikləri istəyir. Bu, catch-up recovery-dir.

Leader çökəndə: failover

Leader düşəndə follower-lərdən biri yeni leader olmalı, client-lər yazmaları ona yönləndirməli, qalan follower-lər isə onu izləməlidir. Bu proses adlanır və üç addımdan ibarətdir: çökməni aşkar etmək, adətən ilə; yeni leader seçmək, ən son data-ya malik olan ; sistemi yenidən konfiqurasiya etmək. Köhnə leader qayıdanda follower olduğunu qəbul etməlidir.

Hər addımda nəsə səhv gedə bilər:

  • Asynchronous yazmalar itir. Yeni leader köhnə leader-in bütün yazmalarını almayıbsa, həmin yazmalar adətən atılır. GitHub-ın məşhur insidenti bu qəbildəndir: köhnəlmiş MySQL follower leader olub, auto-increment primary key-ləri artıq istifadə olunmuş dəyərlərdən təkrar verdi. Redis-dəki həmin key-ləri köhnə qeydlərə bağlamışdı və bəzi istifadəçilər başqalarının şəxsi data-sını gördülər.
  • Split brain. İki node eyni anda özünü leader sayır və hər ikisi yazma qəbul edir. Bəzi sistemlər bir node-u zorla söndürür, amma mexanizm diqqətsiz qurulsa, hər ikisi sönə bilər.
  • seçimi. Qısa lazımsız səbəb olur, məsələn yük zamanı gecikən leader sağlam ola-ola əvəz edilir, bu da yükü daha da artırır. Uzun isə bərpanı gecikdirir.

Bu səbəbdən bir çox operations komandası əl ilə edir. Fəsil 8 və 9 bu problemlərin kökünə, yəni distributed sistemlərdə qeyri-müəyyənliyə qayıdacaq.

Replication log-un formaları

Leader dəyişikliyi follower-ə hansı formada göndərir? Dörd yanaşma var:

ÜsulNə göndərilirProblem
Statement-basedINSERT, UPDATE sətirləri olduğu kimiNOW(), RAND() kimi nondeterministic funksiyalar, auto-increment, trigger-lər fərqli nəticə verir
WAL shippingFəsil 3-dəki write-ahead log-un byte-larıStorage engine-in daxili formatına bağlıdır; leader və follower eyni versiyada olmalıdır, zero-downtime upgrade çətinləşir
Logical (row-based)Sətir səviyyəsində dəyişiklik: insert-də bütün sütunlar, update-də key və yeni dəyərlərStorage engine-dən ayrılıb, fərqli versiyalar və hətta fərqli sistemlər oxuya bilir
Trigger-basedApplication səviyyəsində trigger ayrı cədvələ yazır, kənar proses oxuyurOverhead və bug-lara meyl, amma ən çevikdir

Logical log həm də üçün təməldir: dəyişikliklər , və search index-ə eyni log ilə axır. Fəsil 11 bunu ətraflı açır.

Replication lag-ın problemləri

Asynchronous follower-dən oxuyanda köhnəlmiş data görə bilərsiniz. Yazmanı dayandırsanız, bir müddət sonra bütün replica-lar eyniləşir: buna deyilir. "Eventual" nə qədər çəkdiyini demir: normal halda millisaniyələr, yük altında dəqiqələr. Bu gecikmə üç anomaliya yaradır.

Read-after-write consistency

İstifadəçi şərh yazır, leader-ə gedir; səhifəni yeniləyir, hələ yenilənməmiş follower-dən oxuyur və şərhi görmür. İstifadəçi data-nın itdiyini düşünür. zəmanəti bu halı istisna edir: istifadəçi öz yazdığını həmişə görür, başqalarının yazdığı isə gecikə bilər. Üsullar:

  • İstifadəçinin dəyişdirə biləcəyi data-nı leader-dən, qalanını follower-dən oxumaq: məsələn öz profilini leader-dən, başqalarınınkını follower-dən.
  • Son yazmadan bir dəqiqə ərzində bütün oxumaları leader-ə yönləltmək və ya lag-ı bir dəqiqədən çox olan follower-dən oxumamaq.
  • Client son yazmanın timestamp-ini saxlayır və ən azı o nöqtəyə çatmayıbsa, sorğunu başqasına ötürür.

Bir neçə cihaz olanda çətinləşir: timestamp cihazlar arasında paylaşılmalı, fərqli şəbəkələrdən gələn sorğular eyni data mərkəzinə yönləndirilməlidir.

Monotonic reads

İstifadəçi əvvəlcə az gecikən oxuyur və şərhi görür, sonra çox gecikəndən oxuyur və şərh yoxa çıxır: zamanda geriyə gedir. Monotonic reads bunu qadağan edir: ardıcıl oxumalar heç vaxt daha köhnə vəziyyət qaytarmır. Sadə həll hər istifadəçinin həmişə eyni oxumasıdır, məsələn user id-nin ilə.

Consistent prefix reads

Partition olunmuş sistemlərdə sual və cavab fərqli partition-larda ola bilər və üçüncü şəxs cavabı sualdan əvvəl görür. Consistent prefix reads yazmaların oxucu üçün eyni sırada görünməsini tələb edir. Həll səbəb-nəticə ilə bağlı yazmaları eyni partition-a yazmaqdır; Fəsil 9 buna causality adı ilə qayıdır.

Bu anomaliyalarla application kodunda mübarizə aparmaq çətindir; daha yaxşısı database-in transaction ilə zəmanət verməsidir. Distributed sistemlərə keçiddə bir çox vendor transaction-ları performans naminə atdı; Fəsil 7 və 9 bunun nə qədər əsaslı olduğunu müzakirə edir.

Multi-leader replication

Tək leader-in zəif tərəfi odur ki, hər yazma ondan keçməlidir. Bir neçə node-un yazma qəbul etdiyi modelə multi-leader deyilir: hər leader eyni zamanda digərlərinin follower-idir.

Tək data mərkəzi daxilində nadir hallarda dəyər. Mənalı olduğu üç hal:

  • Bir neçə data mərkəzi. Hər data mərkəzinin öz leader-i var, yazmalar lokal təsdiqlənir və asinxron olaraq digər mərkəzlərə axır. aşağı, data mərkəzi itkisi müstəqil idarə olunur.
  • Offline client-lər. Telefondakı təqvim şəbəkəsiz işləyir, dəyişikliklər sonradan sinxronlaşır. Hər cihaz bir leader-dir, "data mərkəzləri arası" gecikmə isə saatlar və ya günlər ola bilər.
  • Collaborative editing. Bir neçə istifadəçinin eyni sənədi redaktə etməsi eyni problemdir: hər istifadəçinin lokal var.

Yazma konfliktləri

Multi-leader-in böyük problemi eyni qeydin iki leader-də eyni anda fərqli cür dəyişdirilməsidir. Tək leader ikinci yazmanı birincinin bitməsinə qədər gözlədir. Burada isə hər iki yazma lokal qəbul edilib və konflikt yalnız sonradan, asinxron aşkarlanır.

Ən yaxşı strategiya konflikti qarşısını almaqdır: hər qeyd üçün yalnız bir "ev" leader-i təyin etmək, məsələn istifadəçinin bütün yazmaları ən yaxın mərkəzə gedir. Qaçılmaz olanda isə konflikti converge etmək lazımdır, yəni bütün replica-lar eyni nəticəyə gəlməlidir:

  • Last write wins: hər yazmaya id və ya timestamp verib ən böyüyü saxlamaq. Sadədir və data itirir.
  • Birləşdirmə: dəyərləri qarışdırmaq, məsələn əlifba sırası ilə birləşdirilmiş string. Nadir hallarda məna kəsb edir.
  • Konflikti saxlamaq: hər iki dəyəri qeyd edib sonradan application-a və ya istifadəçiyə həll etdirmək.

Application səviyyəsində həll yazmada, zamanı konflikt aşkarlananda handler çağırmaqla, və ya oxumada, növbəti oxuma hər iki versiyanı alıb birləşdirməklə ola bilər. Avtomatik həll üçün CRDT-lər, yəni concurrent dəyişikliklərə riyazi olaraq converge edən data strukturları, və Google Docs-un əsasındakı operational transformation var.

Topologiyalar

All-to-all topologiyada hər leader hər leader-ə göndərir. Circular və star topologiyalarda node-lar aralıq ötürücüdür və bir node çökəndə yol kəsilir. All-to-all-ın problemi sıradır: iki yazma fərqli yollarla fərqli sırada çata bilər, insert-dən əvvəl update gəlir. Düzgün həll üçün Fəsil 9-dakı version vector-lər lazımdır.

Leaderless replication

Üçüncü yanaşma leader anlayışını atır. Amazon-un Dynamo dizaynından sonra Cassandra, Riak və Voldemort bu modeli yayıb. Client yazmanı eyni anda bir neçə göndərir, oxumanı da bir neçəsindən edir.

Quorum

n olsun. Yazma w təsdiqləyəndə uğurlu sayılır, oxuma r cavab alır. Şərt belədir:

w + r > n

Bu halda oxuduğunuz r ən azı biri ən son yazmanı görüb. Tipik seçim n = 3, w = 2, r = 2-dir: bir node çöksə də, oxuma və yazma davam edir. Çox oxunan sistemlərdə w = n, r = 1 seçilir: oxumalar sürətli, yazmalar isə bir node çökəndə dayanır.

Çökük node qayıdanda köhnəlmiş olur. Bunu iki mexanizm düzəldir: read repair, client oxuyanda fərqli versiyalar görüb köhnə yenisini yazır, və anti-entropy, arxa plan prosesi müqayisə edib fərqləri kopyalayır.

Quorum-un məhdudiyyətləri

w + r > n yazmanın görünməsinə zəmanət verir, amma incə hallar qalır: iki yazma concurrent olanda hansının qalib olduğu aydın deyil; oxuma yazma ilə eyni anda olanda nəticə qeyri-müəyyəndir; yazma w-ə çatmayanda olunmur və uğurlu replica-lar yeni dəyəri saxlayır. Buna görə leaderless sistemlər yalnız vəd edir, kimi zəmanətlər isə yoxdur.

Sloppy quorum və hinted handoff

Şəbəkə kəsilməsində client w sayda "düzgün" çata bilmir. Ya yazmanı rədd etmək, ya da müvəqqəti olaraq başqa node-lara yazmaq olar; ikincisi sloppy quorum-dur. Şəbəkə bərpa olunanda müvəqqəti node-lar yazmaları əsl replica-lara ötürür: hinted handoff. artır, amma w + r > n şərti artıq oxumanın ən son yazmanı görməsinə zəmanət vermir, çünki yazma "səhv" node-lardadır.

Concurrent yazmaları aşkar etmək

Leaderless sistemdə konfliktlər normadır: iki client eyni key-ə eyni anda yazanda replica-lar fərqli sırada ala bilər. "Concurrent" sözünü dəqiq təyin edək: A əməliyyatı B-dən əvvəl baş verib, əgər B A-nın nəticəsini görüb və ya ona əsaslanıb. Nə A B-dən əvvəl, nə B A-dan əvvəldirsə, onlar concurrent-dir. Fiziki vaxt yox, bir-birindən xəbərdarlıq önəmlidir.

Bunun üçün server hər key üçün version nömrəsi saxlayır. Client yazmazdan əvvəl oxuyur, mövcud versiyaları birləşdirir və yazanda hansı versiyanı gördüyünü bildirir. Server həmin versiyadan köhnələri silir, görülməyənləri isə sibling kimi saxlayır. Bir neçə hər öz sayğacı olur və onların toplusu version vector adlanır.

Sibling-ləri birləşdirmək application-ın işidir. Alış-veriş səbətində union əlverişlidir, amma silmə problemlidir: bir sibling-də məhsul silinib, digərində var, union onu qaytarır. Həll tombstone-dur: silməni açıq işarə ilə qeyd etmək. Bu məntiq mürəkkəb olduğuna görə CRDT-lər cəlbedicidir.

Üç yanaşmanın müqayisəsi

XüsusiyyətSingle-leaderMulti-leaderLeaderless
Yazma qəbul edən nodebirbir neçəistənilən
Konfliktyoxdurvar, asinxron aşkarlanırvar, version vector ilə
Leader çökəndə lazımdırdigər leader işləyir yoxdur
Yazma çox mərkəzdəyüksəkaşağıaşağı
Consistency zəmanətiən güclüzəifzəif
Tipik istifadəəksər geo-distributed, offlineyüksək tələb edən key-value

Single-leader sadəliyinə görə default-dur. Multi-leader və leaderless və qazandırır, qiyməti application-a sızan konfliktlərdir. Növbəti fəsil ikinci oxu əlavə edir: data-nı node-lar arasında bölmək.

Tapşırıqlar

  1. Bir leader və iki asynchronous follower olan sistemdə leader çökür. Hansı şərtlərdə client-in "uğurlu" cavab aldığı yazma itir? Semi-synchronous rejimə keçid bu riski necə dəyişir və yazma nə edir? Cavabınızı Fəsil 1-dəki percentile-lər baxımından əsaslandırın.
  2. Üç data mərkəzində multi-leader işləyir. İstifadəçi adı unikal olmalıdır. Hansı konflikt həlli strategiyası bu invariant-ı qoruya bilər, hansı qoruya bilməz? Konfliktin qarşısını tamamilə alan dizayn təklif edin və onun qiymətini göstərin.
  3. n = 5 leaderless sistemdə w və r üçün üç fərqli kombinasiya seçin: oxuma-ağır, yazma-ağır və balanslı. Hər biri üçün neçə node çöksə sistemin işlədiyini və sloppy quorum açıq olanda w + r > n zəmanətinin niyə pozulduğunu izah edin.