Seni bina pengimbang beban rangkaian dalam Yandex.Cloud

Seni bina pengimbang beban rangkaian dalam Yandex.Cloud
Halo, saya Sergey Elantsev, saya berkembang pengimbang beban rangkaian dalam Yandex.Cloud. Sebelum ini, saya mengetuai pembangunan pengimbang L7 untuk portal Yandex - rakan sekerja bergurau bahawa tidak kira apa yang saya lakukan, ia ternyata menjadi pengimbang. Saya akan memberitahu pembaca Habr cara menguruskan beban dalam platform awan, perkara yang kami lihat sebagai alat yang ideal untuk mencapai matlamat ini, dan cara kami bergerak ke arah membina alat ini.

Mula-mula, mari kita perkenalkan beberapa istilah:

  • VIP (IP Maya) - alamat IP pengimbang
  • Pelayan, bahagian belakang, contoh - mesin maya yang menjalankan aplikasi
  • RIP (IP Sebenar) - alamat IP pelayan
  • Pemeriksaan kesihatan - menyemak kesediaan pelayan
  • Zon Ketersediaan, AZ - infrastruktur terpencil di pusat data
  • Rantau - kesatuan AZ yang berbeza

Pengimbang beban menyelesaikan tiga tugas utama: mereka melakukan pengimbangan itu sendiri, meningkatkan toleransi kesalahan perkhidmatan dan memudahkan penskalaannya. Toleransi kesalahan dipastikan melalui pengurusan trafik automatik: pengimbang memantau keadaan aplikasi dan mengecualikan keadaan daripada pengimbangan yang tidak melepasi semakan keaktifan. Penskalaan dipastikan dengan mengagihkan beban secara sama rata merentas kejadian, serta mengemas kini senarai kejadian dengan cepat. Jika pengimbangan tidak cukup seragam, sesetengah kejadian akan menerima beban yang melebihi had kapasitinya dan perkhidmatan akan menjadi kurang dipercayai.

Pengimbang beban selalunya diklasifikasikan oleh lapisan protokol daripada model OSI di mana ia dijalankan. Pengimbang Awan beroperasi pada tahap TCP, yang sepadan dengan lapisan keempat, L4.

Mari kita beralih kepada gambaran keseluruhan seni bina pengimbang Awan. Kami akan meningkatkan tahap perincian secara beransur-ansur. Kami membahagikan komponen pengimbang kepada tiga kelas. Kelas satah konfigurasi bertanggungjawab untuk interaksi pengguna dan menyimpan keadaan sasaran sistem. Pesawat kawalan menyimpan keadaan semasa sistem dan mengurus sistem daripada kelas pesawat data, yang bertanggungjawab secara langsung untuk menghantar trafik daripada pelanggan ke kejadian anda.

Pesawat data

Trafik berakhir pada peranti mahal yang dipanggil penghala sempadan. Untuk meningkatkan toleransi kesalahan, beberapa peranti sedemikian beroperasi serentak dalam satu pusat data. Seterusnya, trafik pergi ke pengimbang, yang mengumumkan alamat IP anycast kepada semua AZ melalui BGP untuk pelanggan. 

Seni bina pengimbang beban rangkaian dalam Yandex.Cloud

Trafik dihantar melalui ECMP - ini ialah strategi penghalaan yang mengikutnya terdapat beberapa laluan yang sama baik ke sasaran (dalam kes kami, sasaran ialah alamat IP destinasi) dan paket boleh dihantar bersama mana-mana daripadanya. Kami juga menyokong kerja di beberapa zon ketersediaan mengikut skema berikut: kami mengiklankan alamat di setiap zon, trafik pergi ke yang terdekat dan tidak melampaui hadnya. Kemudian dalam siaran kami akan melihat dengan lebih terperinci tentang apa yang berlaku kepada trafik.

Pesawat konfigurasi

 
Komponen utama satah konfigurasi ialah API, yang melaluinya operasi asas dengan pengimbang dilakukan: mencipta, memadam, menukar komposisi kejadian, mendapatkan hasil pemeriksaan kesihatan, dsb. Di satu pihak, ini ialah API REST dan pada yang lain, kami dalam Awan sangat kerap menggunakan rangka kerja gRPC, jadi kami "terjemah" REST kepada gRPC dan kemudian hanya menggunakan gRPC. Sebarang permintaan membawa kepada penciptaan satu siri tugas idempoten tak segerak yang dilaksanakan pada kumpulan biasa pekerja Yandex.Cloud. Tugasan ditulis sedemikian rupa sehingga ia boleh digantung pada bila-bila masa dan kemudian dimulakan semula. Ini memastikan kebolehskalaan, kebolehulangan dan pengelogan operasi.

