ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

ВКонтактенің құрылу тарихы Википедияда, оны Павелдің өзі айтты. Оны бәрі бұрыннан танитын сияқты. HighLoad++ Pavel сайтының ішкі бөліктері, архитектурасы және құрылымы туралы маған 2010 жылы айтты. Содан бері көптеген серверлер ағып кетті, сондықтан біз ақпаратты жаңартамыз: біз оны бөлшектейміз, ішін шығарамыз, өлшейміз және VK құрылғысын техникалық тұрғыдан қараймыз.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Алексей Акулович (AterCattus) ВКонтакте тобындағы бэкенд әзірлеушісі. Бұл есептің стенограммасы платформаның жұмысы, инфрақұрылым, серверлер және олардың арасындағы өзара әрекеттесу туралы жиі қойылатын сұрақтарға ұжымдық жауап болып табылады, бірақ әзірлеу туралы емес, атап айтқанда темір туралы. Деректер базасы және оның орнына ВК-да не бар, журналдарды жинау және тұтас жобаны бақылау туралы бөлек. Кесу астындағы мәліметтер.



Төрт жылдан астам уақыт бойы мен серверге қатысты барлық тапсырмалармен айналыстым.

  • Жүктеу, сақтау, өңдеу, тарату: бейне, тікелей трансляция, аудио, фотосуреттер, құжаттар.
  • Инфрақұрылым, платформа, әзірлеушілер мониторингі, журналдар, аймақтық кэштер, CDN, меншікті RPC протоколы.
  • Сыртқы қызметтермен интеграция: push хабарландырулары, сыртқы сілтемелерді талдау, RSS арнасы.
  • Әріптестерге әртүрлі сұрақтармен көмектесу, олардың жауаптары белгісіз кодқа сүңгуді қажет етеді.

Осы уақыт ішінде мен сайттың көптеген компоненттеріне қол жеткіздім. Мен бұл тәжірибемен бөліскім келеді.

Жалпы сәулет

Барлығы, әдеттегідей, сұрауларды қабылдайтын серверден немесе серверлер тобынан басталады.

Алдыңғы сервер

Алдыңғы сервер HTTPS, RTMP және WSS арқылы сұрауларды қабылдайды.

HTTPS - бұл сайттың негізгі және мобильді веб-нұсқаларына сұраныстар: vk.com және m.vk.com және API-нің басқа ресми және бейресми клиенттері: мобильді клиенттер, мессенджерлер. Бізде қабылдау бар RTMP-жеке алдыңғы серверлері бар тікелей трансляцияларға арналған трафик және WSS- Streaming API үшін қосылымдар.

Серверлердегі HTTPS және WSS үшін бұл тұр nginx. RTMP хабарлары үшін біз жақында өз шешімімізге көштік киве, бірақ ол есептің ауқымынан тыс. Ақауларға төзімділік үшін бұл серверлер жалпы IP мекенжайларын жарнамалайды және серверлердің бірінде ақаулық болса, пайдаланушы сұраулары жоғалып кетпеуі үшін топтарда әрекет етеді. HTTPS және WSS үшін дәл сол серверлер CPU жүктемесінің бір бөлігін өздеріне алу үшін трафикті шифрлайды.

Біз WSS және RTMP туралы бұдан әрі сөйлеспейміз, тек әдетте веб-жобамен байланысты стандартты HTTPS сұраулары туралы.

Тетік бағдарламасы

Алдыңғы жағында әдетте сервер серверлері бар. Олар алдыңғы сервер клиенттерден алатын сұрауларды өңдейді.

осы kPHP серверлері, HTTP демоны жұмыс істейді, себебі HTTPS әлдеқашан шифры шешілген. kPHP — жұмыс істейтін сервер префорк модельдері: негізгі процесті, еншілес процестердің жиынтығын бастайды, оларға тыңдау ұяшықтарын береді және олар өз сұрауларын өңдейді. Бұл жағдайда процестер пайдаланушының әрбір сұрауы арасында қайта іске қосылмайды, қайта іске қосудың орнына олардың күйін бастапқы нөлдік күйге – сұраудан кейінгі сұрауға қалпына келтіріңіз.

Жүктемені бөлу

Біздің барлық серверлер кез келген сұранысты өңдей алатын үлкен машиналар пулы емес. Біз олар жеке топтарға бөлінеді: жалпы, мобильді, api, бейне, сахналау... Машиналардың жеке тобындағы мәселе басқалардың бәріне әсер етпейді. Бейнеге қатысты мәселелер туындаған жағдайда, музыканы тыңдайтын пайдаланушы проблемалар туралы тіпті білмейді. Сұраныс қай серверге жіберілетінін конфигурацияға сәйкес алдыңғы жағындағы nginx шешеді.

Метрикалық жинау және қайта теңестіру

Әр топта қанша көлік болуы керек екенін түсіну үшін біз QPS-ке сенбеңіз. Артқы беттер әртүрлі, олардың сұраулары әртүрлі, әр сұрауда QPS есептеудің әртүрлі күрделілігі бар. Сондықтан біз біз тұтастай серверге жүктеме тұжырымдамасымен жұмыс істейміз - процессор мен перф.

Бізде мыңдаған осындай серверлер бар. Әрбір физикалық сервер барлық ядроларды қайта өңдеу үшін kPHP тобын іске қосады (себебі kPHP бір ағынды).

Мазмұн сервері

