Skip to content

PostgreSQL'de WAL Kavramı

Bu yazıda, PostgreSQL'in transaction loglama konusuna yaklaşımını gösteren WAL kavramını inceleyeceğiz.
Bu bölümün hazırlanmasında son 11 yıldır geliştirici listesindeki birçok e-postayı taradım de bilgileri bir araya getirdim.

PostgreSQL'de WAL kavramı

WAL (Write Ahead Logging), PostgreSQL'de transactionların kaydedilmesi işlemidir. WAL ile ilgili bazı bilgilere aşağıda ulaşabilirsiniz. Yazıda transaction loglara xlog da denecektir.

WAL PostgreSQL'in gömülü bir özelliğidir -- açılıp kapatılabilen birşey değildir. Transaction logları PostgreSQL'de veri dizininin altındaki pg_xlog dizininde tutulur. Her bir transaction log dosyası 16 MB'lık yer tutar. Bu alan, xlog boş ya da dolu olsa da dosya sistemi üzerinde ayrılır.

Xlog dosya adları 24 karakterden oluşur ve değerler hexadecimal olarak tutulur. İlk 8 karakter timeline bilgisini verir. Sonraki 16 karakter ise WAL idsini verir. Örnek:

00000001000000000000003F

Koyu kısım timeline id'yi belirtir. Her bir PITR işleminden sonra bu sayı bir artar.

PostgreSQL'in transactionları commit etme şekli nedeniyle, en çok I/O işlemi bu dizinde olur. Bu nedenle pg_xlog dizinini ayrı bir diskte tutmak önemlidir. WAL bize bir sistemi kurtarmak için bilgileri vereceğinden bu dosyaların güvenli bir ortamda tutulması (RAID?) çok önemlidir.

Peki nedir bu transaction commit etme şekli? PostgreSQL'de bir istemci bir commit mesajı gönderdiğinde, xloga transaction bilgisi yazıldığında PostgreSQL istemciye onay mesajını gönderir. Transaction ile değişen verinin diske yazılmasına gerek yoktur. Bunu bgwriter ve checkpoint süreçlerı zaten yapar. Olası bir sorunda bile xloglar replay edilip sunucu düzgün bir halde açılabilir.

Her bir checkpoint işleminden sonra transaction log dosyası sıfırlanır ve checkpoint ile ilgili bilgiler pg_control dosyasında saklanır. PostgreSQL belgelerinde de belirtildiği gibi, recovery işlemi yapılacağında sunucu öncelikle pg_control dosyasını ve checkpoint kaydını okur -- ve checkpoint kaydından sonraki transactionları aşağıda ayrıntılarını yazdığım REDO işleminden geçirir. pg_control dosyasının sağlam kalması bu açıdan çok önemlidir. pg_control dosyasının bozulması durumunda PostgreSQL mevcut log segmentlerini ters sırada (yeniden eskiye) okunması ve son checkpoint kaydının bulunması özelliği şu anda PostgreSQL'de yoktur. pg_control dosyası 8kB civarındadır.

Bu dosyanın zarar görmesi verilerin silinmesine neden olabilir.


UNDO ve REDO

Peki, UNDO ve REDO nedir?

Öncelikle PostgreSQL 8.0'dan önceki durumu inceleyelim ve WAL kavramını açalım:

Üstte de belirttiğimiz gibi, 7.1 sürümü ile birlikte PostgreSQL'e WAL (Write Ahead Logging, xlog olarak da bilinir) eklenmiştir. PostgreSQL'de transactionlar, o transaction commit edilmeden hemen önce diskte transaction loguna yazılırlar (xlog, WAL). Bu dosyaların boyutu ön tanımlı olarak 16 MB'tır (bu değer derleme aşamasında değiştirilebilir). WAL sayesinde disk işlemlerinin sayısı azalmaktadır; çünkü diskteki veri her transactionda değil; belirli aralıklarla değişir. WAL yapılandırması ile ilgili ayrıntıları kitabımızın “Başarım” ile ilgili bölümünde bulabilirsiniz.

xloglar, bilinen bir başlama noktasından veri kurtarmak için gerekli olacak tüm bilgileri sağlar. Bu işleme REDO işlemi denir. Bu bilinen başlama noktaları, biten transactionların kaydedildiği ve clog adı verilen yerde tutulur. Cloglar transactionlar commit edildikten hemen sonra diske yazılırlar. Xloglar pg_xlog, cloglar da pg_clog dizini altında bulunur.

