Bioyino - agregator metrik yang terdistribusi dan terukur

Jadi, Anda mengumpulkan metrik. Seperti kita. Kami juga mengumpulkan metrik. Tentu saja diperlukan untuk bisnis. Hari ini kita akan berbicara tentang tautan pertama dari sistem pemantauan kami - server agregasi yang kompatibel dengan statsd bioyino, mengapa kami menulisnya dan mengapa kami meninggalkan brubeck.

Bioyino - agregator metrik yang terdistribusi dan terukur

Dari artikel kami sebelumnya (1, 2) Anda dapat mengetahuinya sampai beberapa waktu kami mengumpulkan nilai menggunakan Brubeck. Itu ditulis dalam C. Dari sudut pandang kode, ini sesederhana sebuah plug (ini penting ketika Anda ingin berkontribusi) dan, yang paling penting, ini menangani volume 2 juta metrik per detik (MPS) pada puncaknya tanpa masalah. Dokumentasi menyatakan dukungan untuk 4 juta MPS dengan tanda bintang. Ini berarti Anda akan mendapatkan angka yang disebutkan jika Anda mengkonfigurasi jaringan dengan benar di Linux. (Kami tidak tahu berapa banyak MPS yang bisa Anda peroleh jika Anda meninggalkan jaringan apa adanya). Terlepas dari kelebihan ini, kami mempunyai beberapa keluhan serius tentang brubeck.

Klaim 1. Github, pengembang proyek, berhenti mendukungnya: menerbitkan tambalan dan perbaikan, menerima PR kami dan (bukan hanya milik kami). Dalam beberapa bulan terakhir (sekitar Februari-Maret 2018), aktivitas telah kembali normal, namun sebelumnya hampir 2 tahun dalam keadaan tenang. Selain itu, proyek ini sedang dikembangkan untuk kebutuhan internal Gihub, yang dapat menjadi hambatan serius dalam pengenalan fitur-fitur baru.

Klaim 2. Akurasi perhitungan. Brubeck mengumpulkan total 65536 nilai untuk agregasi. Dalam kasus kami, untuk beberapa metrik, selama periode agregasi (30 detik), lebih banyak nilai yang mungkin muncul (1 pada puncaknya). Akibat pengambilan sampel ini, nilai maksimum dan minimum tampak tidak berguna. Misalnya seperti ini:

Bioyino - agregator metrik yang terdistribusi dan terukur
Seperti itu

Bioyino - agregator metrik yang terdistribusi dan terukur
Bagaimana seharusnya

Untuk alasan yang sama, jumlah pada umumnya dihitung secara tidak benar. Tambahkan di sini bug dengan float overflow 32-bit, yang biasanya mengirim server ke segfault ketika menerima metrik yang tampaknya tidak berbahaya, dan semuanya menjadi baik-baik saja. Omong-omong, bug tersebut belum diperbaiki.

Dan, akhirnya, Klaim X. Pada saat penulisan, kami siap menyajikannya ke 14 implementasi statsd yang kurang lebih berfungsi yang dapat kami temukan. Bayangkan saja suatu infrastruktur telah berkembang pesat sehingga menerima 4 juta MPS saja tidak lagi cukup. Atau bahkan jika grafiknya belum berkembang, namun metriknya sudah sangat penting bagi Anda sehingga bahkan penurunan singkat selama 2-3 menit saja sudah bisa menjadi hal yang kritis dan menyebabkan depresi yang tidak dapat diatasi di kalangan manajer. Karena mengobati depresi adalah tugas tanpa pamrih, solusi teknis diperlukan.

Pertama, toleransi kesalahan, sehingga masalah mendadak di server tidak menyebabkan kiamat zombie psikiatris di kantor. Kedua, melakukan penskalaan agar dapat menerima lebih dari 4 juta MPS, tanpa menggali lebih dalam tumpukan jaringan Linux dan dengan tenang berkembang β€œsecara luas” ke ukuran yang dibutuhkan.