CS немесе Content Server — сақтау орны. CS - файлдарды сақтайтын, сонымен қатар жүктелген файлдарды және негізгі веб-френд оған тағайындайтын фондық синхронды тапсырмалардың барлық түрлерін өңдейтін сервер.

Бізде файлдарды сақтайтын ондаған мың физикалық серверлер бар. Пайдаланушылар файлдарды жүктеп салуды жақсы көреді, біз оларды сақтауды және бөлісуді жақсы көреміз. Бұл серверлердің кейбірі арнайы pu/pp серверлері арқылы жабылады.

pu/pp

ВК-да желі қойындысын ашсаңыз, pu/pp дегенді көрдіңіз.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

pu/pp дегеніміз не? Егер серверді бірінен соң бірін жапсақ, жабылған серверге файлды жүктеп салу және жүктеп алудың екі нұсқасы бар: тікелей через http://cs100500.userapi.com/path немесе аралық сервер арқылы - http://pu.vk.com/c100500/path.

Pu - фотосуреттерді жүктеп салудың тарихи атауы, ал pp - фото прокси. Яғни, бір сервер фотосуреттерді жүктеуге арналған, ал екіншісі жүктеуге арналған. Енді тек фотосуреттер жүктеліп қана қоймай, аты сақталды.

Бұл серверлер HTTPS сеанстарын тоқтатупроцессор жүктемесін жадтан алып тастау үшін. Сондай-ақ, пайдаланушы файлдары осы серверлерде өңделетіндіктен, бұл машиналарда сақталатын құпия ақпарат неғұрлым аз болса, соғұрлым жақсы болады. Мысалы, HTTPS шифрлау кілттері.

Машиналар біздің басқа машиналармен жабылғандықтан, біз оларға «ақ» сыртқы IP мекенжайларын бермей аламыз және «сұр» беру. Осылайша, біз IP пулында сақтадық және машиналарды сыртқы кіруден қорғауға кепілдік бердік - оған кіру үшін IP жоқ.

Ортақ IP мекенжайларына төзімділік. Ақауларға төзімділік тұрғысынан схема бірдей жұмыс істейді - бірнеше физикалық серверлерде жалпы физикалық IP бар және олардың алдындағы аппараттық құрал сұрауды қайда жіберу керектігін таңдайды. Басқа нұсқалар туралы кейінірек айтамын.

Даулы мәселе - бұл жағдайда клиент қосылымдарды азайтады. Бірнеше машиналар үшін бірдей IP болса - бір хостпен: pu.vk.com немесе pp.vk.com, клиент браузерінде бір хостқа бір уақыттағы сұраулар санына шектеу бар. Бірақ барлық жерде HTTP/2 уақытында бұл енді соншалықты маңызды емес деп ойлаймын.

Схеманың айқын кемшілігі - бұл міндетті барлық трафикті сору, ол басқа сервер арқылы қоймаға өтеді. Біз трафикті машиналар арқылы айдайтындықтан, сол схеманы пайдаланып, ауыр трафикті, мысалы, бейнені әлі шығара алмаймыз. Біз оны тікелей жібереміз - бейне үшін арнайы бөлек қоймалар үшін бөлек тікелей қосылым. Біз прокси арқылы жеңілірек мазмұнды жібереміз.

Жақында біз проксидің жетілдірілген нұсқасын алдық. Енді мен олардың қарапайымдардан қалай ерекшеленетінін және бұл не үшін қажет екенін айтып беремін.

күн

2017 жылдың қыркүйегінде бұрын Sun сатып алған Oracle, Sun қызметкерлерін жұмыстан шығарды. Қазіргі уақытта компания жұмысын тоқтатты деп айта аламыз. Жаңа жүйеге атау таңдағанда, біздің әкімшілер осы компанияның естелігіне құрмет көрсетуді шешіп, жаңа жүйені Sun деп атады. Арамызда оны жай ғана «күн» деп атаймыз.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

pp бірнеше проблемаларға тап болды. Әр топқа бір IP – тиімсіз кэш. Бірнеше физикалық серверлер ортақ IP мекенжайын бөліседі және сұрау қай серверге жіберілетінін басқарудың ешқандай жолы жоқ. Сондықтан, егер әртүрлі пайдаланушылар бір файл үшін келсе, онда бұл серверлерде кэш болса, файл әрбір сервердің кэшінде аяқталады. Бұл өте тиімсіз схема, бірақ ештеңе істеу мүмкін емес еді.

Демек - біз мазмұнды бөле алмаймыз, өйткені біз бұл топ үшін арнайы серверді таңдай алмаймыз - олардың ортақ IP бар. Сондай-ақ бізде кейбір ішкі себептер бар аймақтарда мұндай серверлерді орнату мүмкін болмады. Олар тек Санкт-Петербургте тұрды.

Күнмен бірге біз селекция жүйесін өзгерттік. Қазір бізде кез келген тарату маршруттауы: динамикалық маршруттау, кез келген тарату, өзін-өзі тексеру демоны. Әрбір серверде жеке IP бар, бірақ жалпы ішкі желі. Барлығы бір сервер сәтсіз болса, трафик сол топтың басқа серверлеріне автоматты түрде таралатын етіп конфигурацияланған. Енді белгілі бір серверді таңдауға болады, артық кэштеу жоқ, және сенімділікке әсер еткен жоқ.

Салмақты қолдау. Енді біз қажет болған жағдайда әртүрлі қуаттағы машиналарды орнатуға мүмкіндік аламыз, сондай-ақ уақытша ақаулар туындаған жағдайда, жұмыс істейтін «күндердің» салмағын өзгертіп, олар «демалып», қайтадан жұмыс істей бастайды.

