Arsitektur penyeimbang beban jaringan di Yandex.Cloud

Arsitektur penyeimbang beban jaringan di Yandex.Cloud
Halo, saya Sergey Elantsev, saya berkembang penyeimbang beban jaringan di Yandex.Cloud. Sebelumnya, saya memimpin pengembangan penyeimbang L7 untuk portal Yandex - rekan saya bercanda bahwa apa pun yang saya lakukan, ternyata itu adalah penyeimbang. Saya akan memberi tahu pembaca Habr cara mengelola beban di platform cloud, apa yang kami anggap sebagai alat ideal untuk mencapai tujuan ini, dan bagaimana kami bergerak menuju pembuatan alat ini.

Pertama, mari kita perkenalkan beberapa istilah:

  • VIP (IP Virtual) - alamat IP penyeimbang
  • Server, backend, instance - mesin virtual yang menjalankan aplikasi
  • RIP (IP Asli) - alamat IP server
  • Healthcheck - memeriksa kesiapan server
  • Availability Zone, AZ - infrastruktur terisolasi di pusat data
  • Wilayah - gabungan AZ yang berbeda

Penyeimbang beban menyelesaikan tiga tugas utama: mereka melakukan penyeimbangan itu sendiri, meningkatkan toleransi kesalahan layanan, dan menyederhanakan penskalaannya. Toleransi kesalahan dipastikan melalui manajemen lalu lintas otomatis: penyeimbang memantau status aplikasi dan mengecualikan instance dari penyeimbangan yang tidak lolos pemeriksaan keaktifan. Penskalaan dipastikan dengan mendistribusikan beban secara merata ke seluruh instans, serta memperbarui daftar instans dengan cepat. Jika penyeimbangannya tidak cukup seragam, beberapa instance akan menerima beban yang melebihi batas kapasitasnya, dan layanan akan menjadi kurang dapat diandalkan.

Penyeimbang beban sering kali diklasifikasikan berdasarkan lapisan protokol dari model OSI yang dijalankannya. Cloud Balancer beroperasi pada level TCP, yang sesuai dengan lapisan keempat, L4.

Mari beralih ke ikhtisar arsitektur penyeimbang Cloud. Kami secara bertahap akan meningkatkan tingkat detailnya. Kami membagi komponen penyeimbang menjadi tiga kelas. Kelas bidang konfigurasi bertanggung jawab atas interaksi pengguna dan menyimpan status target sistem. Bidang kontrol menyimpan status sistem saat ini dan mengelola sistem dari kelas bidang data, yang secara langsung bertanggung jawab untuk mengirimkan lalu lintas dari klien ke instans Anda.

Pesawat data

Lalu lintas berakhir di perangkat mahal yang disebut router perbatasan. Untuk meningkatkan toleransi kesalahan, beberapa perangkat tersebut beroperasi secara bersamaan di satu pusat data. Selanjutnya, lalu lintas menuju ke penyeimbang, yang mengumumkan alamat IP siaran apa pun ke semua AZ melalui BGP untuk klien. 

Arsitektur penyeimbang beban jaringan di Yandex.Cloud

Lalu lintas ditransmisikan melalui ECMP - ini adalah strategi perutean yang menurutnya mungkin terdapat beberapa rute yang sama bagusnya ke target (dalam kasus kami, targetnya adalah alamat IP tujuan) dan paket dapat dikirim melalui salah satu rute tersebut. Kami juga mendukung pekerjaan di beberapa zona ketersediaan sesuai dengan skema berikut: kami mengiklankan alamat di setiap zona, lalu lintas menuju ke zona terdekat dan tidak melampaui batasnya. Nanti di postingan kita akan melihat lebih detail apa yang terjadi pada lalu lintas.

Konfigurasi pesawat

 
Komponen kunci dari bidang konfigurasi adalah API, yang melaluinya operasi dasar dengan penyeimbang dilakukan: membuat, menghapus, mengubah komposisi instance, memperoleh hasil pemeriksaan kesehatan, dll. Di satu sisi, ini adalah REST API, dan di sisi lain, ini adalah REST API, dan di sisi lain, ini adalah REST API. lainnya, kami di Cloud sangat sering menggunakan kerangka kerja gRPC, jadi kami “menerjemahkan” REST ke gRPC dan kemudian hanya menggunakan gRPC. Permintaan apa pun mengarah pada pembuatan serangkaian tugas idempoten asinkron yang dijalankan pada kumpulan umum pekerja Yandex.Cloud. Tugas ditulis sedemikian rupa sehingga dapat ditangguhkan kapan saja dan kemudian dimulai kembali. Hal ini memastikan skalabilitas, pengulangan, dan pencatatan operasi.

