Soalan Lazim mengenai seni bina dan kerja VKontakte

Sejarah penciptaan VKontakte ada di Wikipedia; ia diberitahu oleh Pavel sendiri. Nampaknya semua orang sudah mengenalinya. Mengenai dalaman, seni bina dan struktur tapak pada HighLoad++ Pavel memberitahu saya pada tahun 2010. Banyak pelayan telah bocor sejak itu, jadi kami akan mengemas kini maklumat: kami akan membedahnya, mengeluarkan bahagian dalam, menimbangnya, dan melihat peranti VK dari sudut teknikal.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Alexey Akulovich (AterCattus) pembangun bahagian belakang dalam pasukan VKontakte. Transkrip laporan ini adalah jawapan kolektif kepada soalan lazim tentang pengendalian platform, infrastruktur, pelayan dan interaksi antara mereka, tetapi bukan tentang pembangunan, iaitu tentang besi. Secara berasingan, mengenai pangkalan data dan apa yang ada pada VK, tentang mengumpul log dan memantau keseluruhan projek secara keseluruhan. Butiran di bawah potongan.



Selama lebih empat tahun saya telah menangani pelbagai tugas yang berkaitan dengan bahagian belakang.

  • Memuat naik, menyimpan, memproses, mengedar media: video, penstriman langsung, audio, foto, dokumen.
  • Infrastruktur, platform, pemantauan pembangun, log, cache wilayah, CDN, protokol RPC proprietari.
  • Penyepaduan dengan perkhidmatan luaran: pemberitahuan tolak, penghuraian pautan luaran, suapan RSS.
  • Membantu rakan sekerja dengan pelbagai soalan, jawapan yang memerlukan menyelam ke dalam kod yang tidak diketahui.

Pada masa ini, saya mempunyai banyak bahagian dalam laman web ini. Saya ingin berkongsi pengalaman ini.

Seni bina umum

Semuanya, seperti biasa, bermula dengan pelayan atau kumpulan pelayan yang menerima permintaan.

Pelayan hadapan

Pelayan hadapan menerima permintaan melalui HTTPS, RTMP dan WSS.

HTTPS - ini adalah permintaan untuk versi web utama dan mudah alih tapak: vk.com dan m.vk.com, dan pelanggan rasmi dan tidak rasmi API kami yang lain: pelanggan mudah alih, messenger. Kami ada majlis resepsi RTMP-trafik untuk siaran Langsung dengan pelayan hadapan yang berasingan dan WSS- sambungan untuk API Penstriman.

Untuk HTTPS dan WSS pada pelayan adalah berbaloi nginx. Untuk siaran RTMP, kami baru-baru ini bertukar kepada penyelesaian kami sendiri kive, tetapi ia di luar skop laporan. Untuk toleransi kesalahan, pelayan ini mengiklankan alamat IP biasa dan bertindak dalam kumpulan supaya jika terdapat masalah pada salah satu pelayan, permintaan pengguna tidak hilang. Untuk HTTPS dan WSS, pelayan yang sama ini menyulitkan trafik untuk mengambil sebahagian daripada beban CPU sendiri.

Kami tidak akan bercakap lebih lanjut tentang WSS dan RTMP, tetapi hanya tentang permintaan HTTPS standard, yang biasanya dikaitkan dengan projek web.

Backend

Di belakang bahagian hadapan biasanya terdapat pelayan bahagian belakang. Mereka memproses permintaan yang diterima oleh pelayan hadapan daripada pelanggan.

ini pelayan kPHP, di mana daemon HTTP sedang berjalan, kerana HTTPS sudah dinyahsulitkan. kPHP ialah pelayan yang berjalan model prefork: memulakan proses induk, sekumpulan proses kanak-kanak, memberikan soket mendengar kepada mereka dan mereka memproses permintaan mereka. Dalam kes ini, proses tidak dimulakan semula antara setiap permintaan daripada pengguna, tetapi hanya menetapkan semula keadaannya kepada keadaan nilai sifar asal - permintaan demi permintaan, bukannya dimulakan semula.

Pembahagian beban

Semua bahagian belakang kami bukanlah kumpulan besar mesin yang boleh memproses sebarang permintaan. Kita mereka dibahagikan kepada kumpulan yang berasingan: umum, mudah alih, api, video, pementasan... Masalah pada kumpulan mesin yang berasingan tidak akan menjejaskan semua yang lain. Dalam kes masalah dengan video, pengguna yang mendengar muzik tidak akan tahu tentang masalah tersebut. Bahagian belakang mana untuk menghantar permintaan diputuskan oleh nginx di bahagian hadapan mengikut konfigurasi.

Pengumpulan metrik dan pengimbangan semula

Untuk memahami berapa banyak kereta yang perlu kita ada dalam setiap kumpulan, kita jangan bergantung pada QPS. Bahagian belakang adalah berbeza, mereka mempunyai permintaan yang berbeza, setiap permintaan mempunyai kerumitan yang berbeza untuk mengira QPS. Sebab itu kita kami beroperasi dengan konsep beban pada pelayan secara keseluruhan - pada CPU dan perf.

Kami mempunyai beribu-ribu pelayan sedemikian. Setiap pelayan fizikal menjalankan kumpulan kPHP untuk mengitar semula semua teras (kerana kPHP berbenang tunggal).