Мазмұн идентификаторы бойынша бөлісу. Бөлшектеу туралы күлкілі нәрсе: біз әдетте мазмұнды әртүрлі пайдаланушылар ортақ кэшке ие болу үшін бірдей «күн» арқылы бір файлға өтетін етіп бөлеміз.

Жақында біз «Clover» қосымшасын іске қостық. Бұл тікелей эфирдегі онлайн викторина, онда хост сұрақтар қояды және пайдаланушылар нақты уақыт режимінде опцияларды таңдап жауап береді. Қолданбада пайдаланушылар сөйлесе алатын чат бар. Таратылымға бір уақытта қосыла алады 100 мыңнан астам адам. Олардың барлығы барлық қатысушыларға жіберілетін хабарламаларды жазады және аватар хабармен бірге келеді. Бір «күнде» бір аватар үшін 100 мың адам келсе, ол кейде бұлттың артына айналып кетуі мүмкін.

Бір файлға арналған сұраулардың көптігіне төтеп беру үшін, біз файлдарды аймақтағы барлық қолжетімді «күндерге» тарататын ақымақ схеманы белгілі бір мазмұн түріне қосамыз.

Іштен күн

Nginx жүйесінде кері прокси, жедел жадта немесе жылдам Optane/NVMe дискілерінде кэш. Мысалы: http://sun4-2.userapi.com/c100500/path — төртінші аймақта, екінші сервер тобында орналасқан «күнге» сілтеме. Ол 100500 серверінде физикалық түрде орналасқан жол файлын жабады.

қақпақ

Біз архитектуралық схемаға тағы бір түйінді қосамыз - кэштеу ортасы.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Төменде орналасу диаграммасы берілген аймақтық кэштер, олардың шамамен 20-сы бар. Бұл кэштер мен «күндер» орналасқан орындар, олар трафикті өздері арқылы кэштей алады.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Бұл мультимедиялық мазмұнды кэштеу; мұнда пайдаланушы деректері сақталмайды - тек музыка, бейне, фотосуреттер.

Пайдаланушының аймағын анықтау үшін біз біз аймақтарда жарияланған BGP желі префикстерін жинаймыз. Қайта оралған жағдайда, префикстер бойынша IP таба алмасақ, геоип дерекқорын талдауымыз керек. Біз аймақты пайдаланушының IP арқылы анықтаймыз. Кодта біз пайдаланушының бір немесе бірнеше аймақтарын - географиялық тұрғыдан ол ең жақын нүктелерді қарай аламыз.

Бұл қалай жұмыс істейді?

Біз файлдардың танымалдылығын аймақтар бойынша есептейміз. Пайдаланушы орналасқан аймақтық кэштің бірқатары және файл идентификаторы бар - біз бұл жұпты аламыз және әрбір жүктеп алу кезінде рейтингті арттырамыз.

Сонымен қатар, жындар - аймақтардағы қызметтер - мезгіл-мезгіл API-ге келіп: «Мен анау-мынау кэшпін, менің аймағымдағы әлі менде жоқ ең танымал файлдардың тізімін беріңізші. » API рейтинг бойынша сұрыпталған файлдар топтамасын береді, демон оларды жүктеп алады, аймақтарға апарады және файлдарды сол жерден жеткізеді. Бұл pu/pp және Sun-тың кэштерден түбегейлі айырмашылығы: олар бұл файл кэште болмаса да, файлды бірден өздері арқылы береді және кэш алдымен файлды өзіне жүктеп алады, содан кейін оны қайтара бастайды.

Бұл жағдайда біз аламыз мазмұнды пайдаланушыларға жақындатады және желі жүктемесін тарату. Мысалы, тек Мәскеу кэшінен біз ең жоғары сағаттарда 1 Тбит/с артық таратамыз.

Бірақ проблемалар бар - кэш серверлері резеңке емес. Өте танымал мазмұн үшін кейде бөлек сервер үшін желі жеткіліксіз. Біздің кэш-серверлер 40-50 Гбит/с құрайды, бірақ мұндай арнаны толығымен бітеп тастайтын мазмұн бар. Біз аймақтағы танымал файлдардың бірнеше көшірмелерін сақтауды жүзеге асыруға көшеміз. Оны жыл соңына дейін жүзеге асырамыз деп сенемін.

Біз жалпы архитектураны қарастырдық.

  • Сұраныстарды қабылдайтын алдыңғы серверлер.
  • Сұрауларды өңдейтін серверлер.
  • Проксидің екі түрімен жабылатын қоймалар.
  • Аймақтық кэштер.

Бұл диаграммада не жетіспейді? Әрине, біз деректерді сақтайтын дерекқорлар.

Мәліметтер базасы немесе қозғалтқыштар

Біз оларды деректер базасы емес, қозғалтқыштар деп атаймыз - Қозғалтқыштар, өйткені бізде жалпы қабылданған мағынада деректер базасы іс жүзінде жоқ.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Бұл қажетті шара. Бұл 2008-2009 жылдары ВК-ның танымалдылығы қарқынды өскен кезде, жоба толығымен MySQL және Memcache жүйелерінде жұмыс істеді және проблемалар туындады. MySQL файлдарды бұзып, бүлдіргісі келді, содан кейін ол қалпына келтірілмейді және Memcache бірте-бірте өнімділігін төмендетті және қайта іске қосылуы керек болды.

