Daftar periksa: apa yang harus dilakukan sebelum menjalankan layanan microser di prod

Artikel ini berisi kutipan singkat dari pengalaman saya sendiri dan pengalaman rekan-rekan saya, yang dengannya saya menghabiskan waktu berhari-hari untuk menyapu kejadian. Dan banyak insiden tidak akan pernah terjadi jika semua orang menyukai layanan microser mereka ditulis setidaknya sedikit lebih akurat.


Sayangnya, beberapa programmer tingkat rendah serius percaya bahwa Dockerfile dengan beberapa jenis perintah di dalamnya sendiri adalah microservice dan dapat digunakan bahkan sekarang. Dockers berputar, bangku berlumpur. Pendekatan ini penuh dengan masalah mulai dari penurunan kinerja, ketidakmampuan untuk debug dan penolakan layanan untuk mimpi buruk yang disebut Data Inconsistency.


Jika Anda merasa sudah tiba saatnya untuk meluncurkan aplikasi lain di Kubernetes / ECS / apa pun, maka saya memiliki sesuatu yang tidak diinginkan.


Versi bahasa Inggris juga tersedia .


Saya membentuk sendiri serangkaian kriteria untuk menilai kesiapan aplikasi untuk diluncurkan dalam produksi. Beberapa poin dari daftar periksa ini tidak dapat diterapkan untuk semua aplikasi, tetapi hanya untuk yang khusus. Lainnya umumnya berlaku untuk semuanya. Saya yakin Anda dapat menambahkan opsi Anda di komentar atau membantah beberapa poin ini.


Jika layanan mikro Anda tidak memenuhi setidaknya satu dari kriteria, saya tidak akan mengizinkannya berada di kluster ideal saya, dibangun di dalam bunker 2000 meter di bawah tanah dengan pemanas di bawah lantai dan sistem pasokan Internet mandiri yang tertutup.


Ayo pergi ....


Catatan: urutan barang tidak masalah. Ngomong-ngomong, untukku.


Readme Deskripsi Singkat


Ini berisi deskripsi singkat tentang dirinya sendiri di awal Readme.md dalam repositori-nya.

Ya Tuhan, sepertinya sangat sederhana. Tetapi seberapa sering saya menemukan bahwa repositori tidak mengandung penjelasan sekecil apa pun mengapa diperlukan, tugas apa yang dipecahkannya, dan sebagainya. Tidak perlu membicarakan sesuatu yang lebih rumit, seperti opsi konfigurasi.


Integrasi dengan sistem pemantauan


Mengirim metrik ke DataDog, NewRelic, Prometheus, dan sebagainya.

Analisis konsumsi sumber daya, kebocoran memori, stacktraces, saling ketergantungan layanan, tingkat kesalahan - tanpa memahami semua ini (dan tidak hanya), sangat sulit untuk mengendalikan apa yang terjadi dalam aplikasi terdistribusi besar.


Lansiran terkonfigurasi


Layanan ini mencakup peringatan yang mencakup semua situasi standar plus situasi unik yang diketahui.

Metrik baik, tetapi tidak ada yang akan mengikutinya. Karena itu, kami secara otomatis menerima panggilan / push / sms jika:


  • Konsumsi CPU / memori telah meningkat secara dramatis.
  • Lalu lintas meningkat / turun tajam.
  • Jumlah transaksi yang diproses per detik telah berubah secara dramatis ke segala arah.
  • Ukuran artefak setelah perakitan telah berubah secara dramatis (exe, app, toples, ...).
  • Persentase kesalahan atau frekuensinya melebihi ambang batas yang diizinkan.
  • Layanan telah berhenti mengirim metrik (situasi yang sering diabaikan).
  • Keteraturan acara yang diharapkan tertentu dilanggar (cron job tidak berfungsi, tidak semua acara diproses dll.)
  • ...

Runbook dibuat


