Read replica gecikmesi yüzünden kullanıcı kendi yazdığı veriyi göremiyor; bunu uygulama tarafında nasıl çözerim?
Soru
PostgreSQL'de bir primary ve bir read replica ile çalışıyorum; okumaları ölçeklemek için okuma sorgularını replica'ya yönlendiriyorum. Ama kullanıcı profilini kaydettikten hemen sonra açılan bir sonraki sayfa replica'dan okuyor ve eski veriyi gösteriyor. Kullanıcı kendi yazdığı veriyi anında göremediği için "kaydedilmedi mi?" diye tekrar tekrar kaydediyor. Bu read-after-write tutarlılığını uygulama tarafında nasıl çözerim?
Cevap
Kısa cevap
Read replica gecikmesinden doğan bu sorun klasik bir read-your-writes problemidir.
Bağlam
Replication’ı anlık yapmaya çalışmayın — taze veriyi görmesi gereken dar okuma kümesini primary’ye yönlendirin, gerisini replica’da bırakın. Bunu global değil, cerrahi yapın.
Neden
- Önce tradeoff’u kabul edin. Asenkron replication tasarım gereği gecikmelidir; bu, okuma ölçeklemenin bedelidir. Gecikmeyi yok edemezsiniz — yalnızca staleness’in kullanıcıya görünür olduğu dar okumalar için etrafından dolaşırsınız.
Ne yapmalı
- En basit sağlam çözüm: yazımdan sonra sticky-primary penceresi. Bir kullanıcı yazdıktan sonra, onun okumalarını kısa bir süre (örneğin birkaç saniye) primary’ye sabitleyin. Laravel bunu hazır sunar: DB config’inde
'sticky' => true, yazma yapmış bir isteğin kalan okumalarını writer’a gönderir.// config/database.php — okumalar replica'ya, yazmalar primary'ye gider; // yazma yapan bir istek, kalan okumaları için primary'ye sticky kalır. 'pgsql' => [ 'read' => ['host' => ['replica.internal']], 'write' => ['host' => ['primary.internal']], 'sticky' => true, // ... ], - Sticky bayrağı yalnızca aynı isteği kapsar. Sizin bug’unuz bir sonraki sayfa okuması, yani yeni bir istek. Bu yüzden daha uzun ömürlü bir sinyale ihtiyacınız var: kullanıcı başına bir “son yazma zamanı” tutun (session/Redis) ve
now - last_write < lag_budgetolduğu sürece okumaları primary’ye yönlendirin. - Daha kesin yol: LSN fencing. Yazmanın WAL LSN’ini yakalayın (
pg_current_wal_lsn()), ileriye taşıyın (cookie/token) ve okumada ya replica bunu geçene kadar bekleyin (pg_last_wal_replay_lsn()) ya da primary’ye düşün. Herkesi primary’ye göndermeden doğruluk verir; daha fazla tesisat ama tam isabetli.-- Yazarken pozisyonu yakalayın: SELECT pg_current_wal_lsn(); -- Replica'dan okurken yakaladığını doğrulayın: SELECT pg_last_wal_replay_lsn() >= '0/16B62C0'::pg_lsn; - Kapsamı kullanıcının kendi verisiyle sınırlayın. Read-your-writes yalnızca yazan kişinin gördüğü veri için önemlidir. Başka kullanıcıların birkaç saniyelik staleness’i tolere etmesi genelde sorun değildir. Tüm uygulamayı primary’ye gönderip okuma ölçeklemenizi kaybetmeyin.
- Gecikmeyi izleyin.
pg_last_xact_replay_timestamp()/ replication gecikmesi üzerine alert kurun. Gecikme düzenli olarak bütçenizi aşıyorsa hiçbir uygulama numarası kurtarmaz — replica’yı düzeltin (I/O, primary’deki uzun transaction’lar, ağ).
Sonuç: Ben olsam kullanıcı başına “yazımdan sonra N saniye primary’den oku” kuralıyla başlardım — birkaç satır, profil-kaydet senaryosunu tam olarak kapsar ve replica’ları herkes için ağır işte tutar. LSN fencing’i yalnızca birkaç saniyelik primary yönlendirmesi yeterince kesin olmazsa ya da yazma hacmi bunu pahalılaştırırsa kurardım. Global “hep primary’den oku” yaklaşımı, replica eklemenizin sebebini boşa çıkarır.
Yorumlar
Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.