Menskalakan ke 5M RPM

Di Trendyol, kami memiliki tanggung jawab untuk menyajikan halaman konten dan data. Kami juga menyajikan data konten secara massal untuk favorit, koleksi, atau bahkan halaman checkout. Sebentar lagi, kami akan terlibat setiap kali Anda melihat layar di bawah ini.


Apa kebutuhan kita atau beban yang diharapkan?
Seperti yang diharapkan, kami biasanya mendapatkan lebih banyak lalu lintas di musim belanja atau waktu acara/diskon. Meskipun kami mendapatkan sekitar 1 juta rpm (permintaan per menit) pada hari-hari biasa, beban naik menjadi sekitar 3 juta rpm di waktu sibuk. Pada masa itu, kami tidak dapat memenuhi persyaratan dengan tepat. Waktu respons kami menjadi dua kali lipat dari biasanya, dan kami bahkan memiliki lebih banyak waktu tunggu daripada yang dapat kami abaikan.
Sasaran dan harapan kami berikutnya adalah mencapai setidaknya 8M rpm dengan, paling banyak, sumber daya yang sama. Jadi masalahnya adalah kami tidak dapat menskalakan sebanyak yang kami butuhkan, apalagi yang kami harapkan selanjutnya.
Siapa yang senang dengan tantangan? Ya tentu kita :)

Bagaimana kami menemukan penyebab masalah?
Jadi kami melakukan pembuatan profil untuk memahami bagian kode mana yang membutuhkan lebih banyak waktu dan menggunakan lebih banyak sumber daya. Pertama, kami menggunakan profiler Java untuk mempersempit bagian mana yang akan dilacak. Setelah itu, kami menambahkan beberapa jejak Relik Baru khusus dalam kode. Ketika kami melihat hasilnya, kami melihat bahwa bagian kode tertentu adalah yang paling memakan waktu dan sumber daya.
Bagian itu adalah logika konversi untuk mengonversi dokumen Couchbase menjadi data yang kami perlukan untuk menjalankan logika bisnis dan berfungsi sebagai massal. Itu berjalan untuk setiap permintaan dan setiap konten. Kami mulai memikirkan apakah kami dapat melakukan logika konversi ini secara asinkron. Kami dapat menjalankan logika ini sekali untuk setiap konten. Untuk sebagian besar bagian, jawabannya adalah: YA!
Melakukan yang terbaik saja tidak cukup ; Anda harus tahu apa yang harus dilakukan, dan kemudian melakukan yang terbaik. —W Edwards Deming

Bisakah kita menangani data secara asinkron?
Kami menggunakan Couchbase sebagai sumber data. Ketika kami melihat bagaimana kami dapat mengonversi data Couchbase kami secara asinkron, kami melihat bahwa Couchbase memiliki protokol perubahan basis data (DCP). DCP dapat memberi kita aliran untuk mutasi. Jadi kita dapat mendengarkan dari sumber data lama kita, melakukan konversi asinkron, dan menulis ke sumber data baru kita. Anda dapat memeriksa artikel Ahmet Hatipoglu jika Anda bertanya-tanya tentang detailnya.
Sekarang saatnya menentukan apakah kita dapat mengoptimalkan data.
Apakah kita membutuhkan semua data?
Kami menggunakan model data yang sama untuk halaman konten dan permintaan massal. Untuk permintaan massal, beberapa klien memerlukan data yang berbeda. Jadi kami membutuhkan analisis untuk memahami siapa yang membutuhkan bagian data yang mana. Kami melakukan analisis komprehensif dengan semua klien kami bersama-sama.
Setelah analisis, kami menyadari bahwa kami hanya membutuhkan beberapa data, dan hampir semua klien kami membutuhkan bagian yang hampir sama. Tetapi kami tidak dapat menyentuh skema karena beberapa klien kami menggunakan sumber data yang sama secara langsung. Kami bergandengan erat. Kesimpulannya, memisahkan sumber data mungkin merupakan langkah menuju solusi.
Apa yang kita miliki sekarang sejauh ini?
Layanan yang mendengarkan perubahan dari sumber data konten melakukan konversi berat dan menulis ke sumber data baru. Dan kami tahu dari analisis bahwa kami hanya membutuhkan sebagian data. Jadi kami dapat menghilangkan semua bagian yang tidak perlu saat kami melakukan konversi.
Apakah kamu siap? Kami menghemat 77% data (1,28TB). Apa yang lega!