Барған сайын танымал жобада деректерді бүлдіретін тұрақты сақтау орны және баяулататын кэш бар екені белгілі болды. Мұндай жағдайларда өсіп келе жатқан жобаны әзірлеу қиын. Жобаның маңыздылығын өз велосипедтерімізде қайта жазуға тырысу туралы шешім қабылданды.

Шешім сәтті болды. Мұны істеуге мүмкіндік болды, сонымен қатар аса қажеттілік болды, өйткені ол кезде масштабтаудың басқа әдістері жоқ еді. Дерекқорлардың бір тобы болмады, NoSQL әлі болған жоқ, тек MySQL, Memcache, PostrgreSQL болды - және бәрі де болды.

Әмбебап операция. Әзірлеуді біздің C әзірлеушілер тобы басқарды және барлығы дәйекті түрде жасалды. Қозғалтқышқа қарамастан, олардың барлығында дискіге жазылған шамамен бірдей файл пішімі, бірдей іске қосу параметрлері, бірдей өңделген сигналдар болды және шеткі жағдайлар мен проблемалар туындаған жағдайда шамамен бірдей әрекет етті. Қозғалтқыштардың өсуімен әкімшілерге жүйені басқару ыңғайлы болды - оны күтіп ұстауды қажет ететін хайуанаттар бағы жоқ және олар үшінші тараптың әрбір жаңа дерекқорын қалай басқару керектігін қайта үйренуі керек, бұл тез және жылдам жасауға мүмкіндік берді. олардың санын ыңғайлы түрде көбейту.

Қозғалтқыштардың түрлері

Команда бірнеше қозғалтқыштар жазды. Міне, олардың кейбіреулері: дос, кеңестер, сурет, ipdb, хаттар, тізімдер, журналдар, memcached, meowdb, жаңалықтар, nostradamus, фото, ойнату тізімдері, pmemcached, құмсалғыш, іздеу, сақтау, ұнатулар, тапсырмалар, ...

Арнайы деректер құрылымын талап ететін немесе типтік емес сұрауларды өңдейтін әрбір тапсырма үшін C тобы жаңа қозғалтқышты жазады. Неге жоқ.

Бізде бөлек қозғалтқыш бар memcached, ол кәдімгіге ұқсас, бірақ көптеген тәттілермен және жылдамдығын төмендетпейді. ClickHouse емес, бірақ ол да жұмыс істейді. Бөлек қол жетімді pmemcached Мүмкін тұрақты жад кэштелген, ол сонымен қатар деректерді дискіде сақтай алады, сонымен қатар қайта іске қосу кезінде деректерді жоғалтпау үшін жедел жадыға сыймайды. Жеке тапсырмалар үшін әртүрлі қозғалтқыштар бар: кезектер, тізімдер, жинақтар - біздің жобаға қажет нәрсенің бәрі.

Кластерлер

Код тұрғысынан қозғалтқыштарды немесе дерекқорларды процестер, нысандар немесе даналар ретінде қарастырудың қажеті жоқ. Код арнайы кластерлермен, қозғалтқыштар топтарымен жұмыс істейді - кластерге бір түрі. Мемкэштелген кластер бар делік - бұл жай ғана машиналар тобы.

Код физикалық орынды, өлшемді немесе серверлердің санын мүлде білудің қажеті жоқ. Ол белгілі бір идентификатор арқылы кластерге барады.

Бұл жұмыс істеуі үшін код пен қозғалтқыштар арасында орналасқан тағы бір нысанды қосу керек - прокси.

RPC прокси

Прокси қосатын автобус, сайттың барлығы дерлік жұмыс істейді. Сонымен бірге бізде бар қызмет табылмады — оның орнына осы прокси үшін барлық кластерлердің және осы кластердің барлық бөліктерінің орнын білетін конфигурация бар. Админдер осылай істейді.

Бағдарламашыларға оның қанша, қайда және қанша тұратыны маңызды емес - олар жай ғана кластерге барады. Бұл бізге көп мүмкіндік береді. Сұрауды алған кезде прокси қай жерде екенін біле отырып, сұрауды қайта бағыттайды - мұны өзі анықтайды.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Бұл жағдайда прокси-сервис ақаулығынан қорғау нүктесі болып табылады. Кейбір қозғалтқыш баяуласа немесе бұзылса, прокси мұны түсінеді және клиенттік тарапқа сәйкес жауап береді. Бұл күту уақытын жоюға мүмкіндік береді - код қозғалтқыштың жауап беруін күтпейді, бірақ оның жұмыс істемейтінін түсінеді және басқаша әрекет ету керек. Код дерекқорлардың әрдайым жұмыс істемейтіні үшін дайындалуы керек.

Арнайы іске асырулар

Кейде біз әлі де қозғалтқыш ретінде стандартты емес шешімге ие болғымыз келеді. Сонымен қатар, біздің қозғалтқыштарымыз үшін арнайы жасалған дайын rpc-проксиді пайдаланбай, тапсырма үшін жеке прокси жасау туралы шешім қабылданды.

Бізде әлі де бар MySQL үшін db-прокси қолданамыз, ал ClickHouse үшін - Котенка.

