Paylanmış proqramların tikinti blokları. İkinci yaxınlaşma

Duyurular

Həmkarlar, yayın ortalarında növbə sistemlərinin dizaynı ilə bağlı daha bir məqalə silsiləsi buraxmağı planlaşdırıram: "VTrade Eksperimenti" - ticarət sistemləri üçün çərçivə yazmaq cəhdi. Serialda birja, auksion və mağazanın qurulması nəzəriyyəsi və təcrübəsi araşdırılacaq. Məqalənin sonunda sizi ən çox maraqlandıran mövzulara səs verməyə dəvət edirəm.

Paylanmış proqramların tikinti blokları. İkinci yaxınlaşma

Bu, Erlang/Elixir-də paylanmış reaktiv proqramlar seriyasının yekun məqaləsidir. IN ilk məqalə reaktiv arxitekturanın nəzəri əsaslarını tapa bilərsiniz. İkinci məqalə belə sistemlərin qurulması üçün əsas nümunələri və mexanizmləri təsvir edir.

Bu gün biz kod bazasının və ümumilikdə layihələrin inkişafı məsələlərini qaldıracağıq.

Xidmətlərin təşkili

Real həyatda, bir xidmət inkişaf etdirərkən, tez-tez bir nəzarətçidə bir neçə qarşılıqlı əlaqə nümunəsini birləşdirməlisiniz. Məsələn, layihə istifadəçi profillərinin idarə edilməsi problemini həll edən istifadəçilər xidməti req-resp sorğularına cavab verməli və pub-sub vasitəsilə profil yeniləmələrini bildirməlidir. Bu iş olduqca sadədir: mesajlaşmanın arxasında xidmət məntiqini həyata keçirən və yeniləmələri dərc edən bir nəzarətçi var.

Qüsurlara dözümlü paylanmış xidmət tətbiq etməmiz lazım olduqda vəziyyət daha da mürəkkəbləşir. Təsəvvür edək ki, istifadəçilər üçün tələblər dəyişib:

  1. indi xidmət 5 klaster qovşağında sorğuları emal etməlidir,
  2. fon emal tapşırıqlarını yerinə yetirə bilmək,
  3. və həmçinin profil yeniləmələri üçün abunə siyahılarını dinamik şəkildə idarə edə bilərsiniz.

Şərh: Biz ardıcıl saxlama və məlumatların təkrarlanması məsələsini nəzərdən keçirmirik. Fərz edək ki, bu məsələlər daha əvvəl həll olunub və sistem artıq etibarlı və miqyaslana bilən yaddaş təbəqəsinə malikdir və işləyicilərin onunla qarşılıqlı əlaqə qurma mexanizmləri var.

İstifadəçilər xidmətinin rəsmi təsviri daha da mürəkkəbləşib. Proqramçının nöqteyi-nəzərindən, mesajlaşmanın istifadəsi səbəbindən dəyişikliklər minimaldır. Birinci tələbi yerinə yetirmək üçün biz req-resp mübadilə nöqtəsində balanslaşdırmanı konfiqurasiya etməliyik.

Fon tapşırıqlarını emal etmək tələbi tez-tez baş verir. İstifadəçilərdə bu, istifadəçi sənədlərinin yoxlanılması, yüklənmiş multimedianın işlənməsi və ya məlumatların sosial media ilə sinxronlaşdırılması ola bilər. şəbəkələr. Bu tapşırıqlar bir şəkildə klaster daxilində paylanmalı və icranın gedişatına nəzarət edilməlidir. Buna görə də, iki həll variantımız var: ya əvvəlki məqalədəki tapşırıq paylama şablonundan istifadə edin, ya da uyğun gəlmirsə, prosessorlar hovuzunu bizə lazım olan şəkildə idarə edəcək fərdi tapşırıq planlaşdırıcısı yazın.

3-cü bənd pub-sub şablon uzantısını tələb edir. Və həyata keçirmək üçün, bir pub-sub mübadilə nöqtəsi yaratdıqdan sonra, xidmətimiz daxilində bu nöqtənin nəzarətçisini əlavə olaraq işə salmalıyıq. Beləliklə, sanki mesajlaşma qatından abunəliklərin və abunəliklərin işlənməsi məntiqini istifadəçilərin həyata keçirilməsinə köçürürük.

Nəticədə, problemin parçalanması göstərdi ki, tələblərə cavab vermək üçün müxtəlif qovşaqlarda xidmətin 5 instansiyasını işə salmalı və abunə üçün cavabdeh olan əlavə bir qurum - pub-sub nəzarətçisi yaratmalıyıq.
5 işləyicini işə salmaq üçün xidmət kodunu dəyişməyə ehtiyac yoxdur. Yeganə əlavə hərəkət mübadilə nöqtəsində balanslaşdırma qaydalarının qurulmasıdır, bu barədə bir az sonra danışacağıq.
Əlavə bir mürəkkəblik də var: pub-sub nəzarətçisi və xüsusi tapşırıq planlayıcısı bir nüsxədə işləməlidir. Yenə də mesajlaşma xidməti fundamental xidmət kimi liderin seçilməsi mexanizmini təmin etməlidir.

