Rehber: Redis Pub/Sub ve Streams ile Event-Driven Sistemler
Event-driven mimaride servisler birbirini doğrudan çağırmak yerine olay yayınlar ve bu olaylarla ilgilenen bileşenler tepki verir. Redis, bu iş için iki farklı araç sunar: Pub/Sub ve Streams. İkisi de "mesaj yayınlama" gibi görünse de güvenilirlik, kalıcılık ve tüketim modeli açısından temelden ayrılır. Bu rehberde ikisini de uygulamalı olarak ele alıp hangi senaryoda hangisinin seçileceğini netleştiriyoruz.
Önkoşullar ve Kapsam
- Redis sunucusu çalışıyor olmalı. Komutlar Redis 5.0 ve sonrasında kararlıdır; Streams (
XADD,XREAD,XACKvb.) Redis 5.0 ile geldi. Bu rehberdeki akış komutları için Redis 5.0+ gerekir.XAUTOCLAIMgibi bazı yardımcı komutlar Redis 6.2+ ile gelmiştir; kullandığınız sürümün komut setiniCOMMAND DOCSile doğrulayın. - Örnekler
redis-cliüzerinden verilmiştir; herhangi bir istemci kütüphanesiyle aynı mantık geçerlidir. - Redis 7.x sonrası sürümlerde Pub/Sub için sharded pub/sub (
SPUBLISH/SSUBSCRIBE) veRESP3tabanlı istemci tarafı önbellekleme gibi ek yetenekler vardır. Bu rehber klasik Pub/Sub ve Streams temeline odaklanır.
Redis Pub/Sub: Ateşle ve Unut
Pub/Sub, adı üstünde "yayınla/abone ol" modelidir. Bir kanala yayınlanan mesaj, o anda abone olan tüm istemcilere iletilir. Mesaj saklanmaz; abone değilseniz mesajı kaçırırsınız.
Temel Kullanım
Bir terminalde abone olun:
SUBSCRIBE orders.created
Başka bir terminalde yayınlayın:
PUBLISH orders.created '{"orderId":42,"total":199.90}'
Abone terminalinde mesajı görürsünüz. PUBLISH komutu, mesajın kaç aboneye ulaştığını döndürür. Hiç abone yoksa 0 döner ve mesaj kaybolur.
Desen ile Abone Olma
PSUBSCRIBE orders.*
orders.created, orders.cancelled gibi tüm eşleşen kanalları dinler. Desen aboneliği esneklik sağlar ama her mesajın hangi kanaldan geldiğini ayrıca takip etmeniz gerekir.
Ne Zaman Uygun?
- Anlık bildirim, canlı skor, sohbet odası gibi kayıp tolere edilebilir akışlar.
- Düşük gecikme öncelikli, yüksek fan-out senaryoları.
- Önbellek invalidation sinyalleri.
Sınırları
- Kalıcılık yok: Sunucu yeniden başlarsa veya ağ koparsa mesajlar kaybolur.
- Teslim garantisi yok: Abone yavaşsa veya kopmuşsa mesajı alamaz; geri alma mekanizması yoktur.
- Tüketici grubu yok: Aynı kanala abone olan her istemci aynı mesajı alır; iş yükünü paylaşmak için yerleşik bir yol yoktur.
- Birikme yok: Abone mesajları işleyemeden birikirse Redis belleği şişer ve istemci bağlantısı kesilebilir.
Redis Streams: Kalıcı ve İzlenebilir Olay Günlüğü
Streams, her mesajın bir kimlikle (ID) saklandığı, ekleme odaklı (append-only) bir veri yapısıdır. Kafka'nın basitleştirilmiş, Redis içinde yaşayan bir karşılığı gibi düşünülebilir.
Mesaj Ekleme
XADD orders * orderId 42 total 199.90
* işareti Redis'in zaman damgası tabanlı benzersiz bir ID üretmesini söyler. Dönen değer, örneğin 1700000000000-0 gibi bir ID'dir.
Okuma
Belirli bir noktadan sonraki tüm yeni mesajları okumak için:
XREAD COUNT 10 STREAMS orders 0
0, "en baştan itibaren" demektir. Yalnızca yeni mesajları beklemek için $ kullanılır:
XREAD BLOCK 5000 STREAMS orders $
BLOCK 5000, en fazla 5 saniye yeni mesaj bekler. Süre dolarsa boş döner.
Tüketici Grupları
Streams'in güçlü tarafı buradadır. Bir grup oluşturun:
XGROUP CREATE orders workers $ MKSTREAM
orders: stream adıworkers: grup adı$: grubun şu andan itibaren okumaya başlamasıMKSTREAM: stream yoksa oluştur
Grup içindeki bir tüketici mesajları şöyle alır:
XREADGROUP GROUP workers worker-1 COUNT 10 STREAMS orders >
>, "bu gruba henüz teslim edilmemiş yeni mesajlar" anlamına gelir. Her mesaj gruptaki tek bir tüketiciye gider; yani iş yükü paylaşılır.
Onaylama (ACK)
Bir mesaj işlendikten sonra onaylanmalıdır:
XACK orders workers 1700000000000-0
Onaylanmayan mesajlar Pending Entries List (PEL) içinde kalır. Bu, çöken bir tüketicinin işini başka bir tüketicinin devralmasını mümkün kılar.
Bekleyen mesajları görmek için:
XPENDING orders workers
Sahipsiz kalan mesajları başka bir tüketiciye devretmek için:
XAUTOCLAIM orders workers worker-2 60000 0-0
Burada 60000, "60 saniyeden uzun süredir bekleyen mesajları devral" anlamına gelir (XAUTOCLAIM, Redis 6.2+).
Stream Uzunluğunu Sınırlama
Stream sonsuza kadar büyür. XADD sırasında üst sınır koyun:
XADD orders MAXLEN ~ 100000 * orderId 43 total 50
~ işareti, Redis'in tam sayı yerine yaklaşık bir sınır uygulamasına izin verir; bu, iç verimlilik açısından tercih edilir.
Pub/Sub ve Streams Karşılaştırması
| Özellik | Pub/Sub | Streams |
|---|---|---|
| Kalıcılık | Yok | Var |
| Geçmişi okuma | Yok | Var (ID ile) |
| Tüketici grubu | Yok | Var |
| Onaylama / yeniden teslim | Yok | Var (PEL) |
| Fan-out | Tüm aboneler | Grup başına bir tüketici |
| Bellek kullanımı | Anlık | Birikimli (sınırlanabilir) |
Kısa kural: kaybı tolere edemiyorsanız Streams, gecikme ve fan-out öncelikliyse Pub/Sub.
Pratik Mimari Önerileri
- Olay şemasını sabitleyin. Alan adlarını (
orderId,type,occurredAt) baştan belirleyin; tüketiciler buna göre yazılır. - Idempotent tüketici yazın. Streams onay verilmeden önce çökerse mesaj yeniden teslim edilir. Aynı olayı iki kez işlemek zarar vermemeli.
- Stream'i sınırlayın.
MAXLENkullanmazsanız disk ve bellek zamanla dolar. - Dead-letter düşünün. Sürekli hata veren mesajları ayrı bir stream'e taşıyın ki grup tıkanmasın.
- Pub/Sub'ı kritik iş akışlarında kullanmayın. Sipariş, ödeme, stok gibi kayıp kabul etmeyen olaylar Streams'e ait.
Yaygın Hatalar
- Pub/Sub'ı kuyruk sanmak.
PUBLISHmesajı saklamaz; abone yoksa mesaj yoktur. XREADGROUPyerineXREADkullanmak.XREADgrup semantiğini atlar; her tüketici aynı mesajları görür.XACKçağırmayı unutmak. PEL şişer,XPENDINGlistesi büyür, devralma mantığı bozulur.$ile grubu yanlış noktadan başlatmak.XGROUP CREATE ... $mevcut mesajları atlar; geçmişi işlemek istiyorsanız0kullanın.- Tüketici sayısını grup adıyla karıştırmak. Grup adı sabit, tüketici adı her işçi için farklı olmalı.
MAXLENkoymadan stream büyütmek. Uzun vadede bellek sorununa yol açar.
Güvenlik ve Operasyonel Notlar
- Kimlik doğrulama: Redis'i asla internete açık bırakmayın.
requirepassveya ACL (ACL SETUSER) ile erişimi kısıtlayın. Redis 6+ ile kanal ve komut bazlı ACL tanımlanabilir. - TLS: Ağ üzerinden geçen olay verisi hassas olabilir;
tls-portve sertifika yapılandırması kullanın. - Yetki ayrımı: Yayıncıya yalnızca
PUBLISH/XADD, tüketiciyeXREADGROUP/XACKizni verin. Tek bir "her şeyi yapabilen" kullanıcıdan kaçının. - Hassas veri: Olay gövdelerine gereksiz kişisel veri koymayın; stream kalıcıdır ve geçmişi okuyan herkes görebilir.
- İzleme:
INFO,SLOWLOG,XPENDINGçıktılarını düzenli kontrol edin. PEL büyümesi erken uyarı sinyalidir. - Yüksek erişilebilirlik: Sentinel veya Cluster ile replikasyon kurun; ancak Redis replikasyonunun asenkron olduğunu unutmayın, failover sırasında son mesajlar kaybolabilir.
Sonuç
Pub/Sub ve Streams aynı ihtiyacın iki farklı cevabı değil, iki farklı ihtiyacın cevabıdır. Anlık, kayıp tolere edilebilir sinyaller için Pub/Sub yeterli ve basittir. Sipariş, ödeme, envanter gibi geri alınamaz olaylar için Streams'in kalıcılığı, tüketici grupları ve onay mekanizması vazgeçilmezdir. Doğru seçim, olayı kaybettiğinizde ne olacağı sorusuna verdiğiniz yanıtla başlar.