Ол әдетте осылай жұмыс істейді. Белгілі бір сервер бар, ол kPHP, Go, Python жұмыс істейді - жалпы алғанда, біздің RPC протоколын пайдалана алатын кез келген код. Код жергілікті түрде RPC проксиінде жұмыс істейді - код орналасқан әрбір сервер өзінің жергілікті проксиін іске қосады. Сұраныс бойынша прокси қайда бару керектігін түсінеді.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Бір қозғалтқыш екіншісіне барғысы келсе, тіпті көрші болса да, ол прокси арқылы өтеді, себебі көрші басқа деректер орталығында болуы мүмкін. Қозғалтқыш өзінен басқа ештеңенің орнын білуге ​​сенбеуі керек - бұл біздің стандартты шешіміміз. Бірақ, әрине, ерекше жағдайлар бар :)

Барлық қозғалтқыштар жұмыс істейтін TL-схемасының мысалы.

memcache.not_found                                = memcache.Value;
memcache.strvalue	value:string flags:int = memcache.Value;
memcache.addOrIncr key:string flags:int delay:int value:long = memcache.Value;

tasks.task
    fields_mask:#
    flags:int
    tag:%(Vector int)
    data:string
    id:fields_mask.0?long
    retries:fields_mask.1?int
    scheduled_time:fields_mask.2?int
    deadline:fields_mask.3?int
    = tasks.Task;
 
tasks.addTask type_name:string queue_id:%(Vector int) task:%tasks.Task = Long;

Бұл екілік протокол, оның ең жақын аналогы протобуф. Схема қосымша өрістерді, күрделі типтерді - кірістірілген скалярлардың кеңейтімдерін және сұрауларды алдын ала сипаттайды. Барлығы осы протоколға сәйкес жұмыс істейді.

TCP/UDP бойынша TL арқылы RPC… UDP?

Бізде TL схемасының үстінде жұмыс істейтін қозғалтқыш сұрауларын орындауға арналған RPC протоколы бар. Мұның бәрі TCP/UDP қосылымы арқылы жұмыс істейді. TCP түсінікті, бірақ неліктен бізге UDP жиі қажет?

UDP көмектеседі серверлер арасындағы байланыстардың көптігі мәселесін болдырмаңыз. Егер әрбір серверде RPC проксиі болса және жалпы ол кез келген қозғалтқышқа бара алатын болса, онда бір серверде ондаған мың TCP қосылымдары болады. Жүк бар, бірақ пайдасыз. UDP жағдайында бұл мәселе жоқ.

Артық TCP қол алысу жоқ. Бұл әдеттегі мәселе: жаңа қозғалтқыш немесе жаңа сервер іске қосылғанда, көптеген TCP қосылымдары бірден орнатылады. Шағын жеңіл сұраулар үшін, мысалы, UDP пайдалы жүктемесі код пен қозғалтқыш арасындағы барлық байланыс болып табылады екі UDP пакеттері: біреуі бір бағытта, екіншісі екіншісінде ұшады. Бір реттік сапар - және код қозғалтқыштан қол алысусыз жауап алды.

Иә, барлығы жұмыс істейді пакеттердің жоғалуының өте аз пайызымен. Хаттамада ретрансляциялар мен күту уақыттары үшін қолдау бар, бірақ егер біз көп нәрсені жоғалтсақ, біз дерлік TCP аламыз, бұл пайдалы емес. Біз UDP-ді мұхиттар арқылы өткізбейміз.

Бізде мыңдаған мұндай серверлер бар және схемасы бірдей: әрбір физикалық серверде қозғалтқыштар пакеті орнатылған. Олар негізінен блоктаусыз мүмкіндігінше жылдам іске қосу үшін бір ағынды және бір ағынды шешімдер ретінде бөлінген. Сонымен қатар, бізде бұл қозғалтқыштардан сенімді ештеңе жоқ және деректерді тұрақты сақтауға көп көңіл бөлінеді.

Деректерді тұрақты сақтау

Қозғалтқыштар бинлогтарды жазады. Бинлог - бұл күйдің немесе деректердің өзгеруіне арналған оқиға қосылатын файл. Әртүрлі шешімдерде ол басқаша аталады: екілік журнал, WAL, AOF, бірақ принципі бірдей.

Қозғалтқышты қайта іске қосу кезінде көптеген жылдар бойы бүкіл бинлогты қайта оқуға жол бермеу үшін қозғалтқыштар жазады суреттер - ағымдағы күй. Қажет болса, олар алдымен одан оқиды, содан кейін бинлогтан оқуды аяқтайды. Барлық бинлогтар бірдей екілік пішімде жазылады - TL схемасына сәйкес, әкімшілер оларды құралдарын пайдалана отырып бірдей басқара алады. Мұндай суреттердің қажеті жоқ. Кімнің суреті int, қозғалтқыштың сиқыры және қай корпус ешкім үшін маңызды емес екенін көрсететін жалпы тақырып бар. Бұл суретті жазған қозғалтқышқа қатысты мәселе.

Мен жұмыс принципін тез сипаттаймын. Қозғалтқыш жұмыс істейтін сервер бар. Ол жазу үшін жаңа бос бинлогты ашады және оны өзгерту үшін оқиға жазады.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Бір сәтте ол суретке түсіруді шешеді немесе сигнал алады. Сервер жаңа файл жасайды, оның бүкіл күйін оған жазады, файлдың соңына ағымдағы бинлог өлшемін – офсетті қосады және әрі қарай жазуды жалғастырады. Жаңа бинлог жасалмады.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Қозғалтқыш қайта іске қосылған кезде, дискіде бинлог пен сурет болады. Қозғалтқыш бүкіл суретті оқиды және белгілі бір сәтте оның күйін көтереді.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Сурет жасалған кездегі орынды және бинлог өлшемін оқиды.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Ағымдағы күйді алу үшін бинлогтың соңын оқиды және одан әрі оқиғаларды жазуды жалғастырады. Бұл қарапайым схема, біздің барлық қозғалтқыштар соған сәйкес жұмыс істейді.