Lider seçimi

Paylanmış sistemlərdə liderin seçilməsi bəzi yükün paylanmış emalını planlaşdırmaq üçün məsul olan vahid prosesin təyin edilməsi prosedurudur.

Mərkəzləşməyə meylli olmayan sistemlərdə paxos və ya raft kimi universal və konsensusa əsaslanan alqoritmlərdən istifadə olunur.
Mesajlaşma bir broker və mərkəzi element olduğundan, bütün xidmət nəzarətçiləri - namizəd liderləri haqqında bilir. Mesajlaşma səs vermədən lider təyin edə bilər.

Başladıqdan və mübadilə nöqtəsinə qoşulduqdan sonra bütün xidmətlər sistem mesajı alır #'$leader'{exchange = ?EXCHANGE, pid = LeaderPid, servers = Servers}. Əgər LeaderPid ilə üst-üstə düşür pid Mövcud prosesdə lider olaraq təyin edilir və siyahıya alınır Servers bütün qovşaqları və onların parametrlərini ehtiva edir.
Hazırda yenisi görünür və işləyən klaster qovşağı ayrılır, bütün xidmət nəzarətçiləri #'$slave_up'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts} и #'$slave_down'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts} müvafiq.

Beləliklə, bütün komponentlər bütün dəyişikliklərdən xəbərdar olur və klasterin istənilən vaxt bir liderə malik olacağına zəmanət verilir.

Vasitəçilər

Mürəkkəb paylanmış emal proseslərini həyata keçirmək üçün, eləcə də mövcud arxitekturanın optimallaşdırılması problemlərində vasitəçilərdən istifadə etmək rahatdır.
Xidmət kodunu dəyişdirməmək və məsələn, əlavə emal, marşrutlaşdırma və ya mesajların qeydiyyatı problemlərini həll etməmək üçün xidmətdən əvvəl bütün əlavə işləri yerinə yetirəcək bir proxy işləyicisini işə sala bilərsiniz.

Pub-sub optimallaşdırmasının klassik nümunəsi bazarda qiymət dəyişiklikləri kimi yeniləmə hadisələrini yaradan biznes nüvəsi və veb müştəriləri üçün veb-socket API təmin edən giriş səviyyəsi olan N serverləri olan paylanmış proqramdır.
Başa düşsəniz, müştəri xidməti belə görünür:

  • müştəri platforma ilə əlaqə qurur. Trafiki dayandıran server tərəfində bu əlaqəyə xidmət etmək üçün bir proses işə salınır.
  • Xidmət prosesi kontekstində avtorizasiya və yeniləmələrə abunə baş verir. Proses mövzular üçün abunə metodunu çağırır.
  • Nüvədə hadisə yarandıqdan sonra o, əlaqələrə xidmət edən proseslərə çatdırılır.

Təsəvvür edək ki, “xəbərlər” mövzusuna 50000 abunəçimiz var. Abunəçilər 5 server arasında bərabər paylanır. Nəticədə, mübadilə məntəqəsinə gələn hər yeniləmə 50000 10000 dəfə təkrarlanacaq: hər serverdə ondakı abunəçilərin sayına uyğun olaraq XNUMX XNUMX dəfə. Çox təsirli bir sxem deyil, elə deyilmi?
Vəziyyəti yaxşılaşdırmaq üçün mübadilə nöqtəsi ilə eyni ada malik bir proxy təqdim edək. Qlobal ad qeydiyyatçısı ən yaxın prosesi adla qaytara bilməlidir, bu vacibdir.

Gəlin bu proksini giriş qatının serverlərində işə salaq və websocket api-yə xidmət edən bütün proseslərimiz nüvədəki orijinal pub-sub mübadilə nöqtəsinə deyil, ona abunə olacaq. Proksi yalnız unikal abunə olduğu halda nüvəyə abunə olur və gələn mesajı bütün abunəçilərinə təkrarlayır.
Nəticədə kernel və giriş serverləri arasında 5 deyil, 50000 mesaj göndəriləcək.

Marşrutlaşdırma və balanslaşdırma

Tələb - Cavab

