Di bagian pertama
artikel saya
, saya berbicara tentang bagaimana kami di Badoo membuat versi pertama dari sistem patch. Singkatnya, kami perlu menemukan cara untuk memperbaiki bug serius tepat pada produksi, dapat diakses oleh semua pengembang. Namun, versi pertama bukan tanpa kekurangannya: kami menggunakan metode tata letak khusus, yang tidak menjamin atomicity tata letak tambalan dan konsistensi kode.
Pada bagian artikel ini, saya akan berbicara tentang cara baru untuk mengeluarkan kode yang kami temukan ketika mencoba menyelesaikan masalah kami, dan bagaimana sistem patch kami ditransformasikan dengannya.
Gambar: sumberSolusi Universal - Kit Penerapan Multiversional
Setelah review lain dari sistem Jura kami,
youROCK Nasretdinov menyatakan bahwa ia memiliki ide tentang bagaimana menyelesaikan semua masalah kami. Semua yang dia tanyakan adalah banyak waktu untuk membuat ulang sistem tata letak. Beginilah konsep Multiversional Deployment Kit, atau, pada orang biasa, MDK muncul (Jura membandingkannya dengan cara tata letak kode lain dalam
laporannya tentang HighLoad ++ ).
Sistem baru dirancang untuk mengubah prosedur tata letak kami. Bagi mereka yang belum membaca bagian pertama artikel saya, saya akan memberi tahu Anda secara singkat bagaimana proses penyebarannya: pertama-tama kami mengumpulkan semua file yang diperlukan dalam satu direktori, kemudian kami menyimpan dan mengirimkan status direktori ke server.
Sebelum era MDK, kami menggunakan perangkat blok (yaitu, gambar sistem file) yang disebut loop untuk menyimpan dan mengirim. Direktori disalin ke loop kosong, itu diarsipkan dan dikirim ke server.
Dalam sistem baru, kami membuat versi bukan seluruh direktori, tetapi setiap file satu per satu sehingga versi file berkorelasi dengan kontennya. Untuk direktori ada peta (maps) - file khusus di mana versi semua file dalam direktori dicatat. Kartu-kartu ini juga versi, dan semuanya terlihat seperti ini:

Terlihat familier? Ini adalah bagaimana objek diatur dalam Git (Anda dapat membacanya di
sini , tetapi ini tidak diperlukan untuk memahami artikel).
Untuk versi, kami menggunakan delapan karakter pertama dari hash MD5 (dari representasi heksadesimalnya, tepatnya), yang diambil dari konten file. Versi ini ditulis di akhir nama file atau di awal nama peta (sehingga Anda dapat membedakan file peta dari peta versi yang dihasilkan):
Versi kode adalah versi peta direktori root www. Untuk menemukan peta saat ini, kami memiliki tautan simbolik (symlink) current.map.
Mengapa tidak menggunakan git?Terlepas dari kenyataan bahwa MDK sebagian meminjam ide dari Git, mereka memiliki beberapa perbedaan. Yang paling penting adalah bagaimana file disimpan di direktori kerja (mis. Pada mesin). Jika Git hanya menyimpan satu, versi saat ini, di sana, maka MDK menyimpan semua versi file yang tersedia di sana. Pada saat yang sama, hanya satu symlink current.map menunjuk ke versi kode saat ini, yang menggunakan autoload dalam kerjanya dan yang dapat diubah secara atom. Sebagai perbandingan, Git menggunakan
checkout git untuk mengubah versi, yang mengubah file pada gilirannya dan bukan atom.
Bangun dengan MDK
MDK diperlukan untuk menyimpan status direktori di akhir perakitan. Untuk melakukan ini, kami memiliki tempat khusus, yang kami sebut repositori, - repositori semua versi file yang bernilai bagi kami (yaitu, yang mungkin ingin kami dekomposisi). Ketika konten baru direktori siap, kami menghitung versi semua file di dalamnya dan melaporkan yang hilang ke repositori.
Layout dengan MDK
Selama tata letak pada masing-masing server penerima, kami menjalankan skrip yang memeriksa apakah semua file yang diperlukan ada di server dan meminta yang hilang dari repositori. Kami hanya dapat mengalihkan versi ke yang baru dengan mengubah symlink current.map.
Bagaimana seharusnya memecahkan masalah kita
Diasumsikan bahwa jika hanya beberapa file berubah dalam versi baru, perakitan dan tata letaknya menggunakan sistem baru harus setidaknya sebanding dalam waktu dengan tata letak tambalan sebagai file terpisah. Jika demikian, maka untuk setiap tambalan kami hanya akan menghasilkan versi baru.
Implementasi MDK
MDK memiliki satu kelemahan: pada mesin terakhir, nama setiap file harus memiliki versinya. Inilah yang memungkinkan Anda untuk menyimpan banyak versi dari satu file dalam direktori sekaligus, tetapi itu tidak memungkinkan Anda untuk memasukkan menyertakan user.php dari kode - Anda harus menentukan versi tertentu. Tambahkan ke ini berbagai bug yang bisa tetap berada dalam kode sistem tata letak, algoritma tata letak baru, yang lebih rumit daripada yang lama, dan akan menjadi jelas mengapa kami memutuskan untuk menerapkan sistem baru dalam langkah-langkah kecil. Kami mulai secara harfiah dengan satu atau dua server dan secara bertahap memperluas daftar mereka, sekaligus memperbaiki masalah yang muncul.
Mengingat bahwa beralih ke sistem baru seharusnya menghabiskan banyak waktu, kami harus memikirkan bagaimana patch kami akan bekerja selama periode transisi. Pada saat itu, untuk tata letak tambalan, kami menggunakan utilitas mscp self-writing, yang meletakkan file satu per satu. Kami mengajarinya untuk mengganti file saat ini di server dengan MDK sebelumnya, tetapi kami tidak dapat menambahkan file baru ke server tersebut (karena saya harus mengubah peta file). Saya tidak ingin memperkenalkan beberapa solusi perantara yang sangat rumit - karena kami akan menuju masa depan yang cerah, di mana mscp tidak diperlukan. Akibatnya, saya harus mengatasi masalah ini. Secara umum, selama masa transisi, para pengembang berhasil menderita, tetapi sekarang bagi kami itu sepadan.
Jangan percaya siapapun
Gambar: sumberMungkin, pertanyaannya akan logis, tetapi apakah akan ada tabrakan versi di MDK (yaitu, situasi di mana dua file dengan konten yang berbeda diberikan versi yang sama)?
Sebenarnya, kami cukup terlindungi dari kesalahan semacam ini. Kami memberi
{ }.{}
file seperti ini:
{ }.{}
, yang berarti bahwa lebih dari delapan karakter harus cocok agar kesalahan terjadi.
Tapi begitu sesuatu terjadi kesalahan. Setelah perhitungan berikutnya, kami melihat semakin banyak kesalahan dengan kode HTTP 404 (file tidak ditemukan). Investigasi kecil menunjukkan bahwa beberapa file statis hilang. Ternyata kami membuat peta statis yang sangat lama dan memberikan tautan ke file yang seharusnya belum ada di server. Tapi dari mana kartu ini berasal? Di bagian pertama artikel, saya mencatat bahwa statis didekomposisi oleh proses terpisah, dan hanya peta versi yang tersisa dengan kode PHP. Ketika kami membuat versi baru MDK, kami melaporkan versi file yang hilang ke repositori, dari mana tidak ada yang dihapus (ada banyak ruang, kami tidak keberatan). Dan kita sering memberikan semua yang terbaik untuk pementasan, dan oleh karena itu peta versi statika adalah salah satu file yang lebih sering berubah daripada yang lain. Semua ini mengarah pada fakta bahwa kami dihadapkan pada tabrakan. Setelah memeriksa versi, MDK memutuskan bahwa semuanya baik-baik saja, karena file versi seperti itu sudah ada, dan meletakkannya di server. Adalah baik bahwa kami menemukan kesalahan dengan cepat.
Sekarang, di samping versi, kami memeriksa ukuran file: jika itu sama di repositori, maka kemungkinan besar itu adalah file yang sama. Dalam kasus terburuk, kami akan memiliki cerita untuk artikel baru.
MDK - Pencuri Natal
Gambar: sumberDan saya ingin memberi tahu Anda tentang kesalahan lain, karena itu setidaknya lucu. Mudah ditebak bahwa kami memiliki proses pembersihan versi lama file di server tujuan. Dalam upaya untuk dengan cepat menyelesaikan salah satu masalah, kami membuat keputusan yang menentukan: mengatur periode pembersihan menjadi satu hari (bukan tujuh, seperti sebelumnya). Itu berhasil - dan masalahnya hilang. Kami bahkan hidup sebentar.
Sekitar pukul lima pagi pada hari Minggu, sebuah telepon berdering di kamar saya, dan monitor on call berdering: “Skrip tidak berfungsi untuk kita. Mereka mengatakan bahwa Anda tahu apa masalahnya. " Bagi saya, itu terdengar seperti “Di kantor, juicernya sudah hangus. Mereka mengatakan Anda tahu apa masalahnya. " Saya hanya tahu tentang prinsip-prinsip kerangka penulisan kami dari artikel dan cerita, saya tidak memiliki "hubungan pribadi" dengannya, dan terlebih lagi, saya tidak pernah memperbaikinya. Tetapi saya naik ke server untuk mencari tahu apa yang terjadi, dan menemukan bahwa masalahnya benar-benar "ada di pihak kita": sama sekali tidak ada kode di server.
Saya mengunggah kode lagi - dan itu berhasil. Omong-omong, kesalahannya ternyata primitif: pada hari Sabtu, tidak ada satu pun MDK versi baru yang ditata, dan skrip pembersih, ternyata, tidak melakukan pemeriksaan apa pun untuk tidak menghapus versi saat ini. Akibatnya, pada pukul lima pagi dia (sesuai jadwal) menghapus kode dari semua server. Setelah cerita ini, kami menyadari bahwa dengan pengaturan lama, itu akan muncul pada hari libur 7 hari, misalnya, pada liburan Tahun Baru, tepat pada Malam Natal. “Kristus telah lahir - kodenya hilang” - untuk waktu yang lama kita dapat mendengar lelucon ini.
Sistem tambalan baru
Pada akhirnya, kami memperkenalkan sistem tata letak baru - dan inilah saatnya untuk memperbaiki sistem tambalan. Tidak perlu lagi mscp dan tidak perlu menghindari membuat versi baru. Pertama, kami mengubah siklus hidup tambalan. Sekarang, setelah mengkonfirmasi perubahan, dia kembali ke pengembang, yang membuat keputusan ketika patch siap untuk perhitungan. Dia mengklik tombol Deploy, setelah itu kami menambahkan tambalan untuk menguasai, menghasilkan, dan menggunakan versi baru MDK. Keterlibatan pengembang pada tahap ini tidak lagi diperlukan.
Kami telah mencapai kecepatan tata letak yang sangat baik: perubahan sampai ke server dalam satu menit. Namun, untuk melakukan ini, kami harus menggunakan beberapa trik: misalnya, kami masih tidak menghasilkan statika atau terjemahan - sebagai gantinya, kami mengambil versi dari versi dekomposisi yang terakhir. Karena itu, kami mempertahankan batasan pada tambalan untuk file JS dan CSS.
Eksperimennya
Kami benar-benar berhasil menyelesaikan semua masalah yang kami miliki sebelumnya. Anda tidak perlu lagi memikirkan bagaimana cara membuat perubahan dengan benar, yang tidak akan menyebabkan kesulitan dengan tata letak file per file - hanya saja jangan menyentuh statika, dan semuanya akan berfungsi.
Tetapi kesulitan baru muncul. Sebelumnya, kami mengizinkan pengembang untuk mengirim perubahan mereka ke satu atau lebih server, hanya untuk memastikan bahwa semuanya akan bekerja dengan mereka. Dengan sistem baru, fitur ini menghilang, karena master kini telah menjadi versi saat ini untuk semua server, tanpa kecuali.
Gambar: sumberKarena itu, persyaratan baru untuk sistem tambalan telah muncul: Anda perlu kemampuan untuk memeriksa perubahan pada sejumlah kecil server tanpa menambahkan perubahan pada master. Kami menyebut eksperimen fungsionalitas baru.
Untuk pengembang, prosesnya terlihat seperti ini: setelah menerima upgrade, halaman baru tersedia di antarmuka sistem patch tempat Anda dapat memilih server tempat Anda ingin bereksperimen. Itu bisa berupa sekelompok server, satu server atau kombinasi apa pun yang akan dimengerti oleh sistem kami. Sistem menyebarkan tambalan dan memberi tahu pengembang. Pada saat yang sama, log kesalahan terbaru dari server yang terpengaruh muncul di halaman.
Kami tidak membatasi pengembang dengan cara apa pun, mereka dapat membuat eksperimen di server yang sama. Satu dapat bereksperimen pada 10% cluster, yang lain pada seluruh cluster.
Ini menjadi mungkin karena fakta bahwa kita memiliki "versi tambalan" yang sangat kurang. Ini adalah versi yang secara teori mungkin unik untuk setiap server. Sepertinya string pengidentifikasi dipisahkan oleh koma, misalnya, "32,45,79". Ini berarti bahwa server harus memiliki semua perubahan dari wizard dan tambalan bernomor 32, 45 dan 79. Untuk setiap versi seperti itu, kami membuat versi MDK kami sendiri. Kami mengambil perubahan terbaru dari cabang utama, dan kemudian secara berurutan menerapkan setiap patch. Jika konflik muncul selama pembuatan salah satu versi, kami cukup membatalkan eksperimen untuk tambalan terbaru dan memberi tahu pengembang.
File yang dihasilkan
Sejak hari pertama keberadaan sistem patch, kami melakukan trik: kami menolak untuk menghasilkan statis sehingga perubahan akan mencapai server secepat mungkin. Tentu saja, kami benar-benar ingin mendapatkan kesempatan untuk mengubah kode JS dengan cara yang sama seperti kami mengubah kode PHP, tetapi semua upaya untuk membangun proses ini tidak berhasil.
Sekitar enam bulan yang lalu, kami kembali ke masalah ini. Tujuan: Anda perlu mengubah statika, tetapi Anda tidak dapat mengorbankan kecepatan tata letak kode PHP. Masalah utama: perakitan lengkap membutuhkan waktu delapan menit. Apa yang harus dilakukan
Anda harus berkompromi. Kami mulai dengan fakta bahwa kode JS tidak dapat ditata sebagai bagian dari eksperimen. Ini akan menghemat banyak waktu: cukup perbarui satu versi statika daripada menghasilkan lusinan versi yang berbeda untuk berbagai kelompok mesin. Tapi ini masih lama. Apa lagi yang bisa Anda simpan? Kami tidak menemukan cara mengurangi waktu, tetapi memutuskan bahwa tidak akan ada masalah jika perakitan tidak memblokir tata letak kode PHP.
Kami mulai membuat statika secara asinkron. Dengan perubahan pada file JS atau CSS, kami memulai proses terpisah yang membuat peta baru dari versi statis. Proses merakit kode PHP di awal pekerjaan memeriksa untuk melihat apakah ada peta statis baru, dan, jika ada, ambil dan letakkan di semua server. Apakah Anda menyelesaikan masalah? Dalam praktek. Dengan pendekatan ini, kami menggunakan batasan baru: Anda tidak dapat mengubah kode JS dan PHP dalam satu tambalan, karena kami menguraikan perubahan ini secara tidak sinkron dan tidak dapat menjamin bahwa mereka akan berada di mesin pada saat yang sama.
Ringkasan
Kami sangat senang dengan pembaruan tersebut. Itu tidak mudah bagi kami, tetapi itu membuat sistem kami jauh lebih dapat diandalkan. Pengembang menemukan aplikasi alternatif untuk eksperimen: dengan mereka Anda dapat dengan mudah mengumpulkan log spesifik dari sepasang server tanpa menambahkan perubahan Anda ke master.
Kami masih memiliki ide untuk memperbaiki sistem, untuk implementasi yang belum cukup waktu. Sebagai contoh, kami ingin mengulang proses pembuatan tambalan dan menambahkan kemampuan untuk mengubah file JS pada saat yang sama dengan kode utama untuk menyingkirkan pembatasan terbaru.
Setiap hari kami memposting sekitar 60 tambalan, terkadang ada beberapa kali lebih banyak, misalnya, selama pengembangan beberapa fungsi yang hanya tersedia untuk penguji sejauh ini. Sekitar sepertiga dari tambalan melalui percobaan sebelum ditata. Secara total, selama keberadaan sistem, kami memiliki sekitar 46.000 tambalan untuk master.