{"id":52389,"date":"2019-11-07T00:00:00","date_gmt":"2019-11-06T21:00:00","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/kak-realizuetsya-otkazoustojchivaya-veb-arhitektura-v-platforme-mail-ru-cloud-solutions"},"modified":"2020-02-18T14:00:05","modified_gmt":"2020-02-18T11:00:05","slug":"kak-realizuetsya-otkazoustojchivaya-veb-arhitektura-v-platforme-mail-ru-cloud-solutions","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kak-realizuetsya-otkazoustojchivaya-veb-arhitektura-v-platforme-mail-ru-cloud-solutions","title":{"rendered":"Jak wdra\u017cana jest architektura odporna na awarie w platformie Mail.ru Cloud Solutions.","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Jak wdra\u017cana jest architektura odporna na awarie w platformie Mail.ru Cloud Solutions.\" src=\"\/wp-content\/uploads\/2019\/11\/fe7af07f3ac5ca4e75009993b742293e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCze\u015b\u0107, Habr! Jestem Artem Karamyszev, kierownik zespo\u0142u administracji systemowej. <noindex><a rel=\"nofollow\" href=\"https:\/\/mcs.mail.ru\/\">Rozwi\u0105zania chmurowe Mail.Ru (MCS)<\/a><\/noindex>. W ci\u0105gu ostatniego roku mieli\u015bmy wiele premier nowych produkt\u00f3w. Chcieli\u015bmy, aby us\u0142ugi API by\u0142y \u0142atwo skalowalne, odporne na awarie i gotowe na szybki wzrost obci\u0105\u017cenia u\u017cytkownik\u00f3w. Nasza platforma jest zrealizowana na OpenStack, a ja chcia\u0142bym opowiedzie\u0107, jakie problemy z odporno\u015bci\u0105 komponent\u00f3w musieli\u015bmy rozwi\u0105za\u0107, aby uzyska\u0107 system odporny na awarie. My\u015bl\u0119, \u017ce b\u0119dzie to interesuj\u0105ce dla tych, kt\u00f3rzy r\u00f3wnie\u017c rozwijaj\u0105 produkty na OpenStack.<\/p>\n<p>Og\u00f3lna odporno\u015b\u0107 platformy sk\u0142ada si\u0119 z odporno\u015bci jej komponent\u00f3w. Przeto stopniowo przejdziemy przez wszystkie poziomy, na kt\u00f3rych zidentyfikowali\u015bmy ryzyka i je wyeliminowali\u015bmy.<\/p>\n<p>Wersj\u0119 wideo tej historii, kt\u00f3rej \u017ar\u00f3d\u0142em by\u0142a prezentacja na konferencji Uptime Day 4, zorganizowanej przez <noindex><a rel=\"nofollow\" href=\"http:\/\/www.itsumma.ru\">ITSumma<\/a><\/noindex>, mo\u017cna obejrze\u0107 <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=3b06MVou-vg&amp;list=PLmXjIrLllpkjwuIGkzBkLbI7oHtUadmvZ&amp;index=5\">na kanale YouTube Uptime Community.<\/a><\/noindex>. <br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Odporno\u015b\u0107 architektury fizycznej<\/h2>\n<p>\nPubliczna cz\u0119\u015b\u0107 chmury MCS obecnie bazuje w dw\u00f3ch centrach danych poziomu Tier III, mi\u0119dzy nimi znajduje si\u0119 w\u0142asne w\u0142\u00f3kno ciemne, zarezerwowane na poziomie fizycznym r\u00f3\u017cnymi trasami, o przepustowo\u015bci 200 Gbit\/s. Poziom Tier III zapewnia wymagany poziom odporno\u015bci fizycznej infrastruktury. <\/p>\n<p>W\u0142\u00f3kno ciemne zosta\u0142o zarezerwowane zar\u00f3wno na poziomie fizycznym, jak i logicznym. Proces rezerwacji kana\u0142\u00f3w by\u0142 iteracyjny, pojawi\u0142y si\u0119 problemy i ci\u0105gle doskonalimy \u0142\u0105czno\u015b\u0107 mi\u0119dzy centrami danych. <\/p>\n<blockquote><p>Na przyk\u0142ad, niedawno podczas prac w studzience obok jednego z centr\u00f3w danych, koparka przebi\u0142a rur\u0119, a wewn\u0105trz tej rury znajdowa\u0142y si\u0119 zar\u00f3wno g\u0142\u00f3wny, jak i zapasowy kabel optyczny. Nasz odporny na awarie kana\u0142 komunikacji z centrum danych okaza\u0142 si\u0119 wra\u017cliwy w jednym punkcie, w studzience. W zwi\u0105zku z tym stracili\u015bmy cz\u0119\u015b\u0107 infrastruktury. Wyci\u0105gn\u0119li\u015bmy wnioski, podj\u0119li\u015bmy szereg dzia\u0142a\u0144, w tym po\u0142o\u017cyli\u015bmy dodatkow\u0105 optyk\u0119 w s\u0105siedniej studzience.<\/p><\/blockquote>\n<p>\nW centrach danych znajduj\u0105 si\u0119 punkty obecno\u015bci dostawc\u00f3w \u0142\u0105czno\u015bci, do kt\u00f3rych przesy\u0142amy nasze prefiksy za po\u015brednictwem BGP. Dla ka\u017cdego kierunku sieci wybierana jest najlepsza metryka, co pozwala zapewni\u0107 r\u00f3\u017cnym klientom najwy\u017csz\u0105 jako\u015b\u0107 po\u0142\u0105czenia. Je\u015bli po\u0142\u0105czenie przez jednego dostawc\u0119 zostaje przerwane, dostosowujemy nasz\u0105 tras\u0119 przez dost\u0119pnych dostawc\u00f3w.<\/p>\n<p>W przypadku awarii dostawcy automatycznie prze\u0142\u0105czamy si\u0119 na nast\u0119pnego. W przypadku awarii jednego z centr\u00f3w danych posiadamy lustrzan\u0105 kopi\u0119 naszych us\u0142ug w drugim centrum, kt\u00f3re przejmuje ca\u0142y ruch.<\/p>\n<p><img decoding=\"async\" alt=\"Jak wdra\u017cana jest architektura odporna na awarie w platformie Mail.ru Cloud Solutions.\" src=\"\/wp-content\/uploads\/2019\/11\/295ca212f48dd074d834154666e5b0c3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Odporno\u015b\u0107 infrastruktury fizycznej<\/i><\/p>\n<h2>Czego u\u017cywamy do zapewnienia odporno\u015bci na poziomie aplikacji<\/h2>\n<p>\nNasz serwis oparty jest na szeregu komponent\u00f3w open source. <\/p>\n<p><b>ExaBGP<\/b> \u2014 serwis, kt\u00f3ry realizuje szereg funkcji z u\u017cyciem protoko\u0142u dynamicznego routingu opartego na BGP. Aktywnie go wykorzystujemy do og\u0142aszania naszych publicznych adres\u00f3w IP, przez kt\u00f3re u\u017cytkownicy uzyskuj\u0105 dost\u0119p do API.<\/p>\n<p><b>HAProxy<\/b> \u2014 wysokoobci\u0105\u017cony balancer, kt\u00f3ry umo\u017cliwia ustawianie bardzo elastycznych regu\u0142 balansowania ruchu na r\u00f3\u017cnych poziomach modelu OSI. U\u017cywamy go do balansowania przed wszystkimi naszymi us\u0142ugami: bazami danych, brokerami wiadomo\u015bci, us\u0142ugami API, us\u0142ugami webowymi, naszymi projektami wewn\u0119trznymi \u2014 wszystko to jest obs\u0142ugiwane przez HAProxy.<\/p>\n<p><b>API application<\/b> \u2014 aplikacja webowa napisana w Pythonie, za pomoc\u0105 kt\u00f3rej u\u017cytkownik zarz\u0105dza swoj\u0105 infrastruktur\u0105 i swoimi us\u0142ugami.<\/p>\n<p><b>Worker application <\/b>(dalej po prostu worker) \u2014 w us\u0142ugach OpenStack to demon infrastrukturalny, kt\u00f3ry pozwala na przesy\u0142anie polece\u0144 API do infrastruktury. Na przyk\u0142ad, tworzenie dysku odbywa si\u0119 w\u0142a\u015bnie w workerze, a zapytanie o utworzenie \u2014 w aplikacji API. <\/p>\n<h2>Standardowa architektura OpenStack Application<\/h2>\n<p>\nWi\u0119kszo\u015b\u0107 us\u0142ug opracowywanych dla OpenStack stara si\u0119 pod\u0105\u017ca\u0107 jednolit\u0105 paradygmat\u0105. Us\u0142uga zwykle sk\u0142ada si\u0119 z dw\u00f3ch cz\u0119\u015bci: API i worker\u00f3w (wykonawc\u00f3w backendu). Zazwyczaj API to aplikacja WSGI napisana w Pythonie, kt\u00f3ra dzia\u0142a jako niezale\u017cny proces (daemon) lub za pomoc\u0105 gotowego serwera webowego Nginx, Apache. API przetwarza zapytanie u\u017cytkownika i przekazuje dalsze instrukcje do realizacji aplikacji worker. Przekazanie odbywa si\u0119 za po\u015brednictwem brokera wiadomo\u015bci, kt\u00f3rym zazwyczaj jest RabbitMQ, inne s\u0105 s\u0142abo wspierane. Gdy wiadomo\u015bci trafiaj\u0105 do brokera, s\u0105 przetwarzane przez worker\u00f3w i w razie potrzeby zwracaj\u0105 odpowied\u017a. <\/p>\n<p>Ten paradygmat zak\u0142ada izolowane wsp\u00f3lne punkty awarii: RabbitMQ i baz\u0119 danych. Jednak RabbitMQ jest izolowany w ramach jednej us\u0142ugi i w teorii mo\u017ce by\u0107 indywidualny dla ka\u017cdej us\u0142ugi. Dlatego w MCS maksymalnie dzielimy te us\u0142ugi, dla ka\u017cdego oddzielnego projektu tworzymy osobn\u0105 baz\u0119, oddzielny RabbitMQ. Takie podej\u015bcie jest dobre, poniewa\u017c w przypadku awarii w niekt\u00f3rych wra\u017cliwych punktach nie psuje si\u0119 ca\u0142a us\u0142uga, a tylko jej cz\u0119\u015b\u0107.<\/p>\n<p>Liczba aplikacji worker nie jest niczym ograniczona, dlatego API mo\u017ce \u0142atwo skalowa\u0107 si\u0119 horyzontalnie za balancerami w celu zwi\u0119kszenia wydajno\u015bci i odporno\u015bci na awarie.<\/p>\n<blockquote><p>W niekt\u00f3rych us\u0142ugach konieczna jest koordynacja wewn\u0105trz serwisu \u2014 gdy zachodz\u0105 z\u0142o\u017cone, sekwencyjne operacje mi\u0119dzy API a workerami. W takim przypadku u\u017cywane jest centralne miejsce koordynacji, system klastrowy typu Redis, Memcache, etcd, kt\u00f3ry pozwala jednemu workerowi powiedzie\u0107 drugiemu, \u017ce to zadanie jest przypisane do niego (\u201eprosz\u0119, nie bierz go\u201d). U\u017cywamy etcd. Z regu\u0142y workerzy aktywnie komunikuj\u0105 si\u0119 z baz\u0105 danych, zapisuj\u0105 i odczytuj\u0105 z niej informacje. Jako baz\u0119 danych u\u017cywamy mariadb, kt\u00f3ra znajduje si\u0119 w klastrze wielomistrzowskim.\n<\/p><\/blockquote>\n<p>\nTaka klasyczna pojedyncza us\u0142uga jest zorganizowana w powszechnie akceptowany spos\u00f3b dla OpenStack. Mo\u017cna j\u0105 traktowa\u0107 jako zamkni\u0119ty system, dla kt\u00f3rego sposoby skalowania i odporno\u015bci na awarie s\u0105 do\u015b\u0107 oczywiste. Na przyk\u0142ad, aby zapewni\u0107 odporno\u015b\u0107 na awarie, przed API wystarczy umie\u015bci\u0107 balancer. Skalowanie worker\u00f3w osi\u0105ga si\u0119 poprzez zwi\u0119kszenie ich liczby. <\/p>\n<p>S\u0142abym punktem ca\u0142ej konstrukcji s\u0105 RabbitMQ i MariaDB. Ich architektura zas\u0142uguje na osobny artyku\u0142. W tym artykule chcia\u0142bym skupi\u0107 si\u0119 na odporno\u015bci na awarie API.<\/p>\n<p><img decoding=\"async\" alt=\"Jak wdra\u017cana jest architektura odporna na awarie w platformie Mail.ru Cloud Solutions.\" src=\"\/wp-content\/uploads\/2019\/11\/f39e5a8ae350864e311bf4db3b9c34b3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Architektura Openstack Application. Balansowanie i odporno\u015b\u0107 na awarie platformy chmurowej<\/i><\/p>\n<h2>Tworzymy odporno\u015b\u0107 na awarie dla balancer\u00f3w HAProxy z pomoc\u0105 ExaBGP<\/h2>\n<p>\nAby nasze API by\u0142y skalowalne, szybkie i odporne na awarie, postawili\u015bmy przed nimi balancer. Wybrali\u015bmy HAProxy. Moim zdaniem, posiada on wszystkie wymagane cechy dla naszego zadania: balansowanie na wielu poziomach OSI, interfejs zarz\u0105dzania, elastyczno\u015b\u0107 i skalowalno\u015b\u0107, du\u017c\u0105 liczb\u0119 metod balansowania, wsparcie dla tabel sesji.<\/p>\n<p>Pierwszy problem, kt\u00f3ry nale\u017ca\u0142o rozwi\u0105za\u0107, to odporno\u015b\u0107 samego balancera. Proste zainstalowanie balancera r\u00f3wnie\u017c tworzy punkt awarii: balancer si\u0119 psuje \u2014 serwis pada. Aby do tego nie dopu\u015bci\u0107, u\u017cyli\u015bmy HAProxy wraz z ExaBGP.<\/p>\n<p>ExaBGP pozwala na realizacj\u0119 mechanizmu sprawdzania stanu serwisu. U\u017cyli\u015bmy tego mechanizmu do monitorowania sprawno\u015bci HAProxy i w przypadku problem\u00f3w wy\u0142\u0105czali\u015bmy serwis HAProxy z BGP. <\/p>\n<p><b>Schemat ExaBGP+HAProxy<\/b><\/p>\n<ol>\n<li>Instalujemy potrzebne oprogramowanie, ExaBGP i HAProxy, na trzech serwerach. <\/li>\n<li>Na ka\u017cdym z serwer\u00f3w tworzymy interfejs loopback.<\/li>\n<li>Na wszystkich trzech serwerach przypisujemy do tego interfejsu ten sam publiczny adres IP.<\/li>\n<li>Publiczny adres IP jest og\u0142aszany w internecie przez ExaBGP. <\/li>\n<\/ol>\n<p>\nOdporno\u015b\u0107 na awarie osi\u0105gamy poprzez og\u0142aszanie tego samego adresu IP ze wszystkich trzech serwer\u00f3w. Z punktu widzenia sieci jeden i ten sam adres jest dost\u0119pny z trzech r\u00f3\u017cnych next hop\u00f3w. Router widzi trzy identyczne trasy, wybiera najbardziej priorytetow\u0105 wed\u0142ug w\u0142asnej metryki (zwykle to ta sama opcja) i ruch kierowany jest tylko do jednego z serwer\u00f3w. <\/p>\n<p>W przypadku problem\u00f3w z dzia\u0142aniem HAProxy lub awarii serwera, ExaBGP przestaje og\u0142asza\u0107 tras\u0119, a ruch p\u0142ynnie prze\u0142\u0105cza si\u0119 na inny serwer. <\/p>\n<p>W ten spos\u00f3b osi\u0105gn\u0119li\u015bmy odporno\u015b\u0107 na awarie dla balancer\u00f3w.<\/p>\n<p><img decoding=\"async\" alt=\"Jak wdra\u017cana jest architektura odporna na awarie w platformie Mail.ru Cloud Solutions.\" src=\"\/wp-content\/uploads\/2019\/11\/9fba0718176dc1266f25a2c01ec87348.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Odporno\u015b\u0107 na awarie balancer\u00f3w HAProxy<\/i><\/p>\n<p>Schemat okaza\u0142 si\u0119 niedoskona\u0142y: nauczyli\u015bmy si\u0119 rezerwowa\u0107 HAProxy, ale nie nauczyli\u015bmy si\u0119 rozk\u0142ada\u0107 obci\u0105\u017cenia wewn\u0105trz serwis\u00f3w. Dlatego nieco rozszerzyli\u015bmy t\u0119 konstrukcj\u0119: przeszli\u015bmy do balansowania pomi\u0119dzy kilkoma publicznymi adresami IP.<\/p>\n<h2>Balansowanie na bazie DNS plus BGP<\/h2>\n<p>\nProblem z \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a\u043e\u0439 obci\u0105\u017cenia przed naszymi HAProxy nadal pozostaje nierozwi\u0105zany. Niemniej jednak, mo\u017cna go do\u015b\u0107 prosto rozwi\u0105za\u0107, tak jak zrobili\u015bmy to u siebie.<\/p>\n<p>Do balansowania trzech serwer\u00f3w potrzebne b\u0119d\u0105 3 bia\u0142e adresy IP i dobry stary DNS. Ka\u017cdy z tych adres\u00f3w jest przypisywany do interfejsu loopback ka\u017cdego HAProxy i og\u0142aszany w internecie. <\/p>\n<p>W OpenStack do zarz\u0105dzania zasobami u\u017cywany jest katalog us\u0142ug, w kt\u00f3rym definiowany jest punkt ko\u0144cowy API danej us\u0142ugi. W tym katalogu zapisujemy nazw\u0119 domeny \u2014 public.infra.mail.ru, kt\u00f3ra resolwuje si\u0119 przez DNS za pomoc\u0105 trzech r\u00f3\u017cnych adres\u00f3w IP. W rezultacie uzyskujemy rozk\u0142ad obci\u0105\u017cenia pomi\u0119dzy trzema adresami za pomoc\u0105 DNS. <\/p>\n<p>Jednak\u017ce, poniewa\u017c og\u0142aszaj\u0105c bia\u0142e adresy IP, nie zarz\u0105dzamy priorytetami wyboru serwera, wci\u0105\u017c nie jest to balansowanie. Zazwyczaj wybierany b\u0119dzie tylko jeden serwer na podstawie wy\u017cszo\u015bci adresu IP, podczas gdy dwa inne b\u0119d\u0105 bezczynne, poniewa\u017c nie podano \u017cadnych metryk w BGP.<\/p>\n<p>Zacz\u0119li\u015bmy og\u0142asza\u0107 trasy przez ExaBGP z r\u00f3\u017cnymi metrykami. Ka\u017cdy balansuj\u0105cy og\u0142asza wszystkie trzy bia\u0142e adresy IP, ale jeden z nich, g\u0142\u00f3wny dla danego balansuj\u0105cego, jest og\u0142oszony z minimaln\u0105 metryk\u0105. Tak wi\u0119c, p\u00f3ki wszystkie trzy balansuj\u0105ce s\u0105 w akcji, zapytania do pierwszego adresu IP trafiaj\u0105 do pierwszego balansuj\u0105cego, zapytania do drugiego do drugiego, a do trzeciego do trzeciego.<\/p>\n<p>Co si\u0119 dzieje w momencie, gdy jeden z balansuj\u0105cych pada? W przypadku awarii jakiegokolwiek balansuj\u0105cego, jego podstawowy adres wci\u0105\u017c jest og\u0142aszany przez dw\u00f3ch pozosta\u0142ych, a ruch mi\u0119dzy nimi jest redystrybucjonowany. W ten spos\u00f3b przekazujemy u\u017cytkownikowi przez DNS od razu kilka adres\u00f3w IP. Dzi\u0119ki balansowaniu za pomoc\u0105 DNS i r\u00f3\u017cnym metrykom uzyskujemy r\u00f3wnomierny rozk\u0142ad obci\u0105\u017cenia na wszystkie trzy balansuj\u0105ce. I przy tym nie tracimy odporno\u015bci na awarie.<\/p>\n<p><img decoding=\"async\" alt=\"Jak wdra\u017cana jest architektura odporna na awarie w platformie Mail.ru Cloud Solutions.\" src=\"\/wp-content\/uploads\/2019\/11\/1485367a934aea06b68c6d05c184d263.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Balansowanie HAProxy na bazie DNS + BGP<\/i><\/p>\n<h2>Interakcja mi\u0119dzy ExaBGP a HAProxy<\/h2>\n<p>\nZrealizowali\u015bmy wi\u0119c odporno\u015b\u0107 na awarie w przypadku odej\u015bcia serwera, opart\u0105 na zaprzestaniu og\u0142aszania tras. Jednak HAProxy mo\u017ce si\u0119 wy\u0142\u0105czy\u0107 z innych powod\u00f3w ni\u017c awaria serwera: b\u0142\u0119dy administracyjne, awarie w obr\u0119bie us\u0142ugi. Chcemy usun\u0105\u0107 uszkodzony balansuj\u0105cy z obci\u0105\u017cenia i w tych przypadkach potrzebny jest inny mechanizm. <\/p>\n<p>Dlatego, rozwijaj\u0105c wcze\u015bniej przedstawiony schemat, wdro\u017cyli\u015bmy heartbeat mi\u0119dzy ExaBGP a HAProxy. To programowa implementacja interakcji mi\u0119dzy ExaBGP a HAProxy, gdzie ExaBGP wykorzystuje niestandardowe skrypty do sprawdzania statusu aplikacji.<\/p>\n<p>W tym celu w konfiguracji ExaBGP nale\u017cy skonfigurowa\u0107 health checker, kt\u00f3ry b\u0119dzie w stanie sprawdza\u0107 status HAProxy. W naszym przypadku skonfigurowali\u015bmy health backend w HAProxy, a z strony ExaBGP sprawdzamy to za pomoc\u0105 prostego zapytania GET. Je\u015bli og\u0142oszenie przestaje mie\u0107 miejsce, oznacza to, \u017ce HAProxy prawdopodobnie nie dzia\u0142a i nie nale\u017cy go og\u0142asza\u0107. <\/p>\n<p><img decoding=\"async\" alt=\"Jak wdra\u017cana jest architektura odporna na awarie w platformie Mail.ru Cloud Solutions.\" src=\"\/wp-content\/uploads\/2019\/11\/d5cda30043fe02ab81355b28c0d83ac6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>HAProxy Health Check<\/i><\/p>\n<h2>HAProxy Peers: synchronizacja sesji <\/h2>\n<p>\nNast\u0119pnie, co by\u0142o konieczne do zrobienia, to synchronizacja sesji. Przy pracy przez rozproszone load balancery trudno zorganizowa\u0107 przechowywanie informacji o sesjach klient\u00f3w. Jednak HAProxy jest jednym z nielicznych load balancer\u00f3w, kt\u00f3re potrafi\u0105 to zrobi\u0107 dzi\u0119ki funkcjonalno\u015bci Peers \u2014 mo\u017cliwo\u015bci transferu tablic sesji mi\u0119dzy r\u00f3\u017cnymi procesami HAProxy. <\/p>\n<p>Istniej\u0105 r\u00f3\u017cne metody balansowania: proste, takie jak <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/Round-robin_(%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC)\">round-robin<\/a><\/noindex>, oraz zaawansowane, kiedy zapami\u0119tywana jest sesja klienta, a on za ka\u017cdym razem trafia na ten sam serwer, co wcze\u015bniej. Chcieli\u015bmy wdro\u017cy\u0107 drug\u0105 opcj\u0119.<\/p>\n<p>W HAProxy do przechowywania sesji klienta wykorzystuje si\u0119 mechanizm stick-tables. Zachowuj\u0105 one pierwotny adres IP klienta, wybrany adres docelowy (backend) oraz pewne informacje pomocnicze. Zwykle stick-tables s\u0105 u\u017cywane do przechowywania par source-IP + destination-IP, co jest szczeg\u00f3lnie przydatne dla aplikacji, kt\u00f3re nie mog\u0105 przekazywa\u0107 kontekstu sesji u\u017cytkownika przy prze\u0142\u0105czaniu na inny load balancer, na przyk\u0142ad \u2014 w trybie balansowania RoundRobin.<\/p>\n<p>Je\u015bli stick-table nauczy si\u0119 przemieszcza\u0107 mi\u0119dzy r\u00f3\u017cnymi procesami HAProxy (mi\u0119dzy kt\u00f3rymi odbywa si\u0119 balansowanie), nasze load balancery b\u0119d\u0105 mog\u0142y pracowa\u0107 z jednym zestawem stick-tables. To umo\u017cliwi bezproblemowe prze\u0142\u0105czanie sieci klienta przy awarii jednego z load balancer\u00f3w, a praca z sesjami klient\u00f3w b\u0119dzie kontynuowana na tych samych backendach, kt\u00f3re zosta\u0142y wybrane wcze\u015bniej.<\/p>\n<p>Aby dzia\u0142a\u0142o to prawid\u0142owo, nale\u017cy rozwi\u0105za\u0107 problem adresu IP \u017ar\u00f3d\u0142owego load balancera, z kt\u00f3rego nawi\u0105zana jest sesja. W naszym przypadku jest to dynamiczny adres na interfejsie loopback. <\/p>\n<p>Prawid\u0142owe dzia\u0142anie peers osi\u0105ga si\u0119 jedynie w okre\u015blonych warunkach. To znaczy, \u017ce czasy oczekiwania TCP musz\u0105 by\u0107 wystarczaj\u0105co d\u0142ugie, a prze\u0142\u0105czenie wystarczaj\u0105co szybkie, aby sesja TCP nie zd\u0105\u017cy\u0142a si\u0119 zerwa\u0107. Niemniej jednak pozwala to na p\u0142ynne prze\u0142\u0105czanie. <\/p>\n<p>W naszym IaaS mamy us\u0142ug\u0119 opart\u0105 na tej samej technologii. To <noindex><a rel=\"nofollow\" href=\"https:\/\/mcs.mail.ru\/app\/services\/infra\/balancers-list\/\">Load Balancer jako us\u0142uga dla OpenStack<\/a><\/noindex>, kt\u00f3ra nazywa si\u0119 Octavia. Opiera si\u0119 ona na dw\u00f3ch procesach HAProxy, w kt\u00f3rych od pocz\u0105tku zaimplementowano wsparcie dla peers. W tej us\u0142udze sprawdzi\u0142y si\u0119 one doskonale.<\/p>\n<p>Na rysunku schematycznie przedstawiono przenoszenie tabel peers mi\u0119dzy trzema instancjami HAProxy, zaproponowano konfiguracj\u0119, jak mo\u017cna to ustawi\u0107:<\/p>\n<p><img decoding=\"async\" alt=\"Jak wdra\u017cana jest architektura odporna na awarie w platformie Mail.ru Cloud Solutions.\" src=\"\/wp-content\/uploads\/2019\/11\/d31fab761da627923345b7ace7f0b943.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>HAProxy Peers (synchronizacja sesji)<\/i><\/p>\n<p>Je\u015bli b\u0119dziesz wdra\u017ca\u0107 taki sam schemat, trzeba dok\u0142adnie przetestowa\u0107 jego dzia\u0142anie. Nie ma pewno\u015bci, \u017ce zadzia\u0142a w ten sam spos\u00f3b w 100% przypadk\u00f3w. Niemniej jednak przynajmniej nie stracisz tabel stick, kiedy trzeba zapami\u0119ta\u0107 adres IP \u017ar\u00f3d\u0142a klienta.<\/p>\n<h2>Limit liczby r\u00f3wnoczesnych zapyta\u0144 od jednego i tego samego klienta<\/h2>\n<p>\nWszystkie us\u0142ugi dost\u0119pne publicznie, w tym nasze API, mog\u0105 by\u0107 nara\u017cone na lawiny zapyta\u0144. Powody mog\u0105 by\u0107 ca\u0142kowicie r\u00f3\u017cne, od b\u0142\u0119d\u00f3w u\u017cytkownik\u00f3w, po celowe ataki. Regularnie jeste\u015bmy DDoS-owani po adresach IP. Klienci cz\u0119sto myl\u0105 si\u0119 w swoich skryptach, powoduj\u0105c mini-DDoSy.<\/p>\n<p>W ka\u017cdym razie konieczne jest przewidzenie dodatkowej ochrony. Oczywistym rozwi\u0105zaniem jest ograniczenie liczby zapyta\u0144 do API i nie marnowanie czasu procesora na przetwarzanie z\u0142o\u015bliwych zapyta\u0144.<\/p>\n<p>Aby wdro\u017cy\u0107 takie ograniczenia, stosujemy limity szybko\u015bci, zorganizowane na bazie HAProxy, przy pomocy tych samych tabel stick. Limity ustawia si\u0119 do\u015b\u0107 \u0142atwo i pozwala to ograniczy\u0107 u\u017cytkownika pod wzgl\u0119dem liczby zapyta\u0144 do API. Algorytm zapami\u0119tuje adres IP \u017ar\u00f3d\u0142a, z kt\u00f3rego wysy\u0142ane s\u0105 zapytania, i ogranicza liczb\u0119 r\u00f3wnoczesnych zapyta\u0144 od jednego u\u017cytkownika. Oczywi\u015bcie obliczyli\u015bmy \u015bredni profil obci\u0105\u017cenia API dla ka\u017cdej us\u0142ugi i ustawili\u015bmy limit \u2248 10 razy wi\u0119kszy od tej warto\u015bci. Nadal uwa\u017cnie monitorujemy sytuacj\u0119, maj\u0105c r\u0119k\u0119 na pulsie.<\/p>\n<p>Jak to wygl\u0105da w praktyce? Mamy klient\u00f3w, kt\u00f3rzy regularnie korzystaj\u0105 z naszego API do automatycznego skalowania. Tworz\u0105 oko\u0142o dwustu-trzystu maszyn wirtualnych przed po\u0142udniem, a nast\u0119pnie usuwaj\u0105 je p\u00f3\u017anym popo\u0142udniem. Dla OpenStack stworzenie maszyny wirtualnej, a tak\u017ce z us\u0142ugami PaaS, to co najmniej 1000 zapyta\u0144 API, poniewa\u017c interakcja mi\u0119dzy us\u0142ugami r\u00f3wnie\u017c odbywa si\u0119 za po\u015brednictwem API. <\/p>\n<p>Takie przenoszenie zada\u0144 generuje do\u015b\u0107 du\u017c\u0105 obci\u0105\u017cenie. Oszacowali\u015bmy to obci\u0105\u017cenie, zebrali\u015bmy dzienne szczyty, zwi\u0119kszyli\u015bmy je dziesi\u0119ciokrotnie, co sta\u0142o si\u0119 naszym limitem rate. Mamy r\u0119k\u0119 na pulsie. Cz\u0119sto widzimy boty, skanery, kt\u00f3re pr\u00f3buj\u0105 sprawdzi\u0107, czy mamy jakie\u015b skrypty CGA, kt\u00f3re mo\u017cna uruchomi\u0107, intensywnie je eliminujemy.<\/p>\n<h2>Jak aktualizowa\u0107 baz\u0119 kodu bez zauwa\u017cania przez u\u017cytkownik\u00f3w<\/h2>\n<p>\nRealizujemy odporno\u015b\u0107 na awarie tak\u017ce na poziomie proces\u00f3w wdra\u017cania kodu. Przy wdro\u017ceniach zdarzaj\u0105 si\u0119 awarie, ale ich wp\u0142yw na dost\u0119pno\u015b\u0107 us\u0142ug mo\u017cna zminimalizowa\u0107.<\/p>\n<p>Nieustannie aktualizujemy nasze us\u0142ugi i musimy zapewni\u0107 proces aktualizacji bazy kodu bez wp\u0142ywu na u\u017cytkownik\u00f3w. Zrealizowali\u015bmy to, wykorzystuj\u0105c mo\u017cliwo\u015bci zarz\u0105dzania HAProxy oraz implementacj\u0119 Graceful Shutdown w naszych us\u0142ugach.<\/p>\n<p>Aby rozwi\u0105za\u0107 ten problem, trzeba zapewni\u0107 zarz\u0105dzanie load balancerem i \"prawid\u0142owe\" wy\u0142\u0105czanie us\u0142ug:<\/p>\n<ul>\n<li>W przypadku HAProxy zarz\u0105dzanie odbywa si\u0119 przez plik stats, kt\u00f3ry w zasadzie jest socketem i jest definiowany w konfiguracji HAProxy. Mo\u017cna mu przekazywa\u0107 polecenia przez stdio. Jednak naszym g\u0142\u00f3wnym narz\u0119dziem do kontroli konfiguracji jest ansible, dlatego zawiera on wbudowany modu\u0142 do zarz\u0105dzania HAProxy, kt\u00f3ry intensywnie wykorzystujemy. <\/li>\n<li>Wi\u0119kszo\u015b\u0107 naszych us\u0142ug API i Engine wspiera technologie graceful shutdown: podczas wy\u0142\u0105czania czekaj\u0105 na zako\u0144czenie bie\u017c\u0105cego zadania, niezale\u017cnie czy jest to \u017c\u0105danie http, czy jaka\u015b zadanie pomocnicze. To samo dotyczy workera. Zna wszystkie zadania, kt\u00f3re wykonuje i ko\u0144czy prac\u0119, gdy wszystko zosta\u0142o pomy\u015blnie zrealizowane. <\/li>\n<\/ul>\n<p>\nDzi\u0119ki tym dw\u00f3m aspektom, bezpieczny algorytm naszego wdro\u017cenia wygl\u0105da nast\u0119puj\u0105co.<\/p>\n<ol>\n<li>Programista zbiera nowy pakiet kodu (u nas to RPM), testuje w \u015brodowisku dev, testuje na stage, a nast\u0119pnie zostawia w repozytorium stage.<\/li>\n<li>Programista stawia zadanie na wdro\u017cenie z jak najdok\u0142adniejszym opisem \u00abartefakt\u00f3w\u00bb: wersja nowego pakietu, opis nowych funkcjonalno\u015bci oraz inne szczeg\u00f3\u0142y dotycz\u0105ce wdro\u017cenia, je\u015bli zajdzie taka potrzeba.<\/li>\n<li>Administrator systemu rozpoczyna aktualizacj\u0119. Uruchamia playbook Ansible, kt\u00f3ry z kolei wykonuje nast\u0119puj\u0105ce czynno\u015bci: \n<ul>\n<li>Pobiera pakiet z repozytorium stagingowego, aktualizuj\u0105c wersj\u0119 pakietu w repozytorium produkcyjnym.<\/li>\n<li>Tworzy list\u0119 backend\u00f3w aktualizowanej us\u0142ugi.<\/li>\n<li>Wy\u0142\u0105cza pierwszy aktualizowany serwis w HAProxy i czeka na zako\u0144czenie pracy jego proces\u00f3w. Dzi\u0119ki graceful shutdown mamy pewno\u015b\u0107, \u017ce wszystkie bie\u017c\u0105ce zapytania klient\u00f3w zako\u0144cz\u0105 si\u0119 pomy\u015blnie.<\/li>\n<li>Po ca\u0142kowitym zatrzymaniu API, worker\u00f3w i wy\u0142\u0105czeniu HAProxy nast\u0119puje aktualizacja kodu.<\/li>\n<li>Ansible uruchamia us\u0142ugi.<\/li>\n<li>Dla ka\u017cdej us\u0142ugi wykonuje okre\u015blone \u00abruchy\u00bb, kt\u00f3re przeprowadzaj\u0105 testy jednostkowe wed\u0142ug z g\u00f3ry ustalonych kluczowych test\u00f3w. Nast\u0119puje podstawowa weryfikacja nowego kodu.<\/li>\n<li>Je\u015bli na poprzednim etapie nie wykryto b\u0142\u0119d\u00f3w, backend zostaje aktywowany.<\/li>\n<li>Przechodzimy do kolejnego backendu.<\/li>\n<\/ul>\n<\/li>\n<li>Po zaktualizowaniu wszystkich backend\u00f3w uruchamiane s\u0105 testy funkcjonalne. Je\u015bli ich brakuje, programista sprawdza wszelk\u0105 now\u0105 funkcjonalno\u015b\u0107, kt\u00f3r\u0105 wprowadza\u0142.<\/li>\n<\/ol>\n<p>\nNa tym wdro\u017cenie si\u0119 ko\u0144czy.<\/p>\n<p><img decoding=\"async\" alt=\"Jak wdra\u017cana jest architektura odporna na awarie w platformie Mail.ru Cloud Solutions.\" src=\"\/wp-content\/uploads\/2019\/11\/2d889fe1af33653e4bfebabe1cce6552.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Cykl aktualizacji us\u0142ugi<\/i><\/p>\n<p>Ten schemat nie by\u0142by u\u017cyteczny, gdyby\u015bmy nie mieli jednej zasady. Utrzymujemy w ruchu jednocze\u015bnie star\u0105 i now\u0105 wersj\u0119. Z wyprzedzeniem, na etapie rozwoju oprogramowania, zak\u0142ada si\u0119, \u017ce nawet je\u015bli dojdzie do zmian w bazie danych us\u0142ugi, nie b\u0119d\u0105 one \u0142ama\u0142y poprzedniego kodu. W rezultacie nast\u0119puje stopniowa aktualizacja bazy kodowej.<\/p>\n<h2>Podsumowanie<\/h2>\n<p>\nDziel\u0105c si\u0119 w\u0142asnymi przemy\u015bleniami na temat odpornej architektury WEB, chc\u0119 jeszcze raz podkre\u015bli\u0107 jej kluczowe punkty:<\/p>\n<ul>\n<li>fizyczna odporno\u015b\u0107;<\/li>\n<li>odporno\u015b\u0107 sieciowa (load balancery, BGP);<\/li>\n<li>odporno\u015b\u0107 u\u017cywanego i rozwijanego oprogramowania.<\/li>\n<\/ul>\n<p>\n\u017bycz\u0119 wszystkim stabilnego uptime!<br \/>\n<br \/>\u0179r\u00f3d\u0142o: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/mailru\/blog\/474180\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u042f \u0410\u0440\u0442\u0435\u043c \u041a\u0430\u0440\u0430\u043c\u044b\u0448\u0435\u0432, \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f Mail.Ru Cloud Solutions (MCS). \u0417\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0433\u043e\u0434 \u0443 \u043d\u0430\u0441 \u0431\u044b\u043b\u043e \u043c\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432 \u043d\u043e\u0432\u044b\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432. \u041c\u044b \u0445\u043e\u0442\u0435\u043b\u0438 \u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e\u0431\u044b API-\u0441\u0435\u0440\u0432\u0438\u0441\u044b \u043b\u0435\u0433\u043a\u043e \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043b\u0438\u0441\u044c, \u0431\u044b\u043b\u0438 \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u044b\u043c\u0438 \u0438 \u0433\u043e\u0442\u043e\u0432\u044b\u043c\u0438 \u043a \u0431\u044b\u0441\u0442\u0440\u043e\u043c\u0443 \u0440\u043e\u0441\u0442\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438. \u041d\u0430\u0448\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 OpenStack, \u0438 \u044f \u0445\u043e\u0447\u0443 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u043d\u0430\u043c \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0437\u0430\u043a\u0440\u044b\u0442\u044c, [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-52389","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\".\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kak-realizuetsya-otkazoustojchivaya-veb-arhitektura-v-platforme-mail-ru-cloud-solutions\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"pl_PL\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u0430\u044f \u0432\u0435\u0431-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0432 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 Mail.ru Cloud Solutions | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\".\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kak-realizuetsya-otkazoustojchivaya-veb-arhitektura-v-platforme-mail-ru-cloud-solutions\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-11-06T21:00:00+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-02-18T11:00:05+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Jak realizowana jest odporna architektura webowa w platformie Mail.ru Cloud Solutions | ProHoster","description":".","canonical_url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kak-realizuetsya-otkazoustojchivaya-veb-arhitektura-v-platforme-mail-ru-cloud-solutions","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pl_PL","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u0430\u044f \u0432\u0435\u0431-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0432 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 Mail.ru Cloud Solutions | ProHoster","og:description":".","og:url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kak-realizuetsya-otkazoustojchivaya-veb-arhitektura-v-platforme-mail-ru-cloud-solutions","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-11-06T21:00:00+00:00","article:modified_time":"2020-02-18T11:00:05+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"52389","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-24 03:27:21","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 20:44:43","updated":"2026-01-24 03:27:21","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/52389","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/comments?post=52389"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/52389\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=52389"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=52389"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=52389"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}