Деректерді репликациялау

Нәтижесінде деректердің қайталануы біздің мәлімдемеге негізделген — біз бинлогқа ешқандай бет өзгерістерін емес, дәлірек айтқанда жазамыз сұрауларды өзгерту. Желі арқылы келетінге өте ұқсас, тек сәл өзгертілген.

Сол схема тек репликация үшін ғана емес, сонымен қатар қолданылады сақтық көшірмелерді жасау үшін. Бізде қозғалтқыш бар - бинлогқа жазатын жазу шебері. Әкімшілер оны орнатқан кез келген басқа жерде бұл бинлог көшіріледі, және бәрі - бізде сақтық көшірме бар.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Қажет болса көшірме оқуОрталық процессордың оқу жүктемесін азайту үшін бинлогтың соңын оқитын және осы командаларды жергілікті түрде орындайтын оқу қозғалтқышы жай ғана іске қосылады.

Мұндағы артта қалу өте аз және репликаның шеберден қаншалықты артта қалғанын білуге ​​болады.

RPC проксиінде деректерді бөлу

Sharding қалай жұмыс істейді? Прокси қай кластер фрагментін жіберу керектігін қалай түсінеді? Кодта: «15 сынықтарға жібер!» Демейді. - жоқ, мұны прокси жасайды.

Ең қарапайым схема - firstint — сұраудағы бірінші сан.

get(photo100_500) => 100 % N.

Бұл қарапайым мемкэштелген мәтіндік протоколға мысал, бірақ, әрине, сұраулар күрделі және құрылымды болуы мүмкін. Мысал сұраудағы бірінші санды және кластер өлшеміне бөлінгенде қалғанын алады.

Бұл бір нысанның деректер локализациясын алғымыз келгенде пайдалы. 100 пайдаланушы немесе топ идентификаторы делік және біз бір нысанның барлық деректерінің күрделі сұраулар үшін бір бөлікте болуын қалаймыз.

Сұраныстардың кластер бойынша қалай таралатыны бізге маңызды болмаса, басқа нұсқа бар - бүкіл сынықты хэштеу.

hash(photo100_500) => 3539886280 % N

Біз сондай-ақ хэшті, бөлімнің қалған бөлігін және бөлшек нөмірін аламыз.

Бұл опциялардың екеуі де кластердің өлшемін ұлғайтқанда оны бөлуге немесе бірнеше есе көбейтуге дайын болған жағдайда ғана жұмыс істейді. Мысалы, бізде 16 сынық болды, бізде жеткіліксіз, біз көбірек алғымыз келеді - біз тоқтаусыз 32-ні қауіпсіз ала аламыз. Егер біз еселік емес көбейткіміз келсе, тоқтаулар болады, өйткені біз жоғалтпай барлығын дәл бөле алмаймыз. Бұл опциялар пайдалы, бірақ әрқашан емес.

Серверлердің еркін санын қосу немесе жою қажет болса, біз пайдаланамыз A la Ketama сақинасындағы тұрақты хэшинг. Бірақ сонымен бірге біз деректердің локализациясын толығымен жоғалтамыз; әрбір бөлік өзінің шағын жауабын қайтаратындай сұрауды кластерге біріктіруіміз керек, содан кейін проксиге жауаптарды біріктіру керек.

Өте ерекше сұраныстар бар. Бұл келесідей көрінеді: RPC проксиі сұрауды алады, қай кластерге өту керектігін анықтайды және үзіндіні анықтайды. Содан кейін не жазу шеберлері бар немесе кластерде реплика қолдауы болса, ол сұрау бойынша репликаға жібереді. Мұның бәрін прокси жасайды.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Журналдар

Біз журналдарды бірнеше жолмен жазамыз. Ең айқын және қарапайым memcache журналына жазу.

ring-buffer: prefix.idx = line

Негізгі префикс бар - журналдың аты, жол, және бұл журналдың өлшемі бар - жолдар саны. Біз кездейсоқ санды 0-ден минус 1-ге дейінгі жолдар санына аламыз. Memcache-дегі кілт осы кездейсоқ санмен біріктірілген префикс болып табылады. Журнал жолын және ағымдағы уақытты мәнге сақтаймыз.

Журналдарды оқу қажет болғанда, біз орындаймыз Multi Get уақыт бойынша сұрыпталған барлық кілттер, осылайша нақты уақытта өндіріс журналын алыңыз. Схема нақты уақыт режимінде, ештеңені бұзбай, басқа машиналарға трафикті тоқтатпай немесе рұқсат етпей, өндірісте бірдеңені жөндеу қажет болғанда қолданылады, бірақ бұл журнал ұзаққа созылмайды.

Бөренелерді сенімді сақтау үшін бізде қозғалтқыш бар журналдар қозғалтқышы. Дәл осы себепті ол құрылды және көптеген кластерлерде кеңінен қолданылады. Мен білетін ең үлкен кластер 600 ТБ оралған журналдарды сақтайды.

Қозғалтқыш өте ескі, қазірдің өзінде 6-7 жаста кластерлер бар. Біз шешуге тырысып жатқан проблемалар бар, мысалы, журналдарды сақтау үшін ClickHouse-ды белсенді пайдалана бастадық.