Arsitektur penyeimbang beban jaringan di Yandex.Cloud

Akibatnya, tugas dari API akan membuat permintaan ke pengontrol layanan penyeimbang, yang ditulis dalam Go. Itu dapat menambah dan menghapus penyeimbang, mengubah komposisi backend dan pengaturan. 

Arsitektur penyeimbang beban jaringan di Yandex.Cloud

Layanan ini menyimpan statusnya di Database Yandex, database terkelola terdistribusi yang akan segera dapat Anda gunakan. Di Yandex.Cloud, seperti yang sudah kami lakukan diceritakan, konsep makanan anjing berlaku: jika kami sendiri yang menggunakan jasa kami, maka klien kami juga akan dengan senang hati menggunakannya. Database Yandex adalah contoh penerapan konsep semacam itu. Kami menyimpan semua data kami di YDB, dan kami tidak perlu memikirkan tentang pemeliharaan dan penskalaan database: masalah ini telah terpecahkan bagi kami, kami menggunakan database sebagai layanan.

Mari kembali ke pengontrol penyeimbang. Tugasnya adalah menyimpan informasi tentang penyeimbang dan mengirimkan tugas untuk memeriksa kesiapan mesin virtual ke pengontrol healthcheck.

Pengontrol pemeriksaan kesehatan

Ia menerima permintaan untuk mengubah aturan pemeriksaan, menyimpannya di YDB, mendistribusikan tugas di antara node healthcheck dan mengumpulkan hasilnya, yang kemudian disimpan ke database dan dikirim ke pengontrol penyeimbang beban. Ini, pada gilirannya, mengirimkan permintaan untuk mengubah komposisi cluster di bidang data ke node penyeimbang beban, yang akan saya bahas di bawah.

Arsitektur penyeimbang beban jaringan di Yandex.Cloud

Mari kita bicara lebih banyak tentang pemeriksaan kesehatan. Mereka dapat dibagi menjadi beberapa kelas. Audit memiliki kriteria keberhasilan yang berbeda-beda. Pemeriksaan TCP harus berhasil membuat koneksi dalam jangka waktu tertentu. Pemeriksaan HTTP memerlukan koneksi yang berhasil dan respons dengan kode status 200.

Selain itu, cek berbeda berdasarkan kelas tindakannya - aktif dan pasif. Pemeriksaan pasif hanya memantau apa yang terjadi dengan lalu lintas tanpa mengambil tindakan khusus apa pun. Ini tidak berfungsi dengan baik di L4 karena bergantung pada logika protokol tingkat yang lebih tinggi: di L4 tidak ada informasi tentang berapa lama operasi berlangsung atau apakah penyelesaian koneksi baik atau buruk. Pemeriksaan aktif memerlukan penyeimbang untuk mengirim permintaan ke setiap server.

Kebanyakan penyeimbang beban melakukan pemeriksaan keaktifan sendiri. Di Cloud, kami memutuskan untuk memisahkan bagian-bagian sistem ini untuk meningkatkan skalabilitas. Pendekatan ini akan memungkinkan kami meningkatkan jumlah penyeimbang sekaligus mempertahankan jumlah permintaan pemeriksaan kesehatan ke layanan. Pemeriksaan dilakukan oleh node pemeriksaan kesehatan terpisah, di mana target pemeriksaan dipisahkan dan direplikasi. Anda tidak dapat melakukan pemeriksaan dari satu host, karena mungkin gagal. Maka kita tidak akan mendapatkan status dari instance yang dia periksa. Kami melakukan pemeriksaan pada salah satu instance dari setidaknya tiga node healthcheck. Kami membagi tujuan pemeriksaan antar node menggunakan algoritma hashing yang konsisten.

Arsitektur penyeimbang beban jaringan di Yandex.Cloud