Karena kami memiliki ruang untuk penskalaan, kami memutuskan untuk memulai dengan toleransi kesalahan. "TENTANG! Toleransi kesalahan! Sederhana saja, kita bisa melakukannya,” pikir kami dan meluncurkan 2 server, memunculkan salinan brubeck di masing-masing server. Untuk melakukan ini, kami harus menyalin lalu lintas dengan metrik ke kedua server dan bahkan menulis untuk ini utilitas kecil. Kami memecahkan masalah toleransi kesalahan dengan ini, tapi... tidak terlalu baik. Pada awalnya semuanya tampak hebat: setiap brubeck mengumpulkan versi agregasinya sendiri, menulis data ke Grafit setiap 30 detik, menimpa interval lama (ini dilakukan di sisi Grafit). Jika satu server tiba-tiba gagal, kami selalu memiliki server kedua dengan salinan data agregatnya sendiri. Tapi inilah masalahnya: jika server gagal, β€œgergaji” muncul di grafik. Hal ini disebabkan oleh fakta bahwa interval 30 detik Brubeck tidak disinkronkan, dan pada saat terjadi tabrakan, salah satunya tidak ditimpa. Saat server kedua dimulai, hal yang sama terjadi. Cukup lumayan, tapi saya ingin yang lebih baik! Masalah skalabilitas juga belum hilang. Semua metrik masih β€œterbang” ke satu server, dan oleh karena itu kami dibatasi pada 2-4 juta MPS yang sama, bergantung pada tingkat jaringan.