Pelayan Kandungan

CS atau Content Server ialah storan. CS ialah pelayan yang menyimpan fail dan juga memproses fail yang dimuat naik dan semua jenis tugas segerak latar belakang yang diperuntukkan oleh bahagian hadapan web utama kepadanya.

Kami mempunyai puluhan ribu pelayan fizikal yang menyimpan fail. Pengguna suka memuat naik fail, dan kami suka menyimpan dan mengongsinya. Beberapa pelayan ini ditutup oleh pelayan pu/pp khas.

pu/pp

Jika anda membuka tab rangkaian dalam VK, anda melihat pu/pp.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Apakah pu/pp? Jika kita menutup satu demi satu pelayan, maka terdapat dua pilihan untuk memuat naik dan memuat turun fail ke pelayan yang telah ditutup: secara langsung melalui http://cs100500.userapi.com/path atau melalui pelayan perantaraan - http://pu.vk.com/c100500/path.

Pu ialah nama sejarah untuk muat naik foto, dan pp ialah proksi foto. Iaitu, satu pelayan adalah untuk memuat naik foto, dan satu lagi adalah untuk memuat naik. Kini bukan sahaja foto dimuatkan, tetapi nama itu telah dipelihara.

Pelayan ini menamatkan sesi HTTPSuntuk mengeluarkan beban pemproses daripada storan. Selain itu, oleh kerana fail pengguna diproses pada pelayan ini, lebih kurang maklumat sensitif yang disimpan pada mesin ini, lebih baik. Contohnya, kunci penyulitan HTTPS.

Memandangkan mesin ditutup oleh mesin kami yang lain, kami mampu untuk tidak memberi mereka IP luaran "putih", dan berikan "kelabu". Dengan cara ini kami menjimatkan kumpulan IP dan menjamin untuk melindungi mesin daripada akses luar - langsung tiada IP untuk masuk ke dalamnya.

Ketahanan terhadap IP yang dikongsi. Dari segi toleransi kesalahan, skema berfungsi sama - beberapa pelayan fizikal mempunyai IP fizikal biasa, dan perkakasan di hadapan mereka memilih tempat untuk menghantar permintaan. Saya akan bercakap tentang pilihan lain kemudian.

Perkara yang menjadi kontroversi ialah dalam kes ini pelanggan menyimpan lebih sedikit sambungan. Jika terdapat IP yang sama untuk beberapa mesin - dengan hos yang sama: pu.vk.com atau pp.vk.com, penyemak imbas pelanggan mempunyai had pada bilangan permintaan serentak kepada satu hos. Tetapi dalam masa HTTP/2 di mana-mana, saya percaya bahawa ini tidak lagi begitu relevan.

Kelemahan yang jelas dari skim ini ialah ia perlu pam semua lalu lintas, yang pergi ke storan, melalui pelayan lain. Memandangkan kami mengepam trafik melalui mesin, kami belum boleh mengepam trafik yang berat, contohnya, video, menggunakan skim yang sama. Kami menghantarnya terus - sambungan langsung yang berasingan untuk storan berasingan khusus untuk video. Kami menghantar kandungan yang lebih ringan melalui proksi.

Tidak lama dahulu kami mendapat versi proksi yang lebih baik. Sekarang saya akan memberitahu anda bagaimana mereka berbeza daripada yang biasa dan mengapa ini perlu.

matahari

Pada September 2017, Oracle, yang sebelum ini telah membeli Sun, memecat sebilangan besar pekerja Sun. Kita boleh mengatakan bahawa pada masa ini syarikat itu tidak lagi wujud. Apabila memilih nama untuk sistem baharu, pentadbir kami memutuskan untuk memberi penghormatan kepada ingatan syarikat ini dan menamakan sistem baharu itu Sun. Di antara kita kita hanya memanggilnya "matahari".

Soalan Lazim mengenai seni bina dan kerja VKontakte

pp mempunyai beberapa masalah. Satu IP setiap kumpulan - cache tidak berkesan. Beberapa pelayan fizikal berkongsi alamat IP biasa, dan tidak ada cara untuk mengawal pelayan mana permintaan akan pergi. Oleh itu, jika pengguna yang berbeza datang untuk fail yang sama, maka jika terdapat cache pada pelayan ini, fail itu berakhir dalam cache setiap pelayan. Ini adalah skim yang sangat tidak cekap, tetapi tiada apa yang boleh dilakukan.

Akibatnya - kita tidak boleh memecahkan kandungan, kerana kami tidak boleh memilih pelayan khusus untuk kumpulan ini - mereka mempunyai IP yang sama. Juga atas beberapa sebab dalaman yang kami ada adalah tidak mungkin untuk memasang pelayan sedemikian di kawasan. Mereka berdiri hanya di St. Petersburg.

Dengan matahari, kami menukar sistem pemilihan. Sekarang kita ada penghalaan anycast: penghalaan dinamik, anycast, daemon semak sendiri. Setiap pelayan mempunyai IP individu sendiri, tetapi subnet biasa. Semuanya dikonfigurasikan sedemikian rupa sehingga jika satu pelayan gagal, trafik tersebar merentasi pelayan lain kumpulan yang sama secara automatik. Sekarang adalah mungkin untuk memilih pelayan tertentu, tiada caching berlebihan, dan kebolehpercayaan tidak terjejas.

