Cara Discord Menyimpan Triliunan Pesan (2023)
(discord.com)- Saat volume penyimpanan pesan Discord tumbuh dari miliaran menjadi triliunan, pada awal 2022 beban operasional cluster Cassandra dengan 177 node dan latensi yang sulit diprediksi menjadi makin sulit ditangani
- Desain Cassandra yang berpusat pada
channel_iddan bucket waktu menciptakan hot partition saat trafik baca terpusat pada server besar, dan karena baca/tulis quorum, latensi menyebar menjadi dampak yang lebih luas bagi pengguna - Discord menempatkan data service berbasis Rust di antara API dan database, menggabungkan permintaan bersamaan untuk baris yang sama, serta mengurangi beban database dengan routing consistent hashing berbasis ID channel
- Peralihan ke ScyllaDB dilakukan dengan konfigurasi cluster baru dan migrator Rust, memangkas pekerjaan yang dengan Spark diperkirakan 3 bulan menjadi sekitar 9 hari, serta memigrasikan hingga 3,2 juta pesan per detik
- Setelah peralihan pada Mei 2022, jumlah node turun dari 177 Cassandra menjadi 72 ScyllaDB; p99 pencarian pesan lama membaik dari 40–125 ms menjadi 15 ms, dan p99 penyisipan pesan dari 5–70 ms menjadi 5 ms
Beban operasional yang membesar di Cassandra
- Pada 2017, Discord memublikasikan cara menyimpan miliaran pesan dan membagikan proses migrasi dari MongoDB ke Cassandra
- Saat itu tujuannya adalah database yang dapat diskalakan, tahan gangguan, dan relatif minim pemeliharaan, tetapi seiring bertambahnya volume penyimpanan, cluster Cassandra itu sendiri menjadi beban operasional besar
- Cluster
cassandra-messagesuntuk penyimpanan pesan tumbuh dari 12 node pada 2017 menjadi 177 node pada awal 2022, dan menyimpan triliunan pesan - Tim operasi sering dipanggil karena masalah database, latensi sulit diprediksi, dan pekerjaan pemeliharaan yang biayanya sudah terlalu besar perlu dikurangi
Skema pesan dan hot partition
- Skema pesan yang disederhanakan mencakup
channel_id,bucket,message_id,author_id,content, dengan primary key((channel_id, bucket), message_id) - ID Discord berbasis Snowflake, sehingga dapat diurutkan berdasarkan waktu, dan pesan dipartisi berdasarkan channel serta jendela waktu statis bernama bucket
- Di Cassandra, semua pesan untuk channel dan bucket tertentu disimpan bersama, lalu direplikasi ke beberapa node sesuai replication factor
- Server grup pertemanan kecil dan server berskala ratusan ribu anggota memiliki selisih jumlah pesan hingga beberapa orde magnitudo, dan perbedaan ini berujung pada perbedaan beban di tingkat partisi
- Penulisan di-append ke commit log dan struktur memori memtable lalu di-flush ke disk, tetapi pembacaan bisa menelusuri memtable dan beberapa SSTable sehingga biayanya lebih besar
- Ketika pembacaan bersamaan menumpuk di server besar, partisi tertentu menjadi hot partition, latensi pada node tersebut meningkat, dan query lain ikut terdampak
- Karena quorum consistency level digunakan untuk baca dan tulis, kenaikan latensi pada node yang menangani hot partition menyebar menjadi dampak yang lebih luas bagi pengguna
Bottleneck pemeliharaan Cassandra
- Compaction Cassandra juga menjadi penyebab berulang respons insiden
- SSTable harus di-compact di disk agar performa baca membaik, tetapi jika compaction tertinggal, biaya baca meningkat
- Selama sebuah node menjalankan compaction, latensi dapat meningkat secara berantai
- Discord sering menjalankan pekerjaan yang mereka sebut “gossip dance”
- Mengeluarkan node dari trafik untuk menjalankan compaction
- Memasukkannya kembali agar mengejar hint dari Cassandra hinted handoff
- Mengulangi proses ini hingga backlog compaction habis
- Banyak waktu juga dihabiskan untuk tuning garbage collector JVM dan pengaturan heap, sementara GC pause menciptakan lonjakan latensi besar
Mengapa pindah ke ScyllaDB
- Selain pesan, Discord juga mengoperasikan beberapa cluster Cassandra lain, dan masalah serupa muncul di tiap cluster
- ScyllaDB, yang sempat mereka tunjukkan minatnya pada tulisan sebelumnya, adalah database kompatibel Cassandra yang ditulis dalam C++; ScyllaDB menawarkan performa lebih baik, repair lebih cepat, isolasi workload berbasis arsitektur shard-per-core, serta struktur tanpa garbage collection
- ScyllaDB bukan tanpa masalah, tetapi fakta bahwa ia ditulis dalam C++ alih-alih Java sehingga tidak memiliki garbage collector menjadi kontras langsung dengan masalah operasional Cassandra
- Setelah eksperimen dan pengujian menunjukkan peningkatan, Discord memutuskan memigrasikan semua database ke ScyllaDB, dan pada 2020 semua database selain
cassandra-messagessudah dipindahkan - Cluster pesan tetap menjadi yang terakhir karena merupakan cluster besar dengan triliunan pesan dan hampir 200 node
- Performa reverse query ScyllaDB pada pengujian awal belum memenuhi kebutuhan
- Reverse query adalah pemindaian berlawanan arah dengan urutan tabel; contohnya adalah memindai pesan secara menaik
- Ketika tim ScyllaDB memprioritaskan dan mengimplementasikan peningkatan performa, faktor yang menghambat migrasi database terakhir pun tersingkir
Data service berbasis Rust
- Discord menilai bahwa mengganti database saja tidak otomatis menyelesaikan semua masalah, sehingga lapisan di atas database juga ikut diubah
- Mereka menempatkan data service di antara monolith API dan cluster database untuk mengendalikan permintaan bersamaan yang menuju database
- Data service ditulis dalam Rust
- Discord sebelumnya juga sudah menggunakan Rust untuk beberapa proyek
- Rust menawarkan kecepatan setara C/C++ tanpa mengorbankan keselamatan
- Ekosistem Tokio digunakan sebagai fondasi membangun sistem I/O asinkron, dan dukungan driver Cassandra serta ScyllaDB juga tersedia
- Data service memiliki kira-kira satu endpoint gRPC untuk setiap query database, dan sengaja tidak memuat logika bisnis
- Intinya adalah penggabungan permintaan
- Jika beberapa pengguna secara bersamaan meminta row yang sama, database hanya di-query sekali
- Permintaan pertama membuat worker task di dalam service, lalu permintaan berikutnya melihat keberadaan task tersebut dan berlangganan padanya
- Worker task meng-query database dan mengembalikan row hasilnya kepada semua subscriber
Meningkatkan efek penggabungan dengan routing
- Di depan data service, Discord menerapkan routing berbasis consistent hashing
- Setiap permintaan data service diberi routing key, dan untuk pesan routing key-nya adalah ID channel
- Karena semua permintaan untuk channel yang sama menuju instance service yang sama, penggabungan permintaan bekerja lebih baik
- Misalnya, jika notifikasi
@everyoneterjadi di server besar, banyak pengguna dapat membuka aplikasi dan membaca pesan yang sama, sehingga trafik database melonjak - Pada arsitektur sebelumnya, situasi seperti ini dapat berujung pada hot partition dan mungkin perlu memanggil tim operasi, tetapi data service sangat mengurangi lonjakan trafik yang menuju database
- Peningkatan ini tidak sepenuhnya menghilangkan hot partition dan latensi pada cluster Cassandra, tetapi memberi waktu untuk menyiapkan cluster ScyllaDB baru dan menjalankan migrasi
Migrasi triliunan pesan
- Persyaratan migrasinya jelas
- Triliunan pesan harus dipindahkan
- Tidak boleh ada downtime
- Cassandra masih sering memicu respons insiden, jadi migrasi harus cepat selesai
- Discord terlebih dahulu menyiapkan cluster ScyllaDB baru yang menggunakan super-disk storage topology
- Kecepatan diperoleh dari Local SSD
- Data di-mirror ke persistent disk dengan RAID
- Konfigurasi ini menggabungkan kecepatan disk lokal dan durabilitas persistent disk
- Rencana awalnya adalah menggunakan ScyllaDB untuk data baru mulai cutover time, sementara data lama dimigrasikan di belakang layar
- Untuk data baru, Discord mulai melakukan dual write ke Cassandra dan ScyllaDB, sambil menyiapkan migrator Spark milik ScyllaDB
- Migrator Spark memerlukan banyak tuning, dan setelah dikonfigurasi estimasi waktu selesai adalah 3 bulan
- Setelah itu, Discord memperluas library database cepat yang sudah ada dan menulis ulang migrator data dalam Rust
- Membaca token range dari database
- Mencatat checkpoint lokal dengan SQLite
- Mengirim data secara massal ke ScyllaDB
- Estimasi waktu selesai migrator Rust baru turun menjadi 9 hari, dan berkat kecepatan ini mereka dapat melakukan keseluruhan peralihan sekaligus alih-alih memakai pendekatan berbasis waktu yang kompleks
Peralihan dan verifikasi
- Migrasi berjalan hingga kecepatan maksimum 3,2 juta pesan per detik
- Progresnya berhenti di 99,9999% karena beberapa token range terakhir berisi rentang tombstone sangat besar yang belum di-compact di Cassandra
- Setelah token range tersebut di-compact, migrasi selesai beberapa detik kemudian
- Discord menjalankan verifikasi data otomatis dengan mengirim sebagian kecil permintaan baca ke kedua database dan membandingkan hasilnya, dan hasilnya tidak bermasalah
- Cluster ScyllaDB bertahan baik bahkan di bawah seluruh trafik produksi, sementara Cassandra semakin sering mengalami masalah latensi
- Tim kemudian mengalihkan ScyllaDB menjadi primary database secara langsung di lapangan
Performa dan skala setelah peralihan
- Peralihan database pesan terjadi pada Mei 2022
- Setelah itu, operasional menjadi tenang dan stabil; tidak ada lagi situasi harus menangani insiden sepanjang akhir pekan atau terus menyesuaikan node cluster demi menjaga uptime
- Jumlah node turun dari 177 node Cassandra menjadi 72 node ScyllaDB
- Ruang disk per node ScyllaDB adalah 9 TB, lebih besar daripada rata-rata 4 TB per node Cassandra
- Tail latency juga membaik secara signifikan
- p99 pencarian pesan lama: Cassandra 40–125 ms → ScyllaDB 15 ms
- p99 penyisipan pesan: Cassandra 5–70 ms → ScyllaDB 5 ms
- Berkat peningkatan performa, Discord dapat membuka use case produk baru berdasarkan kepercayaan terhadap database pesannya
Pemrosesan beban yang terbukti pada trafik World Cup
- Pada akhir 2022 selama World Cup, saat pengguna di seluruh dunia menonton pertandingan, adegan gol juga terlihat pada grafik pengiriman pesan Discord
- Grafik pengiriman pesan Final World Cup menunjukkan beberapa spike yang sesuai dengan peristiwa pertandingan
- Tendangan penalti Messi dan keunggulan 1-0 Argentina
- Gol tambahan Argentina
- Plateau 15 menit yang berlanjut selama halftime
- Spike saat Mbappe mencetak gol untuk France lalu mencetak gol lagi 90 detik kemudian untuk menyamakan kedudukan
- Akhir waktu normal dan masuk ke extra time
- Chat saat halftime babak pertama extra time
- Gol tambahan Messi
- Gol penyama kedudukan Mbappe
- Akhir extra time dan masuk ke adu penalti
- Kegagalan France dan kemenangan Argentina
- Bahkan saat volume pengiriman pesan meningkat tajam, data service berbasis Rust dan ScyllaDB menangani trafik tersebut
- Sistem akhir dirapikan menjadi arsitektur yang mampu menangani triliunan pesan
1 komentar
Opini Hacker News
Tulisan ini tampaknya banyak menyalahkan garbage collection, tetapi jika melihat tulisan sebelumnya [0], masalahnya lebih terlihat sebagai keterbatasan cara penggunaan Cassandra, cara Cassandra menangani penghapusan massal, atau keduanya
Seorang pengguna menghapus jutaan pesan lewat API hingga hanya menyisakan 1 pesan di channel, dan karena Cassandra menangani penghapusan sebagai tombstone, saat pengguna membuka channel itu, Cassandra harus memindai jutaan tombstone meski pesan sebenarnya hanya 1. Penjelasannya adalah dalam proses itu garbage tercipta lebih cepat daripada kemampuan JVM untuk mengumpulkannya
Selain itu ada pembahasan tentang tuning GC, tetapi dari [1] tampaknya tuning-nya juga tidak terlalu banyak, dan sepertinya mereka memakai Cassandra, dan mungkin JVM juga, versi lama. Fakta bahwa mereka baru saja pindah dari CMS juga cukup berpengaruh
0) https://discord.com/blog/how-discord-stores-billions-of-messages
Meski awalnya mereka menggunakan solusi dengan cara yang keliru, menurut saya solusi yang sulit disalahgunakan memang lebih baik
Jika pada 2022 mereka memakai Java 11, berarti runtime-nya sudah berusia 4 tahun; jika Java 8, berarti runtime-nya sudah berusia 8 tahun, jadi besar kemungkinan mereka kehilangan cukup banyak performa
Needs (2023)
Lapisan layanan ini tampak seperti Varnish Cache terdistribusi yang besar dan mewah. Melihat mereka memilih kata “coalesce” tanpa menyebut caching, sepertinya mereka tidak melakukan caching dalam jumlah besar, tetapi ini mengingatkan saya pada “grace mode” Varnish dan penggunaannya untuk mencegah stampede, yaitu konteks saat saya pertama kali mendengar istilah ‘request coalescing’ https://varnish-cache.org/docs/6.1/users-guide/vcl-grace.htm...
Senang juga melihat consistent hashing terus muncul. Ini teknologi seperti lakban yang hebat dan sudah terbukti berguna dalam situasi serupa. Jika kita tahu sesuatu seharusnya berada di mana, kita juga tahu semua orang akan datang mencarinya ke mana
proxy_cache_use_stale updating;Ada beberapa tambahan dari salah satu pendiri ScyllaDB: Discord tidak bisa menyelesaikan repair dengan Cassandra, tetapi tidak demikian di Scylla; meski Scylla punya banyak kesamaan dengan Cassandra seperti LSM tree dan compaction, Scylla memiliki scheduler CPU/IO sendiri yang dapat memberi prioritas lebih tinggi pada query dibanding compaction
Menurutnya, compaction bisa ditunda ke slot setengah milidetik saat bandwidth menganggur cukup tersedia, dan ada banyak tulisan terkait. Scylla memiliki mode yang lebih aman bernama
tombstone_gc=repairyang sudah berusia 1,5 tahun, dan arsitektur baru berbasis Raft serta tablets yang baru dirilis disebut sebagai perubahan besar berikutnya bagi para penggunaMasalah seperti ini sebenarnya tidak akan ada sejak awal jika memakai IRC, protokol chat terdistribusi yang sudah ada selama lebih dari 40 tahun
Keunggulannya juga ada spesifikasi terbuka dan banyak implementasi. Bukan taman bertembok juga. Kalau merasa IRC terlalu usang untuk masa kini, lihat saja Matrix atau XMPP. Sulit memahami bagaimana Discord bisa mendominasi, dan lebih tepatnya itu hampir seperti tragedi
IRC pada dasarnya membutuhkan bouncer agar bisa mengikuti percakapan di beberapa perangkat. Pesan juga tidak dienkripsi; secara opsional hanya koneksi klien dan server yang dienkripsi. Tanpa enkripsi ujung-ke-ujung, tidak ada privasi terhadap server atau operatornya, dan server itu menjadi titik kegagalan tunggal yang mudah dijadikan target
Protokol Matrix masih terus berubah, dan implementasinya belum mampu mengikuti spesifikasi. Jika tidak memakai Element, Anda tertinggal dalam hal fitur dan keamanan. XMPP juga, seperti IRC, mengandalkan ekstensi opsional untuk fitur dasar seperti enkripsi ujung-ke-ujung, dan klien belum tentu mendukungnya secara lengkap dan benar
Saya menyarankan membaca analisis soatok: https://soatok.blog/2024/08/04/against-xmppomemo/ https://soatok.blog/2024/08/14/security-issues-in-matrixs-ol...
Peristiwa Snowden pada 2013 terjadi 11 tahun lalu. Sekarang enkripsi ujung-ke-ujung harus diperlakukan sebagai fitur dasar dan sebagai komoditas, dan harus dituntut sekeras dulu kita menuntut HTTPS. Tentu saja Discord tidak mengimplementasikan enkripsi ujung-ke-ujung
Baru-baru ini sebuah grup yang sangat teknis tempat saya tergabung pindah dari Telegram ke Matrix, dan pengalaman penggunanya tidak bagus. Aplikasinya penuh bug dan tampilannya juga kurang menarik, dan di aplikasi “Element” yang baru SSO tidak didukung sehingga saya tidak bisa memakai akun. Ini ketidaknyamanan kecil yang masih oke bagi orang seperti saya yang mau mengulik sendiri, tetapi saya tidak bisa membujuk teman-teman untuk memakainya
Unduh exe, pasang, buat akun, lalu langsung berjalan. Siapa pun bisa melakukannya. Ada banyak perangkat lunak yang berguna dan hebat, tetapi sebagian besar tidak mudah bagi khalayak umum, dan sebagian atau kebanyakan bahkan tidak punya GUI. Orang lebih memilih menjual identitas mereka, bahkan membayar uang, daripada menanggung terlalu banyak langkah
Kesimpulan yang saya ambil dari tulisan ini mungkin agak berbeda dari maksud penulis
“Yang terakhir? Teman kita cassandra-messages. [...] Sejak awal ini adalah klaster besar. Dengan triliunan pesan dan hampir 200 node, migrasi apa pun pasti menjadi pekerjaan yang kompleks.”
Mengingat skala Discord, kurang dari 200 node untuk penyimpanan pesan tampak mengejutkan kecil. Saya mengira akan ada arsitektur kompleks yang menargetkan skalabilitas jauh lebih cepat dan memiliki lebih banyak komponen bergerak. Kompleksitas sebenarnya mungkin lebih tinggi daripada yang ditampilkan di tulisan, tetapi mengingat pengalaman saya pernah ikut bertanggung jawab atas lebih dari 200 node fisik yang melakukan pekerjaan jauh lebih sedikit, saya jadi bertanya-tanya seberapa berlebihan arsitektur cloud modern dirancang
Dari pengalaman menyimpan miliaran record dengan kumpulan node Cassandra yang jauh lebih kecil, Cassandra benar-benar menyakitkan untuk on-call dan pernah menjadi penyebab beberapa insiden besar
[0] https://news.ycombinator.com/item?id=34950843
Tulisannya sangat bagus. Syukurlah sebagian solusinya bukan memperkenalkan sesuatu yang sama sekali berbeda, melainkan beralih ke ScyllaDB, yang bisa dipakai seperti pengganti Cassandra
Discord pada dasarnya membuat penghapusan pesan lama menjadi mustahil. Ini adalah mimpi buruk privasi, dan saya bertanya-tanya kenapa UE belum turun tangan
Pertanyaan intinya bisa diringkas menjadi apakah Matrix harus dipandang lebih mirip email, atau lebih mirip Facebook. Kalau email, orang akan terkejut bila pengirim bisa menghapus pesannya dari spool email saya; kalau Facebook, orang akan terkejut bila postingan masih terlihat di suatu tempat setelah hak penghapusan digunakan
Penjelasannya, untuk menyelesaikan ini diperlukan penilaian, dan pendekatan yang diambil adalah terlebih dahulu mempertimbangkan apa sebenarnya yang ingin dicapai oleh semangat GDPR
https://matrix.org/blog/2018/05/08/gdpr-compliance-in-matrix...
Masalah dari sudut pandang GDPR adalah Discord membuat hal ini sulit dihapus. Ketika mendeteksi niat untuk menghapus data akun, mereka mengarahkan pengguna ke “anonimisasi”; secara publik nama pengguna dipisahkan dari pesan, tetapi masih bisa dilacak ke orang tertentu. Jika di sisi server juga diproses seperti ini, maka untuk menegakkan permintaan penghapusan informasi pengenal pribadi pengguna, mereka harus menyisir pesan dalam jumlah sangat besar atau menghapus pesan lama secara massal
Parlemen UE bukanlah parlemen sungguhan dalam arti bahwa rancangan undang-undang baru hanya bisa diajukan oleh Komisi dan parlemen terpilih pada dasarnya hanya melakukan pemungutan suara; menurut saya yang mengendalikan Komisi bukan publik, melainkan Departemen Luar Negeri AS. Big Tech AS selain Newsguard dan Musk, termasuk Discord, juga berada dalam jaringan kemapanan politik dan finansial yang sama, dan ada banyak mantan personel Departemen Luar Negeri di sana
Tanpa kemarahan publik, lembaga tingkat UE sangat mungkin dikuasai, dan menurut saya opini publik juga dikendalikan oleh kemapanan bergaya cyberpunk yang melatih LLM dengan data Discord ilegal dan menargetkan iklan pemilu. Pada akhirnya kita perlu khawatir tentang kemungkinan munculnya kondisi ala Orwell di mana kita tidak bisa lepas dari kemapanan permanen
Namun, sebagian besar dari ini saya anggap hanya punya peluang sekitar lebih dari 50% untuk benar dalam arti luas, jadi sebaiknya disaring banyak-banyak
Cassandra pada dasarnya lebih mirip tabel hash terdistribusi yang toleran terhadap kegagalan dan sebagian besar hanya menambahkan data. Jika Anda memang membutuhkan hal seperti itu dengan throughput tulis tinggi, ini pilihan yang bagus
Saya tidak paham kenapa orang memakainya seperti database. Anda akan segera menabrak batasannya, dan rasa sakit ketika mencoba memakainya seperti database akan makin parah seiring skala membesar
Kalau begitu, menurut saya ini tidak masuk akal sebagai penyimpanan pesan untuk server chat. Ini tampak cocok sebagai tujuan pengumpulan log dalam sistem terdistribusi, yaitu ketika banyak klien menuangkan data tetapi kebanyakan log bahkan tidak perlu diaudit sehingga jumlah pembacaan untuk item tertentu kurang dari 1. Pesan Discord jelas bukan seperti itu
Dari pengalaman saya, saya belum pernah melihat proyek yang mulai memakai Cassandra masih terus memakainya setelah kira-kira setahun. Butuh sekitar setahun untuk menabrak batasannya, lalu pada akhirnya diganti dengan database seperti Postgres
Saya tidak mengerti kenapa tidak sekadar melakukan sharding. Bukankah setiap ‘server’ Discord terisolasi satu sama lain? Kalau mereka tidak bisa saling mengirim pesan, saya penasaran kenapa triliunan pesan itu tidak dibagi ke ribuan shard sehingga tiap shard menangani beberapa miliar pesan saja
Tertulis bahwa “tim ScyllaDB memprioritaskan pekerjaan peningkatan dan mengimplementasikan kueri balik yang berkinerja baik, sehingga menghapus hambatan database terakhir dalam rencana migrasi”
Saya penasaran berapa banyak mereka membayar agar fitur itu dibuat bahkan sebelum mereka memakai ScyllaDB