Sebuah dokumen telah dibuat untuk layanan yang menggambarkan kemungkinan yang diketahui atau diperkirakan.

  • bagaimana memastikan bahwa kesalahan itu internal dan tidak bergantung pada pihak ketiga;
  • jika itu tergantung di mana, kepada siapa dan apa yang harus ditulis;
  • cara me-restart dengan aman;
  • bagaimana memulihkan dari cadangan dan di mana cadangan berada;
  • Apa dasbor / kueri khusus yang dibuat untuk memantau layanan ini;
  • Apakah layanan memiliki panel admin sendiri dan bagaimana menuju ke sana;
  • apakah ada API / CLI dan bagaimana menggunakannya untuk memperbaiki masalah yang diketahui;
  • dan sebagainya.

Daftar ini dapat sangat bervariasi antar organisasi, tetapi setidaknya hal-hal dasar harus ada di sana.


Semua log ditulis dalam STDOUT / STDERR


Layanan tidak membuat file log apa pun dalam mode produksi, tidak mengirimnya ke layanan eksternal apa pun, tidak mengandung abstraksi yang berlebihan untuk rotasi log, dll.

Ketika aplikasi membuat file log, log ini tidak berguna. Anda tidak akan masuk ke 5 kontainer berjalan secara paralel, berharap untuk menangkap kesalahan yang Anda butuhkan (dan di sini Anda, menangis ...). Memulai ulang wadah akan menyebabkan hilangnya seluruh log ini.


Jika aplikasi menulis log sendiri ke sistem pihak ketiga, misalnya, ke Logstash, ini menciptakan redundansi yang tidak berguna. Layanan tetangga tidak tahu bagaimana melakukan ini, karena apakah itu memiliki kerangka kerja yang berbeda? Anda mendapatkan kebun binatang.


Aplikasi menulis sebagian log ke file, dan sebagian lagi ke stdout karena nyaman bagi pengembang untuk melihat INFO di konsol, dan DEBUG dalam file? Ini biasanya merupakan pilihan terburuk. Tidak ada yang membutuhkan kompleksitas dan kode dan konfigurasi yang sepenuhnya berlebihan yang perlu Anda ketahui dan pelihara.


Log adalah Json


Setiap baris log ditulis dalam format Json dan berisi kumpulan bidang yang konsisten

Sampai sekarang, hampir semua orang menulis log dalam teks biasa. Ini benar-benar bencana. Saya akan senang tidak pernah tahu tentang Pola Grok . Saya memimpikan mereka kadang-kadang dan saya membeku, berusaha untuk tidak bergerak, agar tidak menarik perhatian mereka. Coba parsing pengecualian Java di log sekali saja.


Json itu baik, itu adalah api yang diberikan dari surga. Cukup tambahkan di sana:


  • cap waktu milidetik menurut RFC 3339 ;
  • level: info, peringatan, kesalahan, debug
  • user_id;
  • app_name
  • dan bidang lainnya.

Unduh ke sistem yang sesuai (misalnya, ElasticSearch yang dikonfigurasi dengan benar) dan nikmati. Hubungkan log dari banyak layanan mikro dan sekali lagi rasakan apa yang merupakan aplikasi monolitik yang baik.


(Dan Anda dapat menambahkan ID Permintaan dan melacak ...)


Log dengan tingkat verbositas


Aplikasi harus mendukung variabel lingkungan, misalnya LOG_LEVEL, dengan setidaknya dua mode operasi: ERRORS dan DEBUG.

Sangat diharapkan bahwa semua jasa dalam ekosistem yang sama mendukung variabel lingkungan yang sama. Bukan opsi konfigurasi, bukan opsi di baris perintah (walaupun ini bisa dibalikkan, tentu saja), tetapi langsung secara default dari lingkungan. Anda harus bisa mendapatkan sebanyak mungkin log jika ada masalah dan sesedikit mungkin log, jika semuanya baik-baik saja.


Memperbaiki versi ketergantungan


Dependensi untuk manajer paket diperbaiki, termasuk versi minor (misalnya, cool_framework = 2.5.3).