Sokongan berat badan. Sekarang kita mampu memasang mesin dengan kuasa yang berbeza mengikut keperluan, dan juga, sekiranya berlaku masalah sementara, tukar berat "matahari" yang berfungsi untuk mengurangkan beban padanya, supaya mereka "berehat" dan mula bekerja semula.

Perkongsian mengikut id kandungan. Perkara yang lucu tentang sharding: kami biasanya memecah kandungan supaya pengguna yang berbeza pergi ke fail yang sama melalui "matahari" yang sama supaya mereka mempunyai cache yang sama.

Kami baru-baru ini melancarkan aplikasi "Clover". Ini adalah kuiz dalam talian dalam siaran langsung, di mana hos bertanya soalan dan pengguna menjawab dalam masa nyata, memilih pilihan. Apl ini mempunyai sembang di mana pengguna boleh bersembang. Boleh menyambung secara serentak ke siaran lebih 100 ribu orang. Mereka semua menulis mesej yang dihantar kepada semua peserta, dan avatar disertakan bersama mesej itu. Jika 100 ribu orang datang untuk satu avatar dalam satu "matahari", maka ia kadang-kadang boleh bergolek di belakang awan.

Untuk menahan semburan permintaan untuk fail yang sama, kami menghidupkan skim bodoh yang menyebarkan fail ke semua "matahari" yang tersedia di rantau ini untuk jenis kandungan tertentu.

Matahari dari dalam

Proksi terbalik pada nginx, cache sama ada dalam RAM atau pada cakera Optane/NVMe pantas. Contoh: http://sun4-2.userapi.com/c100500/path β€” pautan ke "matahari", yang terletak di rantau keempat, kumpulan pelayan kedua. Ia menutup fail laluan, yang secara fizikal terletak pada pelayan 100500.

Cache

Kami menambah satu lagi nod pada skema seni bina kami - persekitaran caching.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Di bawah ialah gambarajah susun atur tembolok serantau, terdapat kira-kira 20 daripadanya. Ini ialah tempat di mana cache dan "matahari" terletak, yang boleh menyimpan trafik melalui diri mereka sendiri.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Ini adalah caching kandungan multimedia; tiada data pengguna disimpan di sini - hanya muzik, video, foto.

Untuk menentukan wilayah pengguna, kami kami mengumpulkan awalan rangkaian BGP yang diumumkan di wilayah tersebut. Dalam kes sandaran, kami juga perlu menghuraikan pangkalan data geoip jika kami tidak dapat mencari IP dengan awalan. Kami menentukan rantau mengikut IP pengguna. Dalam kod tersebut, kita boleh melihat satu atau lebih kawasan pengguna - titik yang paling dekat dengannya secara geografi.

Bagaimana ia berfungsi?

Kami mengira populariti fail mengikut wilayah. Terdapat beberapa cache serantau di mana pengguna berada, dan pengecam fail - kami mengambil pasangan ini dan menambah rating dengan setiap muat turun.

Pada masa yang sama, syaitan - perkhidmatan di wilayah - dari semasa ke semasa datang ke API dan berkata: "Saya ini dan ini cache, berikan saya senarai fail paling popular di rantau saya yang belum ada pada saya. ” API menyampaikan sekumpulan fail yang diisih mengikut rating, daemon memuat turunnya, membawanya ke kawasan dan menghantar fail dari sana. Ini ialah perbezaan asas antara pu/pp dan Sun daripada cache: mereka memberikan fail melalui diri mereka serta-merta, walaupun jika fail ini tiada dalam cache, dan cache mula-mula memuat turun fail itu kepada dirinya sendiri, dan kemudian mula memberikannya semula.

Dalam kes ini kita dapat kandungan lebih dekat dengan pengguna dan menyebarkan beban rangkaian. Sebagai contoh, hanya dari cache Moscow kami mengedarkan lebih daripada 1 Tbit/s pada waktu puncak.

Tetapi ada masalah - pelayan cache bukan getah. Untuk kandungan yang sangat popular, kadangkala tiada rangkaian yang mencukupi untuk pelayan yang berasingan. Pelayan cache kami adalah 40-50 Gbit/s, tetapi terdapat kandungan yang menyumbat saluran sedemikian sepenuhnya. Kami bergerak ke arah melaksanakan penyimpanan lebih daripada satu salinan fail popular di rantau ini. Saya harap kita akan melaksanakannya pada penghujung tahun ini.

Kami melihat seni bina umum.

  • Pelayan hadapan yang menerima permintaan.
  • Mengakhiri permintaan yang memproses.
  • Storan yang ditutup oleh dua jenis proksi.
  • Cache serantau.

Apa yang kurang daripada rajah ini? Sudah tentu, pangkalan data di mana kami menyimpan data.

Pangkalan data atau enjin

