
Ini adalah artikel selanjutnya dari seri yang menggambarkan bagaimana kami meningkatkan ketersediaan layanan kami di Citymobil (Anda dapat membaca bagian sebelumnya di
sini dan di
sini ). Di bagian selanjutnya, saya akan berbicara tentang kecelakaan dan pemadaman secara rinci. Tetapi pertama-tama izinkan saya menyoroti sesuatu yang seharusnya saya bicarakan di artikel pertama tetapi tidak. Saya mengetahuinya dari umpan balik pembaca saya. Artikel ini memberi saya kesempatan untuk memperbaiki kekurangan yang mengganggu ini.
1. Prolog
Seorang pembaca bertanya kepada saya pertanyaan yang sangat adil: "Apa yang menyulitkan tentang backend dari layanan naik-naik?" Itu pertanyaan yang bagus. Musim panas lalu, saya bertanya pada diri sendiri pertanyaan itu sebelum mulai bekerja di Citymobil. Saya berpikir: "itu hanya layanan taksi dengan aplikasi tiga tombolnya." Seberapa keras itu? Itu berubah menjadi produk yang sangat berteknologi tinggi. Untuk sedikit memperjelas apa yang saya bicarakan dan betapa besarnya teknologi itu, saya akan memberi tahu Anda tentang beberapa arah produk di Citymobil:
- Harga Tim penetapan harga kami menangani masalah harga perjalanan terbaik di setiap titik dan setiap saat. Harga ditentukan oleh prediksi keseimbangan penawaran dan permintaan berdasarkan statistik dan beberapa data lainnya. Itu semua dilakukan oleh layanan yang rumit dan terus berkembang berdasarkan pembelajaran mesin. Tim penetapan harga juga berurusan dengan penerapan berbagai metode pembayaran, biaya tambahan setelah menyelesaikan perjalanan, tolak bayar, penagihan, interaksi dengan mitra dan pengemudi.
- Pengiriman pesanan. Mobil mana yang melengkapi pesanan klien? Misalnya, opsi untuk memilih kendaraan terdekat bukanlah yang terbaik dalam hal memaksimalkan sejumlah perjalanan. Opsi yang lebih baik adalah mencocokkan mobil dan klien sehingga memaksimalkan jumlah perjalanan dengan mempertimbangkan kemungkinan klien khusus ini membatalkan pesanannya dalam keadaan khusus ini (karena penantiannya terlalu lama) dan kemungkinan pengemudi khusus ini membatalkan atau menyabotase pesanan ( mis. karena jaraknya terlalu besar atau harganya terlalu kecil).
- Geo. Semua tentang pencarian alamat dan saran, titik pengambilan, penyesuaian perkiraan waktu kedatangan (mitra penyedia peta kami tidak selalu memberi kami informasi ETA yang akurat dengan penyisihan untuk lalu lintas), peningkatan akurasi geocoding langsung dan balik, peningkatan akurasi titik kedatangan mobil. Ada banyak data, banyak analitik, banyak layanan berbasis pembelajaran mesin.
- Antifraud Perbedaan biaya perjalanan untuk penumpang dan pengemudi (misalnya, dalam perjalanan singkat) menciptakan insentif ekonomi bagi pengganggu yang mencoba mencuri uang kami. Berurusan dengan penipuan agak mirip dengan berurusan dengan spam mail - ketepatan dan penarikan sangat penting. Kami perlu memblokir jumlah maksimum penipuan (penarikan kembali), tetapi pada saat yang sama kami tidak dapat mengambil pengguna yang baik untuk penipuan (presisi).
- Tim insentif pengemudi mengawasi pengembangan segala sesuatu yang dapat meningkatkan penggunaan platform kami oleh pengemudi dan loyalitas pengemudi karena berbagai jenis insentif. Misalnya, selesaikan perjalanan X dan dapatkan uang Y ekstra. Atau beli shift untuk Z dan berkeliling tanpa komisi.
- Backend aplikasi pengemudi. Daftar pesanan, peta permintaan (ini menunjukkan driver ke mana harus pergi untuk memaksimalkan keuntungannya), perubahan status, sistem komunikasi dengan driver dan banyak hal lainnya.
- Backend aplikasi klien (ini mungkin bagian yang paling jelas dan itulah yang biasanya orang sebut "taksi backend"): penempatan pesanan, informasi tentang status pesanan, menyediakan pergerakan mobil kecil di peta, tips backend, dll.
Ini hanya puncak gunung es. Ada lebih banyak fungsi. Ada bagian bawah laut besar dari gunung es di belakang yang tampaknya merupakan antarmuka yang cukup sederhana.
Dan sekarang mari kita kembali ke kecelakaan. Pencatatan riwayat kecelakaan selama enam bulan menghasilkan klasifikasi berikut:
- rilis buruk: 500 kesalahan server internal;
- rilis buruk: kelebihan database;
- interaksi operasi sistem manual yang kurang menguntungkan;
- Telur paskah;
- alasan eksternal;
- rilis buruk: fungsionalitas rusak.
Di bawah ini saya akan membahas secara terperinci tentang kesimpulan yang telah kami ambil mengenai jenis kecelakaan kami yang paling umum.
2. Rilis buruk: 500 kesalahan server internal
Backend kami sebagian besar ditulis dalam PHP - bahasa yang ditafsirkan dengan lemah mengetik. Kami akan merilis kode yang macet karena kesalahan di kelas atau nama fungsi. Dan itu hanya satu contoh ketika 500 kesalahan terjadi. Itu juga bisa disebabkan oleh kesalahan logis dalam kode; cabang yang salah dirilis; folder dengan kode dihapus karena kesalahan; artefak sementara yang diperlukan untuk pengujian dibiarkan dalam kode; struktur tabel tidak diubah sesuai dengan kode; skrip cron yang diperlukan tidak direstart atau dihentikan.
Kami secara bertahap menangani masalah ini secara bertahap. Perjalanan yang hilang karena rilis yang buruk jelas sebanding dengan waktu produksi. Oleh karena itu, kita harus melakukan yang terbaik dan memastikan untuk meminimalkan waktu rilis yang buruk dalam produksi. Setiap perubahan dalam proses pengembangan yang mengurangi waktu rata-rata waktu operasi rilis buruk bahkan 1 detik adalah baik untuk bisnis dan harus diimplementasikan.
Pelepasan yang buruk dan, pada kenyataannya, setiap kecelakaan dalam produksi memiliki dua status yang kami namakan "tahap pasif" dan "tahap aktif". Selama tahap pasif kami belum mengetahui adanya kecelakaan. Tahap aktif berarti kita sudah tahu. Kecelakaan dimulai pada tahap pasif; pada saatnya ia memasuki tahap aktif - saat itulah kami mengetahuinya dan mulai mengatasinya: pertama kami mendiagnosisnya dan kemudian - memperbaikinya.
Untuk mengurangi durasi pemadaman apa pun, kita perlu mengurangi durasi tahapan aktif dan pasif. Hal yang sama berlaku untuk rilis yang buruk karena dianggap semacam pemadaman.
Kami mulai menganalisis sejarah pemecahan masalah pemadaman. Rilis buruk yang kami alami ketika kami baru mulai menganalisis kecelakaan menyebabkan downtime rata-rata 20-25 menit (lengkap atau sebagian). Tahap pasif biasanya akan memakan waktu 15 menit, dan yang aktif - 10 menit. Selama tahap pasif kami akan menerima keluhan pengguna yang diproses oleh call center kami; dan setelah ambang tertentu, pusat panggilan akan mengeluh dalam obrolan Slack. Terkadang salah satu kolega kami mengeluh tidak bisa mendapatkan taksi. Keluhan kolega tersebut akan memberi sinyal tentang masalah serius. Setelah rilis buruk memasuki tahap aktif, kami memulai diagnosa masalah, menganalisis rilis terbaru, berbagai grafik dan log untuk mengetahui penyebab kecelakaan. Setelah menentukan penyebabnya, kami akan mundur jika rilis yang buruk adalah yang terbaru atau kami akan melakukan penyebaran baru dengan komit yang dikembalikan.
Ini adalah proses penanganan rilis yang buruk yang kami atur untuk ditingkatkan.
Tahap pasif: 20 menit.
Tahap aktif: 10 menit.
3. Pengurangan tahap pasif
Pertama-tama, kami perhatikan bahwa jika rilis yang buruk disertai dengan 500 kesalahan, kami dapat mengatakan bahwa masalah telah terjadi bahkan tanpa keluhan pengguna. Untungnya, semua 500 kesalahan telah dicatat dalam New Relic (ini adalah salah satu sistem pemantauan yang kami gunakan) dan yang harus kami lakukan adalah menambahkan pemberitahuan SMS dan IVR tentang melebihi jumlah spesifik 500 kesalahan. Ambang akan terus diturunkan seiring berjalannya waktu.
Proses pada saat kecelakaan akan terlihat seperti itu:
- Seorang insinyur menyebarkan rilis.
- Rilis ini menyebabkan kecelakaan (sejumlah besar 500-an).
- Pesan teks diterima.
- Insinyur dan devops mulai mencari ke dalamnya. Terkadang tidak langsung tetapi dalam 2-3 menit: pesan teks dapat ditunda, suara telepon mungkin tidak aktif; dan tentu saja, kebiasaan reaksi langsung setelah menerima teks ini tidak dapat dibentuk dalam semalam.
- Tahap aktif kecelakaan dimulai dan berlangsung 10 menit sama seperti sebelumnya.
Akibatnya, tahap aktif jenis "Rilis buruk: 500 kesalahan server internal" akan dimulai 3 menit setelah rilis. Oleh karena itu, tahap pasif berkurang dari 15 menit menjadi 3.
Hasil:
Tahap pasif: 3 menit.
Tahap aktif: 10 menit.
4. Pengurangan lebih lanjut dari tahap pasif
Meskipun tahap pasif telah dikurangi menjadi 3 menit, itu masih mengganggu kami lebih dari satu yang aktif karena selama tahap aktif kami melakukan sesuatu yang mencoba untuk memperbaiki masalah, dan selama tahap pasif layanan ini benar-benar atau sebagian turun, dan kami benar-benar tidak mengerti.
Untuk lebih mengurangi tahap pasif, kami memutuskan untuk mengorbankan 3 menit dari waktu teknisi kami setelah setiap rilis. Idenya sangat sederhana: kami akan menyebarkan kode dan selama tiga menit setelah itu kami mencari 500 kesalahan di New Relic, Sentry dan Kibana. Segera setelah kami melihat masalah di sana, kami menganggapnya sebagai terkait kode dan mulai mengatasi masalah.
Kami memilih periode tiga menit ini berdasarkan statistik: kadang-kadang masalah muncul dalam grafik dalam 1-2 menit, tetapi tidak lebih dari 3 menit.
Aturan ini ditambahkan ke do dan dont's. Pada awalnya, itu tidak selalu diikuti, tetapi seiring waktu teknisi kami terbiasa dengan aturan ini seperti yang mereka lakukan pada kebersihan dasar: menyikat gigi di pagi hari juga membutuhkan waktu, tetapi itu masih perlu.
Akibatnya, tahap pasif dikurangi menjadi 1 menit (grafik kadang-kadang masih terlambat). Ini juga mengurangi tahap aktif sebagai bonus yang bagus. Karena sekarang seorang insinyur akan menghadapi masalah yang disiapkan dan siap untuk segera memutar kodenya. Meskipun itu tidak selalu membantu, karena masalahnya bisa disebabkan oleh rilis yang digunakan secara bersamaan oleh orang lain. Yang mengatakan, tahap aktif rata-rata berkurang menjadi lima menit.
Hasil:
Tahap pasif: 1 menit.
Tahap aktif: 5 menit.
5. Pengurangan lebih lanjut dari tahap aktif
Kami mendapat lebih atau kurang puas dengan tahap pasif 1 menit dan mulai berpikir tentang cara untuk mengurangi tahap aktif lebih lanjut. Pertama-tama kami memusatkan perhatian kami pada sejarah pemadaman (kebetulan itu menjadi landasan dalam membangun ketersediaan kami!) Dan menemukan bahwa dalam kebanyakan kasus kami tidak memutar rilis segera karena kami tidak tahu versi mana yang harus kita gunakan: ada banyak rilis paralel. Untuk mengatasi masalah ini, kami memperkenalkan aturan berikut (dan menuliskannya dalam do's and dont's): tepat sebelum rilis, seseorang harus memberi tahu semua orang di obrolan Slack tentang apa yang akan Anda gunakan dan mengapa; jika terjadi kecelakaan orang harus menulis: "Kecelakaan, jangan menyebarkan!" Kami juga mulai memberi tahu mereka yang tidak membaca obrolan tentang rilis melalui SMS.
Aturan sederhana ini secara drastis menurunkan jumlah rilis selama kecelakaan yang sedang berlangsung, mengurangi durasi pemecahan masalah, dan mengurangi tahap aktif dari 5 menit menjadi 3.
Hasil:
Tahap pasif: 1 menit.
Tahap aktif: 3 menit.
6. Pengurangan tahap aktif yang lebih besar
Terlepas dari kenyataan bahwa kami memposting peringatan dalam obrolan mengenai semua rilis dan kecelakaan, kondisi balapan kadang-kadang masih terjadi - seseorang memposting tentang rilis dan insinyur lain sedang menyebarkan pada saat itu; atau kecelakaan terjadi, kami menulis tentang hal itu dalam obrolan tetapi seseorang baru saja menyebarkan kodenya. Keadaan seperti itu memperpanjang pemecahan masalah. Untuk mengatasi masalah ini, kami menerapkan larangan otomatis pada rilis paralel. Itu adalah ide yang sangat sederhana: selama 5 menit setelah setiap rilis, sistem CI / CD melarang penyebaran lain untuk siapa pun kecuali penulis rilis terbaru (sehingga ia dapat memutar kembali atau menggunakan perbaikan terbaru jika diperlukan) dan beberapa pengembang berpengalaman (di kasus darurat). Lebih dari itu, sistem CI / CD mencegah penyebaran pada saat kecelakaan (yaitu, sejak saat pemberitahuan tentang awal kecelakaan tiba dan hingga kedatangan pemberitahuan tentang berakhirnya).
Jadi, proses kami mulai terlihat seperti ini: seorang insinyur menyebarkan rilis, memantau grafik selama tiga menit, dan setelah itu tidak ada yang bisa menyebarkan apa pun selama dua menit lagi. Jika terjadi masalah, insinyur memutar rilis ke belakang. Aturan ini menyederhanakan pemecahan masalah secara drastis, dan total durasi tahapan aktif dan pasif berkurang dari 3 + 1 = 4 menit menjadi 1 + 1 = 2 menit.
Tetapi bahkan kecelakaan dua menit itu terlalu banyak. Karena itulah kami terus berupaya mengoptimalkan proses kami.
Hasil:
Tahap pasif: 1 menit.
Tahap aktif: 1 menit.
7. Penentuan dan kemunduran kecelakaan otomatis
Kami telah berpikir untuk sementara waktu bagaimana mengurangi durasi kecelakaan yang disebabkan oleh rilis buruk. Kami bahkan mencoba memaksa diri untuk melihat ke dalam
tail -f error_log | grep 500
tail -f error_log | grep 500
. Tetapi pada akhirnya, kami memilih solusi otomatis yang drastis.
Singkatnya, ini adalah kemunduran otomatis. Kami punya server web terpisah dan memuatnya melalui balancer 10 kali lebih sedikit dari server web kami yang lain. Setiap rilis akan secara otomatis digunakan oleh sistem CI / CD pada server terpisah ini (kami menyebutnya
preprod, tetapi meskipun namanya akan menerima beban nyata dari pengguna nyata). Maka skrip akan melakukan
tail -f error_log | grep 500
tail -f error_log | grep 500
. Jika dalam satu menit tidak ada kesalahan 500, CI / CD akan menyebarkan rilis baru dalam produksi ke server web lain. Jika ada kesalahan, sistem mengembalikan semuanya. Pada tingkat penyeimbang, semua permintaan menghasilkan 500 kesalahan pada preprod akan dikirim kembali pada salah satu server web produksi.
Ukuran ini mengurangi dampak rilis 500 kesalahan ke nol. Yang mengatakan, untuk berjaga-jaga jika ada bug dalam kontrol otomatis, kami tidak menghapus aturan pengawasan grafik tiga menit kami. Itu semua tentang rilis buruk dan 500 kesalahan. Mari kita beralih ke jenis kecelakaan berikutnya.
Hasil:
Tahap pasif: 0 menit.
Tahap aktif: 0 menit.
Di bagian selanjutnya, saya akan berbicara tentang jenis pemadaman lain dalam pengalaman Citymobil dan menjelaskan secara terperinci tentang setiap jenis pemadaman; Saya juga akan memberi tahu Anda tentang kesimpulan yang kami buat tentang pemadaman, bagaimana kami memodifikasi proses pengembangan, otomatisasi apa yang kami perkenalkan. Tetap disini!