Memisahkan keseimbangan dan pemeriksaan kesehatan dapat menimbulkan masalah. Jika node healthcheck membuat permintaan ke instance, melewati penyeimbang (yang saat ini tidak melayani lalu lintas), maka situasi aneh akan muncul: sumber daya tampaknya hidup, tetapi lalu lintas tidak mencapainya. Kami memecahkan masalah ini dengan cara ini: kami dijamin memulai pemeriksaan kesehatan lalu lintas melalui penyeimbang. Dengan kata lain, skema untuk memindahkan paket dengan lalu lintas dari klien dan dari pemeriksaan kesehatan sedikit berbeda: dalam kedua kasus, paket akan mencapai penyeimbang, yang akan mengirimkannya ke sumber daya target.

Perbedaannya adalah klien membuat permintaan ke VIP, sedangkan healthcheck membuat permintaan ke masing-masing RIP. Masalah menarik muncul di sini: kami memberikan kesempatan kepada pengguna kami untuk membuat sumber daya di jaringan IP abu-abu. Bayangkan ada dua pemilik cloud berbeda yang menyembunyikan layanannya di balik penyeimbang. Masing-masing memiliki sumber daya di subnet 10.0.0.1/24, dengan alamat yang sama. Anda harus dapat membedakannya, dan di sini Anda perlu menyelami struktur jaringan virtual Yandex.Cloud. Lebih baik mencari tahu lebih detail di video dari tentang: acara cloud, penting bagi kami sekarang bahwa jaringan tersebut berlapis-lapis dan memiliki terowongan yang dapat dibedakan berdasarkan id subnet.

Node pemeriksaan kesehatan menghubungi penyeimbang menggunakan apa yang disebut alamat kuasi-IPv6. Alamat kuasi adalah alamat IPv6 dengan alamat IPv4 dan id subnet pengguna tertanam di dalamnya. Lalu lintas mencapai penyeimbang, yang mengekstrak alamat sumber daya IPv4 darinya, menggantikan IPv6 dengan IPv4 dan mengirimkan paket ke jaringan pengguna.

Lalu lintas sebaliknya berjalan dengan cara yang sama: penyeimbang melihat bahwa tujuannya adalah jaringan abu-abu dari pemeriksa kesehatan, dan mengubah IPv4 menjadi IPv6.

VPP - jantung dari bidang data

Penyeimbang ini diimplementasikan menggunakan teknologi Vector Packet Processing (VPP), sebuah kerangka kerja dari Cisco untuk pemrosesan batch lalu lintas jaringan. Dalam kasus kami, kerangka kerja ini bekerja di atas perpustakaan manajemen perangkat jaringan ruang pengguna - Data Plane Development Kit (DPDK). Hal ini memastikan kinerja pemrosesan paket yang tinggi: lebih sedikit interupsi yang terjadi di kernel, dan tidak ada peralihan konteks antara ruang kernel dan ruang pengguna. 

VPP melangkah lebih jauh dan meningkatkan kinerja sistem dengan menggabungkan paket-paket ke dalam batch. Peningkatan kinerja berasal dari penggunaan cache yang agresif pada prosesor modern. Kedua cache data digunakan (paket diproses dalam "vektor", datanya berdekatan satu sama lain) dan cache instruksi: di VPP, pemrosesan paket mengikuti grafik, yang nodenya berisi fungsi yang melakukan tugas yang sama.

Misalnya, pemrosesan paket IP di VPP terjadi dalam urutan berikut: pertama, header paket diurai di node pengurai, dan kemudian dikirim ke node, yang meneruskan paket lebih lanjut sesuai dengan tabel perutean.

Sedikit keras. Penulis VPP tidak mentolerir kompromi dalam penggunaan cache prosesor, sehingga kode khas untuk memproses vektor paket berisi vektorisasi manual: ada loop pemrosesan di mana situasi seperti "kami memiliki empat paket dalam antrian" diproses, lalu sama untuk dua orang, lalu - untuk satu orang. Instruksi pengambilan awal sering kali digunakan untuk memuat data ke dalam cache guna mempercepat akses ke data tersebut pada iterasi 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 menyampaikan IPv6 ke VPP, yang mengubahnya menjadi IPv4. Hal ini dilakukan oleh sebuah node dalam grafik, yang kita sebut NAT algoritmik. Untuk lalu lintas balik (dan konversi dari IPv6 ke IPv4) terdapat node NAT algoritmik yang sama.