Ini sudah banyak dibahas, tentu saja. Beberapa memperbaiki ketergantungan pada versi utama, berharap bahwa hanya perbaikan bug kecil dan perbaikan keamanan akan di versi kecil. Ini salah.
Setiap perubahan dalam setiap ketergantungan harus tercermin dalam komitmen terpisah . Sehingga bisa dibatalkan jika terjadi masalah. Apakah sulit dikendalikan dengan tangan Anda? Ada robot yang bermanfaat, seperti ini , yang akan melacak pembaruan dan membuat Permintaan Tarik untuk Anda masing-masing.


Dockerized


Repositori berisi Dockerfile siap-produksi dan docker-compose.yml

Docker telah lama menjadi standar bagi banyak perusahaan. Ada pengecualian, tetapi bahkan jika Anda tidak memiliki Docker dalam produksi, insinyur mana pun harus dapat membuat komposisi buruh pelabuhan dan tidak memikirkan hal lain untuk mendapatkan perakitan dev untuk verifikasi lokal. Dan administrator sistem harus memiliki majelis yang sudah diverifikasi oleh pengembang dengan versi perpustakaan, utilitas, dan sebagainya yang diperlukan, di mana aplikasi setidaknya berfungsi untuk menyesuaikannya dengan produksi.


Konfigurasi Lingkungan


Semua opsi konfigurasi penting dibaca dari lingkungan dan lingkungan lebih diutamakan daripada file konfigurasi (tetapi lebih rendah dari argumen baris perintah saat startup).

Tidak seorang pun akan pernah ingin membaca file konfigurasi Anda dan mempelajari formatnya. Terima saja.


Lebih detail di sini: https://12factor.net/config


Probe kesiapan dan semangat


Berisi titik akhir yang sesuai atau perintah klien untuk menguji kesiapan untuk melayani permintaan saat startup dan uptime sepanjang hidup.

Jika aplikasi melayani permintaan HTTP, seharusnya memiliki dua antarmuka secara default:


  1. Untuk memverifikasi bahwa aplikasi itu hidup dan tidak beku, tes Liveness digunakan. Jika aplikasi tidak merespons, aplikasi ini dapat dihentikan secara otomatis oleh orkestra seperti Kubernetes, " tetapi ini tidak akurat ." Bahkan, membunuh aplikasi yang dibekukan dapat menyebabkan efek domino dan secara permanen memberikan layanan Anda. Tapi ini bukan masalah pengembang, lakukan saja titik akhir ini.


  2. Untuk memverifikasi bahwa aplikasi tidak baru saja dimulai, tetapi siap untuk menerima permintaan, tes Kesiapan dilakukan. Jika aplikasi telah membuat koneksi ke database, sistem antrian, dan sebagainya, itu harus merespon dengan status dari 200 hingga 400 (untuk Kubernetes).



Batas sumber daya


Berisi batas pada konsumsi memori, CPU, ruang disk dan sumber daya lain yang tersedia dalam format yang konsisten.

Implementasi spesifik dari item ini akan sangat berbeda di organisasi yang berbeda dan untuk orkestra yang berbeda. Namun, batas-batas ini harus ditetapkan dalam format tunggal untuk semua layanan, berbeda untuk lingkungan yang berbeda (prod, dev, test, ...) dan berada di luar repositori dengan kode aplikasi .


Perakitan dan pengiriman dilakukan secara otomatis


Sistem CI / CD yang digunakan dalam organisasi atau proyek Anda dikonfigurasikan dan dapat mengirimkan aplikasi ke lingkungan yang diinginkan sesuai dengan alur kerja yang diterima.

Tidak ada yang pernah dikirimkan ke produksi secara manual.


