Beş tələbə və üç paylanmış əsas dəyər mağazası

Və ya ZooKeeper, etcd və Consul KV üçün müştəri C++ kitabxanasını necə yazdıq

Paylanmış sistemlər dünyasında bir sıra tipik vəzifələr var: klasterin tərkibi haqqında məlumatın saxlanması, qovşaqların konfiqurasiyasının idarə edilməsi, nasaz qovşaqların aşkarlanması, liderin seçilməsi və digərləri. Bu problemləri həll etmək üçün xüsusi paylanmış sistemlər - koordinasiya xidmətləri yaradılmışdır. İndi onlardan üçü ilə maraqlanacağıq: ZooKeeper, etcd və Consul. Konsulun bütün zəngin funksiyalarından biz Konsul KV-yə diqqət yetirəcəyik.

Beş tələbə və üç paylanmış əsas dəyər mağazası

Əslində, bütün bu sistemlər xətaya dözümlü, xəttiləşdirilə bilən açar-dəyər anbarlarıdır. Onların məlumat modelləri daha sonra müzakirə edəcəyimiz əhəmiyyətli fərqlərə malik olsalar da, eyni praktik problemləri həll edirlər. Aydındır ki, koordinasiya xidmətindən istifadə edən hər bir proqram onlardan birinə bağlıdır ki, bu da müxtəlif proqramlar üçün eyni problemləri həll edən bir məlumat mərkəzində bir neçə sistemi dəstəkləmək ehtiyacına səbəb ola bilər.

Bu problemi həll etmək ideyası Avstraliya konsaltinq agentliyində yaranıb və onu həyata keçirmək bizim kiçik bir tələbə komandasının üzərinə düşdü, bu barədə danışacağam.

ZooKeeper, etcd və Consul KV ilə işləmək üçün ümumi interfeysi təmin edən kitabxana yaratmağa müvəffəq olduq. Kitabxana C++ dilində yazılmışdır, lakin onu başqa dillərə köçürmək planları var.

Məlumat Modelləri

Üç fərqli sistem üçün ümumi interfeys hazırlamaq üçün onların ortaq cəhətlərini və necə fərqləndiyini başa düşməlisiniz. Gəlin bunu anlayaq.

ZooKeeper

Beş tələbə və üç paylanmış əsas dəyər mağazası

Düymələr ağac şəklində təşkil edilir və qovşaqlar adlanır. Müvafiq olaraq, bir node üçün onun uşaqlarının siyahısını əldə edə bilərsiniz. Znode yaratmaq (yaratmaq) və dəyəri dəyişdirmək (setData) əməliyyatları ayrılır: yalnız mövcud düymələri oxumaq və dəyişdirmək olar. Saatlar bir qovşağın mövcudluğunu yoxlamaq, dəyəri oxumaq və uşaqları əldə etmək əməliyyatlarına əlavə edilə bilər. Watch serverdə müvafiq məlumatların versiyası dəyişdikdə işə salınan birdəfəlik tetikleyicidir. Efemer düyünlər uğursuzluqları aşkar etmək üçün istifadə olunur. Onları yaradan müştərinin sessiyasına bağlıdırlar. Müştəri sessiyanı bağladıqda və ya ZooKeeper-a onun mövcudluğu barədə bildiriş verməyi dayandırdıqda, bu qovşaqlar avtomatik olaraq silinir. Sadə əməliyyatlar dəstəklənir - ən azı biri üçün bu mümkün olmadıqda hamısı uğurlu və ya uğursuz olan əməliyyatlar toplusu.

və s

Beş tələbə və üç paylanmış əsas dəyər mağazası