PostgreSQL'de değişen veri sayfaları (data pages) anında diske yazılmazlar; çünkü xlog ve clog içindeki bilgiler verinin kurtarılması zaman gereken her şeye sahiptir. Belirli zamanlarda, değişmiş (dirty-kirli olarak da adlandırılır) veri sayfalarının diske yazılması için checkpoint işlemi gerçekleştirilir. Checkpoint işlemi tamamlandığında, xlog içine son transaction numarasını bir işaretçi olarak yazar ve clog dosyalarını son transaction idsine kadar ilerletir. Değiştirilmiş veri sayfalarının diske yazılması, bgwriter (lazy writer olarak da bilinir) aracılığı ile gerçekleştirilir. bgwriter süreci arka planda gerçekleşir; böylece yoğun veritabanı sunucularında checkpoint işlemlerinin etkisi azaltılmış olur.

Veri kurtarmada, veritabanı dosyalarının eksiksiz olduğu kabul edilir; ancak bu dosyaların güncel olmasına gerek yoktur. postmaster süreci tekrar çalışmaya başladığında, clog içinden arama yapar ve checkpoint yapılan son transaction numarasını bulur. Bu veriyi kullanarak, mevcut xlog dosyaları arasında bir arama yapar. Eğer clog içindeki id, xlog içindeki id'den küçükse, postmaster süreci kalan transactionları da REDO işleminden geçirir ve böylece sistem olası olan en uygun hale gelmiş olur.

Eğer uygun xlog dosyaları yoksa, veri kurtarmak mümkün olamayacaktır.

Initdb sürecinden hemen sonra en az 1 tane xlog yaratılır. xlog içine yeni veriler yazıldıkça, gerekli oldukça yeni xlog dosyaları yaratılacaktır. Checkpoint işleminin sonucu olarak, checkpoint işleminden sonra xlogların gerek duyulmadığı zamanlar olacaktır. Her bir checkpointte, eğer artık gereksinim duyulmayan bir xlog bulunursa, bu xlog ya kaldırılacak ya da bu xlogun üzerine yeni veriler yazılacaktır. xloglar “sıranın” önüne getirileceklerdir; böylece veritabanı yöneticileri bu dosyaları silmek ya da kaldırmak zorunda kalmayacaktır. Belirli miktarda dosya önceden ayrılmış loglar olarak saklanacaklardır; bu miktar önceden kontrol edilebilmektedir. Bu sınıra erişildiğinde, xloglar yeniden başa döndürülmek yerine silineceklerdir. Bunun sonucu olarak, xlogların sayısı zaman içinde değişebilir.

Eğer bir xlog, ilgili disk bölümünde boş yer kalmaması nedeniyle yazılamazsa, xloga bağlı olan transaction (ya da ona bağlı olan diğer tranactionlar), disk sorunu çözülene kadar commit edilemeyecektir. Mevcut durumda bu durum transactionları, pg_xlog dizinindeki yer kadar sınırlamaktadır.

Xloglar göreceli olarak cloglara göre çok daha fazla yer kaplarlar. Clog dizini içinde boş yer kalmaması durumu beklenen birşey değildir.

İşte bu üstte anlatılanlar REDO işlemidir. PostgreSQL 7.1'den 8.0'a kadar geçen sürede üstteki bilgiler geçerli idi. 8.0'dan sonra REDO işleminin yanı sıra UNDO işlemi de PostgreSQL'e eklenmiştir.
Şimdi başarısız olabilecek durumların bir analizini yapalım:

- Bir transaction başarısız olursa, xlog'a birşey yazılmaz ve clog girdisi başarısız olan son transaction id' sini gösterir.

- Eğer bir transaction başarılı olursa, değişiklikler xlog'a kaydedilir ve clog girdisi başarılı olan son transaction id'sini gösterir.

- Eğer xlog dizini dolarsa ya da başka bir nedenden dolayı yazılamıyorsa (dizin izinlerinin
değiştirilmesi gibi...) PANIC hatası verilir.

- Eğer clog dizini dolarsa ya da başka bir nedenden dolayı yazılamıyorsa (dizin izinlerinin
değiştirilmesi gibi...) PANIC hatası verilir.

Burada ilginç olabilecek bir bilgi vermek istiyorum: Kurtarma durumunda WAL kayıtları salt okunur moddadır -- kesinlikle WAL içine veri yazılamaz. Ancak kurtarma modunda değilse WAL sadece yazılabilir.

WAL ayarlanması

Kaynak: PostgreSQL belgeleri


