Ini adalah bagian pertama dari artikel di mana saya akan berbicara tentang bagaimana kami membangun proses bekerja pada proyek migrasi basis data yang besar: tentang eksperimen yang aman, perencanaan tim, dan interaksi lintas tim. Dalam artikel berikut, saya akan berbicara lebih detail tentang masalah teknis yang kami selesaikan: tentang penskalaan dan toleransi kesalahan PostgreSQL dan pengujian beban.

Untuk waktu yang lama, basis data utama di Miro (ex-RealtimeBoard) adalah Redis. Kami menyimpan di dalamnya semua informasi dasar: data tentang pengguna, akun, papan, dll. Semuanya bekerja dengan cepat, tetapi kami mengalami sejumlah masalah.
Masalah dengan Redis- Ketergantungan pada latensi jaringan. Sekarang di cloud kami sekitar 20 waktu Moskow, tetapi ketika Anda meningkatkannya, aplikasi akan mulai bekerja sangat lambat.
- Kurangnya indeks yang kita butuhkan di level logika bisnis. Implementasi independen mereka dapat menyulitkan logika bisnis dan menyebabkan inkonsistensi data.
- Kompleksitas kode juga membuatnya sulit untuk mempertahankan konsistensi data.
- Intensitas sumber daya kueri dengan pilihan.
Masalah-masalah ini, bersama dengan peningkatan jumlah data di server, menyebabkan migrasi basis data.
Pernyataan masalah
Keputusan tentang migrasi telah dibuat. Langkah selanjutnya adalah memahami basis data mana yang cocok untuk model data kami.
Kami melakukan penelitian untuk memilih database yang optimal untuk kami, dan menetap di PostgreSQL. Model data kami sangat cocok dengan database relasional: PostgreSQL memiliki alat bawaan untuk memastikan konsistensi data, ada tipe JSONB dan kemampuan untuk mengindeks bidang-bidang tertentu di JSONB. Itu cocok untuk kita.
Arsitektur aplikasi kami yang disederhanakan tampak seperti ini: ada Server Aplikasi yang mengakses Redis dan RiakKV melalui lapisan data.
Server Aplikasi kami adalah aplikasi Java monolitik. Logika bisnis ditulis dalam kerangka kerja yang disesuaikan untuk NoSQL. Aplikasi ini memiliki sistem transaksinya sendiri, yang memungkinkan Anda menyediakan lebih dari satu pengguna di papan kami.
Kami menggunakan RiakKV untuk menyimpan data dari papan arsip yang tidak terbuka selama 7 hari.
Tambahkan PostgreSQL ke skema ini. Kami membuat server Aplikasi berfungsi dengan database baru. Salin data dari Redis dan RiakKV ke PostgreSQL. Masalahnya terpecahkan!
Tidak ada yang rumit, tetapi ada nuansa:- Kami memiliki 2,2 juta pengguna terdaftar. Setiap hari, Miro mempekerjakan 50 ribu pengguna, beban puncaknya mencapai 14 ribu sekaligus. Pengguna seharusnya tidak mengalami kesalahan karena pekerjaan kami, mereka umumnya tidak akan memperhatikan saat pindah ke basis baru.
- 1 TB data dalam database atau 410 juta objek.
- Pelepasan berkelanjutan fitur baru oleh tim lain, yang pekerjaannya tidak boleh kita campur tangan
Opsi untuk memecahkan masalah
Kami menghadapi pilihan dua opsi untuk migrasi data:
- Hentikan pengembangan layanan → tulis ulang kode di server → uji fungsionalitas → luncurkan versi baru.
- Lakukan migrasi yang lancar: secara bertahap mentransfer bagian-bagian produk ke database baru, mendukung PostgreSQL dan Redis, dan tidak mengganggu pengembangan fitur-fitur baru.
Menghentikan pengembangan layanan adalah hilangnya waktu yang bisa kita gunakan untuk pertumbuhan, yang berarti hilangnya pengguna dan pangsa pasar. Ini penting bagi kami, jadi kami memilih opsi dengan migrasi yang lancar. Terlepas dari kenyataan bahwa dalam kerumitan proses ini dapat dibandingkan dengan mengganti roda pada mobil saat mengemudi.
Saat mengevaluasi pekerjaan, kami membagi produk kami menjadi blok utama: pengguna, akun, papan, dan sebagainya. Secara terpisah, pekerjaan dilakukan untuk membuat infrastruktur PostgreSQL. Dan mereka menempatkan risiko dalam penilaian jika ada yang tidak beres (cara itu terjadi).
Sprint dan Gol
Langkah selanjutnya adalah membangun tim yang terdiri dari lima orang sehingga setiap orang bergerak dengan kecepatan yang tepat ke tujuan bersama.
Kami memiliki dua poin: awal mengerjakan tugas dan tujuan akhir. Ideal ketika kita bergerak menuju tujuan dengan cara langsung. Tetapi sering terjadi bahwa kita ingin jalan lurus, tetapi ternyata seperti ini:

