Kami punya situasi di mana saya harus berurusan dengan gelombang besar peristiwa yang datang ke server kami, sekitar 1000 peristiwa per detik, rata-rata (puncaknya bisa ~ 2000).
Masalah
Sistem kami dihosting di Heroku dan menggunakan Heroku Postgres DB yang relatif mahal , yang memungkinkan maksimum 500 DB koneksi. Kami menggunakan pooling koneksi untuk terhubung dari server ke DB.
Acara datang lebih cepat daripada kelompok koneksi DB yang bisa menangani
Masalah yang kami miliki adalah bahwa acara datang lebih cepat daripada yang bisa ditangani oleh kumpulan koneksi. Pada saat satu koneksi telah menyelesaikan jaringan bolak-balik dari server ke DB, sehingga dapat dilepaskan kembali ke kolam, lebih dari n
peristiwa tambahan yang masuk.
Akhirnya acara menumpuk, menunggu untuk diselamatkan dan karena tidak ada koneksi yang tersedia di kolam, mereka kehabisan waktu dan seluruh sistem dibuat non-operasional.
Kami telah memecahkan keadaan darurat dengan memancarkan peristiwa frekuensi tinggi yang menyinggung dengan kecepatan lebih lambat dari klien, tetapi kami masih ingin tahu bagaimana menangani skenario ini jika kami perlu menangani peristiwa frekuensi tinggi itu.
Kendala
Klien lain mungkin ingin membaca acara secara bersamaan
Klien lain terus menerus meminta untuk membaca semua acara dengan kunci tertentu, bahkan jika mereka belum disimpan dalam DB.
Klien dapat meminta GET api/v1/events?clientId=1
dan mendapatkan semua acara yang dikirim oleh klien 1, bahkan jika acara tersebut belum selesai menyimpan dalam DB dulu.
Apakah ada contoh "ruang kelas" tentang cara menangani ini?
Solusi yang memungkinkan
Enqueue acara di server kami
Kami dapat melakukan enqueue acara di server (dengan antrian memiliki konkurensi maksimum 400 sehingga kumpulan koneksi tidak habis).
Ini ide yang buruk karena:
- Ini akan memakan memori server yang tersedia. Acara enqueued yang ditumpuk akan mengkonsumsi RAM dalam jumlah besar.
- Server kami restart sekali setiap 24 jam . Ini adalah batasan keras yang dikenakan oleh Heroku. Server dapat memulai kembali sementara acara enqueued menyebabkan kita kehilangan acara enqueued.
- Ini memperkenalkan status di server, sehingga merusak skalabilitas. Jika kami memiliki pengaturan multi-server dan klien ingin membaca semua peristiwa yang diselamatkan + enqueued, kami tidak akan tahu di server mana acara enqueued hidup.
Gunakan antrian pesan terpisah
Saya berasumsi kita bisa menggunakan antrian pesan, (seperti RabbitMQ ?), Di mana kita memompa pesan di dalamnya dan di ujung lain ada server lain yang hanya berurusan dengan menyimpan acara di DB.
Saya tidak yakin apakah antrian pesan memungkinkan kueri acara enqueued (yang belum disimpan) jadi jika klien lain ingin membaca pesan klien lain, saya bisa mendapatkan pesan yang disimpan dari DB dan pesan yang tertunda dari antrian dan menyatukannya sehingga saya dapat mengirimnya kembali ke klien baca-permintaan.
Gunakan beberapa basis data, masing-masing menyimpan sebagian pesan dengan server pusat koordinator DB untuk mengelolanya
Solusi lain yang kami miliki adalah menggunakan banyak basis data, dengan pusat "koordinator DB / penyeimbang beban". Setelah menerima suatu acara, koordinator ini akan memilih salah satu database untuk menulis pesan. Ini seharusnya memungkinkan kita untuk menggunakan banyak basis data Heroku sehingga menaikkan batas koneksi ke 500 x jumlah basis data.
Setelah kueri baca, koordinator ini dapat mengeluarkan SELECT
kueri ke setiap basis data, menggabungkan semua hasil dan mengirimkannya kembali ke klien yang meminta baca.
Ini ide yang buruk karena:
- Gagasan ini terdengar seperti ... ahem .. over-engineering? Akan menjadi mimpi buruk untuk dikelola juga (cadangan dll.). Ini rumit untuk dibangun dan dipelihara dan kecuali jika benar-benar diperlukan itu terdengar seperti pelanggaran KISS .
- Itu mengorbankan Konsistensi . Melakukan transaksi lintas banyak DB tidak perlu dilakukan jika kita menggunakan ide ini.
ANALYZE
query sendiri dan mereka tidak masalah. Saya juga telah membangun prototipe untuk menguji hipotesis kumpulan koneksi dan memverifikasi bahwa ini memang masalahnya. Basis data dan server itu sendiri hidup pada mesin yang berbeda maka latensi. Juga, kami tidak ingin melepaskan Heroku kecuali benar-benar diperlukan, tidak khawatir tentang penyebaran adalah nilai tambah yang besar bagi kami.
select null
pada 500 koneksi. Saya yakin Anda akan menemukan bahwa kolam koneksi bukan masalah di sana.