Seni bina pengimbang beban rangkaian dalam Yandex.Cloud

Akibatnya, tugas daripada API akan membuat permintaan kepada pengawal perkhidmatan pengimbang, yang ditulis dalam Go. Ia boleh menambah dan mengalih keluar pengimbang, menukar komposisi hujung belakang dan tetapan. 

Seni bina pengimbang beban rangkaian dalam Yandex.Cloud

Perkhidmatan ini menyimpan keadaannya dalam Pangkalan Data Yandex, pangkalan data terurus yang diedarkan yang anda akan dapat gunakan tidak lama lagi. Dalam Yandex.Cloud, seperti yang telah kita lakukan memberitahu, konsep makanan anjing terpakai: jika kami sendiri menggunakan perkhidmatan kami, maka pelanggan kami juga akan gembira menggunakannya. Pangkalan Data Yandex adalah contoh pelaksanaan konsep sedemikian. Kami menyimpan semua data kami dalam YDB, dan kami tidak perlu memikirkan tentang mengekalkan dan menskala pangkalan data: masalah ini diselesaikan untuk kami, kami menggunakan pangkalan data sebagai perkhidmatan.

Mari kembali kepada pengawal pengimbang. Tugasnya adalah untuk menyimpan maklumat tentang pengimbang dan menghantar tugas untuk menyemak kesediaan mesin maya kepada pengawal pemeriksaan kesihatan.

Pengawal pemeriksaan kesihatan

Ia menerima permintaan untuk menukar peraturan semakan, menyimpannya dalam YDB, mengagihkan tugas antara nod pemeriksaan kesihatan dan mengagregatkan keputusan, yang kemudiannya disimpan ke pangkalan data dan dihantar kepada pengawal loadbalancer. Ia, seterusnya, menghantar permintaan untuk menukar komposisi kluster dalam satah data kepada loadbalancer-nod, yang akan saya bincangkan di bawah.

Seni bina pengimbang beban rangkaian dalam Yandex.Cloud

Mari bercakap lebih lanjut mengenai pemeriksaan kesihatan. Mereka boleh dibahagikan kepada beberapa kelas. Audit mempunyai kriteria kejayaan yang berbeza. Pemeriksaan TCP perlu berjaya mewujudkan sambungan dalam tempoh masa yang tetap. Semakan HTTP memerlukan sambungan yang berjaya dan respons dengan kod status 200.

Juga, semakan berbeza dalam kelas tindakan - mereka aktif dan pasif. Pemeriksaan pasif hanya memantau apa yang berlaku dengan trafik tanpa mengambil sebarang tindakan khas. Ini tidak berfungsi dengan baik pada L4 kerana ia bergantung pada logik protokol peringkat lebih tinggi: pada L4 tiada maklumat tentang tempoh operasi mengambil masa atau sama ada penyiapan sambungan adalah baik atau buruk. Pemeriksaan aktif memerlukan pengimbang untuk menghantar permintaan kepada setiap contoh pelayan.

Kebanyakan pengimbang beban melakukan pemeriksaan keaktifan sendiri. Di Cloud, kami memutuskan untuk memisahkan bahagian sistem ini untuk meningkatkan kebolehskalaan. Pendekatan ini akan membolehkan kami menambah bilangan pengimbang sambil mengekalkan bilangan permintaan pemeriksaan kesihatan kepada perkhidmatan. Pemeriksaan dilakukan oleh nod pemeriksaan kesihatan yang berasingan, yang merentasi sasaran pemeriksaan dipecahkan dan direplikasi. Anda tidak boleh melakukan semakan daripada satu hos, kerana ia mungkin gagal. Kemudian kita tidak akan mendapat keadaan keadaan yang dia semak. Kami melakukan semakan pada mana-mana kejadian daripada sekurang-kurangnya tiga nod pemeriksaan kesihatan. Kami membahagikan tujuan semakan antara nod menggunakan algoritma pencincangan yang konsisten.

Seni bina pengimbang beban rangkaian dalam Yandex.Cloud

Mengasingkan pengimbangan dan pemeriksaan kesihatan boleh membawa kepada masalah. Jika nod pemeriksaan kesihatan membuat permintaan kepada contoh, memintas pengimbang (yang pada masa ini tidak melayani trafik), maka situasi pelik timbul: sumber nampaknya masih hidup, tetapi trafik tidak akan mencapainya. Kami menyelesaikan masalah ini dengan cara ini: kami dijamin untuk memulakan trafik pemeriksaan kesihatan melalui pengimbang. Dalam erti kata lain, skim untuk mengalihkan paket dengan trafik daripada pelanggan dan dari pemeriksaan kesihatan berbeza secara minimum: dalam kedua-dua kes, paket akan mencapai pengimbang, yang akan menghantarnya ke sumber sasaran.

