Perjuangan untuk solusi berkualitas di Erlang / Elixir


@ jcutrer


Hari ini kita akan berbicara tentang log peristiwa, metrik kuantitatif, dan memantau semua ini untuk meningkatkan tingkat respons tim terhadap insiden dan mengurangi waktu henti sistem target.


Erlang / OTP sebagai kerangka kerja dan ideologi membangun sistem terdistribusi memberi kita pendekatan yang diatur untuk pengembangan, alat dan implementasi komponen standar. Katakanlah kita menggunakan potensi OTP dan beralih dari prototipe ke produksi. Proyek Erlang kami terasa hebat di server pertempuran, basis kode terus berkembang, persyaratan dan fungsi baru muncul, orang-orang baru datang ke tim, dan semuanya tampak baik-baik saja. Namun terkadang ada yang salah dan masalah teknis, dikalikan dengan faktor manusia, dapat menyebabkan kecelakaan.


Karena tidak mungkin meletakkan sedotan untuk semua kasus kegagalan dan masalah yang mungkin terjadi, atau tidak layak secara ekonomi, maka perlu untuk mengurangi waktu henti sistem jika terjadi kegagalan oleh solusi manajemen dan perangkat lunak.


Dalam sistem informasi akan selalu ada kemungkinan terjadinya kegagalan berbagai sifat:


  • Kegagalan Perangkat Keras dan Kegagalan Daya
  • Kegagalan jaringan: kesalahan konfigurasi, kurva firmware
  • Kesalahan logis: dari kesalahan pengkodean algoritma hingga masalah arsitektur yang muncul pada batas subsistem dan sistem.
  • Masalah keamanan dan serangan serta peretasan terkait, termasuk penipuan internal.

Kami segera membedakan tanggung jawab: pemantauan infrastruktur, misalnya, yang diselenggarakan oleh zabbix, akan bertanggung jawab atas pengoperasian peralatan komputasi dan jaringan transmisi data. Banyak yang telah ditulis tentang menginstal dan mengkonfigurasi pemantauan tersebut, kami tidak akan mengulanginya.


Dari sudut pandang pengembang, masalah aksesibilitas dan kualitas terletak pada bidang deteksi dini kesalahan dan masalah kinerja dan respons cepat terhadapnya. Ini membutuhkan pendekatan dan cara penilaian. Jadi, mari kita coba untuk mendapatkan metrik kuantitatif, menganalisis yang pada berbagai tahap pengembangan dan operasi proyek, kita dapat secara signifikan meningkatkan kualitas.


Sistem perakitan


Biarkan saya mengingatkan Anda sekali lagi tentang pentingnya pendekatan teknik dan pengujian dalam pengembangan perangkat lunak. Erlang / OTP menawarkan dua kerangka uji sekaligus: eunit dan uji umum.


Sebagai metrik untuk penilaian awal tentang keadaan basis kode dan dinamika, Anda dapat menggunakan jumlah tes yang berhasil dan bermasalah, waktu pelaksanaannya, dan persentase cakupan kode dengan tes. Kedua kerangka kerja memungkinkan menyimpan hasil tes dalam format Junit.
Misalnya, untuk rebar3 dan ct, tambahkan baris berikut ke rebar.config:


{cover_enabled, true}. {cover_export_enabled, true}. {ct_opts,[ {ct_hooks, [{cth_surefire, [{path, "report.xml"}]}]} ]}. 

Jumlah tes yang berhasil dan tidak berhasil memungkinkan Anda untuk membuat grafik tren:

melihat yang mana, Anda dapat mengevaluasi dinamika tim dan regresi tes. Misalnya, dalam Jenkins grafik ini dapat diperoleh dengan menggunakan Plugin Test Results Analyzer.


Jika tes berubah merah atau mulai berjalan untuk waktu yang lama, metrik akan memungkinkan rilis untuk diselesaikan bahkan pada tahap perakitan dan pengujian otomatis.


Metrik aplikasi


Selain metrik sistem operasi, pemantauan harus mencakup metrik aplikasi, seperti jumlah tampilan per detik, jumlah pembayaran, dan indikator penting lainnya.


Dalam proyek saya, saya menggunakan templat seperti ${application}.${metrics_type}.${name} untuk memberi nama metrik. Penamaan ini memungkinkan Anda untuk mendapatkan daftar metrik formulir


 messaging.systime_subs.messages.delivered = 1654 messaging.systime_subs.messages.proxied = 0 messaging.systime_subs.messages.published = 1655 messaging.systime_subs.messages.skipped = 3 