ClickHouse жүйесінде журналдарды жинау

Бұл диаграмма біздің қозғалтқыштарға қалай кіретінімізді көрсетеді.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Жергілікті RPC арқылы RPC-проксиге өтетін код бар және ол қозғалтқышқа қайда бару керектігін түсінеді. Егер біз ClickHouse жүйесінде журналдарды жазғымыз келсе, біз осы схеманың екі бөлігін өзгертуіміз керек:

  • кейбір қозғалтқышты ClickHouse-мен ауыстырыңыз;
  • ClickHouse қатынаса алмайтын RPC проксиін RPC арқылы мүмкін болатын кейбір шешіммен ауыстырыңыз.

Қозғалтқыш қарапайым - біз оны сервермен немесе ClickHouse көмегімен серверлер кластерімен ауыстырамыз.

ClickHouse-қа бару үшін біз жасадық Котенка үйі. Егер біз KittenHouse-тан ClickHouse-қа тікелей барсақ, ол жеңе алмайды. Сұраныссыз да ол көптеген машиналардың HTTP қосылымдарынан қосылады. Схеманың жұмыс істеуі үшін ClickHouse серверінде жергілікті кері прокси көтеріледі, ол қосылымдардың қажетті көлемдеріне төтеп бере алатындай етіп жазылған. Ол сондай-ақ өз ішіндегі деректерді салыстырмалы түрде сенімді түрде буферлей алады.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Кейде біз RPC схемасын стандартты емес шешімдерде, мысалы, nginx-те жүзеге асырғымыз келмейді. Сондықтан, KittenHouse UDP арқылы журналдарды қабылдау мүмкіндігіне ие.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Егер журналдарды жіберуші және алушы бір құрылғыда жұмыс істесе, жергілікті хост ішінде UDP пакетін жоғалту ықтималдығы өте төмен. Үшінші тарап шешімінде RPC енгізу қажеттілігі мен сенімділік арасындағы ымыра ретінде біз жай ғана UDP жіберуді қолданамыз. Бұл схемаға кейінірек ораламыз.

Бақылау

Бізде журналдардың екі түрі бар: әкімшілер өз серверлерінде жинағандар және әзірлеушілер кодтан жазғандар. Олар метриканың екі түріне сәйкес келеді: жүйе және өнім.

Жүйелік көрсеткіштер

Ол біздің барлық серверлерімізде жұмыс істейді Желілік деректер, ол статистиканы жинайды және оларды жібереді Графит көміртегі. Сондықтан ClickHouse, мысалы, Whisper емес, сақтау жүйесі ретінде пайдаланылады. Қажет болса, ClickHouse сайтынан тікелей оқуға немесе пайдалануға болады Графана метрикалар, графиктер және есептер үшін. Әзірлеушілер ретінде бізде Netdata және Grafana қолжетімділігі жеткілікті.

Өнім көрсеткіштері

Ыңғайлы болу үшін біз көп нәрсені жаздық. Мысалы, Counts, UniqueCounts мәндерін статистикаға жазуға мүмкіндік беретін қарапайым функциялар жинағы бар, олар әрі қарай бір жерге жіберіледі.

statlogsCountEvent   ( ‘stat_name’,            $key1, $key2, …)
statlogsUniqueCount ( ‘stat_name’, $uid,    $key1, $key2, …)
statlogsValuetEvent  ( ‘stat_name’, $value, $key1, $key2, …)

$stats = statlogsStatData($params)

Содан кейін біз сұрыптау және топтау сүзгілерін пайдалана аламыз және статистикадан қалағанның бәрін жасай аламыз - графиктер құру, Watchdogs конфигурациялау.

Біз өте жазамыз көптеген көрсеткіштер оқиғалар саны күніне 600 миллиардтан 1 триллионға дейін. Дегенмен, біз оларды сақтағымыз келеді кем дегенде бір-екі жылметрикадағы тенденцияларды түсіну. Осының барлығын біріктіру – әлі шешілмеген үлкен мәселе. Мен сізге соңғы бірнеше жылда қалай жұмыс істейтінін айтып беремін.

Бізде осы көрсеткіштерді жазатын функциялар бар жергілікті memcacheжазбалар санын азайту үшін. Бір рет қысқа мерзімде жергілікті іске қосылды статистика-демон барлық жазбаларды жинайды. Содан кейін жын көрсеткіштерді серверлердің екі қабатына біріктіреді журналдарды жинаушылар, ол артындағы қабат өліп қалмауы үшін біздің көптеген машиналарымыздың статистикасын біріктіреді.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Қажет болса, журналдарды жинаушыларға тікелей жаза аламыз.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Бірақ кодтан тікелей коллекторларға жазу, stas-daemom-ды айналып өту - нашар масштабталатын шешім, себебі ол коллекторға жүктемені арттырады. Шешім қандай да бір себептермен машинада memcache stats-демонды көтере алмасақ немесе ол бұзылып, біз тікелей барған жағдайда ғана қолайлы.

Одан кейін журналдарды жинаушылар статистиканы біріктіреді meowDB - бұл көрсеткіштерді сақтай алатын біздің дерекқорымыз.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Содан кейін кодтан екілік «жақын SQL» таңдауларын жасай аламыз.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Эксперимент

