Çoğu replikasyon diyagramı bir primary, iki replika ve aralarındaki okları gösterir. Bu resim doğrudur ama bir olay anında neredeyse işe yaramaz; çünkü şu anda yazmaları hangi düğümün aldığını, hangi replikanın bayat veri sunabileceğini ya da primary yanıt vermeyi kestiğinde ne olacağını söylemez.
İşe yarayan bir replikasyon diyagramı dört soruyu yanıtlar. Bu rehber bu soruları PostgreSQL, Patroni ve etcd ile ele alıyor, ardından sonucu çiziyor. Aynı sorular MySQL için, diğer failover yöneticileri için ve yönetilen servisler için de geçerlidir.
Her replikasyon diyagramının yanıtlaması gereken dört soru
- Yazmalar nereye gider? Tam olarak bir primary olmalı ve istemcilerin failover'dan sonra onu bulmanın bir yolu olmalı.
- Okumalar ne kadar bayat olabilir? Her replika senkron ya da asenkrondur; asenkron olanlar geride kalır.
- Failover'a kim karar verir? Bir şeyin arızayı fark etmesi, bir replika seçmesi ve onu terfi ettirmesi gerekir.
- İki primary'yi ne önler? Bağlantısı kesilen bir primary, başka bir düğüm terfi ettirilmeden önce yazma almayı bırakmalıdır.
Senkron ve asenkron replikasyon
PostgreSQL streaming replikasyonu varsayılan olarak asenkrondur. Primary, standby veriyi almadan önce commit'i onaylar; bu yüzden bir çökme, henüz ulaşmamış işlemlerin kaybolmasına yol açabilir. PostgreSQL dokümantasyonu bunu açıkça söyler: veri kaybının miktarı, failover anındaki replikasyon gecikmesiyle orantılıdır.
Senkron replikasyon, commit'lerin synchronous_standby_names içinde listelenen bir veya daha fazla standby'ı beklemesini sağlar. Ne kadar bekleyecekleri synchronous_commit ayarına bağlıdır:
synchronous_commit |
Commit, senkron standby şunu yaptıktan sonra döner |
|---|---|
remote_apply |
Uyguladıktan sonra; standby'daki sorgular veriyi görür |
on (varsayılan) |
Kalıcı depolamaya yazıp diske aktardıktan sonra |
remote_write |
İşletim sistemine yazdıktan sonra; henüz diske aktarılmamıştır |
local |
Standby beklenmez; yalnızca yerel diske aktarma beklenir |
off |
Hiç beklenmez; yerel disk bile beklenmez |
Bedeli gecikmedir: her commit standby'a bir gidiş-dönüş içerir; bu yüzden senkron standby'ları başka bir bölgede değil, yakın bir alanda tutun. Tek senkron standby ortadan kaybolursa commit'ler sonsuza kadar bekleyebilir. Birden fazla aday tanımlayın ya da ayarı sizin yerinize bir failover yöneticisinin değiştirmesine izin verin.
Okuma replikaları ve okuma yönlendirme
Asenkron bir replika; raporlar ve okuma ağırlıklı uç noktalar için iyi bir yerdir, yeter ki kod verinin geride olabileceğini bilsin. Primary'de pg_stat_replication görünümü her standby için write_lag, flush_lag ve replay_lag değerlerini gösterir; replay_lag, bir commit'in replikada görünür hâle gelmesine kadar geçen süreye yaklaşık bir değer verir.
Hangi sorguların bayat veri okuyabileceğine sorgu bazında karar verin. Bir formu az önce kaydedip sayfayı yenileyen kullanıcı primary'den okumalıdır. Bir dashboard replikadan okuyabilir.
Failover: kim karar verir
PostgreSQL, arızalı bir primary'yi kendi başına fark etmez ve bir standby'ı terfi ettirmez; dokümantasyonu bunu harici araçlara bırakır. Patroni yaygın bir seçimdir. Her düğümde bir Patroni ajanı çalışır ve ajanlar durumu etcd gibi dağıtık bir yapılandırma deposu üzerinden paylaşır:
- Primary, TTL'i olan bir lider anahtarı tutar ve onu her döngüde yeniler (
loop_wait, varsayılan 10 saniye). - Anahtarı
ttlsaniye boyunca (varsayılan 30) yenileyemezse anahtarın süresi dolar ve uygun replikalar bir liderlik yarışı başlatır. - En iyi aday anahtarı alır ve kendini terfi ettirir; diğerleri onu takip eder.
İstemciler yeni primary'yi bir proxy aracılığıyla bulur. Patroni'nin REST API'si GET /primary isteğine yalnızca lider anahtarını tutan düğümde HTTP 200 ile yanıt verir; böylece HAProxy yazmaları "evet" diyen düğüme gönderebilir:
listen primary
bind *:5000
option httpchk OPTIONS /primary
http-check expect status 200
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
server pg-a 10.0.1.10:5432 check port 8008
server pg-b 10.0.2.10:5432 check port 8008
server pg-c 10.0.3.10:5432 check port 8008
5001 portundaki ikinci bir listener /replica?lag=16MB kontrolünü yapar; WAL'da 16 MB'tan fazla geride kalan replikayı devreden çıkarır. HAProxy'yi birden fazla makinede çalıştırın, yoksa ortadan kaldırmaya çalıştığınız tekil hata noktasına kendisi dönüşür.
Split brain: iki primary'yi ne önler
Yazma kabul eden iki primary, birbirinden ayrışan iki geçmiş demektir ve bunlardan biri çöpe gidecektir. PostgreSQL dokümantasyonu çareye STONITH der: eski primary'ye artık primary olmadığı bildirilmelidir. Patroni birkaç savunma katmanı ekler:
- Kira (lease). Lider anahtarını güncelleyemeyen bir primary yazma almayı bırakır: Patroni PostgreSQL'i durdurur ya da rolünü düşürür. Deponun kendisine
retry_timeoutsüresinden uzun süre ulaşılamazsa, DCS failsafe modu açık değilse Patroni primary'nin rolünü düşürür. - Watchdog. Patroni süreci takılırsa bir Linux watchdog makineyi yeniden başlatır. Patroni onu TTL dolmadan 5 saniye önce tetiklenecek şekilde ayarlar.
- Çoğunluk (quorum). etcd'nin bir yazmayı kabul etmesi için üyelerinin çoğunluğu, yani üçte ikisi gerekir. Üç alanda üç üye, bir alanın kaybına dayanır; ağdan kopmuş bir azınlık da kimseyi seçemez.
- Tek bir yönetici süreç. PostgreSQL'i yalnızca Patroni başlatabilmelidir. Bir çökmeden sonra Postgres'i kendi başına yeniden başlatan bir sistem servisi, ikinci bir primary'yi geri getirebilir.
Eski primary geri döndüğünde replika olarak yeniden katılmalıdır. pg_rewind, değişmeyen veri bloklarını kopyalamadan veri dizinini yeni primary ile senkronize eder; Patroni, use_pg_rewind açıkken bunu çalıştırır.
# Patroni dynamic configuration (patronictl edit-config)
ttl: 30
loop_wait: 10
retry_timeout: 10
synchronous_mode: on # promote only a node that has every acknowledged commit
postgresql:
use_pg_rewind: true
parameters:
wal_log_hints: "on"
# Local patroni.yml tags
# pg-a: noloadbalance: true (failover target, no reads)
# pg-c: nosync: true, nofailover: true (reads only)
synchronous_mode açıkken Patroni yalnızca başarılı olarak bildirilen her commit'e sahip olduğunu bildiği bir standby'ı terfi ettirir. Ödünleşim erişilebilirliktir: primary, bağlı hiçbir senkron standby yokken çökerse Patroni kimseyi terfi ettirmez ve biri müdahale edene kadar yazmalar kapalı kalır.
Replikasyon yedek değildir
Bir DROP TABLE her replikaya milisaniyeler içinde ulaşır. Sürekli WAL arşivlemesi ve düzenli temel yedekler tutun; bunlar size temel yedekten sonraki herhangi bir ana zamanda belirli bir ana kurtarma imkânı verir. Geri yüklemeleri de düzenli olarak test edin.
Diyagram
Diyagram içeriği
- Order service
- HAProxy
- AZ a
- AZ b
- AZ c
- pg-a · sync standby
- pg-b · primary
- pg-c · async replica
- etcd
- WAL archive + base backups
- SQL
- writes :5000
- reads :5001
- WAL (sync)
- WAL (async)
- leader key, TTL 30 s
- races if key expires
- archived WAL
Nasıl okunur:
- Yazmalar. Sipariş servisi HAProxy'ye bağlanır. 5000 portu,
/primaryisteğine 200 ile yanıt veren tek düğüm olan pg-b'ye gider. - Okumalar. 5001 portu, başka bir alandaki asenkron replika pg-c'ye gider. pg-a okuma almaz.
- Replikasyon. pg-b, WAL'ı pg-a'ya senkron (düz çizgi), pg-c'ye asenkron (kesikli çizgi) olarak akıtır.
- Failover. pg-b, etcd'deki lider anahtarını yeniler. Anahtarın süresi dolarsa senkron standby olan pg-a onu almak için yarışır. pg-c
nofailoveretiketlidir. - Kurtarma. pg-b, WAL'ı ve temel yedekleri nesne depolamaya arşivler.
- Hedefler. Sol üstteki not RPO, RTO, gecikme bütçesi ve yedek saklama süresini içerir.
Bir replikasyon diyagramında neler etiketlenmeli
- Her replikasyon okunun modu, senkron ya da asenkron, ve asenkron replikalar için gecikme bütçesi.
- Her replikanın rolü: failover adayı, okuma replikası ya da ikisi birden.
- Lider kilidinin nerede durduğu ve TTL'i, ya da bu rolü üstlenen yönetilen servis.
- İstemcilerin primary'yi nasıl bulduğu: bir proxy, bir DNS adı ya da sanal bir IP.
- Arıza alanları: uzlaşma üyelerinin nerede çalıştığı dahil, çerçeve olarak erişilebilirlik alanları.
- RPO ve RTO hedefleri; böylece inceleyiciler tasarımı bu hedeflere göre kontrol edebilir.
Yönetilen servisler sizin yerinize ne yapar
Yönetilen veritabanları aynı soruları yanıtlar, ama bazı yanıtlar sabittir. Bir Amazon RDS Multi-AZ DB instance yapısında standby senkrondur, başka bir alanda durur ve okuma sunamaz. Failover, DNS kaydını standby'a çevirir ve genellikle 60 ile 120 saniye sürer. Bir Multi-AZ DB cluster'da okunabilen iki standby vardır, yarı senkron replikasyon kullanılır ve failover genellikle 35 saniyenin altında tamamlanır. Diyagramda HAProxy'nin yerini endpoint, Patroni ile etcd'nin yerini de AWS alır. Gecikmeyi, okuma yönlendirmeyi ve hedefleri yine siz etiketlersiniz.
Failover'ı test edin
Primary'yi bilerek değiştirin; örneğin her bakım penceresinde patronictl switchover ile. PostgreSQL dokümantasyonu düzenli geçişi önerir, çünkü bu aynı zamanda failover mekanizmasının bir testidir. Yazmaların ne kadar süre başarısız olduğunu ölçün, HAProxy'nin yeni primary'yi takip ettiğini kontrol edin ve onaylanmış hiçbir commit'in kaybolmadığını doğrulayın. Bölgeler arası failover için AWS çok bölgeli mimari diyagramı yazısına bakın.
Archboard'da oluşturun
- Google ya da GitHub ile giriş yapın ve bir diyagram oluşturun.
- Erişilebilirlik alanları için Temel paketinden üç Çerçeve ekleyin ve her birine Veri paketinden bir Postgres düğümü koyun: pg-a (senkron standby), pg-b (primary) ve pg-c (asenkron replika).
- Alanların üstüne, sipariş servisi için C4 Modeli paketinden bir Konteyner ve HAProxy için Ağ paketinden bir Yük dengeleyici ekleyin.
- Altlarına, etcd için C4 Modeli paketinden bir Konteyner ve WAL arşivi için Veri paketinden bir Nesne deposu ekleyin.
- Kenarları etiketleyin: "writes :5000", "reads :5001", düz çizgiyle "WAL (sync)", kesikli çizgiyle "WAL (async)", pg-b'den etcd'ye "leader key, TTL 30 s" ve liderlik yarışı için pg-a'dan etcd'ye kesikli bir kenar.
- RPO, RTO, gecikme bütçesi ve yedek saklama süresi için Temel paketinden bir Markdown bloğu ekleyin.
Örnek 11 diyagram düğümü kullanıyor ve Free planın sınırları içinde kalıyor. Küme değiştikçe diyagramı güncel tutmak için Eskimeyen mimari diyagramlar yazısına, genel yöntem için de sistem tasarımı diyagramı örneğine bakın.
SSS
Okuma replikası bir yedek midir? Hayır. Silmeler ve hatalı migration'lar da replikaya geçer. WAL arşivlemeli yedekler, hatadan önceki bir ana geri dönmenizi sağlar.
Senkron replikasyon sıfır veri kaybı mı demek? Senkron bir standby'ın onayladığı commit'ler için evet, failover yalnızca o standby'ı terfi ettirdiği sürece. Bağlı hiçbir senkron standby yokken kabul edilen commit'ler yalnızca primary'de bulunur.
Neden iki değil de üç etcd üyesi? etcd'nin yazma kabul etmesi için çoğunluk gerekir. İki üye, ikisinden hiçbirinin kaybına dayanamaz; üç üye ise birinin kaybına dayanır ve bir ağ bölünmesinde bir tarafta çoğunluğu korur.
Primary'yi bulmak için proxy yerine DNS kullanabilir miyim? Evet, yönetilen servisler böyle yapar. DNS TTL'lerini kısa tutun ve istemcilerin sorgu sonuçlarını uzun süre önbelleğe almadığından emin olun; AWS, JVM DNS önbelleği TTL'inin 60 saniyeyi geçmemesini önerir.
Failover'ı ne sıklıkla test etmeliyiz? Ekibin ona güvenmesine yetecek sıklıkta; örneğin her bakım penceresinde planlı bir switchover, buna ek olarak staging'de plansız bir arıza testi.