Misalnya, karena kesulitan dan masalah yang tidak dapat diramalkan sebelumnya.
Suatu situasi mungkin terjadi di mana kita tidak akan mencapai tujuan sama sekali. Misalnya, jika kita masuk ke refactoring yang dalam atau menulis ulang seluruh aplikasi.

Kami membagi tugas menjadi sprint mingguan untuk meminimalkan kesulitan yang dijelaskan di atas. Jika tim tiba-tiba pergi ke samping, itu dapat dengan cepat kembali dengan kerugian minimal untuk proyek, karena iterasi pendek tidak memungkinkan Anda untuk pergi terlalu jauh "jalan yang salah".
Setiap iterasi memiliki tujuan sendiri, yang menggerakkan tim ke hasil besar akhir.

Jika tugas baru muncul selama sprint, kami mengevaluasi apakah implementasinya membawa kami lebih dekat ke tujuan. Ya - ambil sprint berikutnya atau ubah prioritas saat ini, jika tidak - jangan ambil. Jika kesalahan muncul, kami memberi mereka prioritas tinggi dan segera memperbaikinya.
Itu terjadi bahwa pengembang dalam sprint harus melakukan tugas dalam urutan yang ditentukan secara ketat. Atau, misalnya, pengembang menyerahkan tugas yang sudah selesai kepada insinyur QA untuk pengujian mendesak. Pada tahap perencanaan, kami mencoba membangun hubungan serupa antara tugas untuk setiap anggota tim. Ini memungkinkan seluruh tim untuk melihat siapa yang akan melakukan apa, dan kapan, tidak melupakan ketergantungan pada orang lain.
Tim memiliki sinkronisasi harian dan mingguan. Setiap pagi, kita membahas siapa, apa, dan prioritas apa yang akan dilakukan hari ini. Setelah setiap sprint, kami menyinkronkan satu sama lain untuk memastikan bahwa semua orang bergerak ke arah yang benar. Pastikan untuk merencanakan rilis besar atau kompleks. Kami menunjuk pengembang yang bertugas yang, jika perlu, hadir selama rilis dan memantau bahwa semuanya beres.
Perencanaan dan sinkronisasi dalam tim memungkinkan melibatkan semua peserta dalam semua tahap proyek. Rencana dan evaluasi tidak datang kepada kita dari atas, kita membuatnya sendiri. Ini meningkatkan tanggung jawab dan minat tim dalam menyelesaikan tugas.
Ini adalah salah satu sprint kami. Kami membawa semua yang ada di papan Miro:

