PostgreSQL Mimarisi
PostgreSQL, açık kaynak kodlu bir yazılımdır ve yazılımı geliştirenlerin doğrudan ticari kaygıları bulunmamaktadır. Diğer bir deyişle PostgreSQL, diğer açık kaynak kodlu yazılımlarda olduğu gibi ticari sistemlerin yarattığı konfor alanına ve kullanım kolaylığına maalesef sahip değildir. PostgreSQL’de hangi arka plan proseslerinin çalıştığı, bunların görevlerinin ne olduğu ve birbirleriyle nasıl etkileşim içinde bulunduklarının anlaşılması PostgreSQL’den maksimum seviyede faydalanmak için elzemdir.
PostgreSQL, Oracle ve Microsoft SQL Server gibi ticari yazılımlarla benzer bileşenlere sahiptir. Aynı kavramları ve hatta benzer bileşenleri kullanırlar. Bu nedenle, PostgreSQL bahsi geçen ticari sistemlere yakın bir performans seviyesi sunar. Sonuçta, PostgreSQL olsun, Oracle olsun, Microsoft SQL Server olsun 1980’lerde benzer akademik çevrelerce tasarlanmışlardır. Kavramların sadece isimleri değişmekte ve programlama açısından implementasyonları değişmektedir.
Ancak yine de PostgreSQL’in mimari olarak farklı olduğu noktalar bulunmaktadır. Örneğin, PostgreSQL sunucusu, çok iplikli (multi-thread) bir mimariye sahip değildir ve çok prosesli (multi-process) bir yapısı vardır. Eş zamanlı “transaction”larda ACID kriterlerine uyumlu bir şekilde tutarlı işlemler yapılmasını sağlayan MVCC (Multi-Version Concurrency Control) kavramının implementasyonuna PostgreSQL diğer ticari sistemlere göre farklı yaklaşır. Farklılıkların yanında PostgreSQL’in mimari yapısından kaynaklı üstünlükleri de vardır. Örneğin, PostgreSQL, diğer ticari veritabanlarına göre konteynerlerleştirme konusunda daha başarılıdır, çünkü Direct I/O olarak isimlendirilen ve bir veritabanının işletim sistemini baypas ederek doğrudan diske ulaşmasını sağlayan bir yapısı yoktur. İşletim sistemi üzerinde çalışır ve “lightweight” olması sebebiyle sanallaştırma konusunda çok daha başarılıdır.
Daha önceden de belirttiğimiz gibi, PostgreSQL açık kaynak kodlu bir sistem olarak, kullanan kişilerin sistemi öğrenmelerini ve uygulamalarına göre optimize etmelerini gerektirir. Bu ancak sistem mimarisinin öğrenilmesiyle mümkündür. İşte bu nedenle bu blog yayınımızda PostgreSQL’in mimarisini size anlatmak istedik. Daha sonraki bloglarımızda, PostgreSQL’in nasıl optimize edileceğini anlatacağız.
PostgreSQL prosesleri
PostgreSQL’in içinde ve etrafında dört tip proses bulunmaktadır:
- Postmaster (daemon) prosesi: PostgreSQL başlatıldığı zaman devreye girer. İlk anda gerekirse sistem yedeklerini yükler, ortak bellek alanını ayarlar. Geri planda çalışacak (background) modülleri (buffer manager, lock manager, vd) başlatır. Ardından geri plan proseslerini (background) çalıştırır. 5432 numaralı TCP portunu beklemeye başlar.
- Background prosesleri: PostgreSQL’in işlevini yürütebilmesi için gerekli, geri planda çalışan proseslerdir. Logger, checkpointer, writer (BGWriter), wal writer, autovacuum launcher, archiver, stats collector gibi prosesler PostgreSQL’in işlevleri için gerekli arka plan prosesleridir.
- backend prosesleri: Her bir «backend» proses kullanıcı prosesleri tarafından talep edilen sorguları gerçekleştirir ve sorgu sonuçlarını istemci prosesine gönderir. Postgres prosesi olarak da isimlendirilir.
- İstemci prosesi, PostgreSQL protokolü üzerinden PostgreSQL’e sorgular gönderen bir kullanıcı programıdır. İstemci prosesi bir sorguyu backend prosese gönderir ve gelen sonuçları backend prosesten alır.
İstemciler (clients), «postmaster» adı verilen yönetici (supervisor) prosesine 5432 numaralı porttan bağlanır ve genellikle PostgreSQL bağlantı protokolünü gerçekleştiren libpq adı verilen C kütüphanesini kullanırlar. Ancak, libpq kullanmadan PostgreSQL bağlantı protokolünü doğrudan gerçekleştiren Java JDBC gibi sürücüler de vardır. «postmaster», istemci TCP/IP üzerinden bağlandığında yeni bir «backend» proses başlatır ve istemciyi bu «backend» prosese bağlar. Bu proseslere «postgres» prosesi de denir. Her bir istemciye tahsis edilen ve eş zamanlı olarak işletim sistemi üzerinde çalışan bu «backend» prosesler, birbirleriyle «semaphore» ve «shared memory» üzerinden haberleşerek veri bütünlüğünü sağlarlar.
Resim: PostgreSQL mimarisi
PostgreSQL’de geri planda (background) çalışan önemli prosesler şunlardır:
- logger: hata mesajlarını log dosyasına yazar.
- checkpointer: «checkpoint» durumu gerçekleştiği zaman, tamponda bulunan «dirty» sayfalar diske yazılmaya başlanır. PostgreSQL’de varsayılan olarak verilen 5 dakika süre içinde değişiklik olmuş bütün sayfalar DB dosyalarına yazılmış olur. Eğer bellek miktarı fazlaysa ve shared_buffers parametresi büyükse, checkpoint işlemi sistem performansını olumsuz etkileyebilir.
- background writer: ortak bellek alanındaki «dirty» sayfaları, belirli bir kritere göre (örneğin LRU, vb) periyodik olarak DB dosyalarına yazar. Ortak bellek alanının daha etkin şekilde kullanılmasını sağlar.
- wal_writer: Her bir DB işlemi için bir WAL kaydı oluşturulur ve WAL tamponuna yazılır. wal_writer prosesi WAL tamponlarında bulunan kayıtları WAL dosyasına yazar.
- autovacuum launcher: autovacuum özelliği etkinleştirildiyse, autovacuum prosesini çalıştırır ve ölü kayıtlar sayfalardan temizleyerek istatistiksel bilgileri günceller.
- archiver: WAL dosyalarını belirlenen dizinlere aktarır ve arşivler. Biriken WAL kayıtları, her checkpoint sürecinde geçersiz hale gelir.
- stats collector: veritabanında kullanım istatistiklerini toplar ve pg_stat_activity ve pg_stat_all_tables tablolarını günceller.
Postmaster ne iş yapar?
Postmaster, PostgreSQL mimarisi içinde kümenin ilk çalışan prosesidir. Arka planda çalışan bütün prosesleri başlatır ve istemcilerin bağlandığı ağ portunu da o sağlar. Postmaster’in en önemli işlevlerinden biri, çalışmayan arka plan proseslerini ayağa kaldırmaktır. Aksi belirtilmezse varsayılan port olan 5432 numaralı TCP portunu dinler. Bir istemci, ağ üzerinden bağlandığında postmaster tarafından karşılanır ve bağlantı için görevlendirdiği prosesi başlatarak istemciye bağlar.
PostgreSQL’in bellek kullanımı
PostgreSQL çalışmaya başladığında, Postmaster prosesi işletim sisteminden bellek tahsisi alarak ortak tampon (shared_buffers) bölgesi oluşturur. PGA (Process Global Area) PostgreSQL sunucunun bellek denetleyicisi tarafından yönetilen ve her istemcinin açtığı oturum ile ilgili veri yapılarını (sorgu planları, sıralamalar, vb) tuttuğu bellek alanıdır. Bütün arka plan prosesleri (backend’ler dışında), ortak tampon bölgeden tahsis alır. backend prosesler ise işletim sisteminden dinamik olarak bellek tahsisi talep eder.
PostgreSQL’de postmaster, ilk çalışmaya başladığında ortak bellek alanını (shared buffers) işletim sisteminden talep ederek oluşturur. postgresql.conf dosyasında shared_buffers parametresinde belirtilen rakam ortak bellek alanının büyüklüğünü belirler. Dosyalardan okunan veritabanı sayfaları mümkün olduğunca ortak bellek alanında tutulur ve tablolar üzerinde yapılan işlemlerin ve sorguların en kısa sürede yanıt vermesi sağlanır. shared_buffers parametresi değiştirilirse, PostgreSQL yeniden başlatılmalıdır.
Rezerve edilen ortak bellek alanı ne kadar büyükse, o kadar sayfa bu alanda bulunur ve sorgularda kullanılan sayfalar diskten okumak yerine bellekten tedarik edildiğinden performans artar. Bu alanın bir kısmı da WAL tamponu olarak tutulur. Diğer bir kısım da «commit log»ların (CLOG) tutulması için kullanılır ve o anda gerçekleşen tümleşik işlemlerin bütün durumları saklanır. Ancak, önbellek alanının tüm belleğin %25’inden fazla olması durumunda, işletim sistemindeki diğer proseslere yeterli bellek kalmayabilir. Bu nedenle shared_buffers parametresine en fazla sistemdeki RAM miktarının %25’i atanmalıdır.
Bir backend proses oluşturulduğunda, kendisine lokal bellek olarak bir alan tahsis edilir. Her backend prosese postgresql.conf dosyasında work_mem parametresinde belirtilen kadar işletim sisteminden istenir. Bu bellek miktarı varsayılan olarak 4MB’tır. ORDER BY, DISTINCT ve merge-join gibi işlemlerde yapılan sıralama işlemlerinin sonuçları, hash-join yapıldığında gereken hash tablolar bu bellek alanı içinde tutulur. Fazlası gerekirse, depolama alanında geçici dosyalar kullanılarak bellek eksikliği giderilir. Ancak geçici dosya oluşturup depolama alanında disk I/O işlemi yapılması, sistemin performansını düşürür.
Karmaşık sorgularda, 4MB’lık bellek alanından daha fazla bellek gerekli olacağı açıktır. İstemciler gerekirse, oturum içinde geçerli olacak şekilde «SET work_mem='8MB'» diyerek gereken bellek miktarını 8MB’a artırabilir ve artırdıktan sonra işlemlerini yapabilirler.
Resim: PostgreSQL bellek alanları
PostgreSQL, Oracle ve Microsoft SQL Server mimari farklılıkları
PostgreSQL’in aksine hem MS-SQL hem de Oracle «multi-thread» yazılımlardır. Örneğin Oracle v12’yle birlikte multi-thread yapıya geçmiştir. «multi-thread» yazılımlar, bellek alanını ve genel olarak kaynakları paylaştıkları için, «multi-process» olanlara göre kaynak kullanımı konusunda daha etkin çalışırlar. Ancak, «multi-thread» yapılar bellek ve kaynak kullanımı konularında işletim sistemini daha fazla kullanırlar. Bellek kullanımında, yazılım çalıştığı anda ilk başta ortak bellek miktarını rezerve etmez ve gerektikçe işletim sisteminde alır. Her sorguda ve işlemde bellek tahsisi ve iadesi işlemleri gerçekleştirilir. Bu da veritabanı yönetim sisteminin işletim sisteminin bellek yönetim sistemine bağımlılık yaratır ve işletim sistemine bir ölçüde bağımlılık oluşturur. PostgreSQL, Microsoft SQL Server’ın aksine shared_buffers parametresiyle belirtilen miktarı sunucu çalışır çalışmaz rezerve eder. Microsoft SQL Server’da tampon bellek alanı ilk çalışmaya başladığı zaman yoktur ve gelen sorgulara göre işletim sisteminden dinamik bellek alınarak oluşturulur.
Not: PostgreSQL’in multi-process yapısının bırakılması gündemdedir. multi-thread mimariye nasıl geçirilebileceği konusunda tartışmalar PGCon 2023 konferansı sonrasında gerçekleşmiştir. Bu kadar kapsamlı bir mimari değişikliğin kısa sürede olmayacağı açıktır ama yazılımı geliştirenlerin konuşmaya başlamaları sürecin de başladığını ima etmektedir.
Linkler
https://docs.oracle.com/en/database/oracle/oracle-database/12.2/ntqrf/processes-and-threads.html
https://www.yugabyte.com/postgresql/postgresql-architecture/
https://severalnines.com/blog/architecture-and-tuning-memory-postgresql-databases/
https://www.highgo.ca/2020/06/18/an-overview-of-postgresql-backend-architecture/
https://www.postgresql.org/docs/16/index.html