Tidak peduli betapa sulitnya untuk mengotomatisasi perakitan dan pengiriman proyek Anda, ini harus dilakukan sebelum proyek ini masuk ke produksi. Item ini termasuk perakitan dan peluncuran buku masak Ansible / Chef / Salt / ..., perakitan aplikasi untuk perangkat seluler, perakitan garpu sistem operasi, perakitan gambar mesin virtual, apa pun.
Tidak dapat diotomatisasi? Jadi Anda tidak bisa menjalankan ini ke dunia. Setelah Anda, tidak ada yang akan mengumpulkannya.


Shutdown shutdown - shutdown yang benar


Aplikasi ini dapat memproses SIGTERM dan sinyal lainnya dan secara sistematis mengganggu pekerjaannya setelah selesai memproses tugas saat ini.

Ini adalah poin yang sangat penting. Proses Docker menjadi yatim piatu dan bekerja selama berbulan-bulan di latar belakang di mana tidak ada yang melihatnya. Operasi non-transaksional terputus di tengah pelaksanaan, menciptakan ketidakkonsistenan data antara layanan dan database. Ini mengarah pada kesalahan yang tidak bisa diramalkan dan bisa sangat, sangat mahal.


Jika Anda tidak mengontrol dependensi dan tidak dapat menjamin bahwa kode Anda akan memproses SIGTERM dengan benar, gunakan sesuatu seperti dumb-init .


Info lebih lanjut di sini:



Koneksi basis data diperiksa secara teratur


Aplikasi ini terus-menerus mem-ping database dan secara otomatis merespons pengecualian "kehilangan koneksi" untuk setiap permintaan, mencoba mengembalikannya sendiri atau menyelesaikan pekerjaannya dengan benar

Saya melihat banyak kasus (ini bukan hanya pergantian ucapan) ketika layanan yang dibuat untuk memproses antrian atau acara kehilangan koneksi mereka oleh batas waktu dan mulai tanpa henti menuangkan kesalahan ke dalam log, mengembalikan pesan ke antrian, mengirimnya ke Dead Letter Queue atau hanya tidak melakukan pekerjaan mereka.


Diskalakan secara horizontal


Dengan meningkatnya beban, cukup menjalankan lebih banyak contoh aplikasi untuk memastikan bahwa semua permintaan atau tugas diproses.

Tidak semua aplikasi dapat menskala secara horizontal. Contoh yang mencolok adalah Konsumen Kafka . Ini tidak selalu buruk, tetapi jika aplikasi tertentu tidak dapat diluncurkan dua kali, semua pihak yang berkepentingan perlu mengetahui hal ini sebelumnya. Informasi ini harus merusak pemandangan, bertahanlah di Readme dan sedapat mungkin. Beberapa aplikasi secara umum tidak dapat diluncurkan secara paralel dalam keadaan apa pun, yang menimbulkan kesulitan serius dalam dukungannya.


Jauh lebih baik jika aplikasi itu sendiri mengendalikan situasi ini atau pembungkus ditulis untuknya yang secara efektif memonitor "pesaing" dan tidak memungkinkan proses untuk memulai atau memulai pekerjaan sampai proses lain menyelesaikan pekerjaannya atau sampai beberapa konfigurasi eksternal memungkinkan proses N untuk bekerja secara bersamaan.


Antrian surat mati dan ketahanan pesan buruk


Jika layanan mendengarkan antrian atau merespons acara, mengubah format atau konten pesan tidak mengarah pada kejatuhannya. Upaya yang gagal untuk memproses tugas diulang N kali, setelah itu pesan dikirim ke Dead Letter Queue.

Berkali-kali saya melihat konsumen tanpa henti memulai kembali dan jalur yang telah meningkat sedemikian rupa sehingga proses mereka selanjutnya memakan waktu berhari-hari. Setiap pendengar antrian harus siap untuk mengubah format, untuk kesalahan acak dalam pesan itu sendiri (mengetik data dalam json, misalnya), atau ketika diproses oleh kode anak. Saya bahkan menemukan situasi ketika pustaka RabbitMQ standar untuk satu kerangka kerja yang sangat populer tidak mendukung percobaan ulang, percobaan balasan, dll.


