Sunucumuza gelen olayların ortalama saniyede yaklaşık 1000 olayla (en fazla ~ 2000) olabileceği büyük bir olay akışıyla uğraşmak zorunda olduğum bir durum var.
Sorun
Sistemimiz Heroku'da barındırılıyor ve maksimum 500 DB bağlantısına izin veren nispeten pahalı bir Heroku Postgres DB kullanıyor . Sunucudan DB'ye bağlanmak için bağlantı havuzu kullanıyoruz.
Olaylar, DB bağlantı havuzunun işleyebileceğinden daha hızlı gelir
Sorun, olayların bağlantı havuzunun üstesinden gelebileceğinden daha hızlı gelmesidir. Bir bağlantı, sunucudan DB'ye gidiş dönüş ağını tamamladığında, havuza geri gönderilebilir, n
ek olaylar daha fazla gelir.
Sonunda olaylar birikir, kaydedilmeyi bekler ve havuzda kullanılabilir bağlantı olmadığından zaman aşımına uğrar ve tüm sistem çalışmaz hale getirilir.
Acil durumları rahatsız edici yüksek frekanslı olayları müşterilerden daha yavaş bir hızda yayarak çözdük, ancak yine de bu yüksek frekanslı olaylarla başa çıkmamız gerektiğinde bu senaryoların nasıl ele alınacağını bilmek istiyoruz.
Kısıtlamalar
Diğer müşteriler olayları aynı anda okumak isteyebilir
Diğer istemciler, henüz DB'ye kaydedilmemiş olsalar bile, belirli bir anahtarla tüm olayları sürekli olarak okumak ister.
GET api/v1/events?clientId=1
İstemci 1 tarafından gönderilen tüm olayları sorgulayabilir ve alabilir, ancak bu olaylar henüz DB'de kaydedilmemiş olsa bile.
Bununla nasıl başa çıkılacağına dair "sınıf" örnekleri var mı?
Muhtemel çözümler
Sunucumuzdaki olayları sıkın
Sunucudaki olayları sıraya koyabiliriz (kuyrukta maksimum eşzamanlılık 400'dür, bu nedenle bağlantı havuzu tükenmez).
Bu kötü bir fikir çünkü:
- Kullanılabilir sunucu belleğini tüketir. Yığılmış olarak sıralanan olaylar büyük miktarlarda RAM tüketir.
- Sunucularımız 24 saatte bir yeniden başlatılır . Bu Heroku tarafından zor bir sınırlamadır . Olaylar kuyruğa alınırken sunucu yeniden başlatılabilir.
- Sunucuya durum kazandırır, böylece ölçeklenebilirliğe zarar verir. Çok sunuculu bir kurulumumuz varsa ve bir istemci, kaydedilen + kaydedilen tüm etkinlikleri okumak istiyorsa, kaydedilen etkinliklerin hangi sunucuda yaşadığını bilemeyiz.
Ayrı bir mesaj kuyruğu kullanma
Mesaj kuyruğunu ( RabbitMQ gibi ) kullanabileceğimizi varsayalım , burada mesajları pompalıyoruz ve diğer tarafta sadece DB'deki olayları kaydetme ile ilgilenen başka bir sunucu var.
Başka bir istemci başka bir istemcinin iletilerini okumak istiyorsa, yalnızca kaydedilmiş iletileri DB'den ve bekleyen iletileri kuyruktan alabilirim. ve bunları bir araya getirerek okuma isteği istemcisine geri gönderebiliyorum.
Her biri iletilerin bir kısmını merkezi bir DB koordinatörü sunucusuna kaydetmek için birden çok veritabanı kullanın.
Yine de başka bir çözüm, merkezi bir "DB koordinatörü / yük dengeleyici" ile birden fazla veritabanı kullanmaktır. Bir olay alındıktan sonra bu koordinatör mesajı yazmak için veritabanlarından birini seçecektir. Bu, birden fazla Heroku veritabanını kullanmamızı sağlamalı, böylece bağlantı sınırını 500 x veritabanına kadar yükseltmeliyiz.
Bir okuma sorgusu üzerine, bu koordinatör SELECT
her bir veritabanına sorgu gönderebilir, tüm sonuçları birleştirebilir ve bunları okuma isteyen istemciye geri gönderebilir.
Bu kötü bir fikir çünkü:
- Bu fikir ... ahem .. aşırı mühendislik gibi mi geliyor? De yönetmek için bir kabus olurdu (yedekler vb ..). İnşaatı ve bakımı karmaşıktır ve kesinlikle gerekli olmadıkça KISS ihlali gibi görünür .
- Tutarlılığı feda eder . Bu fikirle devam edersek, birden çok DB'de işlem yapmak bir hareket etmiyor.
ANALYZE
Sorguları kendim çalıştırıyorum ve sorun değiller. Ayrıca bağlantı havuzu hipotezini test etmek için bir prototip oluşturdum ve bunun gerçekten sorun olduğunu doğruladım. Veritabanı ve sunucunun kendisi farklı makinelerde yaşıyor, bu nedenle gecikme. Ayrıca, kesinlikle gerekli olmadıkça Heroku'dan vazgeçmek istemiyoruz, konuşlandırmalardan endişe etmemek bizim için büyük bir artı.
select null
500 bağlantı yayınlamayı deneyin . Bahse girerim, bağlantı havuzunun orada sorun olmadığını göreceksiniz.