2018 жылдың жазында бізде ішкі хакатон болды және диаграмманың қызыл бөлігін ClickHouse-да көрсеткіштерді сақтай алатын нәрсемен ауыстыру идеясы пайда болды. Бізде ClickHouse журналдары бар - неге оны қолданып көрмеске?

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Бізде KittenHouse арқылы журналдарды жазатын схема болды.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Біз шештік диаграммаға тағы бір «*Үй» қосыңыз, ол өлшемдерді дәл форматта алады, өйткені біздің код оларды UDP арқылы жазады. Содан кейін бұл *House оларды KittenHouse түсінетін журналдар сияқты кірістірулерге айналдырады. Ол бұл журналдарды ClickHouse-қа өте жақсы жеткізе алады, ол оларды оқи алады.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Memcache, stats-demon және logs-collectors дерекқоры бар схема осымен ауыстырылды.

ВКонтакте архитектурасы мен жұмысы туралы жиі қойылатын сұрақтар

Memcache, stats-demon және logs-collectors дерекқоры бар схема осымен ауыстырылды.

  • Мұнда кодтан жөнелтілім бар, ол StatsHouse ішінде жергілікті түрде жазылған.
  • StatsHouse SQL кірістірулеріне түрлендірілген UDP көрсеткіштерін KittenHouse ішіне пакеттермен жазады.
  • KittenHouse оларды ClickHouse қызметіне жібереді.
  • Егер біз оларды оқығымыз келсе, онда біз оларды StatsHouse-ды айналып өтіп оқимыз - кәдімгі SQL арқылы тікелей ClickHouse-тен.

Әлі де ме эксперимент, бірақ бізге оның қалай шыққаны ұнайды. Егер біз схемадағы ақауларды түзетсек, онда біз оған толығымен ауысамыз. Жеке өзім солай үміттенемін.

Схема темірді үнемдемейді. Аз серверлер қажет, жергілікті статистикалық демондар мен журналдар коллекторлары қажет емес, бірақ ClickHouse ағымдағы схемадағыларға қарағанда үлкенірек серверді қажет етеді. Азырақ серверлер қажет, бірақ олар қымбатырақ және күштірек болуы керек.

Орналастыру

Алдымен PHP қолдануды қарастырайық. Біз дамып келеміз Git: пайдалану GitLab и TeamCity орналастыру үшін. Әзірлеу тармақтары негізгі тармаққа біріктіріледі, сынақтан өткізу үшін олар кезеңге біріктіріледі және қойылымнан өндіріске біріктіріледі.

Орналастыру алдында ағымдағы өндіріс тармағы және алдыңғысы алынады және оларда дифференциалды файлдар қарастырылады - өзгерістер: жасалған, жойылған, өзгертілген. Бұл өзгеріс біздің бүкіл серверлер флотындағы өзгерістерді жылдам қайталай алатын арнайы көшіру жылдамдығы қозғалтқыштың бинлогында жазылған. Мұнда қолданылатын нәрсе тікелей көшіру емес, бірақ өсектің қайталануы, бір сервер өзгертулерді ең жақын көршілеріне жібергенде, оларды көршілеріне және т.б. Бұл бүкіл флот бойынша кодты ондаған және секунд бірліктері ішінде жаңартуға мүмкіндік береді. Өзгеріс жергілікті көшірмеге жеткенде, ол осы патчтарды оған қолданады жергілікті файлдық жүйе. Кері қайтару да сол схема бойынша жүзеге асырылады.

Біз сондай-ақ kPHP-ді көп пайдаланамыз және оның өзіндік дамуы да бар Git жоғарыдағы диаграммаға сәйкес. Содан бері HTTP серверінің екілік, онда біз дифференцияны шығара алмаймыз - екілік шығарылымның салмағы жүздеген МБ құрайды. Сондықтан мұнда тағы бір нұсқа бар - нұсқа жазылған binlog copyfast. Әрбір құрастыру кезінде ол артады, ал кері қайтару кезінде де артады. Нұсқа серверлерге көшіріледі. Жергілікті копифасттар бинлогқа жаңа нұсқаның кіргенін көреді және сол өсек репликациясы арқылы олар біздің басты серверімізді шаршатпай, жүктемені желі бойынша мұқият таратады. Келесі не әсем қайта іске қосу жаңа нұсқа үшін.

Негізінде екілік болып табылатын біздің қозғалтқыштарымыз үшін схема өте ұқсас:

  • git мастер тармағы;
  • екілік ішінде .deb;
  • нұсқа binlog copyfast жүйесіне жазылған;
  • серверлерге көшіріледі;
  • сервер жаңа .dep шығарады;
  • dpkg -i;
  • жаңа нұсқаға керемет қайта қосу.

Айырмашылығы - біздің екілік файлымыз мұрағатта жинақталған .deb, және оларды сору кезінде dpkg -i жүйеге орналастырылады. Неліктен kPHP екілік, ал қозғалтқыштар dpkg ретінде орналастырылған? Бұл солай болды. Ол жұмыс істейді - оған қол тигізбеңіз.

Пайдалы сілтемелер:

Бағдарламалар комитетінің құрамында көмектесіп жүргендердің бірі – Алексей Акулович PHP Ресей 17 мамырда PHP әзірлеушілері үшін соңғы уақыттағы ең үлкен оқиға болады. Қараңызшы, бізде қандай тамаша компьютер бар, не спикерлер (олардың екеуі PHP өзегін жасауда!) - PHP жазсаңыз, жіберіп алмайтын нәрсе сияқты.

Ақпарат көзі: www.habr.com

пікір қалдыру