Bu sistemin tərtibatçıları açıq şəkildə ZooKeeper-dən ilham aldılar və buna görə də hər şeyi fərqli etdilər. Açarların iyerarxiyası yoxdur, lakin onlar leksikoqrafik olaraq sıralanmış dəst təşkil edirlər. Müəyyən bir aralığa aid olan bütün açarları əldə edə və ya silə bilərsiniz. Bu quruluş qəribə görünə bilər, amma əslində çox ifadəlidir və iyerarxik bir baxış onun vasitəsilə asanlıqla təqlid edilə bilər.

etcd standart müqayisə və təyin əməliyyatına malik deyil, lakin daha yaxşı bir şeyə malikdir: əməliyyatlar. Əlbəttə ki, onlar hər üç sistemdə mövcuddur, lakin etcd əməliyyatları xüsusilə yaxşıdır. Onlar üç blokdan ibarətdir: yoxlama, uğur, uğursuzluq. Birinci blokda bir sıra şərtlər, ikinci və üçüncü - əməliyyatlar var. Əməliyyat atomik şəkildə həyata keçirilir. Bütün şərtlər doğrudursa, müvəffəqiyyət bloku yerinə yetirilir, əks halda uğursuzluq bloku yerinə yetirilir. API 3.3-də müvəffəqiyyət və uğursuzluq blokları daxili əməliyyatları ehtiva edə bilər. Yəni, demək olar ki, ixtiyari yuva səviyyəsinin şərti konstruksiyalarını atomik şəkildə yerinə yetirmək mümkündür. Hansı çeklərin və əməliyyatların mövcudluğu haqqında daha çox öyrənə bilərsiniz sənədləşdirmə.

Saatlar burada da mövcuddur, baxmayaraq ki, onlar bir az daha mürəkkəbdir və təkrar istifadə edilə bilər. Yəni, saatı əsas diapazonda quraşdırdıqdan sonra siz yalnız birincini deyil, saatı ləğv edənə qədər bu diapazondakı bütün yeniləmələri alacaqsınız. etcd-də ZooKeeper müştəri seanslarının analoqu icarələrdir.

Konsul K.V.

Burada ciddi iyerarxik quruluş da yoxdur, lakin Konsul mövcud olan görünüşü yarada bilər: siz göstərilən prefikslə bütün açarları əldə edib silə bilərsiniz, yəni açarın “alt ağacı” ilə işləyə bilərsiniz. Belə sorğular rekursiv adlanır. Bundan əlavə, konsul yalnız prefiksdən sonra göstərilən simvolu ehtiva etməyən açarları seçə bilər ki, bu da dərhal "uşaqların" əldə edilməsinə uyğun gəlir. Ancaq xatırlamağa dəyər ki, bu, məhz iyerarxik quruluşun görünüşüdür: əgər onun valideyni yoxdursa, açar yaratmaq və ya uşaqları olan açarı silmək olduqca mümkündür, bu zaman uşaqlar sistemdə saxlanmağa davam edəcəklər.

Beş tələbə və üç paylanmış əsas dəyər mağazası
Saatlar əvəzinə Konsul HTTP sorğularını bloklayır. Əslində bunlar verilənlərin oxunması metoduna adi zənglərdir ki, bunun üçün digər parametrlərlə yanaşı məlumatın son məlum versiyası göstərilir. Serverdəki müvafiq məlumatların cari versiyası göstəriləndən böyükdürsə, cavab dərhal qaytarılır, əks halda - dəyər dəyişdikdə. İstənilən vaxt düymələrə əlavə oluna bilən seanslar da var. Qeyd etmək lazımdır ki, seansların silinməsi əlaqəli açarların silinməsinə səbəb olan etcd və ZooKeeper-dən fərqli olaraq, sessiyanın sadəcə olaraq onlardan ayrıldığı bir rejim var. Mövcuddur əməliyyatlar, filialsız, lakin hər cür çeklərlə.

Hamısını bir yerə yığmaq

