Çoğaltma bir yedekleme değildir. Ya da değil? Kısayolları yanlışlıkla silerek kurtarma için tembel çoğaltmayı şu şekilde kullandık.
Çoğaltma, veritabanı yedekleme aracınız değildir (gitlab-ce
Gecikmeli çoğaltma ile verileri yalnızca 1,5 saatte kurtardık. Nasıl olduğunu görün.
PostgreSQL ile zamanında kurtarma
PostgreSQL, bir veritabanının durumunu zamanın belirli bir noktasına geri yükleyen yerleşik bir işleve sahiptir. denir
Soğuk yedekleme için bu özelliği kullanmak için, düzenli olarak bir temel veritabanı yedeği yaparız ve bunu bir arşivde saklarız (GitLab arşivleri,
Gecikmeli replikasyon nedir?
Gecikmeli replikasyon, WAL'deki değişikliklerin gecikmeli olarak uygulanmasıdır. Yani, işlem saatte gerçekleşti X
, ancak yinelemede gecikmeli olarak görünecektir d
saat başı X + d
.
PostgreSQL'de fiziksel bir veritabanı kopyası kurmanın 2 yolu vardır: arşiv geri yükleme ve akış çoğaltma.
Gecikmeli yedekleme kurtarma nasıl kurulur?
recovery.conf
. Örnek:
standby_mode = 'on'
restore_command = '/usr/bin/envdir /etc/wal-e.d/env /opt/wal-e/bin/wal-e wal-fetch -p 4 "%f" "%p"'
recovery_min_apply_delay = '8h'
recovery_target_timeline = 'latest'
Bu ayarlarla, arşiv geri yüklemeli gecikmeli bir kopya yapılandırdık. Burada kullanılan restore_command
) arşivden alınır ve değişiklikler sekiz saat sonra uygulanır (recovery_min_apply_delay
). Çoğaltma, arşivdeki bir küme yük devretmesi gibi zaman çizelgesi değişikliklerini izleyecektir (recovery_target_timeline
).
С recovery_min_apply_delay
Gecikmeli akış çoğaltmasını ayarlayabilirsiniz, ancak çoğaltma yuvaları, etkin yedek geri bildirimi vb. ile ilişkili birkaç tuzak vardır. WAL arşivi bunlardan kaçınır.
Parametre recovery_min_apply_delay
yalnızca PostgreSQL 9.3'te göründü. Önceki sürümlerde, gecikmeli çoğaltma, aşağıdakilerin bir kombinasyonunu gerektirir: pg_xlog_replay_pause(), pg_xlog_replay_resume()
) veya arşivdeki WAL segmentlerini gecikme süresi boyunca tutun.
PostgreSQL bunu nasıl yapıyor?
PostgreSQL'in tembel geri yüklemeyi nasıl uyguladığını görmek ilginç. Şuna bakalım recoveryApplyDelay(XlogReaderState)
static bool
recoveryApplyDelay(XLogReaderState *record)
{
uint8 xact_info;
TimestampTz xtime;
long secs;
int microsecs;
/* nothing to do if no delay configured */
if (recovery_min_apply_delay <= 0)
return false;
/* no delay is applied on a database not yet consistent */
if (!reachedConsistency)
return false;
/*
* Is it a COMMIT record?
*
* We deliberately choose not to delay aborts since they have no effect on
* MVCC. We already allow replay of records that don't have a timestamp,
* so there is already opportunity for issues caused by early conflicts on
* standbys.
*/
if (XLogRecGetRmid(record) != RM_XACT_ID)
return false;
xact_info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
if (xact_info != XLOG_XACT_COMMIT &&
xact_info != XLOG_XACT_COMMIT_PREPARED)
return false;
if (!getRecordTimestamp(record, &xtime))
return false;
recoveryDelayUntilTime =
TimestampTzPlusMilliseconds(xtime, recovery_min_apply_delay);
/*
* Exit without arming the latch if it's already past time to apply this
* record
*/
TimestampDifference(GetCurrentTimestamp(), recoveryDelayUntilTime,
&secs, µsecs);
if (secs <= 0 && microsecs <= 0)
return false;
while (true)
{
// Shortened:
// Use WaitLatch until we reached recoveryDelayUntilTime
// and then
break;
}
return true;
}
Sonuç olarak, gecikme, işlem taahhüdünün zaman damgasında kaydedilen fiziksel süreye bağlıdır (xtime
). Gördüğünüz gibi, gecikme yalnızca taahhütler için geçerlidir ve diğer kayıtları etkilemez - tüm değişiklikler doğrudan uygulanır ve taahhüt ertelenir, bu nedenle değişiklikleri yalnızca yapılandırılan gecikmeden sonra göreceğiz.
Veri kurtarma için tembel çoğaltma nasıl kullanılır?
Diyelim ki üretimde bir veritabanı kümemiz ve sekiz saatlik gecikmeli bir kopyamız var. Bir örnek kullanarak verilerin nasıl kurtarılacağını görelim
Sorunun farkına vardığımızda,
SELECT pg_xlog_replay_pause();
Bir duraklamayla, kopyanın isteği tekrarlama riski yoktu. DELETE
. Her şeyi anlamak için zamana ihtiyacınız varsa kullanışlı bir şey.
Sonuç olarak, ertelenen kopya istekten önceki ana ulaşmalıdır. DELETE
. Çıkarmanın fiziksel zamanını yaklaşık olarak biliyorduk. Taşındı recovery_min_apply_delay
ve eklendi recovery_target_time
в recovery.conf
. Böylece kopya gecikmeden doğru ana ulaşır:
recovery_target_time = '2018-10-12 09:25:00+00'
Zaman damgalarıyla, kaçırmamak için fazlalığı azaltmak daha iyidir. Doğru, düşüş ne kadar büyük olursa, o kadar çok veri kaybederiz. Yine isteği atlarsak DELETE
, her şey yeniden silinecek ve baştan başlamanız (hatta PITR için soğuk bir yedek almanız) gerekecek.
Geciken Postgres örneğini yeniden başlattık ve belirtilen zamana kadar WAL segmentleri tekrarlandı. Bu aşamadaki ilerlemeyi aşağıdakileri sorgulayarak takip edebilirsiniz:
SELECT
-- current location in WAL
pg_last_xlog_replay_location(),
-- current transaction timestamp (state of the replica)
pg_last_xact_replay_timestamp(),
-- current physical time
now(),
-- the amount of time still to be applied until recovery_target_time has been reached
'2018-10-12 09:25:00+00'::timestamptz - pg_last_xact_replay_timestamp() as delay;
Zaman damgası artık değişmiyorsa geri yükleme tamamlanmıştır. İşlemi özelleştirebilirsiniz recovery_target_action
Veri tabanı, bu talihsiz istekten önce devlete geldi. Artık örneğin verileri dışa aktarabilirsiniz. Uzak etiket verilerini ve sorunlara ve birleştirme isteklerine yönelik tüm bağlantıları dışa aktardık ve bunları üretim veritabanına aktardık. Kayıplar büyükse, kopyayı tanıtabilir ve ana kopya olarak kullanabilirsiniz. Ancak, iyileştiğimiz andan sonra tüm değişiklikler kaybolacaktır.
Zaman damgaları yerine işlem kimliklerini kullanmak daha iyidir. Bu kimlikleri, örneğin DDL ifadeleri için (örneğin, DROP TABLE
), kullanarak log_statements = 'ddl'
. Bir işlem kimliğimiz olsaydı, alırdık recovery_target_xid
ve istekten önce işleme kadar her şeyi yaptı DELETE
.
İşe geri dönmek çok basit: tüm değişiklikleri kaldırın. recovery.conf
ve postgres'i yeniden başlatın. Yakında kopyada yine sekiz saatlik bir gecikme olacak ve gelecekteki sorunlara hazırız.
İyileşme Faydaları
Soğuk bir yedekleme yerine gecikmeli bir çoğaltmayla, anlık görüntünün tamamını arşivden geri yüklemek için saatler harcamanıza gerek kalmaz. Örneğin, 2 TB temel yedeğin tamamını almak için beş saate ihtiyacımız var. Ve sonra, istenen duruma (en kötü durumda) geri dönmek için günlük WAL'ın tamamını uygulamanız gerekir.
Gecikmeli bir çoğaltma, soğuk bir yedeklemeden iki şekilde daha iyidir:
- Tüm temel yedeği arşivden almanıza gerek yoktur.
- Tekrarlanması gereken sekiz saatlik sabit bir WAL segment penceresi vardır.
Ayrıca, WAL'ın PITRed olup olmadığını sürekli olarak kontrol ediyoruz ve gecikmeli kopyanın birikmiş iş listesini izleyerek WAL arşivindeki bozulmaları veya diğer sorunları hemen fark edebiliyoruz.
Bu örnekte, geri yüklememiz 50 dakika sürdü, yani hız saatte 110 GB WAL verisiydi (arşiv hala açıktı
Özet: gecikmeli bir çoğaltmanın yararlı olduğu (ve olmadığı) durumlarda
Yanlışlıkla veri kaybederseniz ve yapılandırılan gecikme içinde bu felaketi fark ederseniz, gecikmeli çoğaltmayı ilk yardım olarak kullanın.
Ancak unutmayın: çoğaltma bir yedekleme değildir.
Yedekleme ve replikasyonun farklı amaçları vardır. Yanlışlıkla yaptıysanız, soğuk bir yedekleme kullanışlı olacaktır. DELETE
veya DROP TABLE
. Soğuk depodan bir yedekleme yapıyoruz ve bir tablonun veya tüm veritabanının önceki durumunu geri yüklüyoruz. Ama aynı zamanda istek DROP TABLE
çalışma kümesindeki tüm kopyalarda neredeyse anında yeniden üretilir, bu nedenle normal çoğaltma burada kaydedilmez. Çoğaltma, tek tek sunucular kiralandığında veritabanını kullanılabilir durumda tutar ve yükü dağıtır.
Gecikmeli bir çoğaltmada bile, aniden bir veri merkezi arızası, gizli hasar veya hemen fark etmediğiniz başka olaylar olursa, bazen gerçekten güvenli bir yerde soğuk bir yedeklemeye ihtiyacımız olur. Burada bir çoğaltmadan hiçbir anlam yok.
Dikkat. Üzerinde
Kaynak: habr.com