Arsitektur penyeimbang beban jaringan di Yandex.Cloud

Lalu lintas langsung dari klien penyeimbang melewati node grafik, yang melakukan penyeimbangan itu sendiri. 

Arsitektur penyeimbang beban jaringan di Yandex.Cloud

Node pertama adalah sesi lengket. Ini menyimpan hash dari 5-tupel untuk sesi yang telah ditetapkan. 5-tuple mencakup alamat dan port klien dari mana informasi dikirimkan, alamat dan port sumber daya yang tersedia untuk menerima lalu lintas, serta protokol jaringan. 

Hash 5 tuple membantu kita melakukan lebih sedikit komputasi pada node hashing konsisten berikutnya, serta menangani perubahan daftar sumber daya di belakang penyeimbang dengan lebih baik. Ketika sebuah paket yang tidak memiliki sesi tiba di penyeimbang, paket tersebut dikirim ke node hashing yang konsisten. Di sinilah penyeimbangan terjadi menggunakan hashing yang konsisten: kami memilih sumber daya dari daftar sumber daya “langsung” yang tersedia. Selanjutnya, paket dikirim ke node NAT, yang sebenarnya menggantikan alamat tujuan dan menghitung ulang checksum. Seperti yang Anda lihat, kami mengikuti aturan VPP - suka dan suka, mengelompokkan perhitungan serupa untuk meningkatkan efisiensi cache prosesor.

Hashing yang konsisten

Mengapa kami memilihnya dan apa itu? Pertama, mari kita pertimbangkan tugas sebelumnya - memilih sumber daya dari daftar. 

Arsitektur penyeimbang beban jaringan di Yandex.Cloud

Dengan hashing yang tidak konsisten, hash dari paket masuk dihitung, dan sumber daya dipilih dari daftar dengan sisa membagi hash ini dengan jumlah sumber daya. Selama daftarnya tidak berubah, skema ini berfungsi dengan baik: kami selalu mengirim paket dengan 5 tupel yang sama ke instance yang sama. Jika, misalnya, beberapa sumber daya berhenti merespons pemeriksaan kesehatan, maka untuk sebagian besar hash, pilihannya akan berubah. Koneksi TCP klien akan terputus: paket yang sebelumnya mencapai instance A mungkin mulai mencapai instance B, yang tidak familiar dengan sesi untuk paket ini.

Hashing yang konsisten memecahkan masalah yang dijelaskan. Cara termudah untuk menjelaskan konsep ini adalah: bayangkan Anda memiliki cincin tempat Anda mendistribusikan sumber daya berdasarkan hash (misalnya, berdasarkan IP:port). Memilih sumber daya berarti memutar roda dengan suatu sudut, yang ditentukan oleh hash paket.

Arsitektur penyeimbang beban jaringan di Yandex.Cloud

Hal ini meminimalkan redistribusi lalu lintas ketika komposisi sumber daya berubah. Menghapus sumber daya hanya akan memengaruhi bagian dari cincin hashing yang konsisten di mana sumber daya tersebut berada. Menambahkan sumber daya juga mengubah distribusi, tetapi kami memiliki node sesi yang melekat, yang memungkinkan kami untuk tidak mengalihkan sesi yang sudah ada ke sumber daya baru.

Kami melihat apa yang terjadi pada lalu lintas langsung antara penyeimbang dan sumber daya. Sekarang mari kita lihat lalu lintas kembali. Ini mengikuti pola yang sama seperti lalu lintas pemeriksaan - melalui NAT algoritmik, yaitu melalui NAT 44 terbalik untuk lalu lintas klien dan melalui NAT 46 untuk lalu lintas pemeriksaan kesehatan. Kami mematuhi skema kami sendiri: kami menyatukan lalu lintas pemeriksaan kesehatan dan lalu lintas pengguna sebenarnya.

Node penyeimbang beban dan komponen rakitan