Kami memanggilnya bukan pangkalan data, tetapi enjin - Enjin, kerana kami secara praktikal tidak mempunyai pangkalan data dalam erti kata yang diterima umum.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Ini adalah langkah yang perlu. Ini berlaku kerana pada 2008-2009, apabila VK mempunyai pertumbuhan yang pesat dalam populariti, projek itu berfungsi sepenuhnya pada MySQL dan Memcache dan terdapat masalah. MySQL suka untuk ranap dan merosakkan fail, selepas itu ia tidak akan pulih, dan Memcache secara beransur-ansur merosot dalam prestasi dan terpaksa dimulakan semula.

Ternyata projek yang semakin popular itu mempunyai storan berterusan, yang merosakkan data, dan cache, yang menjadi perlahan. Dalam keadaan sedemikian, sukar untuk membangunkan projek yang sedang berkembang. Diputuskan untuk cuba menulis semula perkara kritikal yang difokuskan projek pada basikal kami sendiri.

Penyelesaiannya berjaya. Terdapat peluang untuk melakukan ini, serta keperluan yang melampau, kerana cara penskalaan lain tidak wujud pada masa itu. Tidak ada banyak pangkalan data, NoSQL belum wujud lagi, hanya ada MySQL, Memcache, PostrgreSQL - dan itu sahaja.

Operasi sejagat. Pembangunan ini diketuai oleh pasukan pembangun C kami dan semuanya dilakukan secara konsisten. Tanpa mengira enjin, mereka semua mempunyai format fail yang lebih kurang sama yang ditulis pada cakera, parameter pelancaran yang sama, isyarat yang diproses dengan cara yang sama dan berkelakuan lebih kurang sama sekiranya berlaku situasi dan masalah tepi. Dengan pertumbuhan enjin, adalah mudah bagi pentadbir untuk mengendalikan sistem - tidak ada zoo yang perlu diselenggara, dan mereka perlu belajar semula cara mengendalikan setiap pangkalan data pihak ketiga baharu, yang memungkinkan untuk meningkatkan dengan cepat dan mudah. nombor mereka.

Jenis-jenis enjin

Pasukan itu menulis beberapa enjin. Berikut adalah sebahagian daripadanya: rakan, pembayang, imej, ipdb, surat, senarai, log, memcached, meowdb, berita, nostradamus, foto, senarai main, pmemcached, kotak pasir, carian, storan, suka, tugas, …

Untuk setiap tugas yang memerlukan struktur data tertentu atau memproses permintaan atipikal, pasukan C menulis enjin baharu. Kenapa tidak.

Kami mempunyai enjin yang berasingan memcached, yang serupa dengan yang biasa, tetapi dengan banyak barang, dan yang tidak perlahan. Bukan ClickHouse, tetapi ia juga berfungsi. Tersedia secara berasingan pmemcached - Adakah memcached berterusan, yang juga boleh menyimpan data pada cakera, lebih-lebih lagi, daripada muat ke dalam RAM, supaya tidak kehilangan data apabila dimulakan semula. Terdapat pelbagai enjin untuk tugasan individu: baris gilir, senarai, set - semua yang diperlukan oleh projek kami.

Kelompok

Dari perspektif kod, tidak perlu memikirkan enjin atau pangkalan data sebagai proses, entiti atau kejadian. Kod ini berfungsi secara khusus dengan kelompok, dengan kumpulan enjin - satu jenis setiap kluster. Katakan terdapat kluster memcached - ia hanya sekumpulan mesin.

Kod tersebut tidak perlu mengetahui lokasi fizikal, saiz atau bilangan pelayan sama sekali. Dia pergi ke kluster menggunakan pengecam tertentu.

Untuk ini berfungsi, anda perlu menambah satu lagi entiti yang terletak di antara kod dan enjin - proksi.

Proksi RPC

proksi bas penghubung, di mana hampir keseluruhan tapak dijalankan. Pada masa yang sama kita ada tiada penemuan perkhidmatan β€” sebaliknya, terdapat konfigurasi untuk proksi ini, yang mengetahui lokasi semua kluster dan semua serpihan kluster ini. Ini yang admin buat.

Pengaturcara langsung tidak peduli berapa banyak, di mana dan berapa kosnya - mereka hanya pergi ke kluster. Ini membolehkan kita banyak. Apabila menerima permintaan, proksi mengubah hala permintaan, mengetahui di mana - ia menentukan ini sendiri.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Dalam kes ini, proksi ialah titik perlindungan terhadap kegagalan perkhidmatan. Jika sesetengah enjin menjadi perlahan atau rosak, maka proksi memahami perkara ini dan bertindak balas sewajarnya kepada pihak pelanggan. Ini membolehkan anda mengalih keluar tamat masa - kod tidak menunggu enjin bertindak balas, tetapi memahami bahawa ia tidak berfungsi dan perlu berkelakuan dengan cara yang berbeza. Kod mesti disediakan untuk fakta bahawa pangkalan data tidak selalu berfungsi.

Pelaksanaan khusus

Kadang-kadang kita masih benar-benar mahu mempunyai beberapa jenis penyelesaian bukan standard sebagai enjin. Pada masa yang sama, telah diputuskan untuk tidak menggunakan proksi rpc sedia kami, yang dicipta khusus untuk enjin kami, tetapi untuk membuat proksi berasingan untuk tugas itu.

Untuk MySQL, yang masih ada di sana sini, kami menggunakan db-proxy, dan untuk ClickHouse - Rumah kucing.