Perbezaannya ialah pelanggan membuat permintaan kepada VIP, manakala pemeriksaan kesihatan membuat permintaan kepada setiap RIP individu. Masalah menarik timbul di sini: kami memberi pengguna kami peluang untuk mencipta sumber dalam rangkaian IP kelabu. Mari bayangkan bahawa terdapat dua pemilik awan berbeza yang menyembunyikan perkhidmatan mereka di sebalik pengimbang. Setiap daripada mereka mempunyai sumber dalam subnet 10.0.0.1/24, dengan alamat yang sama. Anda perlu entah bagaimana membezakannya, dan di sini anda perlu menyelami struktur rangkaian maya Yandex.Cloud. Adalah lebih baik untuk mengetahui lebih banyak butiran dalam video daripada about:cloud event, adalah penting bagi kami sekarang bahawa rangkaian adalah berbilang lapisan dan mempunyai terowong yang boleh dibezakan oleh subnet id.

Nod pemeriksaan kesihatan menghubungi pengimbang menggunakan alamat quasi-IPv6 yang dipanggil. Alamat kuasi ialah alamat IPv6 dengan alamat IPv4 dan id subnet pengguna yang dibenamkan di dalamnya. Trafik mencapai pengimbang, yang mengekstrak alamat sumber IPv4 daripadanya, menggantikan IPv6 dengan IPv4 dan menghantar paket ke rangkaian pengguna.

Trafik terbalik berjalan dengan cara yang sama: pengimbang melihat bahawa destinasi adalah rangkaian kelabu daripada pemeriksa kesihatan dan menukar IPv4 kepada IPv6.

VPP - nadi pesawat data

Pengimbang dilaksanakan menggunakan teknologi Pemprosesan Paket Vektor (VPP), rangka kerja dari Cisco untuk pemprosesan kelompok trafik rangkaian. Dalam kes kami, rangka kerja berfungsi di atas perpustakaan pengurusan peranti rangkaian ruang pengguna - Kit Pembangunan Data Plane (DPDK). Ini memastikan prestasi pemprosesan paket yang tinggi: lebih sedikit gangguan berlaku dalam kernel, dan tiada suis konteks antara ruang kernel dan ruang pengguna. 

VPP melangkah lebih jauh dan memerah lebih banyak prestasi daripada sistem dengan menggabungkan pakej ke dalam kelompok. Keuntungan prestasi datang daripada penggunaan cache yang agresif pada pemproses moden. Kedua-dua cache data digunakan (paket diproses dalam "vektor", data berdekatan antara satu sama lain) dan cache arahan: dalam VPP, pemprosesan paket mengikut graf, nod yang mengandungi fungsi yang melaksanakan tugas yang sama.

Sebagai contoh, pemprosesan paket IP dalam VPP berlaku dalam susunan berikut: pertama, pengepala paket dihuraikan dalam nod penghuraian, dan kemudian ia dihantar ke nod, yang memajukan paket selanjutnya mengikut jadual penghalaan.

Tegar sikit. Pengarang VPP tidak bertolak ansur dengan kompromi dalam penggunaan cache pemproses, jadi kod tipikal untuk memproses vektor paket mengandungi vektorisasi manual: terdapat gelung pemprosesan di mana situasi seperti "kami mempunyai empat paket dalam baris gilir" diproses, maka sama untuk dua, kemudian - untuk satu. Arahan prefetch sering digunakan untuk memuatkan data ke dalam cache untuk mempercepatkan akses kepada mereka dalam lelaran berikutnya.

n_left_from = frame->n_vectors;
while (n_left_from > 0)
{
    vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    // ...
    while (n_left_from >= 4 && n_left_to_next >= 2)
    {
        // processing multiple packets at once
        u32 next0 = SAMPLE_NEXT_INTERFACE_OUTPUT;
        u32 next1 = SAMPLE_NEXT_INTERFACE_OUTPUT;
        // ...
        /* Prefetch next iteration. */
        {
            vlib_buffer_t *p2, *p3;

            p2 = vlib_get_buffer (vm, from[2]);
            p3 = vlib_get_buffer (vm, from[3]);

            vlib_prefetch_buffer_header (p2, LOAD);
            vlib_prefetch_buffer_header (p3, LOAD);

            CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
            CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
        }
        // actually process data
        /* verify speculative enqueues, maybe switch current next frame */
        vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
                to_next, n_left_to_next,
                bi0, bi1, next0, next1);
    }

    while (n_left_from > 0 && n_left_to_next > 0)
    {
        // processing packets by one
    }

    // processed batch
    vlib_put_next_frame (vm, node, next_index, n_left_to_next);
}