Mungkin semakin banyak metrik, semakin mudah untuk memahami apa yang terjadi dalam sistem yang kompleks.


Metrik VM Erlang


Perhatian khusus harus diberikan untuk memantau Erlang VM. Ideologi membiarkannya crash itu indah, dan penggunaan OTP yang tepat tentu akan membantu mengangkat bagian aplikasi yang jatuh di dalam Erlang VM. Tetapi jangan lupa tentang Erlang VM itu sendiri, karena sulit untuk menjatuhkannya, tetapi itu mungkin. Semua opsi didasarkan pada habisnya sumber daya. Kami daftar yang utama:


  • Tabel atom meluap.
    Atom adalah pengidentifikasi yang tujuan utamanya adalah untuk meningkatkan keterbacaan kode. Atom yang dibuat sekali tetap selamanya dalam ingatan instance Erlang VM, karena mereka tidak dibersihkan oleh pengumpul sampah. Mengapa ini terjadi? Pengumpul sampah bekerja secara terpisah di setiap proses dengan data dari proses ini, sementara atom dapat didistribusikan di seluruh struktur data dari banyak proses.
    Secara default, 1.048.576 atom dapat dibuat. Dalam artikel tentang membunuh Erlang VM, Anda biasanya dapat menemukan sesuatu seperti ini.


     [list_to_atom(integer_to_list(I)) || I <- lists:seq(erlang:system_info(atom_count), erlang:system_info(atom_limit))] 

    sebagai ilustrasi efek ini. Tampaknya masalah buatan juga tidak dapat dicapai dalam sistem nyata, tetapi ada beberapa kasus ... Misalnya, dalam penangan API eksternal, ketika binary_to_atom/2 parsing permintaan, binary_to_atom/2 sebagai ganti binary_to_existing_atom/2 atau list_to_atom/1 alih-alih list_to_existing_atom/1 .
    Parameter berikut harus digunakan untuk memantau keadaan atom:


    1. erlang:memory(atom_used) - jumlah memori yang digunakan untuk atom
    2. erlang:system_info(atom_count) - jumlah atom yang dibuat dalam sistem. Bersama dengan erlang:system_info(atom_limit) , pemanfaatan atom dapat dihitung.

  • Proses kebocoran.
    Saya ingin segera mengatakan bahwa ketika process_limit (+ P tercapai, erl) erlang vm argumen tidak jatuh, tetapi masuk ke keadaan darurat, misalnya, kemungkinan besar tidak mungkin untuk terhubung ke sana. Pada akhirnya, kehabisan memori yang tersedia saat mengalokasikan ke proses yang bocor akan menyebabkan erlang vm crash.


    1. erlang:system_info(process_count) - jumlah proses aktif saat ini. Bersama dengan erlang:system_info(process_limit) , pemanfaatan proses dapat dihitung.
    2. erlang:memory(processes) - memori yang dialokasikan untuk proses
    3. erlang:memory(processes_used) - memori yang digunakan untuk proses.

  • Proses kotak surat meluap.
    Contoh khas dari masalah seperti itu adalah proses pengirim mengirim pesan ke proses penerima tanpa menunggu konfirmasi, sementara receive dalam proses penerima mengabaikan semua pesan ini karena pola yang hilang atau salah. Akibatnya, pesan terakumulasi di kotak surat. Meskipun erlang memiliki mekanisme untuk memperlambat pengirim jika penangan tidak dapat menangani pemrosesan, lagi pula, setelah kehabisan memori yang tersedia, vm crash.
    Untuk memahami jika ada masalah dengan kotak surat meluap, etop akan membantu.


     $ erl -name etop@host -hidden -s etop -s erlang halt -output text -node dest@host -setcookie some_cookie -tracing off -sort msg_q -interval 1 -lines 25 


    Sebagai metrik untuk pemantauan berkelanjutan, Anda dapat mengambil sejumlah proses masalah. Untuk mengidentifikasi mereka, Anda dapat menggunakan fungsi berikut:


     top_msq_q()-> [{P, RN, L, IC, ST} || P <- processes(), { _, L } <- [ process_info(P, message_queue_len) ], L >= 1000, [{_, RN}, {_, IC}, {_, ST}] <- [process_info(P, [registered_name, initial_call, current_stacktrace]) ] ]. 

    Selain itu, daftar ini dapat dicatat, kemudian ketika menerima pemberitahuan dari pemantauan, analisis masalahnya disederhanakan.


  • Binari yang bocor.
    Memori untuk binari besar (lebih dari 64 byte) dialokasikan di heap umum. Blok yang dialokasikan memiliki penghitung referensi yang menunjukkan jumlah proses yang memiliki akses ke sana. Setelah mengatur ulang penghitung, pembersihan terjadi. Sistem yang paling sederhana, tetapi, seperti yang mereka katakan, ada nuansa. Pada prinsipnya, ada kemungkinan proses menghasilkan begitu banyak sampah di heap sehingga sistem tidak memiliki cukup memori untuk melakukan pembersihan.
    erlang:memory(binary) bertindak sebagai metrik untuk pemantauan, menunjukkan memori yang dialokasikan untuk binari.