Ia berfungsi secara amnya seperti ini. Terdapat pelayan tertentu, ia menjalankan kPHP, Go, Python - secara umum, sebarang kod yang boleh menggunakan protokol RPC kami. Kod berjalan secara setempat pada proksi RPC - setiap pelayan di mana kod terletak menjalankan proksi tempatannya sendiri. Atas permintaan, proksi memahami ke mana hendak pergi.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Jika satu enjin mahu pergi ke yang lain, walaupun ia adalah jiran, ia melalui proksi, kerana jiran itu mungkin berada di pusat data lain. Enjin tidak seharusnya bergantung pada mengetahui lokasi apa-apa selain daripada dirinya sendiri - ini adalah penyelesaian standard kami. Tetapi sudah tentu ada pengecualian :)

Contoh skema TL mengikut mana semua enjin beroperasi.

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;

Ini adalah protokol binari, analog yang paling hampir ialah protobuf. Skema ini menerangkan medan pilihan, jenis kompleks - sambungan skalar terbina dalam dan pertanyaan. Semuanya berfungsi mengikut protokol ini.

RPC atas TL atas TCP/UDP... UDP?

Kami mempunyai protokol RPC untuk melaksanakan permintaan enjin yang berjalan di atas skim TL. Ini semua berfungsi melalui sambungan TCP/UDP. TCP boleh difahami, tetapi mengapa kita memerlukan UDP dengan kerap?

UDP membantu elakkan masalah sejumlah besar sambungan antara pelayan. Jika setiap pelayan mempunyai proksi RPC dan, secara amnya, ia boleh pergi ke mana-mana enjin, maka terdapat berpuluh-puluh ribu sambungan TCP bagi setiap pelayan. Ada beban, tetapi tidak berguna. Dalam kes UDP masalah ini tidak wujud.

Tiada jabat tangan TCP yang berlebihan. Ini adalah masalah biasa: apabila enjin baharu atau pelayan baharu dilancarkan, banyak sambungan TCP diwujudkan sekaligus. Untuk permintaan ringan yang kecil, contohnya, muatan UDP, semua komunikasi antara kod dan enjin adalah dua paket UDP: satu terbang ke satu arah, yang kedua ke arah yang lain. Satu perjalanan pergi dan balik - dan kod itu menerima respons daripada enjin tanpa berjabat tangan.

Ya, semuanya hanya berfungsi dengan peratusan kehilangan paket yang sangat kecil. Protokol mempunyai sokongan untuk penghantaran semula dan tamat masa, tetapi jika kita kehilangan banyak, kita akan mendapat hampir TCP, yang tidak menguntungkan. Kami tidak memandu UDP merentasi lautan.

Kami mempunyai beribu-ribu pelayan sedemikian, dan skemanya adalah sama: satu pek enjin dipasang pada setiap pelayan fizikal. Mereka kebanyakannya berbenang tunggal untuk berjalan secepat mungkin tanpa menyekat, dan dipecahkan sebagai penyelesaian berbenang tunggal. Pada masa yang sama, kami tidak mempunyai apa-apa yang lebih dipercayai daripada enjin ini, dan banyak perhatian diberikan kepada penyimpanan data yang berterusan.

Penyimpanan data yang berterusan

Enjin menulis binlog. Binlog ialah fail pada penghujung acara untuk perubahan keadaan atau data ditambahkan. Dalam penyelesaian yang berbeza ia dipanggil secara berbeza: log binari, WAL, AOF, tetapi prinsipnya adalah sama.

Untuk mengelakkan enjin daripada membaca semula keseluruhan binlog selama bertahun-tahun apabila dimulakan semula, enjin menulis syot kilat - keadaan semasa. Jika perlu, mereka membaca daripadanya dahulu, dan kemudian selesai membaca dari binlog. Semua binlog ditulis dalam format binari yang sama - mengikut skema TL, supaya pentadbir boleh mentadbirnya secara sama rata menggunakan alatan mereka. Tidak ada keperluan untuk syot kilat. Terdapat pengepala umum yang menunjukkan syot kilat siapakah int, keajaiban enjin, dan badan mana yang tidak penting kepada sesiapa pun. Ini adalah masalah dengan enjin yang merekodkan syot kilat.

Saya akan menerangkan dengan cepat prinsip operasi. Terdapat pelayan di mana enjin berjalan. Dia membuka binlog kosong baharu untuk menulis dan menulis acara untuk menukarnya.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Pada satu ketika, dia sama ada memutuskan untuk mengambil gambar sendiri, atau dia menerima isyarat. Pelayan mencipta fail baharu, menulis keseluruhan keadaannya ke dalamnya, menambahkan saiz binlog semasa - mengimbangi - ke penghujung fail dan terus menulis lebih lanjut. Binlog baharu tidak dibuat.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Pada satu ketika, apabila enjin dihidupkan semula, akan terdapat kedua-dua binlog dan syot kilat pada cakera. Enjin membaca keseluruhan syot kilat dan menaikkan keadaannya pada titik tertentu.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Membaca kedudukan yang ada pada masa syot kilat dicipta dan saiz binlog.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Membaca penghujung binlog untuk mendapatkan keadaan semasa dan terus menulis acara selanjutnya. Ini adalah skim mudah; semua enjin kami berfungsi mengikutnya.