Komposisi penyeimbang dan sumber daya di VPP dilaporkan oleh layanan lokal - node penyeimbang beban. Ia berlangganan aliran peristiwa dari pengontrol penyeimbang beban dan mampu memplot perbedaan antara status VPP saat ini dan status target yang diterima dari pengontrol. Kami mendapatkan sistem tertutup: peristiwa dari API datang ke pengontrol penyeimbang, yang memberikan tugas ke pengontrol healthcheck untuk memeriksa "keaktifan" sumber daya. Hal ini, pada gilirannya, memberikan tugas ke node healthcheck dan mengumpulkan hasilnya, setelah itu mengirimkannya kembali ke pengontrol penyeimbang. Node penyeimbang beban berlangganan peristiwa dari pengontrol dan mengubah status VPP. Dalam sistem seperti itu, setiap layanan hanya mengetahui apa yang diperlukan tentang layanan tetangganya. Jumlah koneksi terbatas dan kami memiliki kemampuan untuk mengoperasikan dan menskalakan segmen yang berbeda secara mandiri.

Arsitektur penyeimbang beban jaringan di Yandex.Cloud

Masalah apa saja yang dihindari?

Semua layanan kami di bidang kendali ditulis dalam Go dan memiliki karakteristik penskalaan dan keandalan yang baik. Go memiliki banyak perpustakaan sumber terbuka untuk membangun sistem terdistribusi. Kami secara aktif menggunakan GRPC, semua komponen berisi implementasi penemuan layanan open source - layanan kami memantau kinerja satu sama lain, dapat mengubah komposisinya secara dinamis, dan kami menghubungkannya dengan penyeimbangan GRPC. Untuk metrik, kami juga menggunakan solusi sumber terbuka. Di bidang data, kami mendapatkan kinerja yang layak dan cadangan sumber daya yang besar: ternyata sangat sulit untuk membangun landasan yang dapat kami andalkan pada kinerja VPP, daripada kartu jaringan besi.

Masalah dan solusinya

Apa yang tidak berhasil dengan baik? Go memiliki manajemen memori otomatis, namun kebocoran memori masih terjadi. Cara termudah untuk mengatasinya adalah dengan menjalankan goroutine dan ingat untuk menghentikannya. Kesimpulan: Perhatikan konsumsi memori program Go Anda. Seringkali indikator yang baik adalah jumlah goroutine. Ada nilai tambah dalam cerita ini: di Go, mudah untuk mendapatkan data runtime - konsumsi memori, jumlah goroutine yang berjalan, dan banyak parameter lainnya.

Selain itu, Go mungkin bukan pilihan terbaik untuk pengujian fungsional. Mereka cukup bertele-tele, dan pendekatan standar “menjalankan semua yang ada di CI dalam satu batch” sangat tidak cocok untuk mereka. Faktanya adalah pengujian fungsional lebih menuntut sumber daya dan menyebabkan waktu tunggu habis. Oleh karena itu, pengujian mungkin gagal karena CPU sibuk dengan pengujian unit. Kesimpulan: Jika memungkinkan, lakukan pengujian “berat” secara terpisah dari pengujian unit. 

Arsitektur peristiwa layanan mikro lebih kompleks daripada monolit: mengumpulkan log pada lusinan mesin berbeda sangatlah tidak nyaman. Kesimpulan: jika membuat microservices, segera pikirkan tracing.

rencana kami

Kami akan meluncurkan penyeimbang internal, penyeimbang IPv6, menambahkan dukungan untuk skrip Kubernetes, terus melakukan shard pada layanan kami (saat ini hanya healthcheck-node dan healthcheck-ctrl yang disharding), menambahkan healthcheck baru, dan juga menerapkan agregasi pemeriksaan yang cerdas. Kami sedang mempertimbangkan kemungkinan untuk menjadikan layanan kami lebih mandiri - sehingga layanan tersebut tidak berkomunikasi secara langsung satu sama lain, namun menggunakan antrean pesan. Layanan yang kompatibel dengan SQS baru-baru ini muncul di Cloud Antrian Pesan Yandex.

Baru-baru ini, rilis publik Yandex Load Balancer berlangsung. Mengeksplorasi dokumentasi ke layanan ini, kelola penyeimbang dengan cara yang nyaman bagi Anda dan tingkatkan toleransi kesalahan proyek Anda!

Sumber: www.habr.com

Tambah komentar