Jadi, case yang menyebabkan jatuhnya vm disortir, namun, selain itu, ada baiknya untuk memantau parameter yang tidak kalah pentingnya yang secara langsung atau tidak langsung mempengaruhi berfungsinya aplikasi Anda dengan benar:


  • Memori yang digunakan oleh erlang:memory(ets) ETS: erlang:memory(ets) .
  • Memori untuk modul yang dikompilasi: erlang:memory(code) .
    Jika solusi Anda tidak menggunakan kompilasi kode dinamis, maka opsi ini dapat dikecualikan.
    Saya juga ingin menyebutkan erlydtl. Jika Anda mengkompilasi template secara dinamis, maka kompilasi membuat berkas yang dimuat ke memori vm. Ini juga dapat menyebabkan kebocoran memori.
  • Memori sistem: erlang:memory(system) . Menunjukkan konsumsi memori erlang runtime.
  • Total memori yang digunakan: erlang:memory(total) . Ini adalah jumlah memori yang dikonsumsi oleh proses dan runtime.
  • Informasi tentang reduksi: erlang:statistics(reductions) .
  • Jumlah proses dan port yang siap dieksekusi: erlang:statistics(run_queue) .
  • Uptime dari instance vm: erlang:statistics(runtime) memungkinkan Anda untuk memahami apakah ada restart tanpa analisis log.
  • Aktivitas jaringan: erlang:statistics(io) .

Mengirim metrik ke zabbix


Kami akan membuat file yang berisi metrik aplikasi dan metrik erlang vm, yang akan kami perbarui setiap N detik. Untuk setiap node erlang, file metrik harus berisi metrik aplikasi yang berjalan di atasnya dan metrik instance erlang vm. Hasilnya harus seperti ini:


 messaging.systime_subs.messages.delivered = 1654 messaging.systime_subs.messages.proxied = 0 messaging.systime_subs.messages.published = 1655 messaging.systime_subs.messages.skipped = 3 โ€ฆ. erlang.io.input = 2205723664 erlang.io.output = 1665529234 erlang.memory.binary = 1911136 erlang.memory.ets = 1642416 erlang.memory.processes = 23596432 erlang.memory.processes_used = 23598864 erlang.memory.system = 50883752 erlang.memory.total = 74446048 erlang.processes.count = 402 erlang.processes.run_queue = 0 erlang.reductions = 148412771 .... 

Menggunakan zabbix_sender kami akan mengirimkan file ini ke zabbix, di mana representasi grafis dan kemampuan untuk membuat otomatisasi dan pemicu pemberitahuan sudah tersedia.


Sekarang kami memiliki metrik dalam sistem pemantauan dan pemicu otomasi dan acara pemberitahuan yang dibuat atas dasar mereka, kami memiliki kesempatan untuk menghindari kecelakaan dengan bereaksi terlebih dahulu terhadap semua penyimpangan berbahaya dari keadaan berfungsi penuh.


Pertemuan pusat kayu bulat


Ketika ada 1-2 server dalam suatu proyek, Anda mungkin masih dapat hidup tanpa pengumpulan log pusat, tetapi begitu sistem terdistribusi dengan banyak server, cluster, lingkungan muncul, menjadi perlu untuk menyelesaikan masalah pengumpulan dan kenyamanan melihat log.


Untuk menulis log di proyek saya, saya menggunakan lager. Seringkali, dalam perjalanan dari prototipe ke produksi, proyek melewati tahap pengumpulan log berikut:


  • Logging sederhana dengan output ke file lokal atau bahkan ke stdout (lager_file_backend)
  • Pengumpulan log terpusat menggunakan, misalnya, syslogd dan pengiriman log otomatis ke kolektor. Untuk skema seperti itu, lager_syslog cocok.
    Kerugian utama dari skema ini adalah Anda harus pergi ke server pengumpulan log, mencari file dengan log yang diperlukan dan entah bagaimana menyaring peristiwa untuk mencari yang diperlukan untuk debugging.
  • Kumpulan log terpusat dengan penyimpanan di repositori dengan kemampuan untuk memfilter dan mencari berdasarkan catatan.