Cari mesajlaşma tətbiqində 7 sorğu paylama strategiyası mövcuddur:

  • default. Sorğu bütün nəzarətçilərə göndərilir.
  • round-robin. Sorğular sadalanır və nəzarətçilər arasında dövri olaraq paylanır.
  • consensus. Xidmətə xidmət edən nəzarətçilər liderlərə və qullara bölünür. Sorğular yalnız rəhbərə göndərilir.
  • consensus & round-robin. Qrupun lideri var, lakin sorğular bütün üzvlər arasında bölüşdürülür.
  • sticky. Hash funksiyası hesablanır və xüsusi işləyiciyə təyin edilir. Bu imza ilə sonrakı sorğular eyni işləyiciyə gedir.
  • sticky-fun. Mübadilə nöqtəsini işə saldıqda, üçün hash hesablama funksiyası sticky balanslaşdırma.
  • fun. Yapışqan əyləncəyə bənzər, yalnız siz onu əlavə olaraq yönləndirə, rədd edə və ya əvvəlcədən emal edə bilərsiniz.

Paylanma strategiyası mübadilə nöqtəsi işə salındıqda təyin edilir.

Balanslaşdırma ilə yanaşı, mesajlaşma sizə obyektləri etiketləməyə imkan verir. Sistemdəki etiketlərin növlərinə baxaq:

  • Bağlantı etiketi. Hadisələrin hansı əlaqə vasitəsilə baş verdiyini anlamağa imkan verir. Nəzarətçi prosesi eyni mübadilə nöqtəsinə qoşulduqda, lakin fərqli marşrut açarları ilə istifadə olunur.
  • Xidmət etiketi. İşləyiciləri bir xidmət üçün qruplarda birləşdirməyə və marşrutlaşdırma və balanslaşdırma imkanlarını genişləndirməyə imkan verir. req-resp nümunəsi üçün marşrut xətti xəttidir. Mübadilə məntəqəsinə sorğu göndəririk, sonra onu xidmətə ötürür. Amma əgər işləyiciləri məntiqi qruplara bölmək lazımdırsa, onda parçalanma teqlərdən istifadə etməklə həyata keçirilir. Bir etiketi təyin edərkən, sorğu müəyyən bir nəzarətçi qrupuna göndəriləcək.
  • İstək etiketi. Cavablar arasında fərq qoymağa imkan verir. Sistemimiz asinxron olduğundan, xidmət cavablarını emal etmək üçün sorğu göndərərkən RequestTag müəyyən edə bilməliyik. Bizə hansı müraciətin cavabını ondan anlaya biləcəyik.

pub-sub

Pub-sub üçün hər şey bir az daha sadədir. Mesajların dərc olunduğu mübadilə nöqtəmiz var. Mübadilə məntəqəsi onlara lazım olan marşrut açarlarına abunə olmuş abunəçilər arasında mesajlar paylayır (bu mövzuların analoqu olduğunu deyə bilərik).

Ölçeklenebilirlik və xətaya dözümlülük

Bütövlükdə sistemin miqyaslılığı sistemin təbəqələrinin və komponentlərinin miqyaslanma dərəcəsindən asılıdır:

  • Xidmətlər bu xidmət üçün işləyiciləri olan klasterə əlavə qovşaqlar əlavə etməklə miqyaslanır. Sınaq əməliyyatı zamanı optimal balanslaşdırma siyasətini seçə bilərsiniz.
  • Ayrı bir klaster daxilində mesajlaşma xidmətinin özü ümumiyyətlə ya xüsusi yüklənmiş mübadilə nöqtələrini ayrı-ayrı klaster qovşaqlarına köçürməklə və ya klasterin xüsusi yüklənmiş sahələrinə proxy prosesləri əlavə etməklə miqyaslanır.
  • Bir xüsusiyyət kimi bütün sistemin miqyaslılığı arxitekturanın çevikliyindən və ayrı-ayrı klasterləri ümumi məntiqi varlığa birləşdirmək qabiliyyətindən asılıdır.

Layihənin uğuru çox vaxt miqyaslaşdırmanın sadəliyindən və sürətindən asılıdır. Cari versiyada mesajlaşma tətbiqlə birlikdə böyüyür. 50-60 maşından ibarət çoxluq olmasa belə, federasiyaya müraciət edə bilərik. Təəssüf ki, federasiya mövzusu bu məqalənin əhatə dairəsindən kənardadır.

Rezervasyon

Yük balansını təhlil edərkən, biz artıq xidmət nəzarətçilərinin artıqlığını müzakirə etdik. Bununla belə, mesajlaşma da qorunmalıdır. Bir node və ya maşın qəzası halında, mesajlaşma avtomatik olaraq və ən qısa müddətdə bərpa edilməlidir.

Layihələrimdə yıxılma halında yükü götürən əlavə qovşaqlardan istifadə edirəm. Erlang, OTP tətbiqləri üçün standart paylanmış rejim tətbiqinə malikdir. Paylanmış rejim uğursuz tətbiqi əvvəllər işə salınmış başqa bir qovşaqda işə salmaqla uğursuzluq halında bərpanı həyata keçirir. Proses şəffafdır; uğursuzluqdan sonra proqram avtomatik olaraq əvəzetmə qovşağına keçir. Bu funksionallıq haqqında daha çox oxuya bilərsiniz burada.