Jadi, Healthchecks bercakap melalui IPv6 kepada VPP, yang mengubahnya menjadi IPv4. Ini dilakukan oleh nod dalam graf, yang kami panggil NAT algoritma. Untuk trafik terbalik (dan penukaran daripada IPv6 ke IPv4) terdapat nod NAT algoritma yang sama.

Seni bina pengimbang beban rangkaian dalam Yandex.Cloud

Trafik terus daripada pelanggan pengimbang melalui nod graf, yang melakukan pengimbangan itu sendiri. 

Seni bina pengimbang beban rangkaian dalam Yandex.Cloud

Nod pertama ialah sesi melekit. Ia menyimpan hash daripada 5-tuple untuk sesi yang telah ditetapkan. 5-tuple termasuk alamat dan port klien dari mana maklumat dihantar, alamat dan port sumber yang tersedia untuk menerima trafik, serta protokol rangkaian. 

Cincangan 5-tuple membantu kami melakukan kurang pengiraan dalam nod pencincangan konsisten seterusnya, serta mengendalikan perubahan senarai sumber dengan lebih baik di belakang pengimbang. Apabila paket yang tiada sesi tiba di pengimbang, ia dihantar ke nod pencincangan yang konsisten. Di sinilah pengimbangan berlaku menggunakan pencincangan yang konsisten: kami memilih sumber daripada senarai sumber "langsung" yang tersedia. Seterusnya, paket dihantar ke nod NAT, yang sebenarnya menggantikan alamat destinasi dan mengira semula jumlah semak. Seperti yang anda lihat, kami mengikut peraturan VPP - suka suka, mengumpulkan pengiraan yang serupa untuk meningkatkan kecekapan cache pemproses.

Pencincangan yang konsisten

Mengapa kita memilihnya dan apakah itu? Pertama, mari kita pertimbangkan tugas sebelumnya - memilih sumber daripada senarai. 

Seni bina pengimbang beban rangkaian dalam Yandex.Cloud

Dengan pencincangan yang tidak konsisten, cincangan paket masuk dikira dan sumber dipilih daripada senarai dengan baki pembahagian cincang ini dengan bilangan sumber. Selagi senarai itu kekal tidak berubah, skim ini berfungsi dengan baik: kami sentiasa menghantar paket dengan 5-tuple yang sama ke contoh yang sama. Jika, sebagai contoh, sesetengah sumber berhenti bertindak balas kepada pemeriksaan kesihatan, maka untuk sebahagian besar cincang pilihan akan berubah. Sambungan TCP pelanggan akan terputus: paket yang sebelum ini mencapai contoh A mungkin mula mencapai contoh B, yang tidak biasa dengan sesi untuk paket ini.

Pencincangan yang konsisten menyelesaikan masalah yang diterangkan. Cara paling mudah untuk menerangkan konsep ini ialah ini: bayangkan anda mempunyai cincin yang anda agihkan sumber melalui cincang (contohnya, melalui IP:port). Memilih sumber ialah memutar roda mengikut sudut, yang ditentukan oleh cincang paket.

Seni bina pengimbang beban rangkaian dalam Yandex.Cloud

Ini meminimumkan pengagihan semula trafik apabila komposisi sumber berubah. Memadamkan sumber hanya akan menjejaskan bahagian gelang pencincangan yang konsisten di mana sumber itu berada. Menambah sumber juga mengubah pengedaran, tetapi kami mempunyai nod sesi melekit, yang membolehkan kami tidak menukar sesi yang telah ditetapkan kepada sumber baharu.

Kami melihat apa yang berlaku untuk mengarahkan trafik antara pengimbang dan sumber. Sekarang mari kita lihat trafik balik. Ia mengikut corak yang sama seperti trafik semak - melalui NAT algoritma, iaitu, melalui NAT 44 terbalik untuk trafik pelanggan dan melalui NAT 46 untuk trafik pemeriksaan kesihatan. Kami mematuhi skim kami sendiri: kami menyatukan trafik pemeriksaan kesihatan dan trafik pengguna sebenar.

Loadbalancer-nod dan komponen yang dipasang