Lebih buruk lagi, ketika sebuah pesan dihancurkan hanya jika terjadi kegagalan.


Batasan jumlah pesan yang diproses dan tugas per proses


Ini mendukung variabel lingkungan, yang dapat dipaksa untuk membatasi jumlah maksimum tugas yang diproses, setelah itu layanan akan dimatikan dengan benar.

Semuanya mengalir, semuanya berubah, terutama ingatan. Grafik konsumsi memori yang terus tumbuh dan OOM Dibunuh pada akhirnya adalah norma dalam pikiran kubernetic modern. Penerapan tes primitif yang hanya akan menyelamatkan Anda, bahkan kebutuhan untuk memeriksa semua kebocoran memori ini akan membuat hidup lebih mudah. Saya sering melihat orang menghabiskan banyak waktu dan upaya (dan uang) untuk menghentikan pergantian ini, tetapi tidak ada jaminan bahwa komitmen rekan Anda berikutnya tidak akan memperburuk keadaan. Jika aplikasi dapat bertahan seminggu - ini adalah indikator yang bagus. Biarkan itu berakhir begitu saja dan dimulai kembali. Ini lebih baik daripada SIGKILL (tentang SIGTERM lihat di atas) atau pengecualian "kehabisan memori". Selama beberapa dekade, colokan ini cukup untuk Anda.


Tidak menggunakan integrasi pihak ketiga dengan penyaringan berdasarkan alamat IP


Jika aplikasi membuat permintaan ke layanan pihak ketiga yang memungkinkan akses dari alamat IP terbatas, layanan melakukan panggilan ini secara tidak langsung melalui proxy terbalik.

Ini adalah kasus yang jarang terjadi, tetapi sangat tidak menyenangkan. Sangat tidak nyaman ketika satu layanan kecil memblokir kemungkinan mengubah cluster atau memindahkan seluruh infrastruktur ke wilayah lain. Jika Anda perlu berkomunikasi dengan seseorang yang tidak tahu cara menggunakan oAuth atau VPN, konfigurasikan proxy terbalik terlebih dahulu. Jangan mengimplementasikan dalam program Anda penambahan dinamis / penghapusan integrasi eksternal seperti itu, karena dengan melakukan ini Anda memakukan diri Anda ke dalam satu-satunya runtime yang tersedia. Lebih baik segera mengotomatiskan proses ini untuk mengelola konfigurasi Nginx, dan dalam aplikasi Anda, hubungi dia.


Agen Pengguna HTTP yang jelas


Layanan ini menggantikan tajuk Agen-pengguna dengan tajuk khusus untuk semua permintaan ke API apa pun, dan tajuk ini berisi informasi yang cukup tentang layanan itu sendiri dan versinya.

Ketika Anda memiliki 100 aplikasi berbeda yang saling berbicara, Anda bisa menjadi gila melihat di log seperti "Go-http-client / 1.1" dan alamat IP dinamis dari wadah Kubernetes. Identifikasi selalu aplikasi Anda dan versinya secara eksplisit.


Tidak melanggar lisensi


Itu tidak mengandung dependensi yang terlalu membatasi aplikasi, itu bukan salinan kode orang lain, dan sebagainya.

Ini adalah kasus yang jelas, tetapi kebetulan melihat bahwa bahkan pengacara yang menulis NDA sekarang cegukan.


Tidak menggunakan dependensi yang tidak didukung


Ketika Anda pertama kali memulai layanan, itu tidak termasuk dependensi yang sudah usang.

Jika perpustakaan yang Anda ambil dalam proyek tidak lagi didukung oleh siapa pun - cari cara lain untuk mencapai tujuan atau kembangkan perpustakaan itu sendiri.


Kesimpulan


Ada beberapa pemeriksaan yang sangat spesifik pada daftar saya untuk teknologi atau situasi tertentu, tetapi saya hanya lupa untuk menambahkan sesuatu. Saya yakin Anda juga akan menemukan sesuatu untuk diingat.

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


All Articles