Replikasi data

Akibatnya, replikasi data dalam kami berasaskan penyataan β€” kami menulis dalam binlog bukan sebarang perubahan halaman, tetapi iaitu tukar permintaan. Sangat serupa dengan apa yang datang melalui rangkaian, hanya diubah suai sedikit.

Skim yang sama digunakan bukan sahaja untuk replikasi, tetapi juga untuk membuat sandaran. Kami mempunyai enjin - pakar menulis yang menulis kepada binlog. Di mana-mana tempat lain di mana pentadbir menyediakannya, binlog ini disalin, dan itu sahaja - kami mempunyai sandaran.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Jika diperlukan replika bacaanUntuk mengurangkan beban bacaan CPU, enjin bacaan hanya dilancarkan, yang membaca penghujung binlog dan melaksanakan arahan ini secara tempatan.

Ketinggalan di sini adalah sangat kecil, dan adalah mungkin untuk mengetahui sejauh mana replika ketinggalan di belakang tuan.

Perkongsian data dalam proksi RPC

Bagaimanakah sharding berfungsi? Bagaimanakah proksi memahami serpihan kluster yang hendak dihantar? Kod itu tidak mengatakan: "Hantar untuk 15 serpihan!" - tidak, ini dilakukan oleh proksi.

Skim yang paling mudah ialah firstint β€” nombor pertama dalam permintaan.

get(photo100_500) => 100 % N.

Ini adalah contoh untuk protokol teks memcached yang mudah, tetapi, sudah tentu, pertanyaan boleh menjadi rumit dan berstruktur. Contoh mengambil nombor pertama dalam pertanyaan dan bakinya apabila dibahagikan dengan saiz kelompok.

Ini berguna apabila kita ingin mempunyai lokasi data bagi satu entiti. Katakan 100 ialah ID pengguna atau kumpulan dan kami mahu semua data satu entiti berada pada satu serpihan untuk pertanyaan kompleks.

Jika kami tidak peduli bagaimana permintaan tersebar di seluruh kluster, terdapat pilihan lain - pencincangan keseluruhan serpihan.

hash(photo100_500) => 3539886280 % N

Kami juga mendapat cincang, baki bahagian dan nombor serpihan.

Kedua-dua pilihan ini hanya berfungsi jika kami bersedia untuk fakta bahawa apabila kami meningkatkan saiz kluster, kami akan membahagikannya atau meningkatkannya beberapa kali. Sebagai contoh, kami mempunyai 16 serpihan, kami tidak cukup, kami mahu lebih - kami boleh mendapatkan 32 dengan selamat tanpa masa henti. Jika kita mahu meningkatkan bukan gandaan, akan ada masa henti, kerana kita tidak akan dapat membahagikan semuanya dengan tepat tanpa kerugian. Pilihan ini berguna, tetapi tidak selalu.

Jika kami perlu menambah atau mengalih keluar bilangan pelayan sewenang-wenangnya, kami menggunakan Hashing yang konsisten pada gelanggang ala Ketama. Tetapi pada masa yang sama, kami kehilangan lokasi data sepenuhnya; kami perlu menggabungkan permintaan kepada kluster supaya setiap bahagian mengembalikan respons kecilnya sendiri, dan kemudian menggabungkan respons kepada proksi.

Terdapat permintaan yang sangat khusus. Ia kelihatan seperti ini: Proksi RPC menerima permintaan, menentukan kelompok mana yang hendak dituju dan menentukan serpihan. Kemudian terdapat sama ada pakar penulisan, atau, jika kluster mempunyai sokongan replika, ia menghantar kepada replika atas permintaan. Proksi melakukan semua ini.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Log

Kami menulis log dalam beberapa cara. Yang paling jelas dan mudah ialah tulis log ke memcache.

ring-buffer: prefix.idx = line

Terdapat awalan utama - nama log, baris, dan terdapat saiz log ini - bilangan baris. Kami mengambil nombor rawak dari 0 hingga bilangan baris tolak 1. Kunci dalam memcache ialah awalan yang digabungkan dengan nombor rawak ini. Kami menyimpan baris log dan masa semasa kepada nilai.

Apabila perlu membaca log, kami melaksanakan Berbilang Dapatkan semua kunci, diisih mengikut masa, dan dengan itu dapatkan log pengeluaran dalam masa nyata. Skim ini digunakan apabila anda perlu menyahpepijat sesuatu dalam pengeluaran dalam masa nyata, tanpa melanggar apa-apa, tanpa menghentikan atau membenarkan trafik ke mesin lain, tetapi log ini tidak bertahan lama.

Untuk penyimpanan log yang boleh dipercayai, kami mempunyai enjin log-enjin. Inilah sebabnya mengapa ia dicipta dan digunakan secara meluas dalam sejumlah besar kelompok. Kelompok terbesar yang saya tahu menyimpan 600 TB log yang dibungkus.

Enjin dah lama sangat, ada cluster yang dah berumur 6-7 tahun. Terdapat masalah dengannya yang kami cuba selesaikan, sebagai contoh, kami mula aktif menggunakan ClickHouse untuk menyimpan log.

Mengumpul log dalam ClickHouse