postgresql.conf içindeki bazı parametreler ile WAL ayarlamalarını yapabilirsiniz. Bu parametreler ve kısa açıklamaları şunlardır (parametreleri postgresql.conf'daki sıra ile anlatıyorum):

fsync: Boolean değer alan (on/off) bu parametre ile PostgreSQL'in WAL işlemlerini diske wal_sync_method ile belirtilen sistem çağrısı ile yapıp yapmayacağını belirtebilirsiniz. fsync komutunun güvenilirlik ve başarım ile ilgili klasik terazi sorunu vardır. fsync parametresi açık (on) olduğu zaman WAL dosyaları işletim sistemi tarafından anında diske yazılır. Bu parametre kapalı olduğunda, işletim sistemi transaction logları tamponunda saklar ve belirli aralıklarla yazar. Ancak bu bir veri kaybı riski getirir: Olası bir elektrik kesintisinde, vs, henüz diske commit edilmemiş transactionlar varsa onlar kaybolur. PostgreSQL belgelerinde de yazıldığı gibi işletim sistemi seviyesindeki çökme nedeniyle veri kaybolabilir -- PostgreSQL'in çökmesinde veri kaybı olmaz. Bu parametreyi açık tutmak veri bütünlüğü için önemlidir.

synchronous_commit: on, off, local ve remote_write değerlerini bu parametre ile WAL kayıtlarının diske bir miktar gecikmeli yazılmasını sağlayabilirsiniz. Öntanımlı değeri on'dur. Bu parametreyi kapattığınızda, okuma işlemlerinin çok ağırlıklı olduğu veritabanlarında bir miktar kaybı göze alıp önemli bir başarım artışı sağlayabilirsiniz. Off olunca, istemciye onay döndürülmesinden sonra transaction xlog'a gerçekten yazılır. Gecikme süresi en fazla wal_writer_delay değerinin 3 katıdır. Bu gecikme sıralı olacağı için, çökme durumunda veritabanı bütünlüğü bozulmaz. Sadece veri kaybı olur. PostgreSQL 9.1 ile birlikte gelen “synchronous replication” özelliği ile birlikte bu parametrenin en bir özelliği daha olmuştur. Senkron replikasyonu etkinleştirmek için kullanılan synchronous_standby_names parametresi, synchronous_commit parametresinin de on olması ile anlamlıdır. Eğer bu değer remote_write olursa, o zaman transaction bilgisinin standby sunucuda OS buffer'lara yazılması yeterlidir – transaction commit edilmiş sayılır. Bu durumda, PostgreSQL standby sunucuda çökse de veri kaybı olmaz, ama işletim sistemi çökerse veri kaybı kaçınılmaz olur.

wal_sync_method : WAL güncellemelerinin diske hangi yöntemle yapılacağını belirtir. fsync=on olduğu zaman kullanılır. Linux' da kullandığınızda fdatasync ilk parametredir. Solaris' deyse open_datasync ilk parametredir. Bunun dışında 3 parametre daha vardır.

full_page_writes : Öntanımlı olarak on'dur. Veri güvenliği nedeniyle bu şekilde kalması gereklidir.

wal_buffers: WAL verisi için shared_buffers içinde kullanılan bellek miktarıdır. Bu değer, bir transaction tarafından üretilen WAL verisi kadar olmalıdır. 9.1 sürümü itibariyle öntanımlı değeri -1'dir, ve shared_buffers değerinin %3'üne karşılık gelir. Buna “otomatik wal buffer yönetimi” denir.

wal_writer_delay: milisaniye olarak belirtilebilen bir değerdir. 1 ile 10000 ms arasında olabilir. WAL writer sürecinin “uyuma” sürecini ayarlar. Belirtilen süre boyunca WAL writer süreci uyur, ve ertesinde WAL bilgisini diske yazar. Öntanımlı değer 200 milisaniyedir. PostgreSQL belgelerinde de belirtildiği gibi birçok sistemde bu uyku süresinin efektif değeri 10 milisaniyedir. Bu nedenle, bu parametreyi 10 saniye ve katlarına ayarlanmadığında PostgreSQL bunu 10'un bir üst katına tamamlayacaktır (194 ms - > 200 ms olacaktır). Bu parametrenin restart gerektirdiğini unutmayın.

commit_delay: Mikrosaniye cinsinden belirtilen bu değer, bir commit kaydının WAL tamponuna yazılması ve bunun diske yazılması arasındaki bekletme süresini gösterir. Bu sürenin artması ile birçok transaction aynı anda diske yazılabilirler (fsync) . Yoğun sistemler/saatler için bu değerin artması iyi olabilir. Ancak az transaction olan saatlerde / veritabanı sunucularında bu değerin yüksek olması transactionların geç commit edilmesine neden olabilir. Bu nedenle, bu süre eğer aşağıda yazdığım commit_siblings kadar açık transaction, sunucunun commit kaydını yazdığı zaman anında etkin ise geçerli olur. Öntanımlı değeri 0 ms'dir.

commit_siblings : commit_delay parametresinde belirtilen gecikme süresinin uygulanabilmesi için gereken en az sayıda eşzamanlı açık transaction sayısını gösterir. Yüksek değerlerde en az bir tane daha transactionın commit_delay süresinde commit için hazır olacağını söyleyebiliriz.

Trackbacks

No Trackbacks

Comments

Display comments as Linear | Threaded

No comments

Add Comment

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.
E-Mail addresses will not be displayed and will only be used for E-Mail notifications.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA


To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Form options