{"id":55009,"date":"2020-01-10T00:00:00","date_gmt":"2020-01-09T21:00:00","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo"},"modified":"2020-02-18T14:03:04","modified_gmt":"2020-02-18T11:03:04","slug":"arhitektura-hraneniya-i-otdachi-fotografij-v-badoo","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo","title":{"rendered":"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/04d68ff091d9d271bfd352a6639e2f20.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h2>Artur Denisow ( <noindex><a rel=\"nofollow\" href=\"https:\/\/habrahabr.ru\/users\/bo0rsh201\/\" class=\"user_link\">bo0rsh201<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/habrahabr.ru\/company\/badoo\/\">Badoo<\/a><\/noindex>)<\/h2>\n<p>\nBadoo to najwi\u0119ksza na \u015bwiecie strona randkowa. Aktualnie mamy zarejestrowanych oko\u0142o 330 milion\u00f3w u\u017cytkownik\u00f3w na ca\u0142ym \u015bwiecie. Ale, co znacznie wa\u017cniejsze w kontek\u015bcie naszej dzisiejszej rozmowy, to fakt, \u017ce przechowujemy oko\u0142o 3 petabajt\u00f3w zdj\u0119\u0107 u\u017cytkownik\u00f3w. Codziennie nasi u\u017cytkownicy przesy\u0142aj\u0105 oko\u0142o 3,5 miliona nowych zdj\u0119\u0107, a obci\u0105\u017cenie przy odczycie wynosi oko\u0142o <b>80 tysi\u0119cy zapyta\u0144 na sekund\u0119<\/b>. To ca\u0142kiem sporo dla naszego backendu i czasami pojawiaj\u0105 si\u0119 z tym trudno\u015bci.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/4e4690f9b0d95bd76fbbc1cd6805c26c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOpowiem o projektowaniu tego systemu, kt\u00f3ry przechowuje i udost\u0119pnia zdj\u0119cia w og\u00f3le, a tak\u017ce przedstawi\u0119 na to spojrzenie z perspektywy programisty. O tym, jak to wszystko si\u0119 rozwija\u0142o, b\u0119dzie kr\u00f3tka retrospektywa, w kt\u00f3rej zaznacz\u0119 g\u0142\u00f3wne etapy, ale szczeg\u00f3\u0142owo b\u0119d\u0119 m\u00f3wi\u0142 tylko o tych rozwi\u0105zaniach, kt\u00f3re obecnie wykorzystujemy.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nA teraz zacznijmy.<\/p>\n<p><center><div class=\"youtube-placeholder\" data-id=\"SU9ETg39FEg\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/SU9ETg39FEg\/hqdefault.jpg\" alt=\"Odtwarzaj wideo\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><br \/>\nJak ju\u017c wspomnia\u0142em, b\u0119dzie to retrospektywa, a \u017ceby j\u0105 zacz\u0105\u0107, we\u017amy najprostszy przyk\u0142ad.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/22b9627cda7ccadd9869b64e9d043d89.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMamy wsp\u00f3lne zadanie, musimy przyjmowa\u0107, przechowywa\u0107 i udost\u0119pnia\u0107 zdj\u0119cia u\u017cytkownik\u00f3w. W takiej postaci zadanie jest og\u00f3lne, mo\u017cemy u\u017cywa\u0107 czegokolwiek:<\/p>\n<ul>\n<li>nowoczesnego chmurowego magazynu,<\/li>\n<li>rozwi\u0105zania na zasadzie ''box'', kt\u00f3rych teraz te\u017c jest bardzo du\u017co;<\/li>\n<li>mo\u017cemy skonfigurowa\u0107 kilka maszyn w naszym centrum danych, zamontowa\u0107 na nich du\u017ce dyski twarde i przechowywa\u0107 tam zdj\u0119cia.<\/li>\n<\/ul>\n<p>\nBadoo historycznie \u2014 i teraz, i wtedy (w czasach, gdy to si\u0119 dopiero rozwija\u0142o) \u2014 dzia\u0142a na w\u0142asnych serwerach, w naszych w\u0142asnych centrach danych. Dlatego ta opcja by\u0142a dla nas optymalna.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/9434fbabada15670297c551066ad7e71.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPo prostu wzi\u0119li\u015bmy kilka maszyn, nazwali\u015bmy je 'photos', otrzymali\u015bmy taki klaster, kt\u00f3ry przechowuje zdj\u0119cia. Ale wydaje si\u0119, \u017ce czego\u015b brakuje. Aby to wszystko dzia\u0142a\u0142o, musimy w jaki\u015b spos\u00f3b okre\u015bli\u0107, na kt\u00f3rej maszynie jakie zdj\u0119cia b\u0119dziemy przechowywa\u0107. I tutaj te\u017c nie trzeba odkrywa\u0107 Ameryki.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/36258e7107fd8c60f7e9e563a2cb681c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDodajemy do naszego magazynu z informacjami o u\u017cytkownikach jakie\u015b pole. B\u0119dzie to klucz shardingu. W naszym przypadku nazwali\u015bmy go place_id, i ten id miejsca wskazuje na miejsce, w kt\u00f3rym przechowywane s\u0105 zdj\u0119cia u\u017cytkownik\u00f3w. Tworzymy mapy.<\/p>\n<p>Na pierwszym etapie mo\u017cna to robi\u0107 nawet r\u0119cznie \u2014 m\u00f3wimy, \u017ce zdj\u0119cie tego u\u017cytkownika z takim plikem b\u0119dzie l\u0105dowa\u0107 na takim serwerze. Dzi\u0119ki tej mapie zawsze wiemy, kiedy u\u017cytkownik za\u0142adowuje zdj\u0119cie, gdzie je zapisa\u0107 i sk\u0105d je odda\u0107.<\/p>\n<p>To ca\u0142kowicie trywialny schemat, ale ma wystarczaj\u0105co istotne zalety. Po pierwsze, jest prosty, jak ju\u017c powiedzia\u0142em, a po drugie, dzi\u0119ki takiemu podej\u015bciu mo\u017cemy \u0142atwo skalowa\u0107 horyzontalnie, po prostu dostarczaj\u0105c nowe maszyny i dodaj\u0105c je do mapy. Nic wi\u0119cej nie trzeba robi\u0107.<\/p>\n<p>I tak to jaki\u015b czas by\u0142o u nas.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/3effb442702f162f7bad9c18ec54392e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTo by\u0142o gdzie\u015b w 2009 roku. Dostarczali\u015bmy maszyny, dostarczali\u015bmy...<\/p>\n<p>I w pewnym momencie zacz\u0119li\u015bmy zauwa\u017ca\u0107, \u017ce ten schemat ma pewne wady. Jakie wady?<\/p>\n<p>Przede wszystkim to ograniczona pojemno\u015b\u0107. Na jeden fizyczny serwer nie mo\u017cemy zmie\u015bci\u0107 tak wielu dysk\u00f3w twardych, jak by\u015bmy chcieli. A to z up\u0142ywem czasu i wzrostem zbioru danych sta\u0142o si\u0119 pewnym problemem.<\/p>\n<p>I po drugie. To nietypowa konfiguracja maszyn, poniewa\u017c takie maszyny trudno ponownie wykorzysta\u0107 w innych klastrach, s\u0105 do\u015b\u0107 specyficzne, tzn. musz\u0105 by\u0107 niskowydajne, ale jednocze\u015bnie z du\u017cym dyskiem twardym.<\/p>\n<p>To wszystko dzia\u0142o si\u0119 w 2009 roku, ale zasadniczo te wymagania s\u0105 aktualne i dzisiaj. Mamy retrospektyw\u0119, wi\u0119c w 2009 roku wszystko by\u0142o naprawd\u0119 \u017ale z tymi kwestiami.<\/p>\n<p>I ostatni punkt \u2014 to cena.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/e49010eaeab139199d8fe010caa65bf0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCena wtedy by\u0142a bardzo wysoka, i musieli\u015bmy szuka\u0107 jakich\u015b alternatyw. Tzn. musieli\u015bmy jako\u015b lepiej wykorzystywa\u0107 zar\u00f3wno przestrze\u0144 w centrach danych, jak i same fizyczne serwery, na kt\u00f3rych to wszystko by\u0142o umieszczone. Nasi in\u017cynierowie systemowi rozpocz\u0119li du\u017c\u0105 analiz\u0119, w kt\u00f3rej przegl\u0105dali wiele r\u00f3\u017cnych opcji. Zastanawiali si\u0119 nad systemami plik\u00f3w klastr\u00f3w, takimi jak PolyCeph i Lustre. Tam by\u0142y problemy z wydajno\u015bci\u0105 i do\u015b\u0107 trudna eksploatacja. Odrzucili. Pr\u00f3bowali zamontowa\u0107 ca\u0142y zbi\u00f3r danych przez NFS na ka\u017cd\u0105 maszyn\u0119, aby w ten spos\u00f3b jako\u015b to skalowa\u0107. Odczyt te\u017c by\u0142 kiepski, pr\u00f3bowali r\u00f3\u017cnych rozwi\u0105za\u0144 od r\u00f3\u017cnych dostawc\u00f3w.<\/p>\n<p>I w ko\u0144cu zdecydowali\u015bmy si\u0119 na wykorzystanie tzw. Storage Area Network.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/e99402fa641f3bd5fc8d57a9f8995642.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTo s\u0105 du\u017ce SHD, kt\u00f3re s\u0105 skierowane na przechowywanie du\u017cych ilo\u015bci danych. Stanowi\u0105 one p\u00f3\u0142ki z dyskami, kt\u00f3re s\u0105 pod\u0142\u0105czone do ko\u0144cowych maszyn przez \u015bwiat\u0142ow\u00f3d. W ten spos\u00f3b mamy jak\u0105\u015b pul\u0119 maszyn, stosunkowo niewielk\u0105, a te SHD, kt\u00f3re s\u0105 przezroczyste dla naszej logiki wydawania, tzn. dla naszego nginx lub kogo\u015b innego, obs\u0142uguj\u0105 zapytania dotycz\u0105ce tych zdj\u0119\u0107.<\/p>\n<p>To rozwi\u0105zanie mia\u0142o oczywiste zalety. To SHD. Jest skierowane na przechowywanie zdj\u0119\u0107. To wychodzi taniej, ni\u017c gdyby\u015bmy po prostu ustawia\u0107 maszyny z dyskami twardymi.<\/p>\n<p>Druga zaleta. <\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7fd2e7d629cc239096b14c68be5f76bf.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTo, \u017ce pojemno\u015b\u0107 sta\u0142a si\u0119 znacznie wi\u0119ksza, tzn. mo\u017cemy w znacznie mniejszej obj\u0119to\u015bci pomie\u015bci\u0107 znacznie wi\u0119cej storage\u2019u.<\/p>\n<p>Ale by\u0142y te\u017c minusy, kt\u00f3re ujawni\u0142y si\u0119 do\u015b\u0107 szybko. Wraz ze wzrostem liczby u\u017cytkownik\u00f3w i obci\u0105\u017cenia tej systemu zacz\u0119\u0142y pojawia\u0107 si\u0119 problemy z wydajno\u015bci\u0105. A problem jest do\u015b\u0107 oczywisty \u2014 ka\u017cde SHD, kt\u00f3re ma na celu przechowywanie wielu zdj\u0119\u0107 w ma\u0142ym obj\u0119to\u015bci, zazwyczaj cierpi na intensywne odczyty. To w rzeczywisto\u015bci dotyczy ka\u017cdego chmurowego storage\u2019u i czegokolwiek innego. Obecnie nie istnieje idealny storage, kt\u00f3ry by\u0142by niesko\u0144czony skalowalny, do kt\u00f3rego mo\u017cna by wsadzi\u0107 wszystko, co tylko si\u0119 chce, i kt\u00f3ry dobrze by znosi\u0142 odczyty. Szczeg\u00f3lnie przypadkowe odczyty.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/566e836e2fe13a2a3d040ae3fa865d6d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nJak w przypadku naszych zdj\u0119\u0107, poniewa\u017c zdj\u0119cia s\u0105 \u017c\u0105dane w spos\u00f3b nie-sekwencyjny, co znacz\u0105co wp\u0142ywa na ich wydajno\u015b\u0107.<\/p>\n<p>Nawet wed\u0142ug dzisiejszych danych, je\u015bli mamy wi\u0119cej ni\u017c 500 RPS na zdj\u0119cia na maszyn\u0119, do kt\u00f3rej pod\u0142\u0105czony jest storage, zaczynaj\u0105 si\u0119 ju\u017c problemy. I to by\u0142o dla nas do\u015b\u0107 z\u0142e, poniewa\u017c liczba u\u017cytkownik\u00f3w ro\u015bnie, a wszystko powinno tylko pogarsza\u0107 si\u0119. Musimy to jako\u015b zoptymalizowa\u0107.<\/p>\n<p>Aby to zoptymalizowa\u0107, postanowili\u015bmy w\u00f3wczas oczywi\u015bcie przyjrze\u0107 si\u0119 profilowi obci\u0105\u017cenia \u2014 co w og\u00f3le si\u0119 dzieje, co trzeba zoptymalizowa\u0107.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d67310e6b90c4ee1337065790576c9a0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nI w tym momencie wszystko dzia\u0142a na nasz\u0105 korzy\u015b\u0107.<\/p>\n<p>M\u00f3wi\u0142em ju\u017c na pierwszym slajdzie: mamy 80 tysi\u0119cy zapyta\u0144 na sekund\u0119 na odczyt przy zaledwie 3,5 miliona upload\u00f3w dziennie. To oznacza r\u00f3\u017cnic\u0119 na trzy rz\u0119dy wielko\u015bci. Oczywi\u015bcie konieczne jest zoptymalizowanie odczytu i w\u0142a\u015bciwie wiadomo jak.<\/p>\n<p>Jest jeszcze jeden ma\u0142y szczeg\u00f3\u0142. Specyfika us\u0142ugi polega na tym, \u017ce u\u017cytkownik rejestruje si\u0119, wgrywa zdj\u0119cie, a nast\u0119pnie aktywnie przegl\u0105da innych ludzi, lajkuje ich, a jego profil jest intensywnie pokazywany innym. Potem znajduje par\u0119 lub nie, jak to wyjdzie, i na jaki\u015b czas przestaje korzysta\u0107 z us\u0142ugi. W tym momencie, kiedy jest aktywny, jego zdj\u0119cia s\u0105 bardzo popularne \u2014 wiele os\u00f3b je przegl\u0105da. Gdy przestaje to robi\u0107, do\u015b\u0107 szybko wypada z intensywnego pokazywania innym, jak to mia\u0142o miejsce wcze\u015bniej, a jego zdj\u0119cia s\u0105 praktycznie niewidoczne.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/dcc7e306055d8f2b0895f24679bfc3e2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTo znaczy, mamy bardzo ma\u0142y, ale gor\u0105cy zbi\u00f3r danych. Jednak za nim stoi naprawd\u0119 wiele zapyta\u0144. Oczywistym rozwi\u0105zaniem jest dodanie pami\u0119ci podr\u0119cznej.<\/p>\n<p>Pami\u0119\u0107 podr\u0119czna z LRU rozwi\u0105\u017ce wszystkie nasze problemy. Co robimy?<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/2bd0c88a97d928f386db21549fc02500.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDodajemy przed naszym du\u017cym klastrem z magazynem jeszcze jeden stosunkowo niewielki, kt\u00f3ry nazywamy fotokasz\u0105 (photoscache). To w zasadzie po prostu proxy do pami\u0119ci podr\u0119cznej.<\/p>\n<p>Jak to dzia\u0142a od wewn\u0105trz? Oto nasz u\u017cytkownik, oto magazyn. Wszystko jak wcze\u015bniej. Co dodajemy mi\u0119dzy nimi?<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7b7b5f102f1c012b2aef8f02ec731fac.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTo po prostu maszyna z fizycznym szybkim dyskiem lokalnym. Na przyk\u0142ad z SSD. Na tym dysku przechowywana jest jaka\u015b lokalna pami\u0119\u0107 podr\u0119czna.<\/p>\n<p>Jak to wygl\u0105da? U\u017cytkownik wysy\u0142a zapytanie o zdj\u0119cie. NGINX najpierw szuka go w lokalnej pami\u0119ci podr\u0119cznej. Je\u015bli go nie ma, wykonuje po prostu proxy_pass do naszego magazynu, pobiera zdj\u0119cie stamt\u0105d i przekazuje je u\u017cytkownikowi.<\/p>\n<p>Ale to jest bardzo proste i niejasne, co dzieje si\u0119 wewn\u0105trz. Dzia\u0142a to mniej wi\u0119cej tak.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/46be24df171d1008e2a9099b7e4c9be6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPami\u0119\u0107 podr\u0119czna jest logicznie podzielona na trzy warstwy. Kiedy m\u00f3wi\u0119 \u201etrzy warstwy\u201d, nie mam na my\u015bli jakiego\u015b skomplikowanego systemu. Nie, to po prostu trzy katalogi w systemie plik\u00f3w:<\/p>\n<ol>\n<li>To bufor, w kt\u00f3rym znajduj\u0105 si\u0119 w\u0142a\u015bnie wgrane zdj\u0119cia z proxy.<\/li>\n<li>To gor\u0105ca pami\u0119\u0107 podr\u0119czna, w kt\u00f3rej przechowywane s\u0105 aktywnie \u017c\u0105dane zdj\u0119cia.<\/li>\n<li>I zimna pami\u0119\u0107 podr\u0119czna, do kt\u00f3rej stopniowo przesuwane s\u0105 zdj\u0119cia z gor\u0105cej, gdy przychodzi do nich mniej zapyta\u0144.<\/li>\n<\/ol>\n<p>\nAby to dzia\u0142a\u0142o, musimy jako\u015b zarz\u0105dza\u0107 t\u0105 pami\u0119ci\u0105 podr\u0119czn\u0105, musimy przestawia\u0107 zdj\u0119cia w niej itd. To r\u00f3wnie\u017c bardzo prosty proces.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/9b16fe3e99a5f88f06169f6e5eedf2b9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNginx po prostu zapisuje w RAMDisk access.log dla ka\u017cdego \u017c\u0105dania, w kt\u00f3rym wskazuje \u015bcie\u017ck\u0119 do zdj\u0119cia, kt\u00f3re aktualnie obs\u0142u\u017cy\u0142 (oczywi\u015bcie \u015bcie\u017cka wzgl\u0119dna) oraz to, jakim dzia\u0142em zosta\u0142o obs\u0142u\u017cone. Tzn. mo\u017ce tam by\u0107 napisane \u201ezdj\u0119cie 1\u201d, a nast\u0119pnie bufor, gor\u0105cy cache, zimny cache lub proxy.<\/p>\n<p>W zale\u017cno\u015bci od tego musimy jako\u015b podj\u0105\u0107 decyzj\u0119, co zrobi\u0107 ze zdj\u0119ciem.<\/p>\n<p>Na ka\u017cdej maszynie dzia\u0142a ma\u0142y demon, kt\u00f3ry ci\u0105gle odczytuje ten log i w swojej pami\u0119ci przechowuje statystyki dotycz\u0105ce u\u017cycia poszczeg\u00f3lnych zdj\u0119\u0107.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/0dceda5e5ff432d1609520f0c152f152.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPo prostu zbiera tam dane, prowadzi liczniki i okresowo wykonuje nast\u0119puj\u0105ce czynno\u015bci. Aktywnie \u017c\u0105dane zdj\u0119cia, kt\u00f3re zbieraj\u0105 wiele \u017c\u0105da\u0144, przenosi do gor\u0105cego cache, gdziekolwiek si\u0119 znajduj\u0105.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/941c13ecfea88372f3a7eb62d81b0c4e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZdj\u0119cia, kt\u00f3re s\u0105 rzadko \u017c\u0105dane i zacz\u0119\u0142y by\u0107 \u017c\u0105dane rzadziej, stopniowo wypycha z gor\u0105cego cache do zimnego.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/a07235246995ad2fa4e6aeccae23a629.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA kiedy w naszym cache brakuje miejsca, po prostu zaczynamy usuwa\u0107 wszystko z zimnego cache bez rozr\u00f3\u017cnienia. I to, nawiasem m\u00f3wi\u0105c, dzia\u0142a bardzo dobrze.<\/p>\n<p>Aby zdj\u0119cie by\u0142o natychmiast zapisywane podczas proxy w buforze, u\u017cywamy dyrektywy proxy_store, a bufor to r\u00f3wnie\u017c RAMDisk, tzn. dla u\u017cytkownika dzia\u0142a to bardzo szybko. To je\u015bli chodzi o wn\u0119trze samego serwera cache.<\/p>\n<p>Pozosta\u0142o pytanie, jak rozdziela\u0107 \u017c\u0105dania pomi\u0119dzy te serwery.<\/p>\n<p>Powiedzmy, \u017ce mamy klaster dwudziestu maszyn storage i trzy serwery cache (tak si\u0119 z\u0142o\u017cy\u0142o).<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/6bc970b687701f3b6d57e153e3abed18.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMusimy w jaki\u015b spos\u00f3b okre\u015bli\u0107, jakie \u017c\u0105dania dotycz\u0105 jakich zdj\u0119\u0107 i gdzie je umie\u015bci\u0107.<\/p>\n<p>Najprostsza opcja to Round Robin. A mo\u017ce dzia\u0142a\u0107 losowo?<\/p>\n<p>To oczywi\u015bcie ma szereg wad, poniewa\u017c b\u0119dziemy bardzo nieefektywnie wykorzystywa\u0107 cache w takiej sytuacji. \u017b\u0105dania b\u0119d\u0105 trafia\u0142y na jakie\u015b losowe maszyny: tutaj jest cached, na s\u0105siedniej ju\u017c jej nie ma. I wszystko to, je\u015bli w og\u00f3le zadzia\u0142a, to bardzo \u017ale. Nawet przy niewielkiej liczbie maszyn w klastrze.<\/p>\n<p>Musimy w jaki\u015b spos\u00f3b jednoznacznie okre\u015bli\u0107, na kt\u00f3ry serwer trafi kt\u00f3re \u017c\u0105danie.<\/p>\n<p>Jest prosty spos\u00f3b. Bierzemy hash z URL\u2019a lub hash z naszego klucza sharduj\u0105cego, kt\u00f3ry znajduje si\u0119 w URL\u2019u, i dzielimy go ca\u0142kowicie przez liczb\u0119 serwer\u00f3w. Czy to zadzia\u0142a? Tak.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/794a82ac1268b651ab936f0225b802a2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTo znaczy, mamy stuprocentowe \u017c\u0105danie, na przyk\u0142ad dla jakiego\u015b \u00abexample_url\u00bb zawsze b\u0119dzie trafia\u0142o na serwer z indeksem \u201e2\u201d, a pami\u0119\u0107 podr\u0119czna b\u0119dzie stale optymalizowana.<\/p>\n<p>Ale pojawia si\u0119 problem z reshadingiem w takim schemacie. Resharding \u2014 mam na my\u015bli zmian\u0119 liczby serwer\u00f3w.<\/p>\n<p>Za\u0142\u00f3\u017cmy, \u017ce nasz klaster pami\u0119ci podr\u0119cznej przesta\u0142 sobie radzi\u0107, i postanowili\u015bmy doda\u0107 jeszcze jedn\u0105 maszyn\u0119.<\/p>\n<p>Dodajemy.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/5f2fcba4c4f267c069811c3677bd0213.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTeraz wszystko dzieli si\u0119 na cztery, a nie na trzy. W ten spos\u00f3b prawie wszystkie klucze, kt\u00f3re wcze\u015bniej mieli\u015bmy, prawie wszystkie URL-e teraz znajduj\u0105 si\u0119 na innych serwerach. Ca\u0142a pami\u0119\u0107 podr\u0119czna zosta\u0142a uniewa\u017cniona w mgnieniu oka. Wszystkie \u017c\u0105dania sp\u0142yn\u0119\u0142y do naszego klastra storage, sytuacja sta\u0142a si\u0119 z\u0142a, us\u0142uga pad\u0142a, a u\u017cytkownicy byli niezadowoleni. Tak nie chcemy robi\u0107.<\/p>\n<p>Ten wariant r\u00f3wnie\u017c nam nie odpowiada.<\/p>\n<p>Co wi\u0119c musimy zrobi\u0107? Musimy w jaki\u015b spos\u00f3b efektywnie wykorzysta\u0107 pami\u0119\u0107 podr\u0119czn\u0105, stale kierowa\u0107 jedno \u017c\u0105danie na ten sam serwer, ale jednocze\u015bnie by\u0107 odporni na reshading. I takie rozwi\u0105zanie istnieje, nie jest jako\u015b bardzo skomplikowane. Nazywa si\u0119 to consistent hashing.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/1380758686274df9755a7ebf7d1c8753.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nJak to wygl\u0105da?<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/44f97abfac46fa9f361055548819e8a3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nBierzemy jak\u0105\u015b funkcj\u0119 od klucza shardingowego i rozk\u0142adamy wszystkie jej warto\u015bci na okr\u0119gu. To znaczy, w punkcie 0 zbiegaj\u0105 si\u0119 jej minimalne i maksymalne warto\u015bci. Nast\u0119pnie na tym samym okr\u0119gu umieszczamy wszystkie nasze serwery mniej wi\u0119cej w ten spos\u00f3b:<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d470ec615a789913a6baa2726b05acea.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nKa\u017cdy serwer okre\u015blany jest jednym punktem, a sektor, kt\u00f3ry idzie do niego w kierunku wskaz\u00f3wek zegara, odpowiednio, jest obs\u0142ugiwany przez ten host. Kiedy przychodz\u0105 do nas \u017c\u0105dania, od razu widzimy, \u017ce na przyk\u0142ad \u017c\u0105danie A \u2014 ma taki hash \u2014 i jest obs\u0142ugiwane przez serwer 2. \u017b\u0105danie B \u2014 przez serwer 3. I tak dalej.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/fcdbd1caa9f1162cf02e8b0a1c79cb74.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCo w tej sytuacji si\u0119 dzieje podczas reshadingu?<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7386cda826e9419d5f8a9a0d6d6703c8.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNie uniewa\u017cniamy ca\u0142ej pami\u0119ci podr\u0119cznej, jak wcze\u015bniej, i nie przesuwamy wszystkich kluczy, a przesuwamy ka\u017cdy sektor na ma\u0142\u0105 odleg\u0142o\u015b\u0107 w taki spos\u00f3b, aby w zwolnione miejsce, m\u00f3wi\u0105c kolokwialnie, zmie\u015bci\u0142 si\u0119 nasz sz\u00f3sty serwer, kt\u00f3ry chcemy doda\u0107, i dodajemy go tam.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/8680e0cf023ce911b4d162e9102c0545.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOczywi\u015bcie, w takiej sytuacji klucze r\u00f3wnie\u017c mog\u0105 si\u0119 przemieszcza\u0107. Ale przesuwaj\u0105 si\u0119 znacznie mniej ni\u017c wcze\u015bniej. Widzimy, \u017ce nasze dwa pierwsze klucze pozosta\u0142y na swoich serwerach, a zmieni\u0142 si\u0119 tylko serwer cache dla ostatniego klucza. Dzia\u0142a to wystarczaj\u0105co efektywnie, a je\u015bli dodajesz nowe hosty w spos\u00f3b inkrementalny, to nie ma tutaj du\u017cego problemu. Po prostu dodajesz po trochu, czekasz, a\u017c cache znowu si\u0119 nape\u0142ni, i wszystko dzia\u0142a dobrze.<\/p>\n<p>Pozostaje tylko jedno pytanie przy awariach. Za\u0142\u00f3\u017cmy, \u017ce mamy jaki\u015b serwer, kt\u00f3ry przesta\u0142 dzia\u0142a\u0107.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/8e3301af782ce8983716c4bc9add79a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nI w tym momencie nie chcieliby\u015bmy regenerowa\u0107 tej mapy, uniewa\u017cnia\u0107 cz\u0119\u015bci cache i tak dalej, je\u015bli na przyk\u0142ad maszyna zrestartowa\u0142a si\u0119, a my musimy obs\u0142ugiwa\u0107 zapytania. Po prostu trzymamy na ka\u017cdej lokalizacji jedn\u0105 zapasow\u0105 kopi\u0119 cache, kt\u00f3ra pe\u0142ni rol\u0119 zamiennika dla ka\u017cdej maszyny, kt\u00f3ra obecnie jest niedost\u0119pna. I je\u015bli nagle jaki\u015b serwer sta\u0142 si\u0119 niedost\u0119pny, ruch idzie tam. Zasadniczo nie mamy tam \u017cadnego cache, to znaczy jest on zimny, ale przynajmniej zapytania u\u017cytkownik\u00f3w s\u0105 obs\u0142ugiwane. Je\u015bli to kr\u00f3tki interwa\u0142, to spokojnie to przetrwamy. Po prostu wi\u0119ksze obci\u0105\u017cenie trafia na pami\u0119\u0107 masow\u0105. Je\u015bli interwa\u0142 jest d\u0142ugi, mo\u017cemy ju\u017c podj\u0105\u0107 decyzj\u0119 \u2014 usun\u0105\u0107 ten serwer z mapy czy nie, albo mo\u017ce zast\u0105pi\u0107 go innym.<\/p>\n<p>M\u00f3wi\u0105c o systemie cache, przyjrzyjmy si\u0119 wynikom.<\/p>\n<p>Zdawa\u0142oby si\u0119, \u017ce nie ma tu nic skomplikowanego. Ale ten spos\u00f3b zarz\u0105dzania cachem da\u0142 nam wsp\u00f3\u0142czynnik hit\u00f3w na poziomie oko\u0142o 98%. To znaczy, \u017ce z tych 80 tysi\u0119cy zapyta\u0144 na sekund\u0119 tylko 1600 dociera do pami\u0119ci masowej, co jest ca\u0142kowicie normalnym obci\u0105\u017ceniem, kt\u00f3re spokojnie to znosi.<\/p>\n<p>Umie\u015bcili\u015bmy te serwery w trzech naszych centrach danych i uzyskali\u015bmy trzy punkty obecno\u015bci \u2014 Praga, Miami i Hongkong.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/64eef492b65a014d8ba3c808b6579b41.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZatem s\u0105 one mniej wi\u0119cej lokalnie usytuowane wzgl\u0119dem ka\u017cdego z naszych docelowych rynk\u00f3w.<\/p>\n<p>I jako mi\u0142y bonus otrzymali\u015bmy ten cache'uj\u0105cy proxy, na kt\u00f3rym procesor tak naprawd\u0119 stoi bezczynnie, poniewa\u017c do dostarczania tre\u015bci nie jest tak bardzo potrzebny. A tam, przy u\u017cyciu NGINX + Lua, zrealizowali\u015bmy wiele przydatnych funkcjonalno\u015bci.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/b65c609df5e1985240d04ee65a3e4f55.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNa przyk\u0142ad mo\u017cemy eksperymentowa\u0107 z webp lub progresywnym jpeg (to nowoczesne i efektywne formaty), obserwowa\u0107, jak to wp\u0142ywa na ruch, podejmowa\u0107 decyzje, w\u0142\u0105cza\u0107 dla okre\u015blonych kraj\u00f3w itp.; robi\u0107 dynamiczne zmiany rozmiaru lub przycina\u0107 zdj\u0119cia w locie.<\/p>\n<p>To dobry przypadek u\u017cycia, gdy na przyk\u0142ad mamy aplikacj\u0119 mobiln\u0105, kt\u00f3ra pokazuje zdj\u0119cia, a aplikacja mobilna nie chce obci\u0105\u017ca\u0107 CPU klienta, aby za\u017c\u0105da\u0107 du\u017cego zdj\u0119cia i zmienia\u0107 jego rozmiar do jakiego\u015b rozmiaru, aby zmie\u015bci\u0107 je w widoku. Mo\u017cemy po prostu dynamicznie okre\u015bli\u0107 w URL-u jakie\u015b parametry w UPort i pami\u0119\u0107 podr\u0119czna zdj\u0119\u0107 sama przeskaluje zdj\u0119cie. Zazwyczaj dobiera rozmiar, kt\u00f3ry fizycznie mamy na dysku, maksymalnie bliski \u017c\u0105danemu, i dostosowuje go w konkretnych ju\u017c wsp\u00f3\u0142rz\u0119dnych.<\/p>\n<blockquote><p>Przy okazji, udost\u0119pnili\u015bmy nagrania wideo z ostatnich pi\u0119ciu lat konferencji programist\u00f3w system\u00f3w o du\u017cym obci\u0105\u017ceniu. <noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/\">HighLoad++<\/a><\/noindex>. Ogl\u0105daj, poznawaj, dziel si\u0119 i subskrybuj nasz <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/user\/profyclub\">kana\u0142 YouTube<\/a><\/noindex>.<\/p><\/blockquote>\n<p>\nMo\u017cemy tak\u017ce dodawa\u0107 do tego wiele logiki produktowej. Na przyk\u0142ad, mo\u017cemy dodawa\u0107 r\u00f3\u017cne znaki wodne na podstawie parametr\u00f3w URL, mo\u017cemy zamazywa\u0107 zdj\u0119cia, zaciera\u0107 lub pikselizowa\u0107. Kiedy chcemy pokaza\u0107 zdj\u0119cie osoby, ale nie chcemy pokazywa\u0107 jej twarzy, to dzia\u0142a bardzo dobrze, wszystko jest tu zrealizowane.<\/p>\n<p>Co osi\u0105gn\u0119li\u015bmy? Osi\u0105gn\u0119li\u015bmy trzy punkty obecno\u015bci, dobry wska\u017anik trafie\u0144, a jednocze\u015bnie nasz CPU nie stoi bezczynnie na tych maszynach. Teraz sta\u0142 si\u0119, oczywi\u015bcie, wa\u017cniejszy ni\u017c wcze\u015bniej. Musimy stawia\u0107 mocniejsze maszyny, ale to si\u0119 op\u0142aca.<\/p>\n<p>Je\u015bli chodzi o przesy\u0142anie zdj\u0119\u0107, wszystko jest do\u015b\u0107 jasne i oczywiste. My\u015bl\u0119, \u017ce nie odkry\u0142em Ameryki, tak dzia\u0142a praktycznie ka\u017cdy CDN.<\/p>\n<p>I prawdopodobnie do\u015bwiadczony s\u0142uchacz m\u00f3g\u0142by zada\u0107 pytanie: dlaczego po prostu nie wzi\u0105\u0107 i nie zmieni\u0107 wszystkiego na CDN? By\u0142oby mniej wi\u0119cej to samo, wszystkie nowoczesne CDN to potrafi\u0105. I tu jest kilka powod\u00f3w.<\/p>\n<p>Pierwszy to zdj\u0119cia.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/592c10eb74d46191bfcedec120f68556.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTo jeden z kluczowych element\u00f3w naszej infrastruktury, i potrzebujemy nad nimi jak najwi\u0119cej kontroli. Je\u015bli to jakie\u015b rozwi\u0105zanie u zewn\u0119trznego dostawcy, i nie masz nad nim \u017cadnej w\u0142adzy, b\u0119dzie ci do\u015b\u0107 trudno z tym \u017cy\u0107, gdy masz du\u017c\u0105 baz\u0119 danych i kiedy masz bardzo du\u017cy przep\u0142yw zapyta\u0144 u\u017cytkownik\u00f3w.<\/p>\n<p>Podam przyk\u0142ad. Teraz, korzystaj\u0105c z naszej infrastruktury, mo\u017cemy, na przyk\u0142ad, w przypadku jakichkolwiek problem\u00f3w lub podziemnych uderze\u0144, wej\u015b\u0107 na maszyn\u0119, aby przeprowadzi\u0107 debugging. Mo\u017cemy doda\u0107 zbieranie niekt\u00f3rych metryk, kt\u00f3re tylko nas interesuj\u0105, mo\u017cemy eksperymentowa\u0107, patrze\u0107, jak to wp\u0142ynie na wykresy i tak dalej. Obecnie zbieramy bardzo du\u017co statystyk z tego klastra pami\u0119ci podr\u0119cznej. I okresowo na nie patrzymy i d\u0142ugo badamy pewne anomalia. Gdyby to by\u0142o po stronie CDN, kontrolowanie tego by\u0142oby znacznie trudniejsze. Albo, na przyk\u0142ad, gdy dochodzi do jakiejkolwiek awarii, wiemy, co si\u0119 sta\u0142o, wiemy, jak z tym \u017cy\u0107 i jak to pokona\u0107. To pierwszy wniosek.<\/p>\n<p>Drugi wniosek jest r\u00f3wnie\u017c raczej historyczny, poniewa\u017c system rozwija si\u0119 ju\u017c d\u0142ugo, a wiele r\u00f3\u017cnych wymaga\u0144 biznesowych w r\u00f3\u017cnych etapach istnia\u0142o i nie zawsze pasuj\u0105 one do koncepcji CDN.<\/p>\n<p>I punkt, kt\u00f3ry wynika z poprzedniego \u2013<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/007cf3aed2f9cc12185fc3865bf9d196.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTo, \u017ce na fotokashach mamy wiele specyficznej logiki, kt\u00f3rej nie zawsze mo\u017cna doda\u0107 na \u017c\u0105danie. Ma\u0142o prawdopodobne, \u017ce jaki\u015b CDN doda jakie\u015b niestandardowe rzeczy na twoje \u017c\u0105danie. Na przyk\u0142ad, szyfrowanie URL, je\u015bli nie chcesz, aby klient m\u00f3g\u0142 co\u015b zmienia\u0107. Chcesz zmieni\u0107 URL na serwerze i go zaszyfrowa\u0107, a potem przekaza\u0107 tu jakie\u015b dynamiczne parametry.<\/p>\n<p>Jaki wniosek si\u0119 nasuwa? W naszym przypadku CDN to niezbyt dobra alternatywa.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/cfc2963cca2357cf6b0f63419a4dc436.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA w twoim przypadku, je\u015bli masz jakie\u015b specyficzne wymagania biznesowe, mo\u017cesz samodzielnie wdro\u017cy\u0107 to, co ci pokaza\u0142em. I to przy podobnym profilu obci\u0105\u017cenia b\u0119dzie dzia\u0142a\u0107 doskonale.<\/p>\n<p>Ale je\u015bli masz jakie\u015b og\u00f3lne rozwi\u0105zanie, a zadanie nie jest zbyt specyficzne, mo\u017cesz spokojnie korzysta\u0107 z CDN. Albo je\u015bli dla ciebie znacznie wa\u017cniejsze jest czas i zasoby ni\u017c kontrola.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/b76d25404918a5d0d8bf1d6644c8d873.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNowoczesne CDN maj\u0105 praktycznie wszystko, o czym ci teraz opowiedzia\u0142em. Z wyj\u0105tkiem mniej wi\u0119cej kilku funkcji.<\/p>\n<p>To jest w odniesieniu do dostarczania zdj\u0119\u0107.<\/p>\n<p>Przenie\u015bmy si\u0119 teraz nieco naprz\u00f3d w naszej retrospektywie i porozmawiajmy o przechowywaniu.<\/p>\n<p>Rok 2013 trwa\u0142.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f218bfc899512041967842430c02aa9b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSerwery cache'uj\u0105ce do\u0142\u0105czy\u0142y, problemy z wydajno\u015bci\u0105 znikn\u0119\u0142y. Wszystko jest w porz\u0105dku. Dataset ro\u015bnie. W 2013 roku mieli\u015bmy oko\u0142o 80 serwer\u00f3w pod\u0142\u0105czonych do storage, oraz oko\u0142o 40 serwer\u00f3w cache'uj\u0105cych w ka\u017cdym centrum danych. To daje 560 terabajt\u00f3w danych w ka\u017cdym centrum danych, czyli oko\u0142o petabajta w sumie.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/ef741ba4a9164e6940f55e93dfb46ef0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nRazem z rosn\u0105cym dataset'em zacz\u0119\u0142y znacznie wzrasta\u0107 koszty eksploatacyjne. Na czym to polega\u0142o?<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/6cf5e489a4e97bc6e26fc6d4d16505b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nW tym schemacie, kt\u00f3ry jest narysowany \u2014 z SAN, z pod\u0142\u0105czonymi do niego maszynami i cache'ami \u2014 jest bardzo wiele punkt\u00f3w awaryjnych. Je\u015bli z awari\u0105 serwer\u00f3w cache'uj\u0105cych poradzili\u015bmy sobie wcze\u015bniej, tam wszystko jest bardziej przewidywalne i jasne, to po stronie storage by\u0142o znacznie gorzej.<\/p>\n<p>Po pierwsze, sam Storage Area Network (SAN), kt\u00f3ry mo\u017ce ulec awarii.<\/p>\n<p>Po drugie, jest pod\u0142\u0105czony przez \u015bwiat\u0142ow\u00f3d do ko\u0144cowych maszyn. Mog\u0105 wyst\u0105pi\u0107 problemy z kartami optycznymi, switchami.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/6959b79284c5b1244a70a1d64f191893.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nJest ich wprawdzie nieco mniej ni\u017c samego SAN, ale mimo to, s\u0105 to te\u017c punkty awaryjne.<\/p>\n<p>Nast\u0119pnie sama maszyna, kt\u00f3ra jest pod\u0142\u0105czona do storage. Ona r\u00f3wnie\u017c mo\u017ce ulec awarii.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/1801cb502663a4de14329a5e67dfed79.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTak wi\u0119c mamy trzy punkty awaryjne.<\/p>\n<p>Ponadto, opr\u00f3cz punkt\u00f3w awaryjnych, to trudny maintenance samych storage\u2019\u00f3w.<\/p>\n<p>To z\u0142o\u017cony system wielosk\u0142adnikowy, z kt\u00f3rym in\u017cynierowie systemowi maj\u0105 czasem trudno\u015bci.<\/p>\n<p>I ostatni, najwa\u017cniejszy punkt. Je\u015bli w kt\u00f3rymkolwiek z tych trzech punkt\u00f3w wyst\u0105pi awaria, istnieje niezerowe ryzyko utraty danych u\u017cytkownika, poniewa\u017c mo\u017ce uszkodzi\u0107 si\u0119 system plik\u00f3w.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/4bf8bc1c73a2beef74cb4ee0ee45679b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZa\u0142\u00f3\u017cmy, \u017ce uszkodzi\u0142 si\u0119 system plik\u00f3w. Jego przywracanie trwa, po pierwsze, d\u0142ugo \u2014 mo\u017ce to zaj\u0105\u0107 tydzie\u0144 przy du\u017cej ilo\u015bci danych. Po drugie, w efekcie najprawdopodobniej otrzymamy mn\u00f3stwo niezrozumia\u0142ych plik\u00f3w, kt\u00f3re trzeba b\u0119dzie w jaki\u015b spos\u00f3b powi\u0105za\u0107 z zdj\u0119ciami u\u017cytkownik\u00f3w. I ryzykujemy utrat\u0119 danych. Ryzyko jest do\u015b\u0107 wysokie. Im cz\u0119\u015bciej wyst\u0119puj\u0105 takie sytuacje, i im wi\u0119cej problem\u00f3w pojawia si\u0119 w ca\u0142ym \u0142a\u0144cuchu, tym to ryzyko ro\u015bnie.<\/p>\n<p>Trzeba by\u0142o co\u015b z tym zrobi\u0107. I zdecydowali\u015bmy, \u017ce po prostu musimy rezerwowa\u0107 dane. To w zasadzie oczywiste i dobre rozwi\u0105zanie. Co zrobili\u015bmy?<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f80ec2b65003c40bd2fabf88966b3e05.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTak wygl\u0105da\u0142 nasz serwer, kt\u00f3ry by\u0142 wcze\u015bniej pod\u0142\u0105czony do storage. To jedna g\u0142\u00f3wna partycja, to po prostu urz\u0105dzenie blokowe, kt\u00f3re w rzeczywisto\u015bci reprezentuje zamontowany zdalny storage przez \u015bwiat\u0142ow\u00f3d.<\/p>\n<p>Po prostu dodali\u015bmy drug\u0105 partycj\u0119.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d3dba75ef477269d92145cd69d587527.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPostawili\u015bmy obok drugi storage (na szcz\u0119\u015bcie nie kosztuje to tak du\u017co) i nazwali\u015bmy go wydzieleniem backupowym. R\u00f3wnie\u017c jest pod\u0142\u0105czony za pomoc\u0105 \u015bwiat\u0142owodu, znajduje si\u0119 na tej samej maszynie. Musimy jednak jako\u015b zsynchronizowa\u0107 dane mi\u0119dzy nimi.<\/p>\n<p>Tutaj po prostu robimy obok asynchroniczn\u0105 kolejk\u0119.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/67bced2b45c589009cfb01a1c21398a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNie jest to zbyt obci\u0105\u017cone. Wiemy, \u017ce mamy ma\u0142o rekord\u00f3w. Kolejka to po prostu tabelka w MySQL, do kt\u00f3rej wpisywane s\u0105 linijki typu \u201etrzeba zrobi\u0107 backup tej fotografii\u201d. Przy ka\u017cdej zmianie lub przesy\u0142aniu kopiujemy z g\u0142\u00f3wnego wydzia\u0142u na backup asynchronicznie lub po prostu jakim\u015b background workerem.<\/p>\n<p>W ten spos\u00f3b zawsze mamy dwa sp\u00f3jne wydzia\u0142y. Nawet je\u015bli jedna cz\u0119\u015b\u0107 tego systemu ulegnie awarii, zawsze mo\u017cemy zamieni\u0107 g\u0142\u00f3wny wydzia\u0142 z backupem, i wszystko b\u0119dzie dzia\u0142a\u0107 dalej.<\/p>\n<p>Ale przez to znacznie wzrasta obci\u0105\u017cenie odczytu, poniewa\u017c opr\u00f3cz klient\u00f3w, kt\u00f3rzy czytaj\u0105 z g\u0142\u00f3wnego wydzia\u0142u, gdy\u017c najpierw ogl\u0105daj\u0105 zdj\u0119cie tam (jest ono tam bardziej aktualne), a dopiero potem szukaj\u0105 na backupie, je\u015bli nie znale\u017ali (ale to ju\u017c NGINX po prostu robi), jest jeszcze nasz system backupu, kt\u00f3ry teraz wyci\u0105ga z g\u0142\u00f3wnego wydzia\u0142u. To nie jest w\u0105skie gard\u0142o, ale nie chcia\u0142em zwi\u0119ksza\u0107 obci\u0105\u017cenia, w zasadzie prawie bez powodu.<\/p>\n<p>Dodali\u015bmy trzeci dysk, kt\u00f3ry jest ma\u0142ym SSD, i nazwali\u015bmy go buforem.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/fd35481822b4170087e5f670bf338dc5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nJak to teraz dzia\u0142a.<\/p>\n<p>U\u017cytkownik przesy\u0142a zdj\u0119cie na bufor, nast\u0119pnie wysy\u0142any jest event do kolejki o tym, \u017ce nale\u017cy je skopiowa\u0107 na dwa wydzia\u0142y. Jest kopiowane, a zdj\u0119cie przez jaki\u015b czas (powiedzmy 24 godziny) \u017cyje na buforze, a dopiero potem jest usuwane. To znacznie poprawia do\u015bwiadczenie u\u017cytkownika, poniewa\u017c u\u017cytkownik zazwyczaj przesy\u0142a zdj\u0119cie, po czym od razu zaczynaj\u0105 sp\u0142ywa\u0107 requesty, lub sam od\u015bwie\u017ca stron\u0119. Ale to wszystko zale\u017cy od aplikacji, kt\u00f3ra dokonuje uploadu.<\/p>\n<p>Lub na przyk\u0142ad inni ludzie, kt\u00f3rym zaczyna si\u0119 pokazywa\u0107, od razu wysy\u0142aj\u0105 requesty w zwi\u0105zku z tym zdj\u0119ciem. W cache jeszcze go nie ma, pierwszy request nast\u0119puje bardzo szybko. W zasadzie, tak samo jak z cachem zdj\u0119\u0107. Wolny storage w og\u00f3le nie bierze w tym udzia\u0142u. A kiedy po 24 godzinach b\u0119dzie usuni\u0119te, b\u0119dzie ju\u017c albo zakotwiczone w naszej warstwie cache, albo najprawdopodobniej nikomu nie b\u0119dzie ju\u017c potrzebne. Tzn. do\u015bwiadczenie u\u017cytkownika bardzo wzros\u0142o dzi\u0119ki tym prostym manipulacjom.<\/p>\n<p>No i najwa\u017cniejsze: przestali\u015bmy traci\u0107 dane.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/526f549457dd0c438f32b0adb76df76c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPowiedzmy, \u017ce przestali\u015bmy <em>potencjalnie<\/em> mo\u017cemy straci\u0107 dane, poniewa\u017c tak naprawd\u0119 ich nie stracili\u015bmy. Jednak niebezpiecze\u0144stwo istnia\u0142o. Widzimy, \u017ce takie rozwi\u0105zanie jest oczywi\u015bcie dobre, ale przypomina troch\u0119 \u0142agodzenie objaw\u00f3w problemu, zamiast rozwi\u0105za\u0107 go ca\u0142kowicie. Niekt\u00f3re problemy tutaj pozosta\u0142y.<\/p>\n<p>Po pierwsze, to punkt awarii w postaci samego fizycznego hosta, na kt\u00f3rym dzia\u0142a ca\u0142a ta maszyna; to nadal jest problemem.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/0eb3d292655a7edf912793ed81e8931c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPo drugie, pozosta\u0142y problemy z SAN\u2019ami, ci\u0119\u017cka konserwacja itp. To nie by\u0142 krytyczny czynnik, ale mi\u0142o by\u0142oby spr\u00f3bowa\u0107 \u017cy\u0107 bez tego.<\/p>\n<p>Stworzyli\u015bmy trzeci\u0105 wersj\u0119 (w zasadzie drug\u0105) \u2014 wersj\u0119 rezerwowania. Jak to wygl\u0105da\u0142o?<\/p>\n<p>To, co mieli\u015bmy \u2013<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/8b1749b6feed200f8a64529ee2316c1a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nG\u0142\u00f3wne problemy, z kt\u00f3rymi si\u0119 borykamy, dotycz\u0105 faktu, \u017ce to fizyczny host.<\/p>\n<p>Po pierwsze, eliminujemy SAN'y, poniewa\u017c chcemy przeprowadzi\u0107 eksperyment, chcemy spr\u00f3bowa\u0107 po prostu lokalnych dysk\u00f3w twardych.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/fd0f5a8627d9179fcbc7097c1c18505f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTo ju\u017c rok 2014-2015, a sytuacja z dyskami i ich pojemno\u015bci\u0105 w jednym ho\u015bcie znacznie si\u0119 poprawi\u0142a. Postanowili\u015bmy, dlaczego by nie spr\u00f3bowa\u0107.<\/p>\n<p>Nast\u0119pnie po prostu bierzemy nasz\u0105 partycj\u0119 backupow\u0105 i przenosimy j\u0105 fizycznie na oddzieln\u0105 maszyn\u0119.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/456e00bc8557d3340b06efcd1dde8a08.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nW ten spos\u00f3b uzyskujemy nast\u0119puj\u0105cy schemat. Mamy dwie maszyny, kt\u00f3re przechowuj\u0105 te same zestawy danych. Wzajemnie rezerwuj\u0105 si\u0119 ca\u0142kowicie i synchronizuj\u0105 dane przez sie\u0107 poprzez asynchroniczn\u0105 kolejk\u0119 w tym samym MySQL.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d44cdb7b440ad4c58cc625123306a8c8.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDlaczego to dzia\u0142a dobrze \u2014 poniewa\u017c mamy niewiele zapis\u00f3w. To znaczy, gdyby zapis by\u0142 por\u00f3wnywalny z odczytem, mogliby\u015bmy napotka\u0107 jaki\u015b narzut sieciowy i problemy. Ma\u0142o zapis\u00f3w, du\u017co odczyt\u00f3w \u2014 ten spos\u00f3b dzia\u0142a dobrze, tzn. do\u015b\u0107 rzadko kopiujemy zdj\u0119cia mi\u0119dzy tymi dwoma serwerami.<\/p>\n<p>Jak to dzia\u0142a, je\u015bli spojrzymy na to nieco dok\u0142adniej.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/071c11abb6ee1d7734c53052139ff04b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUpload. Balancer po prostu wybiera losowe hosty z pary i umieszcza na nim upload. Oczywi\u015bcie przeprowadza testy zdrowotne, upewniaj\u0105c si\u0119, \u017ce maszyna nie wypad\u0142a. To znaczy, \u017ce przesy\u0142a zdj\u0119cia tylko na dzia\u0142aj\u0105cy serwer, a nast\u0119pnie przez asynchroniczn\u0105 kolejk\u0119 wszystko to kopiuje do jego s\u0105siada. Z upload'em jest wszystko bardzo proste.<\/p>\n<p>Z zadaniem jest troch\u0119 bardziej skomplikowane.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f494904aec823456e18b987a8c98bf56.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTutaj pom\u00f3g\u0142 nam Lua, poniewa\u017c na zwyk\u0142ym NGINX trudno czasami zrealizowa\u0107 tak\u0105 logik\u0119. Najpierw wysy\u0142amy \u017c\u0105danie do pierwszego serwera, sprawdzamy, czy tam jest zdj\u0119cie, poniewa\u017c potencjalnie mo\u017ce by\u0107 ono za\u0142adowane na s\u0105siedni serwer, a do nas jeszcze nie dotar\u0142o. Je\u015bli zdj\u0119cie tam jest, to dobrze. Od razu przekazujemy je klientowi i by\u0107 mo\u017ce je cache'ujemy.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/de5f77e997bb049f4cfc1709da0f1788.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nJe\u015bli go nie ma, po prostu prosimy s\u0105siada o zdj\u0119cie i tam otrzymujemy je gwarantowanie.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/79aa5592acd28dfbc815261d0276c2e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTak wi\u0119c mo\u017cna zn\u00f3w powiedzie\u0107: mog\u0105 by\u0107 problemy z wydajno\u015bci\u0105, poniewa\u017c ci\u0105g\u0142e okr\u0105\u017cenia \u2014 zdj\u0119cie zosta\u0142o za\u0142adowane, a tutaj go nie ma, wykonujemy dwa zapytania zamiast jednego, to powinno dzia\u0142a\u0107 wolno.<\/p>\n<p>W naszej sytuacji to nie dzia\u0142a wolno.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/52ca3902d80990f512201672cd5e6441.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZbieramy mn\u00f3stwo metryk z tego systemu, a hipotetyczny wska\u017anik trafno\u015bci tego mechanizmu wynosi oko\u0142o 95%. To znaczy, \u017ce op\u00f3\u017anienie tego backupu jest ma\u0142e, i dzi\u0119ki temu praktycznie zawsze, po tym jak zdj\u0119cie zosta\u0142o za\u0142adowane, pobieramy je za pierwszym razem i nie chodzimy dwa razy.<\/p>\n<p>W ten spos\u00f3b, co jeszcze zyskali\u015bmy, co jest bardzo fajne?<\/p>\n<p>Dawniej mieli\u015bmy g\u0142\u00f3wny dzia\u0142 backupu i czytali\u015bmy z nich sekwencyjnie. Zawsze najpierw szukali\u015bmy na g\u0142\u00f3wnym, a potem na backupie. To by\u0142o jedno podej\u015bcie.<\/p>\n<p>Teraz utylizujemy odczyt z dw\u00f3ch maszyn jednocze\u015bnie. Rozdzielamy zapytania metod\u0105 Round Robin. W ma\u0142ym procencie przypadk\u00f3w wykonujemy dwa zapytania. Ale dzi\u0119ki temu teraz mamy dwukrotnie wi\u0119ksz\u0105 rezerw\u0119 czytania ni\u017c wcze\u015bniej. I obci\u0105\u017cenie znacznie si\u0119 zmniejszy\u0142o zar\u00f3wno na maszynach odsy\u0142aj\u0105cych, jak i na pami\u0119ciach, kt\u00f3re mieli\u015bmy w tym czasie.<\/p>\n<p>Co do odporno\u015bci na awarie. W\u0142a\u015bciwie to o to g\u0142\u00f3wnie walczyli\u015bmy. Z odporno\u015bci\u0105 na awarie wszystko posz\u0142o \u015bwietnie.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/a030a477e60d6e1f3d0b4e3395013df5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nJedna maszyna przestaje dzia\u0142a\u0107.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/42900b24e340c03ea642fd49f5b410ff.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u017badnych problem\u00f3w! In\u017cynier systemowy mo\u017ce nawet nie budzi\u0107 si\u0119 w nocy, poczeka do rana, nic z\u0142ego si\u0119 nie stanie.<\/p>\n<p>Je\u015bli nawet kolejka zamarza przy awarii tej maszyny, te\u017c nie ma \u017cadnych problem\u00f3w, po prostu log b\u0119dzie gromadzony najpierw na \u017cywej maszynie, a potem ju\u017c dojdzie do kolejki, a nast\u0119pnie do tej maszyny, kt\u00f3ra zostanie przywr\u00f3cona do dzia\u0142ania po pewnym czasie.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/ef42eadaaf3e3ecbf70847e9f88c1582.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTo samo dotyczy konserwacji. Po prostu wy\u0142\u0105czamy jedn\u0105 z maszyn, r\u0119cznie usuwamy j\u0105 ze wszystkich pul, przestaje ona przetwarza\u0107 ruch, wykonujemy jakie\u015b prace konserwacyjne, co\u015b poprawiamy, a potem przywracamy j\u0105 do dzia\u0142ania i ten backup dogania si\u0119 wystarczaj\u0105co szybko. Tzn. przy dobie jednego dnia przestoju jednej maszyny dogania si\u0119 w granicach kilku minut. To jest naprawd\u0119 bardzo ma\u0142o. M\u00f3wi\u0105c o odporno\u015bci na b\u0142\u0119dy, jeszcze raz podkre\u015blam, wszystko tu jest \u015bwietne.<\/p>\n<p>Jakie wnioski mo\u017cna wyci\u0105gn\u0105\u0107 z tego schematu rezerwacji?<\/p>\n<p>Uzyskali\u015bmy odporno\u015b\u0107 na b\u0142\u0119dy.<\/p>\n<p>Prosta eksploatacja. Poniewa\u017c na maszynach znajduj\u0105 si\u0119 lokalne twarde dyski, jest to o wiele wygodniejsze z punktu widzenia in\u017cynier\u00f3w, kt\u00f3rzy z tym pracuj\u0105.<\/p>\n<p>Uzyskali\u015bmy podw\u00f3jny zapas przy odczycie.<\/p>\n<p>To bardzo dobry bonus w dodatku do odporno\u015bci na b\u0142\u0119dy.<\/p>\n<p>Ale s\u0105 i problemy. Teraz mamy znacznie bardziej skomplikowany rozw\u00f3j r\u00f3\u017cnych funkcji zwi\u0105zanych z tym, poniewa\u017c system sta\u0142 si\u0119 w 100% ostatecznie sp\u00f3jny.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/b650276a41730cc303180e8304c5dabb.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMusimy, powiedzmy, w jakiej\u015b pracy w tle ci\u0105gle my\u015ble\u0107: \"Na kt\u00f3rym serwerze teraz dzia\u0142amy?\", \"Czy na pewno tutaj jest aktualne zdj\u0119cie?\" itd. To, naturalnie, wszystko jest owini\u0119te w r\u00f3\u017cne obiekty i dla programisty, kt\u00f3ry pisze logik\u0119 biznesow\u0105, jest to przezroczyste. Jednak\u017ce pojawi\u0142a si\u0119 znaczna z\u0142o\u017cono\u015b\u0107. Ale jeste\u015bmy gotowi to zaakceptowa\u0107 w zamian za korzy\u015bci, kt\u00f3re z tego wynikaj\u0105.<\/p>\n<p>I tutaj zn\u00f3w pojawia si\u0119 pewien konflikt.<\/p>\n<p>Na pocz\u0105tku m\u00f3wi\u0142em, \u017ce trzymanie wszystkiego na lokalnych twardych dyskach jest z\u0142e. A teraz m\u00f3wi\u0119, \u017ce nam si\u0119 to podoba.<\/p>\n<p>Tak, rzeczywi\u015bcie, z biegiem czasu sytuacja znacznie si\u0119 zmieni\u0142a i teraz ten spos\u00f3b ma wiele zalet. Po pierwsze, mamy znacznie prostsza eksploatacj\u0119.<\/p>\n<p>Po drugie, to jest wydajniejsze, poniewa\u017c nie mamy tych automatycznych kontroler\u00f3w do pod\u0142\u0105czania do macierzy dyskowych.<\/p>\n<p>Tam jest ogromna maszyna, a to po prostu kilka dysk\u00f3w, kt\u00f3re konkretne s\u0105 tutaj na maszynie skonfigurowane w RAID.<\/p>\n<p>Ale s\u0105 i minusy.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/3c090e0801f1a686dc0d5fefce697c56.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTo jest oko\u0142o 1,5 razy dro\u017csze ni\u017c u\u017cywanie SAN-\u00f3w nawet przy dzisiejszych cenach. Dlatego zdecydowali\u015bmy si\u0119 tak odwa\u017cnie nie konwertowa\u0107 ca\u0142ego naszego du\u017cego klastra na maszyny z lokalnymi twardymi dyskami i postanowili\u015bmy pozostawi\u0107 rozwi\u0105zanie hybrydowe.<\/p>\n<p>Po\u0142owa naszych maszyn pracuje na dyskach twardych (no, nie po\u0142owa \u2013 pewnie 30 procent). A reszta to stare maszyny, na kt\u00f3rych wcze\u015bniej by\u0142a pierwsza schemat rezerwacji. Po prostu je przestawili\u015bmy, poniewa\u017c nie potrzebujemy ani nowych danych, ani nic innego, po prostu przenie\u015bli\u015bmy monta\u017c z jednego fizycznego hosta na dwa.<\/p>\n<p>I zyskali\u015bmy du\u017c\u0105 rezerw\u0119 w odczycie, a my si\u0119 powi\u0119kszyli\u015bmy. Je\u015bli wcze\u015bniej montowali\u015bmy jeden storage na jedn\u0105 maszyn\u0119, teraz montujemy cztery na jedn\u0105 par\u0119, na przyk\u0142ad. I to dzia\u0142a poprawnie.<\/p>\n<p>Podsumujmy kr\u00f3tko to, co osi\u0105gn\u0119li\u015bmy, o co walczyli\u015bmy i co nam si\u0119 uda\u0142o.<\/p>\n<h3>Podsumowanie<\/h3>\n<p>\nMamy u\u017cytkownik\u00f3w \u2013 ca\u0142e 33 mln.<\/p>\n<p>Mamy trzy punkty obecno\u015bci \u2013 Praga, Miami, Hongkong.<\/p>\n<p>Zawieraj\u0105 one warstw\u0119 buforuj\u0105c\u0105, kt\u00f3ra sk\u0142ada si\u0119 z maszyn z szybkimi lokalnymi dyskami (SSD), na kt\u00f3rych dzia\u0142a prosta infrastruktura z NGINX, jego access.log oraz demony w Pythonie, kt\u00f3re wszystko przetwarzaj\u0105 i zarz\u0105dzaj\u0105 cachem.<\/p>\n<p>Je\u015bli chcesz, w swoim projekcie, je\u015bli zdj\u0119cia nie s\u0105 dla Ciebie tak krytyczne, jak dla nas, lub je\u015bli trade-off kontrola w por\u00f3wnaniu z szybko\u015bci\u0105 rozwoju i kosztami zasob\u00f3w jest dla Ciebie w inny spos\u00f3b, mo\u017cesz spokojnie zast\u0105pi\u0107 to CDN, nowoczesne CDN dobrze to robi\u0105.<\/p>\n<p>Nast\u0119pnie znajduje si\u0119 warstwa pami\u0119ci, na kt\u00f3rej mamy klastry par maszyn, kt\u00f3re wzajemnie si\u0119 rezerwuj\u0105, asynchronicznie kopiuj\u0105c pliki z jednego na drugi przy ka\u017cdej zmianie.<\/p>\n<p>Cz\u0119\u015b\u0107 tych maszyn pracuje z lokalnymi dyskami twardymi.<\/p>\n<p>Cz\u0119\u015b\u0107 tych maszyn jest pod\u0142\u0105czona do SAN.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/5ddbc4f73d86aa1f83734885d8c9dea0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZ jednej strony jest to wygodniejsze w eksploatacji i nieco bardziej wydajne, z drugiej strony jest to wygodne z punktu widzenia g\u0119sto\u015bci rozmieszczenia i ceny za gigabajt.<\/p>\n<p>To taki kr\u00f3tki przegl\u0105d architektury tego, co osi\u0105gn\u0119li\u015bmy i jak to wszystko si\u0119 rozwija\u0142o.<\/p>\n<p>Jeszcze kilka prostych porad od kefa.<\/p>\n<p>Po pierwsze, je\u015bli nagle zdecydujesz, \u017ce musisz pilnie poprawi\u0107 swoj\u0105 infrastruktur\u0119 zdj\u0119\u0107, najpierw zmierz to, bo mo\u017cliwe, \u017ce nic nie trzeba poprawia\u0107.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7770f41d0b190eb78ae0d19f4c8182a6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPodam przyk\u0142ad. Mamy klaster maszyn, kt\u00f3re dostarczaj\u0105 zdj\u0119cia z attachment\u00f3w w czatach, i tam do tej pory dzia\u0142a schemat z 2009 roku, i nikt na tym nie cierpi. Wszystkim jest dobrze, wszystkim si\u0119 podoba.<\/p>\n<p>Aby przeprowadzi\u0107 pomiary, najpierw zbierz wiele metryk, spojrz na nie, a nast\u0119pnie zdecyduj, z czego jeste\u015b niezadowolony i co nale\u017cy poprawi\u0107. Do mierzenia mamy \u015bwietne narz\u0119dzie zwane Pinba.<\/p>\n<p>Umo\u017cliwia on zbieranie bardzo szczeg\u00f3\u0142owych statystyk z NGINX dla ka\u017cdego \u017c\u0105dania, kod\u00f3w odpowiedzi oraz rozk\u0142ad\u00f3w czas\u00f3w \u2014 cokolwiek zechcesz. Posiada wtyczki do r\u00f3\u017cnych system\u00f3w analitycznych, a potem mo\u017cesz wszystko to \u0142adnie przegl\u0105da\u0107.<\/p>\n<p>Najpierw zmierzono - potem poprawiono.<\/p>\n<p>Dalej. Optymalizujemy odczyt za pomoc\u0105 pami\u0119ci podr\u0119cznej, a zapis - poprzez sharding, ale to jest oczywisty punkt.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f53a4777f1a2c7793eba4a72c94263a4.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDalej. Je\u015bli dopiero zaczynasz budowa\u0107 sw\u00f3j system, znacznie lepiej jest traktowa\u0107 zdj\u0119cia jako pliki immutable. Poniewa\u017c w ten spos\u00f3b tracisz od razu ca\u0142y typ problem\u00f3w zwi\u0105zanych z uniewa\u017cnieniem pami\u0119ci podr\u0119cznej, jak logika ma znale\u017a\u0107 odpowiedni\u0105 wersj\u0119 zdj\u0119cia, i tak dalej.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f345c59681275326cda1320b4f188ce9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZa\u0142\u00f3\u017cmy, \u017ce wrzuci\u0142e\u015b st\u00f3wk\u0119, a nast\u0119pnie j\u0105 obr\u00f3ci\u0142e\u015b, upewnij si\u0119, \u017ce jest to fizycznie inny plik. To znaczy, nie my\u015bl: 'teraz zaoszcz\u0119dz\u0119 troch\u0119 miejsca, zapisuj\u0105c w tym samym pliku, zmieniaj\u0105c wersj\u0119'. Zawsze to \u017ale dzia\u0142a, potem jest z tym wiele b\u00f3lu g\u0142owy.<\/p>\n<p>Nast\u0119pny punkt. O resize w locie.<\/p>\n<p>Kiedy\u015b, gdy u\u017cytkownicy przesy\u0142ali zdj\u0119cia, ci\u0119li\u015bmy od razu ca\u0142\u0105 mas\u0119 rozmiar\u00f3w na wszelki wypadek dla r\u00f3\u017cnych klient\u00f3w, kt\u00f3re wszystkie le\u017ca\u0142y na dysku. Teraz z tego zrezygnowali\u015bmy.<\/p>\n<p>Zostawili\u015bmy tylko trzy podstawowe rozmiary: ma\u0142y, \u015bredni i du\u017cy. Wszystko inne po prostu skalujemy w d\u00f3\u0142 z rozmiaru, kt\u00f3ry jest podstaw\u0105 zapytania w Uport, po prostu robi\u0105c downsizing i oddajemy u\u017cytkownikowi.<\/p>\n<p>Koszt CPU w warstwie pami\u0119ci podr\u0119cznej jest znacznie ni\u017cszy ni\u017c gdyby\u015bmy stale regenerowali te rozmiary na ka\u017cdym storage'u. Za\u0142\u00f3\u017cmy, \u017ce chcemy doda\u0107 nowy, to zajmie miesi\u0105c - uruchomi\u0107 wsz\u0119dzie skrypt, kt\u00f3ry to wszystko starannie zrobi, a przy tym nie uszkodzi klastra. To znaczy, je\u015bli jest mo\u017cliwo\u015b\u0107, lepiej jest mie\u0107 jak najmniej fizycznych rozmiar\u00f3w, ale aby istnia\u0142o jakie\u015b rozk\u0142adanie, powiedzmy, trzy. A wszystko inne po prostu resize'owa\u0107 w locie za pomoc\u0105 gotowych modu\u0142\u00f3w. To jest teraz bardzo \u0142atwe i dost\u0119pne.<\/p>\n<p>A inkrementalna asynchroniczna kopia zapasowa to dobra rzecz.<\/p>\n<p>Jak pokazuje nasza praktyka, tego typu schemat \u015bwietnie dzia\u0142a z op\u00f3\u017anionym kopiowaniem zmodyfikowanych plik\u00f3w.<\/p>\n<p><img decoding=\"async\" alt=\"Architektura przechowywania i udost\u0119pniania zdj\u0119\u0107 w Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/0e550721e838654e61e1fa4d08f9bb93.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOstatni punkt jest r\u00f3wnie\u017c oczywisty. Je\u015bli w twojej infrastrukturze nie ma teraz takich problem\u00f3w, ale istnieje co\u015b, co mo\u017ce si\u0119 zepsu\u0107, z pewno\u015bci\u0105 zepsuje si\u0119, gdy tego b\u0119dzie nieco wi\u0119cej. Dlatego lepiej pomy\u015ble\u0107 o tym wcze\u015bniej i unika\u0107 problem\u00f3w. To wszystko ode mnie.<\/p>\n<h3>Kontakt<\/h3>\n<p>\n\u00bb <noindex><a rel=\"nofollow\" href=\"https:\/\/habrahabr.ru\/users\/bo0rsh201\/\" class=\"user_link\">bo0rsh201<\/a><\/noindex> <br \/>\n\u00bb <noindex><a rel=\"nofollow\" href=\"https:\/\/habrahabr.ru\/company\/badoo\/\">Blog firmy Badoo<\/a><\/noindex><\/p>\n<blockquote><p>Ten raport to transkrypcja jednego z najlepszych wyst\u0105pie\u0144 na konferencji dla tw\u00f3rc\u00f3w wysokowydajnych system\u00f3w. <noindex><a rel=\"nofollow\" href=\"http:\/\/highload.ru\/?utm_source=habr&amp;utm_medium=media&amp;utm_campaign=past.articles&amp;utm_content=common\">HighLoad++<\/a><\/noindex>. Do konferencji HighLoad++ 2017 pozosta\u0142o mniej ni\u017c miesi\u0105c.<\/p>\n<p>Mamy ju\u017c gotow\u0105 <noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/2017\/abstracts\">Program konferencji<\/a><\/noindex>, obecnie intensywnie formowane jest harmonogram.<\/p>\n<p>W tym roku kontynuujemy badanie tematu architektur i skalowania:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/2017\/abstracts\/2946.html?utm_source=habr&amp;utm_medium=media&amp;utm_campaign=past.articles&amp;utm_content=common\">Jak obs\u0142u\u017cy\u0107 miliard u\u017cytkownik\u00f3w i dostarczy\u0107 terabity ruchu<\/a><\/noindex> \/ \u0418\u0433\u043e\u0440\u044c \u0412\u0430\u0441\u0438\u043b\u044c\u0435\u0432<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/2017\/abstracts\/3088.html?utm_source=habr&amp;utm_medium=media&amp;utm_campaign=past.articles&amp;utm_content=common\">Jak przepisa\u0107 od podstaw baz\u0119 danych prywatnych wiadomo\u015bci w Vkontakte i migrowa\u0107 na ni\u0105 bez przestoj\u00f3w<\/a><\/noindex> \/ \u0414\u043c\u0438\u0442\u0440\u0438\u0439 \u0415\u0433\u043e\u0440\u043e\u0432<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/2017\/abstracts\/2843.html?utm_source=habr&amp;utm_medium=media&amp;utm_campaign=past.articles&amp;utm_content=common\">\u015amier\u0107 z wyprzeda\u017cy: jak Yandex.Money pr\u00f3bowa\u0142o si\u0119 przyspieszy\u0107 przed Black Friday i przetrwa\u0107<\/a><\/noindex> \/ \u0410\u043d\u0430\u0442\u043e\u043b\u0438\u0439 \u041f\u043b\u0430\u0441\u043a\u043e\u0432\u0441\u043a\u0438\u0439<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/2017\/abstracts\/3003.html?utm_source=habr&amp;utm_medium=media&amp;utm_campaign=past.articles&amp;utm_content=common\">Odporna architektura systemu frontowego banku<\/a><\/noindex> \/ \u0420\u043e\u043c\u0430\u043d \u0428\u0435\u0445\u043e\u0432\u0446\u043e\u0432, \u0410\u043b\u0435\u043a\u0441\u0435\u0439 \u0413\u0440\u043e\u043c\u0430\u0442\u0447\u0438\u043a\u043e\u0432<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/2017\/abstracts\/2948.html?utm_source=habr&amp;utm_medium=media&amp;utm_campaign=past.articles&amp;utm_content=common\">Architektura systemu p\u0142atno\u015bci: prawie enterprise<\/a><\/noindex> \/ \u0424\u0438\u043b\u0438\u043f\u043f \u0414\u0435\u043b\u044c\u0433\u044f\u0434\u043e<\/li>\n<\/ul>\n<p>\nNiekt\u00f3re z tych materia\u0142\u00f3w s\u0105 r\u00f3wnie\u017c wykorzystywane przez nas w kursie online o tworzeniu wysokowydajnych system\u00f3w. <noindex><a rel=\"nofollow\" href=\"http:\/\/highload.guide\/?utm_source=habr&amp;utm_medium=media&amp;utm_campaign=past.articles&amp;utm_content=common\">HighLoad.Guide<\/a><\/noindex> \u2014 to seria starannie dobranych list\u00f3w, artyku\u0142\u00f3w, materia\u0142\u00f3w i film\u00f3w. Ju\u017c teraz w naszym podr\u0119czniku jest ponad 30 unikalnych materia\u0142\u00f3w. Do\u0142\u0105cz do nas!\n<\/p><\/blockquote>\n<p>\u0179r\u00f3d\u0142o: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/oleg-bunin\/blog\/340976\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0410\u0440\u0442\u0435\u043c \u0414\u0435\u043d\u0438\u0441\u043e\u0432 ( bo0rsh201, Badoo) Badoo \u2014 \u044d\u0442\u043e \u043a\u0440\u0443\u043f\u043d\u0435\u0439\u0448\u0438\u0439 \u0432 \u043c\u0438\u0440\u0435 \u0441\u0430\u0439\u0442 \u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432. \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0443 \u043d\u0430\u0441 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430 330 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043f\u043e \u0432\u0441\u0435\u043c\u0443 \u043c\u0438\u0440\u0443. \u041d\u043e, \u0447\u0442\u043e \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0431\u043e\u043b\u0435\u0435 \u0432\u0430\u0436\u043d\u043e \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0435\u0433\u043e \u0440\u0430\u0437\u0433\u043e\u0432\u043e\u0440\u0430, \u2014 \u044d\u0442\u043e \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u0445\u0440\u0430\u043d\u0438\u043c \u043e\u043a\u043e\u043b\u043e 3 \u043f\u0435\u0442\u0430\u0431\u0430\u0439\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439. \u041a\u0430\u0436\u0434\u044b\u0439 \u0434\u0435\u043d\u044c \u043d\u0430\u0448\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0437\u0430\u043b\u0438\u0432\u0430\u044e\u0442 \u043f\u043e\u0440\u044f\u0434\u043a\u0430 3,5 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 [&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-55009","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=\"\u0410\u0440\u0442\u0435\u043c \u0414\u0435\u043d\u0438\u0441\u043e\u0432 (\" \/>\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\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo\" \/>\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\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438 \u043e\u0442\u0434\u0430\u0447\u0438 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0432 Badoo | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0410\u0440\u0442\u0435\u043c \u0414\u0435\u043d\u0438\u0441\u043e\u0432 (\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo\" \/>\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=\"2020-01-09T21:00:00+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-02-18T11:03:04+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\udd47Architektura przechowywania i dostarczania zdj\u0119\u0107 w Badoo | ProHoster","description":"Artur Denisow (","canonical_url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo","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\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438 \u043e\u0442\u0434\u0430\u0447\u0438 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0432 Badoo | ProHoster","og:description":"\u0410\u0440\u0442\u0435\u043c \u0414\u0435\u043d\u0438\u0441\u043e\u0432 (","og:url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo","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":"2020-01-09T21:00:00+00:00","article:modified_time":"2020-02-18T11:03:04+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"55009","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 13:30:15","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 19:53:49","updated":"2026-01-24 13:30:15","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\/55009","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=55009"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/55009\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=55009"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=55009"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=55009"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}