Məhsuldarlıq

Gəlin heç olmasa rabbitmq performansını və xüsusi mesajlaşmamızı müqayisə etməyə çalışaq.
Mən tapdım rəsmi nəticələr openstack komandasından rabbitmq sınağı.

6.14.1.2.1.2.2-ci bənddə. Orijinal sənəd RPC CAST nəticəsini göstərir:
Paylanmış proqramların tikinti blokları. İkinci yaxınlaşma

Biz əvvəlcədən ƏS kernelinə və ya erlang VM-ə əlavə parametrlər etməyəcəyik. Test üçün şərtlər:

  • erl seçimləri: +A1 +sbtu.
  • Tək bir erlang node daxilində test mobil versiyada köhnə i7 ilə noutbukda aparılır.
  • Klaster testləri 10G şəbəkəsi olan serverlərdə aparılır.
  • Kod docker konteynerlərində işləyir. NAT rejimində şəbəkə.

Test kodu:

req_resp_bench(_) ->
  W = perftest:comprehensive(10000,
    fun() ->
      messaging:request(?EXCHANGE, default, ping, self()),
      receive
        #'$msg'{message = pong} -> ok
      after 5000 ->
        throw(timeout)
      end
    end
  ),
  true = lists:any(fun(E) -> E >= 30000 end, W),
  ok.

Ssenari 1: Test köhnə i7 mobil versiyası olan noutbukda aparılır. Test, mesajlaşma və xidmət bir Docker konteynerində bir qovşaqda həyata keçirilir:

Sequential 10000 cycles in ~0 seconds (26987 cycles/s)
Sequential 20000 cycles in ~1 seconds (26915 cycles/s)
Sequential 100000 cycles in ~4 seconds (26957 cycles/s)
Parallel 2 100000 cycles in ~2 seconds (44240 cycles/s)
Parallel 4 100000 cycles in ~2 seconds (53459 cycles/s)
Parallel 10 100000 cycles in ~2 seconds (52283 cycles/s)
Parallel 100 100000 cycles in ~3 seconds (49317 cycles/s)

Ssenari 2: Docker (NAT) altında müxtəlif maşınlarda işləyən 3 qovşaq.

Sequential 10000 cycles in ~1 seconds (8684 cycles/s)
Sequential 20000 cycles in ~2 seconds (8424 cycles/s)
Sequential 100000 cycles in ~12 seconds (8655 cycles/s)
Parallel 2 100000 cycles in ~7 seconds (15160 cycles/s)
Parallel 4 100000 cycles in ~5 seconds (19133 cycles/s)
Parallel 10 100000 cycles in ~4 seconds (24399 cycles/s)
Parallel 100 100000 cycles in ~3 seconds (34517 cycles/s)

Bütün hallarda CPU istifadəsi 250%-dən çox olmamışdır.

Nəticələri

Ümid edirəm ki, bu dövr ağıl zibilliyinə bənzəməz və mənim təcrübəm həm paylanmış sistemlərin tədqiqatçıları, həm də biznes sistemləri üçün paylanmış arxitekturaların qurulmasının başlanğıcında olan və Erlang/Elixir-ə maraqla baxan praktiklər üçün real fayda verəcəkdir. , amma buna dəyər olduğuna şübhə edin...

foto @chuttersnap

Sorğuda yalnız qeydiyyatdan keçmiş istifadəçilər iştirak edə bilər. Daxil olunxahiş edirəm.

VTrade Experiment seriyasının bir hissəsi kimi hansı mövzuları daha ətraflı əhatə etməliyəm?

  • Nəzəriyyə: Bazarlar, sifarişlər və onların vaxtı: DAY, GTD, GTC, IOC, FOK, MOO, MOC, LOO, LOC

  • Sifarişlər kitabı. Qruplaşdırma ilə kitabın həyata keçirilməsi nəzəriyyəsi və təcrübəsi

  • Ticarətin vizuallaşdırılması: gənələr, barlar, qətnamələr. Necə saxlamaq və necə yapışdırmaq olar

  • Backoffice. Planlaşdırma və inkişaf. İşçilərin monitorinqi və insidentlərin araşdırılması

  • API. Hansı interfeyslərə ehtiyac olduğunu və onları necə həyata keçirəcəyini anlayaq

  • Məlumat saxlama: ticarət sistemlərində PostgreSQL, Timescale, Tarantool

  • Ticarət sistemlərində reaktivlik

  • Digər. Şərhlərdə yazacam

6 istifadəçi səs verib. 4 istifadəçi bitərəf qalıb.

Mənbə: www.habr.com

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