Komposisi pengimbang dan sumber dalam VPP dilaporkan oleh perkhidmatan tempatan - loadbalancer-node. Ia melanggan aliran peristiwa daripada pengawal-pemuat dan mampu memplot perbezaan antara keadaan VPP semasa dan keadaan sasaran yang diterima daripada pengawal. Kami mendapat sistem tertutup: peristiwa daripada API datang kepada pengawal pengimbang, yang memberikan tugas kepada pengawal pemeriksaan kesihatan untuk menyemak "keaktifan" sumber. Itu, seterusnya, memberikan tugas kepada nod pemeriksaan kesihatan dan mengagregatkan hasilnya, selepas itu ia menghantarnya kembali kepada pengawal pengimbang. Loadbalancer-node melanggan acara daripada pengawal dan menukar keadaan VPP. Dalam sistem sedemikian, setiap perkhidmatan hanya mengetahui apa yang perlu tentang perkhidmatan jiran. Bilangan sambungan adalah terhad dan kami mempunyai keupayaan untuk mengendalikan dan menskalakan segmen yang berbeza secara bebas.

Seni bina pengimbang beban rangkaian dalam Yandex.Cloud

Apakah isu yang dielakkan?

Semua perkhidmatan kami dalam pesawat kawalan ditulis dalam Go dan mempunyai ciri penskalaan dan kebolehpercayaan yang baik. Go mempunyai banyak perpustakaan sumber terbuka untuk membina sistem teragih. Kami menggunakan GRPC secara aktif, semua komponen mengandungi pelaksanaan sumber terbuka penemuan perkhidmatan - perkhidmatan kami memantau prestasi satu sama lain, boleh menukar komposisi mereka secara dinamik dan kami memautkan ini dengan pengimbangan GRPC. Untuk metrik, kami juga menggunakan penyelesaian sumber terbuka. Dalam pesawat data, kami mendapat prestasi yang baik dan rizab sumber yang besar: ternyata sangat sukar untuk memasang pendirian di mana kami boleh bergantung pada prestasi VPP, dan bukannya kad rangkaian besi.

Masalah dan Penyelesaian

Apa yang tidak berfungsi dengan baik? Go mempunyai pengurusan memori automatik, tetapi kebocoran memori masih berlaku. Cara paling mudah untuk menanganinya adalah dengan menjalankan goroutine dan ingat untuk menamatkannya. Bawa pulang: Tonton penggunaan memori program Go anda. Selalunya penunjuk yang baik ialah bilangan goroutine. Terdapat kelebihan dalam cerita ini: dalam Go adalah mudah untuk mendapatkan data masa jalan - penggunaan memori, bilangan goroutine yang sedang berjalan dan banyak parameter lain.

Selain itu, Go mungkin bukan pilihan terbaik untuk ujian berfungsi. Mereka agak bertele-tele, dan pendekatan standard "menjalankan segala-galanya dalam CI dalam satu kelompok" tidak begitu sesuai untuk mereka. Hakikatnya ialah ujian berfungsi lebih memerlukan sumber dan menyebabkan tamat masa sebenar. Disebabkan ini, ujian mungkin gagal kerana CPU sibuk dengan ujian unit. Kesimpulan: Jika boleh, lakukan ujian "berat" secara berasingan daripada ujian unit. 

Seni bina acara perkhidmatan mikro adalah lebih kompleks daripada monolit: mengumpul log pada berpuluh-puluh mesin yang berbeza tidak begitu mudah. Kesimpulan: jika anda membuat perkhidmatan mikro, segera fikirkan tentang pengesanan.

rancangan kami

Kami akan melancarkan pengimbang dalaman, pengimbang IPv6, menambah sokongan untuk skrip Kubernetes, terus memecah perkhidmatan kami (pada masa ini hanya healthcheck-node dan healthcheck-ctrl dipecahkan), menambah pemeriksaan kesihatan baharu dan juga melaksanakan pengagregatan pintar pemeriksaan. Kami sedang mempertimbangkan kemungkinan untuk menjadikan perkhidmatan kami lebih bebas - supaya mereka tidak berkomunikasi secara langsung antara satu sama lain, tetapi menggunakan baris gilir mesej. Perkhidmatan yang serasi dengan SQS telah muncul dalam Cloud baru-baru ini Barisan Mesej Yandex.

Baru-baru ini, keluaran awam Yandex Load Balancer berlaku. Meneroka dokumentasi kepada perkhidmatan, uruskan pengimbang dengan cara yang mudah untuk anda dan tingkatkan toleransi kesalahan projek anda!

Sumber: www.habr.com

Tambah komen