Tentang minus, plus, dan metrik kuantitatif yang dapat diterapkan menggunakan yang terakhir, dan kami akan berbicara dalam prisma implementasi spesifik - lager_clickhouse , yang saya gunakan di sebagian besar proyek yang dikembangkan. Beberapa kata tentang lager_clickhouse . Ini adalah lager backend untuk menyimpan acara ke clickhouse. Saat ini, ini adalah proyek internal, tetapi ada rencana untuk membuatnya terbuka. Ketika mengembangkan lager_clickhouse, saya harus mem-bypass beberapa fitur clickhouse, misalnya, menggunakan event buffering untuk menghindari membuat permintaan yang sering di clickhouse. Upaya yang telah dilakukan terbayar dengan operasi yang stabil dan kinerja yang baik.


Minus utama dari pendekatan untuk menyimpan ke repositori adalah entitas tambahan - clickhouse dan kebutuhan untuk mengembangkan kode untuk menyimpan acara ke dalamnya dan antarmuka pengguna untuk menganalisis dan mencari acara. Juga, untuk beberapa proyek, mungkin penting untuk menggunakan tcp untuk mengirim log.


Tetapi menurut saya, kelebihannya lebih besar daripada semua kerugian yang mungkin terjadi.


  • Pencarian acara mudah dan cepat:


    • Memfilter berdasarkan tanggal tanpa harus mencari file / file di server pusat yang berisi berbagai acara.
    • Penyaringan berdasarkan lingkungan. Log dari subsistem yang berbeda dan sering dari kelompok yang berbeda ditulis ke satu repositori. Saat ini, pemisahan terjadi sesuai dengan label yang ditetapkan pada setiap node cluster.
    • Saring berdasarkan nama host
    • Memfilter berdasarkan nama modul yang mengirim acara
    • Penyaringan Acara
    • Pencarian teks

    Contoh tampilan antarmuka tampilan log ditunjukkan pada tangkapan layar:


  • Kemampuan otomatisasi.
    Dengan diperkenalkannya penyimpanan log, menjadi mungkin secara real time untuk menerima informasi tentang jumlah kesalahan, terjadinya kegagalan kritis, dan aktivitas sistem. Dengan memperkenalkan batas-batas tertentu, kami dapat menghasilkan peristiwa darurat ketika sistem keluar dari keadaan fungsional, yang penangannya akan melakukan tindakan otomatisasi untuk menghilangkan keadaan ini dan mengirimkan pemberitahuan kepada anggota tim yang bertanggung jawab untuk fungsi:


    • Ketika kesalahan kritis terjadi.
    • Dalam kasus kesalahan massa (turunan waktu meningkat lebih cepat dari batas tertentu).
    • Metrik terpisah adalah tingkat pembuatan acara, yaitu berapa banyak acara baru yang muncul di log peristiwa. Anda hampir selalu dapat mengetahui perkiraan jumlah log yang dihasilkan oleh suatu proyek per unit waktu. Jika melebihi beberapa kali, kemungkinan besar ada sesuatu yang salah.


Pengembangan lebih lanjut dari topik otomatisasi penanganan peristiwa darurat adalah penggunaan skrip lua. Pengembang atau administrator apa pun dapat menulis skrip untuk memproses log dan metrik. Skrip menghadirkan fleksibilitas dan memungkinkan Anda membuat skrip dan pemberitahuan otomatisasi yang dipersonalisasi.


Ringkasan


Untuk memahami proses yang terjadi dalam sistem dan untuk menyelidiki insiden, sangat penting untuk memiliki indikator kuantitatif dan log peristiwa, serta alat yang mudah untuk menganalisisnya. Semakin banyak informasi yang kami kumpulkan tentang sistem, semakin mudah untuk menganalisis perilakunya dan memperbaiki masalah bahkan pada tahap kemunculannya. Jika tindakan kami tidak berhasil, kami selalu memiliki jadwal dan catatan terperinci tentang kejadian yang kami miliki.


Dan bagaimana Anda mengoperasikan solusi pada Erlang / Elixir dan kasus menarik apa yang Anda temui dalam produksi?

Source: https://habr.com/ru/post/id437720/


All Articles