Jika Anda memikirkan sedikit tentang masalahnya dan pada saat yang sama menggali salju dengan sekop, gagasan yang jelas berikut ini mungkin muncul di benak Anda: Anda memerlukan statsd yang dapat bekerja dalam mode terdistribusi. Artinya, yang mengimplementasikan sinkronisasi antar node dalam waktu dan metrik. β€œTentu saja, solusi seperti itu mungkin sudah ada,” kata kami dan membuka Google…. Dan mereka tidak menemukan apa pun. Setelah melalui dokumentasi untuk statsd yang berbeda (https://github.com/etsy/statsd/wiki#server-implementations per 11.12.2017 Desember XNUMX), kami sama sekali tidak menemukan apa pun. Rupanya, baik pengembang maupun pengguna solusi ini belum menemukan begitu banyak metrik, jika tidak, mereka pasti akan menemukan sesuatu.

Dan kemudian kami teringat tentang statsd "mainan" - bioyino, yang ditulis di hackathon Just for Fun (nama proyek dihasilkan oleh skrip sebelum dimulainya hackathon) dan menyadari bahwa kami sangat membutuhkan statsd kami sendiri. Untuk apa?

  • karena terlalu sedikit klon statsd di dunia,
  • karena dimungkinkan untuk memberikan toleransi kesalahan dan skalabilitas yang diinginkan atau mendekati yang diinginkan (termasuk menyinkronkan metrik agregat antar server dan menyelesaikan masalah konflik pengiriman),
  • karena metrik dapat dihitung dengan lebih akurat dibandingkan brubeck,
  • karena Anda dapat mengumpulkan sendiri statistik yang lebih rinci, yang secara praktis tidak diberikan oleh brubeck kepada kami,
  • karena saya berkesempatan memprogram aplikasi lab skala terdistribusi hyperperformance saya sendiri, yang tidak akan sepenuhnya mengulangi arsitektur hyperfor serupa lainnya... yah, itu saja.

Apa yang harus ditulis? Tentu saja, di Rust. Mengapa?

  • karena sudah ada solusi prototipe,
  • karena penulis artikel tersebut sudah mengenal Rust pada saat itu dan sangat ingin menulis sesuatu di dalamnya untuk produksi dengan kesempatan untuk memasukkannya ke dalam open-source,
  • karena bahasa dengan GC tidak cocok untuk kami karena sifat lalu lintas yang diterima (hampir real-time) dan jeda GC secara praktis tidak dapat diterima,
  • karena Anda membutuhkan performa maksimal yang sebanding dengan C
  • karena Rust memberi kita konkurensi yang tak kenal takut, dan jika kita mulai menulisnya dalam C/C++, kita akan mendapatkan lebih banyak kerentanan, buffer overflow, kondisi balapan, dan kata-kata menakutkan lainnya selain brubeck.

Ada juga argumen yang menentang Rust. Perusahaan tidak memiliki pengalaman membuat proyek di Rust, dan sekarang kami juga tidak berencana menggunakannya di proyek utama. Oleh karena itu, ada ketakutan yang serius bahwa tidak ada yang akan berhasil, tetapi kami memutuskan untuk mengambil risiko dan mencoba.

Waktu berlalu...

Akhirnya, setelah beberapa kali gagal, versi pertama yang berfungsi telah siap. Apa yang telah terjadi? Inilah yang terjadi.

Bioyino - agregator metrik yang terdistribusi dan terukur

Setiap node menerima kumpulan metriknya sendiri dan mengakumulasikannya, dan tidak mengagregasi metrik untuk jenis-jenis yang memerlukan kumpulan metrik lengkap untuk agregasi akhir. Node-node tersebut terhubung satu sama lain melalui semacam protokol kunci terdistribusi, yang memungkinkan Anda memilih di antara mereka satu-satunya (di sini kami menangis) yang layak untuk mengirimkan metrik ke Yang Hebat. Masalah ini saat ini sedang diselesaikan oleh Konsul, tapi di masa depan ambisi penulis meluas ke sendiri penerapan Rakit, dimana yang paling layak, tentu saja, akan menjadi simpul pemimpin konsensus. Selain konsensus, node cukup sering (secara default sekali per detik) mengirimkan ke tetangganya bagian-bagian metrik pra-agregat yang berhasil mereka kumpulkan pada detik itu. Ternyata penskalaan dan toleransi kesalahan tetap dipertahankan - setiap node masih menyimpan serangkaian metrik lengkap, namun metrik yang dikirim sudah dikumpulkan, melalui TCP dan dikodekan ke dalam protokol biner, sehingga biaya duplikasi berkurang secara signifikan dibandingkan dengan UDP. Meskipun jumlah metrik masuk cukup besar, akumulasi memerlukan sedikit memori dan bahkan lebih sedikit CPU. Untuk metrik kami yang sangat dapat dikompres, ini hanya beberapa puluh megabita data. Sebagai bonus tambahan, kami tidak mendapatkan penulisan ulang data yang tidak perlu di Graphite, seperti halnya dengan burbeck.

Paket UDP dengan metrik tidak seimbang antar node pada peralatan jaringan melalui Round Robin sederhana. Tentu saja, perangkat keras jaringan tidak menguraikan isi paket dan oleh karena itu dapat menarik lebih dari 4 juta paket per detik, belum lagi metrik yang tidak diketahui sama sekali. Jika kami memperhitungkan bahwa metrik tidak muncul satu per satu di setiap paket, maka kami tidak melihat adanya masalah kinerja di tempat ini. Jika server mogok, perangkat jaringan dengan cepat (dalam 1-2 detik) mendeteksi fakta ini dan menghapus server yang mogok dari rotasi. Hasilnya, node pasif (yaitu, non-pemimpin) dapat diaktifkan dan dinonaktifkan secara praktis tanpa memperhatikan penurunan pada grafik. Kerugian maksimum yang kami alami adalah bagian dari metrik yang masuk pada detik terakhir. Hilangnya/shutdown/pergantian pemimpin secara tiba-tiba masih akan menimbulkan anomali kecil (interval 30 detik masih tidak sinkron), namun jika ada komunikasi antar node, masalah tersebut dapat diminimalkan, misalnya dengan mengirimkan paket sinkronisasi. .

Sedikit tentang struktur internal. Aplikasinya tentu saja multithread, tetapi arsitektur threadingnya berbeda dengan yang digunakan di brubeck. Utas di brubeck sama - masing-masing bertanggung jawab atas pengumpulan dan agregasi informasi. Di bioyino, pekerja dibagi menjadi dua kelompok: mereka yang bertanggung jawab atas jaringan dan mereka yang bertanggung jawab atas agregasi. Pembagian ini memungkinkan Anda mengelola aplikasi dengan lebih fleksibel tergantung pada jenis metrik: jika diperlukan agregasi intensif, Anda dapat menambahkan agregator, jika terdapat banyak lalu lintas jaringan, Anda dapat menambahkan jumlah aliran jaringan. Saat ini, di server kami, kami bekerja di 8 jaringan dan 4 aliran agregasi.

Bagian penghitungan (bertanggung jawab atas agregasi) cukup membosankan. Buffer yang diisi oleh aliran jaringan didistribusikan di antara aliran penghitungan, yang kemudian diurai dan dikumpulkan. Berdasarkan permintaan, metrik diberikan untuk dikirim ke node lain. Semua ini, termasuk pengiriman data antar node dan bekerja dengan Konsul, dilakukan secara asinkron, berjalan pada kerangka kerja Tokyo.

Lebih banyak masalah selama pengembangan disebabkan oleh bagian jaringan yang bertanggung jawab menerima metrik. Tujuan utama memisahkan aliran jaringan menjadi entitas terpisah adalah keinginan untuk mengurangi waktu yang dihabiskan suatu aliran tidak untuk membaca data dari soket. Opsi yang menggunakan UDP asinkron dan recvmsg reguler dengan cepat menghilang: opsi pertama menghabiskan terlalu banyak ruang pengguna CPU untuk pemrosesan acara, opsi kedua memerlukan terlalu banyak pengalih konteks. Oleh karena itu sekarang digunakan recvmmsg dengan buffer yang besar (dan buffer, Tuan-tuan petugas, tidak ada artinya bagi Anda!). Dukungan untuk UDP reguler disediakan untuk kasus-kasus ringan di mana recvmmsg tidak diperlukan. Dalam mode multipesan, hal utama dapat dicapai: sebagian besar waktu, thread jaringan menyapu antrian OS - membaca data dari soket dan mentransfernya ke buffer ruang pengguna, hanya sesekali beralih untuk memberikan buffer yang terisi ke agregator. Antrian di soket praktis tidak menumpuk, jumlah paket yang dijatuhkan praktis tidak bertambah.

Catatan

Pada pengaturan default, ukuran buffer diatur cukup besar. Jika Anda tiba-tiba memutuskan untuk mencoba server sendiri, Anda mungkin menghadapi kenyataan bahwa setelah mengirim sejumlah kecil metrik, metrik tersebut tidak akan tiba di Grafit, tetap berada di buffer aliran jaringan. Untuk bekerja dengan sejumlah kecil metrik, Anda perlu mengatur bufsize dan task-queue-size ke nilai yang lebih kecil di konfigurasi.

Terakhir, beberapa grafik untuk pecinta grafik.

Statistik jumlah metrik yang masuk untuk setiap server: lebih dari 2 juta MPS.

Bioyino - agregator metrik yang terdistribusi dan terukur

Menonaktifkan salah satu node dan mendistribusikan ulang metrik yang masuk.

Bioyino - agregator metrik yang terdistribusi dan terukur

Statistik metrik keluar: hanya satu node yang selalu mengirimkan - bos serangan.

Bioyino - agregator metrik yang terdistribusi dan terukur

Statistik operasi setiap node, dengan mempertimbangkan kesalahan di berbagai modul sistem.

Bioyino - agregator metrik yang terdistribusi dan terukur

Merinci metrik yang masuk (nama metrik disembunyikan).

Bioyino - agregator metrik yang terdistribusi dan terukur

Apa yang akan kita lakukan selanjutnya dengan semua ini? Tentu saja, tulis kodenya, sial...! Proyek ini awalnya direncanakan menjadi open-source dan akan tetap demikian sepanjang masa pakainya. Rencana jangka pendek kami termasuk beralih ke versi Raft kami sendiri, mengubah protokol rekan ke yang lebih portabel, memperkenalkan statistik internal tambahan, jenis metrik baru, perbaikan bug, dan peningkatan lainnya.

Tentu saja, semua orang boleh membantu dalam pengembangan proyek: membuat PR, Isu, jika memungkinkan kami akan merespons, meningkatkan, dll.

Oleh karena itu, semuanya, belilah gajah kami!



Sumber: www.habr.com

Tambah komentar