Rajah ini menunjukkan cara kita masuk ke dalam enjin kita.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Terdapat kod yang dihantar secara tempatan melalui RPC ke proksi RPC, dan ia memahami ke mana hendak pergi ke enjin. Jika kita ingin menulis log dalam ClickHouse, kita perlu menukar dua bahagian dalam skema ini:

  • menggantikan beberapa enjin dengan ClickHouse;
  • gantikan proksi RPC, yang tidak boleh mengakses ClickHouse, dengan beberapa penyelesaian yang boleh, dan melalui RPC.

Enjinnya mudah - kami menggantikannya dengan pelayan atau sekumpulan pelayan dengan ClickHouse.

Dan untuk pergi ke ClickHouse, kami melakukannya KittenHouse. Jika kita pergi terus dari KittenHouse ke ClickHouse, ia tidak akan dapat mengatasinya. Walaupun tanpa permintaan, ia ditambah daripada sambungan HTTP sejumlah besar mesin. Agar skema berfungsi, pada pelayan dengan ClickHouse proksi terbalik tempatan dinaikkan, yang ditulis sedemikian rupa sehingga ia dapat menahan jumlah sambungan yang diperlukan. Ia juga boleh menimbal data dalam dirinya sendiri dengan agak boleh dipercayai.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Kadang-kadang kita tidak mahu melaksanakan skim RPC dalam penyelesaian bukan standard, contohnya, dalam nginx. Oleh itu, KittenHouse mempunyai keupayaan untuk menerima log melalui UDP.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Jika penghantar dan penerima log berfungsi pada mesin yang sama, maka kebarangkalian kehilangan paket UDP dalam hos tempatan adalah agak rendah. Sebagai kompromi antara keperluan untuk melaksanakan RPC dalam penyelesaian pihak ketiga dan kebolehpercayaan, kami hanya menggunakan penghantaran UDP. Kami akan kembali kepada skim ini kemudian.

Pemantauan

Kami mempunyai dua jenis log: yang dikumpul oleh pentadbir pada pelayan mereka dan yang ditulis oleh pembangun daripada kod. Ia sepadan dengan dua jenis metrik: sistem dan produk.

Metrik sistem

Ia berfungsi pada semua pelayan kami netdata, yang mengumpul statistik dan menghantarnya ke Karbon Grafit. Oleh itu, ClickHouse digunakan sebagai sistem storan, dan bukan Whisper, sebagai contoh. Jika perlu, anda boleh terus membaca daripada ClickHouse, atau gunakan grafana untuk metrik, graf dan laporan. Sebagai pembangun, kami mempunyai akses yang mencukupi kepada Netdata dan Grafana.

Metrik produk

Untuk kemudahan, kami telah menulis banyak perkara. Sebagai contoh, terdapat satu set fungsi biasa yang membolehkan anda menulis Counts, UniqueCounts nilai ke dalam statistik, yang dihantar ke tempat yang lebih jauh.

statlogsCountEvent   ( β€˜stat_name’,            $key1, $key2, …)
statlogsUniqueCount ( β€˜stat_name’, $uid,    $key1, $key2, …)
statlogsValuetEvent  ( β€˜stat_name’, $value, $key1, $key2, …)

$stats = statlogsStatData($params)

Selepas itu, kami boleh menggunakan penapis pengisihan dan pengelompokan dan melakukan semua yang kami mahu daripada statistik - membina graf, mengkonfigurasi Pengawas.

Kami menulis sangat banyak metrik bilangan acara adalah dari 600 bilion hingga 1 trilion setiap hari. Walau bagaimanapun, kami mahu mengekalkannya sekurang-kurangnya beberapa tahununtuk memahami arah aliran dalam metrik. Menyatukan semuanya adalah masalah besar yang belum kami selesaikan. Saya akan memberitahu anda bagaimana ia berfungsi selama beberapa tahun kebelakangan ini.

Kami mempunyai fungsi yang menulis metrik ini ke memcache tempatanuntuk mengurangkan bilangan penyertaan. Sekali dalam tempoh yang singkat dilancarkan secara tempatan stats-daemon mengumpul semua rekod. Seterusnya, syaitan menggabungkan metrik ke dalam dua lapisan pelayan pengumpul balak, yang mengagregatkan statistik daripada sekumpulan mesin kami supaya lapisan di belakangnya tidak mati.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Jika perlu, kita boleh menulis terus kepada pengumpul balak.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Tetapi menulis daripada kod terus kepada pengumpul, memintas stas-daemom, adalah penyelesaian yang tidak boleh skala kerana ia meningkatkan beban pada pengumpul. Penyelesaiannya hanya sesuai jika atas sebab tertentu kami tidak dapat menaikkan statistik-daemon memcache pada mesin, atau ia ranap dan kami pergi terus.

Seterusnya, pengumpul log menggabungkan statistik ke dalam meowDB - ini adalah pangkalan data kami, yang juga boleh menyimpan metrik.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Kemudian kita boleh membuat pilihan binari "near-SQL" daripada kod.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Eksperimen

Pada musim panas 2018, kami mengadakan hackathon dalaman, dan idea muncul untuk cuba menggantikan bahagian merah rajah dengan sesuatu yang boleh menyimpan metrik dalam ClickHouse. Kami mempunyai log di ClickHouse - mengapa tidak mencubanya?