ZooKeeper ən ciddi məlumat modelinə malikdir. etcd-də mövcud olan ifadəli diapazon sorğuları nə ZooKeeper, nə də Konsulda effektiv şəkildə təqlid edilə bilməz. Bütün xidmətlərdən ən yaxşısını birləşdirməyə çalışaraq, aşağıdakı əhəmiyyətli istisnalarla demək olar ki, ZooKeeper interfeysinə ekvivalent bir interfeys əldə etdik:

  • ardıcıllıq, konteyner və TTL qovşaqları dəstəklənmir
  • ACL-lər dəstəklənmir
  • set metodu, əgər mövcud deyilsə, açar yaradır (ZK-da setData bu halda səhv qaytarır)
  • set və cas metodları ayrılır (ZK-da onlar mahiyyətcə eyni şeydir)
  • silmə metodu qovşağı alt ağacı ilə birlikdə silir (ZK-da silmə node uşaqları varsa xətanı qaytarır)
  • Hər bir açar üçün yalnız bir versiya var - dəyər versiyası (ZK onlardan üçü var)

Ardıcıl qovşaqların rədd edilməsi, etcd və Consul-un onlar üçün daxili dəstəyinin olmaması ilə əlaqədardır və nəticədə yaranan kitabxana interfeysinin üstündə istifadəçi tərəfindən asanlıqla həyata keçirilə bilər.

Bir təpəni silərkən ZooKeeper-ə bənzər davranışı həyata keçirmək, etcd və Consul-da hər bir açar üçün ayrıca uşaq sayğacının saxlanmasını tələb edəcəkdir. Meta məlumatı saxlamaqdan qaçmağa çalışdığımız üçün bütün alt ağacın silinməsinə qərar verildi.

İcra incəlikləri

Müxtəlif sistemlərdə kitabxana interfeysinin həyata keçirilməsinin bəzi aspektlərinə daha yaxından nəzər salaq.

İerarxiya və s

etcd-də iyerarxik görünüşü saxlamaq ən maraqlı vəzifələrdən biri oldu. Aralıq sorğuları müəyyən bir prefiksi olan düymələrin siyahısını əldə etməyi asanlaşdırır. Məsələn, ilə başlayan hər şeyə ehtiyacınız varsa "/foo", siz diapazon tələb edirsiniz ["/foo", "/fop"). Lakin bu, açarın bütün alt ağacını qaytaracaq, əgər alt ağac böyükdürsə, bu qəbul edilə bilməz. Əvvəlcə əsas tərcümə mexanizmindən istifadə etməyi planlaşdırdıq, zetcd-də həyata keçirilir. Bu, açarın əvvəlinə ağacdakı düyünün dərinliyinə bərabər bir bayt əlavə etməyi nəzərdə tutur. Sizə bir misal deyim.

"/foo" -> "u01/foo"
"/foo/bar" -> "u02/foo/bar"

Sonra açarın bütün uşaqlarını alın "/foo" diapazon tələb etməklə mümkündür ["u02/foo/", "u02/foo0"). Bəli, ASCII-də "0" dərhal sonra dayanır "/".

Bəs bu vəziyyətdə bir zirvənin çıxarılmasını necə həyata keçirmək olar? Belə çıxır ki, növün bütün diapazonlarını silmək lazımdır ["uXX/foo/", "uXX/foo0") XX üçün 01-dən FF-ə qədər. Və sonra qaçdıq əməliyyat sayı limiti bir əməliyyat çərçivəsində.

Nəticədə, həm açarı silməyi, həm də uşaqların siyahısını əldə etməyi effektiv şəkildə həyata keçirməyə imkan verən sadə bir açar çevirmə sistemi icad edildi. Son işarədən əvvəl xüsusi simvol əlavə etmək kifayətdir. Misal üçün:

"/very" -> "/u00very"
"/very/long" -> "/very/u00long"
"/very/long/path" -> "/very/long/u00path"

Sonra açarı silin "/very" silinməyə çevrilir "/u00very" və diapazon ["/very/", "/very0"), və bütün uşaqları əldə etmək - sıradan açarlar üçün sorğuda ["/very/u00", "/very/u01").