Mode dan Eksperimen Aman
Selama migrasi, kami harus menjamin operasi layanan yang stabil dalam kondisi pertempuran. Untuk melakukan ini, Anda harus memastikan bahwa semuanya telah diuji dan tidak ada kesalahan di mana pun. Untuk mencapai tujuan ini, kami memutuskan untuk membuat migrasi yang lancar menjadi lebih lancar.
Idenya adalah untuk secara bertahap mengalihkan blok produk ke database baru. Untuk melakukan ini, kami datang dengan serangkaian mode.
Dalam mode "Redis Baca / Tulis" pertama, hanya database lama, Redis, yang berfungsi.
Dalam mode "PostgreSQL Passive Write" kedua, kita dapat memastikan bahwa menulis ke database baru sudah benar dan databasenya konsisten.
Mode ketiga "PostgreSQL Read / Write, Redis Passive Write" memungkinkan Anda memverifikasi kebenaran membaca data dari PostgreSQL dan melihat bagaimana database baru berperilaku dalam kondisi pertempuran. Pada saat yang sama, Redis tetap menjadi pangkalan utama, yang memungkinkan kami menemukan kasus-kasus spesifik yang bekerja dengan dewan yang dapat menyebabkan kesalahan.
Dalam mode "PostgreSQL Baca / Tulis" terakhir, hanya database baru yang berjalan.

Pekerjaan migrasi dapat memengaruhi fungsi-fungsi utama produk, jadi kami harus 100% yakin bahwa kami tidak akan memecahkan apa pun dan bahwa database baru berfungsi setidaknya selambat yang lama. Oleh karena itu, kami mulai melakukan eksperimen yang aman dengan beralih mode.
Kami mulai beralih mode pada akun perusahaan kami, yang kami gunakan setiap hari dalam pekerjaan. Setelah kami memastikan bahwa tidak ada kesalahan di dalamnya, kami mulai beralih mode pada beberapa pilihan pengguna eksternal.
Garis waktu peluncuran percobaan dengan mode adalah sebagai berikut:
- Januari-Februari: Redis baca / tulis
- Maret-April: PostgreSQL menulis pasif
- Mei-Juni: PostgreSQL baca / tulis, basis data utama - Redis
- Juli-Agustus: PostgreSQL baca / tulis
- September-Desember: migrasi penuh.
Jika kesalahan terjadi, kami memiliki kesempatan untuk memperbaikinya dengan cepat, karena kami sendiri dapat membuat rilis di server tempat pengguna yang berpartisipasi dalam percobaan bekerja. Kami tidak bergantung pada rilis utama, jadi kami memperbaiki kesalahan dengan cepat dan kapan saja.
Kolaborasi lintas tim
Selama migrasi, kami sering bersinggungan dengan tim yang merilis fitur baru. Kami memiliki basis kode tunggal, dan sebagai bagian dari pekerjaan mereka, tim dapat mengubah struktur yang ada dalam database baru atau membuat yang baru. Pada saat yang sama, persimpangan tim untuk pengembangan dan penarikan fitur baru dapat terjadi. Misalnya, salah satu tim produk berjanji kepada tim pemasaran untuk merilis fitur baru pada tanggal tertentu; tim pemasaran telah merencanakan kampanye iklan untuk periode ini; Tim penjualan sedang menunggu fitur dan kampanye untuk mulai berkomunikasi dengan pelanggan baru. Ternyata semua orang saling bergantung, dan menunda tenggat waktu oleh satu tim mengganggu rencana yang lain.
Untuk menghindari situasi seperti itu, kami, bersama dengan tim lain, menyusun peta jalan bahan makanan, yang disinkronkan beberapa kali dalam seperempat, dan dengan beberapa tim setiap minggu.
Kesimpulan
Apa yang kami pelajari selama proyek ini:
- Jangan takut untuk mengerjakan proyek yang rumit. Setelah dekomposisi, evaluasi dan pengembangan pendekatan untuk bekerja, proyek-proyek kompleks tidak lagi tampak mustahil.
- Jangan luangkan waktu dan upaya untuk perkiraan awal, penguraian, dan perencanaan. Ini membantu untuk memahami masalah lebih dalam sebelum Anda mulai mengatasinya, dan untuk memahami volume dan kompleksitas pekerjaan.
- Letakkan risiko dalam proyek teknis dan organisasi yang sulit. Dalam proses kerja, Anda pasti akan menemui masalah yang tidak diperhitungkan saat perencanaan.
- Jangan bermigrasi kecuali jika diperlukan.
Dalam artikel berikut ini saya akan berbicara lebih banyak tentang masalah teknis yang kami selesaikan selama migrasi.