Apa sekarang?
Kami membutuhkan sesuatu yang menggunakan data yang kami siapkan. Kami ingin memisahkan kebutuhan konten massal, dan kebutuhan halaman detail produk hanya karena klien, kebutuhan skala, dan kumpulan aturan bisnis mereka berbeda. Jadi, sekarang saatnya untuk menulis layanan baru.
Apa yang bisa dilakukan secara berbeda?
Mungkin teknologi yang kita gunakan. Layanan lama menggunakan Java 8 dan Spring boot. Kami memiliki pengalaman yang stabil dengan Quarkus . Mungkin kita bisa menurunkan penggunaan sumber daya dan waktu booting agar lebih terukur. Atau kami menggunakan Flux untuk memperoleh dokumen dari Couchbase, dan mungkin kami dapat menggunakan CompletableFuture untuk perubahan. Setelah membuat daftar opsi kami, kami mengembangkan banyak aplikasi POC dan menjalankan banyak uji beban. Tapi hasilnya bisa lebih baik. Setidaknya bukan untuk usaha yang akan kita butuhkan. Penelitian harus dilanjutkan.
Ngomong-ngomong, saya sudah menjadi gopher selama empat tahun. Saya percaya bahwa kita bisa mendapatkan dokumen secara efektif dengan goroutine secara paralel. Jadi saya ingin mencobanya. Kemudian, saya melihat Couchbase Go SDK resmi, yang memiliki fitur “pengambilan dokumen massal”. Tadi sangat menyenangkan! Kebutuhannya cocok untuk menggunakan Go. Dan saya ingin mencoba kedua opsi tersebut.
Saya menjalankan uji beban pada kedua goroutine paralel dan fitur massal. Waktu respons dan penggunaan sumber daya ditingkatkan secara signifikan untuk keduanya. Fitur massal lebih baik daripada penerapan sederhana kami. Tapi ada sesuatu yang salah. Penggunaan jaringan empat kali lebih banyak. Kami dapat memberikan konfigurasi ke koneksi Couchbase di Java SDK yang mengaktifkan kompresi. Tetapi Go SDK tidak memiliki konfigurasi kompresi dalam opsi konfigurasi klusternya. Jadi saya melewatkan konfigurasi yang sesuai. Sayangnya fitur kompresi tidak dapat dikontrol melalui Couchbase Go SDK, tidak seperti Couchbase Java SDK. Jadi saya memeriksa kodenya, melakukan debugging yang menyakitkan, dan menemukan bahwa kompresi dapat dikontrol melalui variabel kueri di akhir string koneksi.
couchbase://{HOST_HERE}?compression=true
- Kami mendapatkan peningkatan penggunaan ram yang sangat besar, dan penggunaan memori menurun dari 800MB menjadi 60MB per pod.
- Waktu respons menjadi setengahnya. 10 md sampai 5 md . Dan lebih stabil terhadap throughput tinggi.
- Penggunaan CPU menurun drastis. Untuk mencapai 5M dengan layanan lama, kami membutuhkan lebih banyak pod. Jadi ini akan menjadi perbandingan dari total penggunaan CPU. Sekarang 130 core bukannya 300 .
- Ukuran total dokumen sekarang kurang dari seperempat dari sebelumnya, dari 1,67TB menjadi hanya 386GB .
- Secara alami, beban jaringan jauh lebih rendah.
- Waktu boot sekarang 85 milidetik , bukan 12 detik !

Terima kasih kepada Emre Odabas atas dukungan dan dorongannya dalam menulis artikel ini.