ZooKeeper-də açarın çıxarılması

Artıq qeyd etdiyim kimi, ZooKeeper-də uşağı varsa, qovşağı silə bilməzsiniz. Biz alt ağacla birlikdə açarı silmək istəyirik. Mən nə etməliyəm? Biz bunu nikbinliklə edirik. Birincisi, biz rekursiv olaraq alt ağacı keçərək, hər bir təpənin uşaqlarını ayrıca sorğu ilə əldə edirik. Sonra alt ağacın bütün qovşaqlarını düzgün ardıcıllıqla silməyə çalışan bir əməliyyat qururuq. Təbii ki, alt ağacın oxunması və silinməsi arasında dəyişikliklər baş verə bilər. Bu vəziyyətdə əməliyyat uğursuz olacaq. Üstəlik, oxu prosesi zamanı alt ağac dəyişə bilər. Növbəti qovşağın uşaqları üçün sorğu, məsələn, bu node artıq silinibsə, xəta verə bilər. Hər iki halda, bütün prosesi yenidən təkrarlayırıq.

Bu yanaşma, uşaqları varsa, açarın silinməsini çox səmərəsiz edir və daha çox, əgər proqram alt ağacla işləməyə davam edərsə, açarları silir və yaradırsa. Bununla belə, bu, etcd və Consul-da digər üsulların tətbiqini çətinləşdirməyə imkan verdi.

ZooKeeper-də quraşdırılmışdır

ZooKeeper-də ağac strukturu ilə işləyən (yaratmaq, silmək, getChildren) və qovşaqlarda verilənlərlə işləyən (setData, getData) ayrıca metodlar var.Bundan başqa, bütün metodların ciddi ilkin şərtləri var: əgər node artıq varsa, yaratmaq xəta qaytaracaq. yaradılmışdır, silin və ya setData – əgər o, artıq mövcud deyilsə. Bizə açarın mövcudluğu barədə düşünmədən çağırıla bilən müəyyən bir üsul lazım idi.

Seçimlərdən biri silinmədə olduğu kimi optimist yanaşmaqdır. Bir node olub olmadığını yoxlayın. Əgər varsa, setData-ya zəng edin, əks halda yaradın. Sonuncu üsul səhv qaytardısa, hər şeyi yenidən təkrarlayın. Qeyd etmək lazım olan ilk şey varlıq testinin mənasız olmasıdır. Dərhal yarat zəng edə bilərsiniz. Müvəffəqiyyətli tamamlama düyünün mövcud olmadığını və yaradıldığını bildirir. Əks təqdirdə, yaratmaq müvafiq səhvi qaytaracaq, bundan sonra setData-ya zəng etməlisiniz. Əlbəttə ki, zənglər arasında bir zirvə rəqib zəng tərəfindən silinə bilər və setData da xəta qaytarır. Bu vəziyyətdə, hər şeyi yenidən edə bilərsiniz, amma buna dəyərmi?

Hər iki üsul bir səhv qaytararsa, rəqabətli silmənin baş verdiyini dəqiq bilirik. Təsəvvür edək ki, bu silmə set çağırıldıqdan sonra baş verdi. O zaman qurmağa çalışdığımız məna artıq silinib. Bu o deməkdir ki, əslində heç bir şey yazılmamış olsa belə, setin uğurla icra olunduğunu güman edə bilərik.

Daha çox texniki təfərrüatlar

Bu bölmədə paylanmış sistemlərə fasilə verəcəyik və kodlaşdırma haqqında danışacağıq.
Müştərinin əsas tələblərindən biri çarpaz platforma idi: xidmətlərdən ən azı biri Linux, MacOS və Windows sistemlərində dəstəklənməlidir. Başlanğıcda biz yalnız Linux üçün inkişaf etdik və sonradan digər sistemlərdə sınaqdan keçirməyə başladıq. Bu, bir müddət necə yanaşmaq lazım olduğu tamamilə aydın olmayan bir çox problemə səbəb oldu. Nəticədə, hər üç koordinasiya xidməti indi Linux və MacOS-da, Windows-da isə yalnız Consul KV dəstəklənir.