Soalan Lazim mengenai seni bina dan kerja VKontakte

Kami mempunyai skema yang menulis log melalui KittenHouse.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Kami telah tentukan tambah satu lagi β€œ*Rumah” pada rajah, yang akan menerima betul-betul metrik dalam format semasa kod kami menulisnya melalui UDP. Kemudian *House ini mengubahnya menjadi sisipan, seperti log, yang KittenHouse faham. Dia boleh menghantar log ini dengan sempurna kepada ClickHouse, yang sepatutnya boleh membacanya.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Skim dengan pangkalan data memcache, stats-daemon dan logs collectors digantikan dengan yang ini.

Soalan Lazim mengenai seni bina dan kerja VKontakte

Skim dengan pangkalan data memcache, stats-daemon dan logs collectors digantikan dengan yang ini.

  • Terdapat penghantaran dari kod di sini, yang ditulis secara tempatan dalam StatsHouse.
  • StatsHouse menulis metrik UDP, sudah ditukar menjadi sisipan SQL, kepada KittenHouse dalam kelompok.
  • KittenHouse menghantarnya ke ClickHouse.
  • Jika kita ingin membacanya, maka kita membacanya memintas StatsHouse - terus dari ClickHouse menggunakan SQL biasa.

Adakah ia masih percubaan, tetapi kami suka bagaimana ia ternyata. Jika kita membetulkan masalah dengan skim itu, maka mungkin kita akan beralih kepadanya sepenuhnya. Secara peribadi, saya harap begitu.

Skim ini tidak menjimatkan besi. Pelayan yang lebih sedikit diperlukan, daemon statistik tempatan dan pengumpul log tidak diperlukan, tetapi ClickHouse memerlukan pelayan yang lebih besar daripada pelayan dalam skema semasa. Lebih sedikit pelayan diperlukan, tetapi ia mesti lebih mahal dan lebih berkuasa.

Sebarkan

Mula-mula, mari kita lihat pada penggunaan PHP. Kami sedang membangun dalam pergi: guna GitLab ΠΈ TeamCity untuk penempatan. Cawangan pembangunan digabungkan ke dalam cawangan induk, daripada induk untuk ujian ia digabungkan menjadi pementasan, dan daripada pementasan kepada pengeluaran.

Sebelum penggunaan, cawangan pengeluaran semasa dan yang sebelumnya diambil, dan fail berbeza dipertimbangkan di dalamnya - perubahan: dibuat, dipadam, diubah. Perubahan ini direkodkan dalam binlog enjin copyfast khas, yang boleh meniru perubahan dengan cepat pada keseluruhan kumpulan pelayan kami. Apa yang digunakan di sini bukan meniru langsung, tetapi replikasi gosip, apabila satu pelayan menghantar perubahan kepada jiran terdekatnya, kepada jirannya, dan sebagainya. Ini membolehkan anda mengemas kini kod dalam berpuluh-puluh dan unit saat merentas seluruh kumpulan. Apabila perubahan mencapai replika tempatan, ia menggunakan tampalan ini padanya sistem fail tempatan. Rollback juga dilakukan mengikut skema yang sama.

Kami juga menggunakan kPHP dengan banyak dan ia juga mempunyai pembangunannya sendiri pergi mengikut rajah di atas. Sejak ini binari pelayan HTTP, maka kita tidak boleh menghasilkan perbezaan - perduaan keluaran seberat ratusan MB. Oleh itu, terdapat pilihan lain di sini - versi ditulis kepada binlog copyfast. Dengan setiap binaan ia meningkat, dan semasa rollback ia juga meningkat. Versi direplikasi kepada pelayan. Copyfast tempatan melihat bahawa versi baharu telah memasuki binlog, dan melalui replikasi gosip yang sama mereka mengambil versi terbaharu binari untuk diri mereka sendiri, tanpa memenatkan pelayan induk kami, tetapi menyebarkan beban dengan teliti ke seluruh rangkaian. Apa yang berikut pelancaran semula yang anggun untuk versi baharu.

Untuk enjin kami, yang juga pada asasnya binari, skema ini sangat serupa:

  • cawangan induk git;
  • binari dalam deb;
  • versi ditulis ke binlog copyfast;
  • direplikasi ke pelayan;
  • pelayan mengeluarkan .dep yang baru;
  • dpkg -i;
  • pelancaran semula anggun kepada versi baharu.

Perbezaannya ialah binari kami dibungkus dalam arkib deb, dan apabila mengepam keluar mereka dpkg -i diletakkan pada sistem. Mengapakah kPHP digunakan sebagai binari, dan enjin digunakan sebagai dpkg? Ia berlaku begitu. Ia berfungsi - jangan sentuhnya.

Pautan yang berguna:

Alexey Akulovich adalah salah seorang daripada mereka yang, sebagai sebahagian daripada Jawatankuasa Program, membantu PHP Rusia pada 17 Mei akan menjadi acara terbesar untuk pembangun PHP sejak kebelakangan ini. Lihatlah betapa hebatnya PC kita, apa pembesar suara (dua daripadanya sedang membangunkan teras PHP!) - nampaknya sesuatu yang anda tidak boleh ketinggalan jika anda menulis PHP.

Sumber: www.habr.com

Tambah komen