Biz əvvəldən xidmətlərə daxil olmaq üçün hazır kitabxanalardan istifadə etməyə çalışırdıq. ZooKeeper vəziyyətində seçim üzərinə düşdü ZooKeeper C++, nəticədə Windows-da tərtib etmək uğursuz oldu. Bununla belə, bu təəccüblü deyil: kitabxana yalnız linux kimi yerləşdirilib. Konsul üçün yeganə seçim idi ppkonsul. Buna dəstək də əlavə edilməli idi sessiyalar и əməliyyatlar. etcd üçün protokolun ən son versiyasını dəstəkləyən tam hüquqlu kitabxana tapılmadı, ona görə də biz sadəcə olaraq yaradılan grpc müştəri.

ZooKeeper C++ kitabxanasının asinxron interfeysindən ilhamlanaraq biz həm də asinxron interfeys tətbiq etmək qərarına gəldik. ZooKeeper C++ bunun üçün gələcək/vəd primitivlərindən istifadə edir. STL-də, təəssüf ki, onlar çox təvazökarlıqla həyata keçirilir. Məsələn, yox sonra üsul, bu, ötürülən funksiyanı mövcud olduqda gələcək nəticəyə tətbiq edir. Bizim vəziyyətimizdə nəticəni kitabxanamızın formatına çevirmək üçün belə bir üsul lazımdır. Bu problemi həll etmək üçün öz sadə iplik hovuzumuzu tətbiq etməli olduq, çünki müştərinin istəyi ilə Boost kimi ağır üçüncü tərəf kitabxanalarından istifadə edə bilmədik.

Sonrakı tətbiqimiz belə işləyir. Zəng edildikdə, əlavə söz/gələcək cüt yaradılır. Yeni gələcək qaytarılır və keçən biri müvafiq funksiya və əlavə vəd ilə birlikdə növbəyə yerləşdirilir. Hovuzdan gələn ip növbədən bir neçə fyuçers seçir və wait_for istifadə edərək onları sorğulayır. Nəticə mövcud olduqda, müvafiq funksiya çağırılır və onun qaytarılması dəyəri vədə ötürülür.

Biz etcd və Consul-a sorğuları yerinə yetirmək üçün eyni mövzu hovuzundan istifadə etdik. Bu o deməkdir ki, əsas kitabxanalara çoxlu müxtəlif mövzular vasitəsilə daxil olmaq olar. ppconsul mövzu üçün təhlükəsiz deyil, ona görə də ona edilən zənglər kilidlərlə qorunur.
grpc ilə çoxlu mövzulardan işləyə bilərsiniz, lakin incəliklər var. etcd-də saatlar grpc axınları vasitəsilə həyata keçirilir. Bunlar müəyyən tipli mesajlar üçün iki istiqamətli kanallardır. Kitabxana bütün saatlar üçün tək başlıq və gələn mesajları emal edən tək başlıq yaradır. Beləliklə, grpc axına paralel yazmağı qadağan edir. Bu o deməkdir ki, saatı işə salarkən və ya silərkən növbəti sorğunu göndərməzdən əvvəl əvvəlki sorğunun göndərilməsini tamamlayana qədər gözləməlisiniz. Sinxronizasiya üçün istifadə edirik şərti dəyişənlər.

Ümumi

Özünüz baxın: liboffkv.

Komandamız: Raed Romanov, İvan Qluşenkov, Dmitri Kamaldinov, Viktor Krapivenski, Vitali İvanin.

Mənbə: www.habr.com

Добавить комментарий