PostgreSQL: Artık VACUUM da yok, Bloat da
(orioledata.com)- PostgreSQL için geliştirilen yeni depolama motoru OrioleDB, yoğun kaynak tüketen VACUUM sürecini ortadan kaldırıyor ve tablo bloat sorununu çözüyor
- Mevcut PostgreSQL, MVCC yapısı nedeniyle manuel vacuum ve autovacuum gerektiriyor; her iki yöntem de önemli ölçüde sistem kaynağı tüketiyor
- OrioleDB, satır ve blok düzeyinde undo log ile otomatik sayfa birleştirme sayesinde veri değişikliklerini verimli şekilde işliyor ve parçalanmış verileri birleştiriyor
- Sentetik benchmark'larda, yalnızca tek bir indeksin güncellenmesi, seyrek sayfaların otomatik birleştirilmesi ve satır düzeyinde WAL kullanımıyla 5 kat daha yüksek TPS ve kaynak tasarrufu sağlandı
- VACUUM gibi uzun süredir devam eden bir sorunu çözerek bakım yükünü azaltıyor ve PostgreSQL'de performans ile kullanıcı deneyimini iyileştiriyor
PostgreSQL VACUUM'un tarihi ve sınırları
- VACUUM süreci, Berkley Postgres projesindeki infinite time-travel kavramından doğan tarihsel bir miras ve bu kavram daha sonra topluluk tarafından terk edildi
- Ancak bu durum, tablo bloat'a açık bir MVCC(Multi-Version Concurrency Control) sistem uygulamasına yol açtı
- MVCC, eşzamanlı işlem yürütme için avantajlı olsa da eski ve gereksiz verileri temizlemek için manuel vacuuming ihtiyacını beraberinde getirdi
- Manuel vacuuming emek yoğun bir iş ve sistem verimsizliğinin potansiyel bir nedeni
- Daha sonra bu manuel yükü azaltmak için otomatik autovacuum devreye alındı
- Bu büyük bir ilerlemeydi, ancak kusursuz bir çözüm değildi; otomatik olmasına rağmen yine de ciddi sistem kaynağı tüketiyordu
- Bu, Uber'in PostgreSQL'den MySQL'e geçiş nedenlerinden biriydi ve Richard Branson'ın PostgreSQL ile ilgili saydığı 10 şikâyetten biri olarak anıldı
- Heap-Only Tuples(HOT) güncellemeleri ve microvacuum'un devreye girmesiyle tüm tabloyu vacuum etme ihtiyacı azaldı
- Buna rağmen VACUUM hâlâ kaynak yoğun bir işlem olarak kaldı ve tablolar bloat'a karşı savunmasız olmaya devam etti
- Bu durum, OtterTune ekibinin en sevmediği PostgreSQL yönlerinden biri olarak anıldı
- Bu sınırlara rağmen sağlamlık, ölçeklenebilirlik ve güçlü topluluk gibi nedenlerle çok sayıda kurum ve geliştirici PostgreSQL kullanmayı sürdürdü
- OtterTune da sorunu kabul etmesine rağmen PostgreSQL kullanmaya devam etmeye karar verdi
OrioleDB'nin temel özellikleri
- OrioleDB, tabloları bloat'tan korumayı ve VACUUM gibi düzenli bakım ihtiyacını ortadan kaldırmayı ana hedef olarak geliştirilmiş yeni bir PostgreSQL motoru
- Bunu satır düzeyi ve blok düzeyi undo log ile otomatik sayfa birleştirme üzerinden gerçekleştiriyor
- Satır ve blok düzeyindeki undo log, daha ince taneli denetim sağlayarak veri değişikliklerini daha verimli işlemeyi mümkün kılıyor
- Otomatik sayfa birleştirme özelliği, arka planda parçalanmış verileri sürekli olarak birleştiriyor
- Her tekniğin çalışma biçimi
- Satır düzeyi undo log, in-place güncellemelere izin veriyor
- Blok düzeyi undo log, silinmiş ancak bazı işlemler için hâlâ görünür olan tuple'ları ana depolamadan kaldırarak yeni tuple'lar için alan açıyor
- Seyrek sayfaların otomatik birleştirilmesi, çok sayıda silme işleminden sonra bile tablo ve indeksleri bloat'tan koruyor
- Sonuç olarak manuel müdahale azalıyor, kaynak tüketimi düşüyor ve tabloların bloat'a açıklığı azalıyor
Benchmark'lar
- Bir tablo ve beş indeks oluşturan başlatma betiğiyle sentetik benchmark kurgulandı
idbirincil anahtarı ilevalue1~value4(float8) vets(timestamp) sütunlarına sahiptesttablosu oluşturulduvalue1,value2,value3,value4,tsalanlarının her biri için indeks oluşturuldu
- pgbench betiği, çakışma durumunda tek bir indeksi seyrek biçimde güncelleyen bir upsert yapısına sahip
- 1~10,000,000 aralığında rastgele
iddeğerleriyle INSERT yapılıyor, çakışma olursa yalnızcatsgüncelleniyor - Bu seyrek güncelleme, normal heap PostgreSQL tablolarında indeks bloat'ına yol açıyor
- 1~10,000,000 aralığında rastgele
- Bu benchmark'ın gösterdiği OrioleDB tasarım avantajları
- Undo log ve in-place güncellemeler sayesinde OrioleDB yalnızca değişen değere ait tek indeksi güncelliyor; buna karşılık PostgreSQL heap motorunda tek bir indeks alanının güncellenmesi HOT'u etkisiz kılıyor ve tüm indeksler güncelleniyor
- Otomatik sayfa birleştirme, seyrek indeksleri bloat'tan koruyor ve seyrek sayfalar otomatik olarak birleştiriliyor
- Satır düzeyinde WAL, blok düzeyindeki WAL'a göre çok daha az yer kapladığı için WAL yazımında IOPS tasarrufu sağlıyor
- Kümülatif iyileştirmelerin sonucunda OrioleDB'nin sunduğu değerler
- İşlem başına 5 kat daha yüksek TPS
- İşlem başına 2.3 kat daha düşük CPU yükü
- İşlem başına 22 kat daha düşük IOPS
- Tablo ve indeks bloat'ı yok
OrioleDB'nin önemi
- OrioleDB'nin kullanıma girmesiyle PostgreSQL topluluğu, VACUUM'un geçmişte kaldığı yeni bir döneme giriyor
- PostgreSQL'in en eski sorunlarından birine çözüm sunarak kullanıcılara daha yüksek verimlilik ve daha düşük bakım yükü sağlıyor
1 yorum
Hacker News yorumları
Yine de birkaç çekincem var. Satır düzeyinde işleme, yazma sıralaması ve fsync sıralaması sorunları yaratıyor; sayfaları sıralamak, rastgele boyutlu satırlardan daha kolay.
PostgreSQL veri güvenliği konusunda çok, hatta belki aşırı derecede muhafazakar; bunu da büyük ölçüde doğru anda yapılan fsync ile sağlıyor ve bunun etkisi SSD firmware'i de dahil olmak üzere tüm I/O yığınına yayılıp sistemi yavaşlatıyor.
MVCC eşzamanlı erişim için çok iyi, ancak Oriole dokümanı grafiklerin hangi eşzamanlılık koşullarında elde edildiğini söylemiyor.
Oriole dokümanının başlığı ve girişi VACUUM sorununu çözmeye odaklanıyor, ancak PostgreSQL'de görülen “kare dalga” grafiğinin gerçekten çoğunlukla VACUUM'dan kaynaklandığını kanıtlamış gibi görünmüyor. Percona'nın başka benchmark'ları (https://www.percona.com/blog/evaluating-checkpointing-in-postgresql/) bu kadar belirgin bir kare dalga deseni göstermiyor.
Yazarlar da muhtemelen bu sorunların farkındadır; bu konuya nasıl yaklaştıklarına dair bir özet yazabilirlerdi.
https://github.com/orioledb/orioledb/blob/main/doc/arch.md
PostgreSQL'in veri güvenliği konusundaki muhafazakar yaklaşımı nedeniyle ilk hedef saf bir extension olmak. PostgreSQL'in bir parçası haline gelmesi için zaman içinde kendini kanıtlaması gerekiyor.
Eşzamanlılık bilgisinin eksik olduğu doğru; blog yazısına VM türü ve eşzamanlılık bilgileri eklendi.
Kare dalga deseni gerçekten checkpoint'lerden kaynaklanıyor. Buradaki iyileşmenin nedeni aslında VACUUM değil; yalnızca ilgili indekslerin güncellenmesi yaklaşımı ve toplam I/O'yu azaltan satır düzeyinde WAL.
Etkileyici ama bunun ana projenin sürüm döngüsüne nasıl ayak uydurmayı planladığını merak ediyorum.
Büyük bir açık kaynak projeyi fork edip üstüne ciddi değişiklikler eklemişsiniz; bu değişikliklerin upstream'e kabul edilmeyeceğini düşünüyorsanız bunun iyi bir fikir olup olmadığından emin değilim.
Bunun eğlence için yapılmış bir oyuncak mı yoksa ileride sürdürülecek ciddi bir proje mi olduğu net olmalı.
Ciddi bir projeyse, gelecekte terk edilmiş bir yazılıma dönüşmemesi için planını, asıl projenin ilerideki sürümlerini içine alma planını ya da tamamen ayrı bir proje olarak ayrılma planını açıkça belirtmeli.
Extension olduğu için PostgreSQL upstream değişikliklerini alabilecek gibi görünüyor ama bu kolay olsaydı zaten en başta PostgreSQL projesinin bir parçası olurdu; dolayısıyla o kadar kolay görünmüyor.
“Evet. Ama önümüzde uzun bir yol var. Şu anda OrioleDB, PostgreSQL core patch'leriyle birlikte gelen bir extension. Orta vadeli hedef OrioleDB'yi saf bir extension haline getirmek, uzun vadeli hedef ise OrioleDB'yi PostgreSQL core'unun bir parçası yapmak.”
Bir dahaki sefere en baştan bu kadar sert girmemek daha iyi olabilir.
https://news.ycombinator.com/item?id=36742001
Düzeltilmiş bir örneği görmek başlı başına kesinlikle faydalı. Postgres fork'unu sürdürecek kaynaklara sahip bir şirket için güzel olabilir; yoksa bu fork'u kullanmanın zorluklarının performans kazancına değip değmeyeceğini değerlendirmek gerekir.
“Uber, Postgres'ten MySQL'e geçti” türü söylemlerin artık bırakılmasını isterim. Uber, ilişkisel veritabanı olarak kullandığı Postgres'ten, MySQL'i dağıtık anahtar-değer deposu olarak kullanan fiilen kendi ilişkisel olmayan veritabanına geçti; yani bu durum çoğu Postgres kullanıcısına doğrudan uygulanabilir değil
Her hâlükârda eski verileri undo log/segment'lere taşıyan bu tür MVCC tasarımı Oracle DB'de de kullanılıyor; dolayısıyla çalışma şekli doğrulanmış durumda
Ortak zorluk, eski veri sürümlerini okumanın yavaşlamasıdır. Bunları log'dan bulmak gerekir ve bazen transaction bitmeden önce veri log'dan kaldırılabildiği için meşhur Snapshot Too Old hatası ortaya çıkabilir
Yazıda satırların undo log'dan ne zaman kaldırıldığını göremedim. Artık gerek kalmadığında kaldırılıyorlarsa benzer miktarda bakım işi gerekecek gibi duruyor; iyileşmenin tam olarak nereden geldiğini anlayamıyorum. Oracle'daki gibi alanı tükenebilen bir halkasal tamponsa, yüksek yazma yükünde uzun süren transaction'lar başarısız olmaya başlar; bu da oldukça can sıkıcıdır
“Bakım işi” ile tam olarak ne kastedildiğine bağlı. İş yükü açısından bakarsak, eski undo kayıtları dosyaları unlink ederek çok ucuza toplu halde silinebildiği için burada bir iyileşme var. VACUUM taraması gerekmiyor
Alan kullanımı açısından bakarsak, aynı sayıda sürümün aynı miktarda alan kaplaması doğrudur. Ancak eski satır sürümlerini ayrı depoda tutmak, ana deponun uzun vadede bozulmasını önleyebilir. OrioleDB ayrıca seyrek sayfaların otomatik birleştirilmesini de uyguluyor
OrioleDB, undo log için bellekte bir halkasal tampon uyguluyor. Halkasal tampon tüm undo kayıtlarını taşıyamazsa en eski kayıtları depolamaya boşaltıyor. Şu anda undo log boyutuna bir sınır koymuyor ve kayıtları herhangi bir transaction ihtiyaç duyabileceği sürece tuttuğu için “Snapshot Too Old” hatası oluşmuyor
Yine de undo boyutunu sınırlandırabilmek için Oracle tarzı bir hatayı isteğe bağlı olarak uygulamayı değerlendirebiliriz. GitHub'daki mimari belgesine de bakmak faydalı olabilir
https://github.com/orioledb/orioledb/blob/main/doc/arch.md
Elbette MySQL, eşzamanlılık konusunda büyük tavizler vererek VACUUM'dan kaçınıyor
Başlık umut vericiydi ama ilk izlenimim bunaltıcı oldu. GitHub'daki ana README[1] bana kurumsal pazarlama metni gibi geldi
Şimdiye kadar anladığım kadarıyla OrioleDB, PostgreSQL için yeni bir depolama motoru; PostgreSQL “en sevilen” veritabanı; OrioleDB, başka uzantıların üzerine kurulan bir uzantı; ve OrioleDB bulutun kapılarını açıyor
Kripto para ve Web 3.0 dolandırıcılıkları dönemi geçtikten sonra, PostgreSQL gibi önemli bir şeyi genişletip iyileştiren bir projeyi tanıtırken böyle bir yaklaşımın kullanılmayacağını düşünürdüm
[1] https://github.com/orioledb/orioledb
Bundan daha açık yazmak zor gibi geliyor. Table access method, zheap gibi alternatif depolama biçimlerini veya sütun odaklı depoları desteklemek için PostgreSQL'e eklenmiş bir özelliktir
Buna değinmek önemli. Çünkü üzerine alternatif veri depolama sistemi eklenmiş epey çok PostgreSQL fork'u var; OrioleDB ise çatallanmış bir PostgreSQL yerine, fork edilmemiş PostgreSQL üzerinde uzantı olarak çalışacak şekilde tasarlanmış. Henüz tamamen öyle değil ama yön o tarafta
PostgreSQL'e aşinaysanız README oldukça açık görünüyor
Oriole'un tasarımı, transaction farkındalığı olan indeksler ve noktasal giriş silmeyi gerektiriyor gibi görünüyor; bunun da ayrı bir maliyeti var
Örneğin uzamsal indeksler için GiST karşılığının, her indeks tuple'ının konumunun tam olarak belirlenememesi nedeniyle bakımı zahmetli olabilir gibi duruyor; tam metin arama indekslemesi için GIN karşılığı ise posting tree sıkıştırması zayıflayacağı için çok büyüyebilir
Ayrıca index-organized table kullanılan bir durumda BRIN karşılığının nasıl uygulanacağını hayal etmekte zorlanıyorum. BRIN, ilgi çekici veri olmadığında fiziksel tablodaki büyük aralıkların sorgu sonucundan hızla elenmesini sağlar. Birincil anahtar aralığına göre partition yapılabilir ama birincil anahtarın değer yoğunluğu zamana ve değer aralığına göre ciddi biçimde değişebilir
Bu daha karmaşık ama çok faydalı indeks yöntemlerini nasıl uygulamayı planladıklarını merak ediyorum
Ayrıca sıralama kuralları, yani collation değiştiğinde ortaya çıkabilecek sorunlar var. Postgres'in heap'i ve VACUUM'u sıralama düzenini bilmediği için, collation değişiminden sonra yanlış yerde duran satırları silip yeniden ekleyerek ve sonunda VACUUM'un bozuk tuple'ları temizlemesine bırakarak hasarı çoğu zaman gidermek mümkün olabiliyor
Oriole'da ise silinmesi gereken özgün tuple'ı noktasal aramayla bulmak zor göründüğünden bunu yapmak güç olabilir; bilinen indeks bozulmalarını düzeltmek için tüm indeksin yeniden oluşturulması gerekebilir, bu da bakım yükünü epey artırıyor gibi görünüyor
GIN benzeri işlevde posting list sıkıştırması hâlâ mümkün. Olası seçeneklerden biri, undo kayıtlarını tek bir posting list öğesine değil tüm posting list'e bağlamak
BRIN için, index-organized table kullandığımızdan doğrudan bir karşılık oluşturmak mümkün görünmüyor. Yine de birincil anahtarın iç sayfalarındaki union key ile ilginç şeyler yapılabilir
Collation konusu doğru ve ciddi. GA'ya geçmeden önce collation farkındalığı olan tüm indeksleri belirli bir libicu collation version'ına sabitlememiz gerekecek gibi görünüyor
Yazının mantığı da ikna edici ve benchmark'lar da performans iddialarını destekliyor gibi görünüyor, ancak önerilen yeni depolama motoru olan OrioleDB ile PostgreSQL'in kendisi arasındaki ayrımı tam anlayamadım
Ticari motivasyon ve yazıda ele alınan yeniliklerden gelir elde etme isteği dışında, bu iyileştirmeleri upstream'e katkı olarak vermek yerine neden OrioleDB adlı yeni bir veritabanı olarak pazarlamak gereksin?
Ancak OrioleDB'deki değişiklikler kademeli olarak eklenemeyecek kadar büyük. Bu yüzden mevcut PostgreSQL motoru, yani heap'in yanı sıra çeşitli alt sistemleri de içeren yapı ile OrioleDB'yi karşılaştırıyorlar
Ayrıntılar için özellikle https://www.socallinuxexpo.org/sites/default/files/presentations/solving-postgres-wicked-problems.pdf içindeki 9-11. slaytlara bakılabilir
Eğer bu bir motor eklentisiyse, diğer eklentilerle birlikte kullanıldığında bir etkisi olup olmadığını merak ediyorum. Örneğin timescaledb[0], alt tablolarda çalışıyor
Böyle yapıldığında nasıl bir sonuç doğacağını merak ediyorum
create table xyz(...) using orioledb;select create_hypertable(xyz, ts);[0] https://github.com/timescale/timescaledb
OrioleDB'nin kararlı bir on-disk format vaat ederek Postgres major sürümleri arasında yükseltme prosedürü gereksinimini ortadan kaldırmasına ilgi var mı? Bu sorunu çözmek için bir fırsat gibi görünüyor
Yeni tipler ve bunları destekleyen fonksiyonların eklenmesi gibi değişikliklerin bir yükseltme prosedürüyle yerleştirilmesi gerekir. Katalog tablolarındaki sütun düzenini değiştiren başka katalog değişiklikleri de vardır; bu durumda da sürümler arasında saklanan veriyi güncelleyecek bir prosedür gerekir
Yükseltme prosedürü olmadan katalog değiştirilemez. Bu yüzden PostgreSQL'de yalnızca minor sürüm yükseltmeleri sadece binary değişimiyle mümkündür ve sorunsuz şekilde güvenli rollback yapılabilir
Eğer yükseltmeler yalnızca dahili API, planner ve executor değişiklikleriyle sınırlı kalsaydı, geliştirme ciddi biçimde kısıtlanırdı. OrioleDB'nin bu yükseltme prosedürü ihtiyacını ortadan kaldırması zor görünüyor
Cluster yükseltme işinin çoğu katalog tablolarının yeniden yazılmasından kaynaklanıyor. Ayrıca çoğu iş yükünde pg_upgrade çok hızlı olduğu için, büyük kazancın tam olarak nerede olacağını da pek göremiyorum
“İşlem başına CPU ek yükünde 2,3 kat azalma” ifadesi biraz rahatsız edici. Postgres'te CPU kullanımı %5 ile %65 arasında dalgalanırken Oriole sürekli %90'da kalıyor
Öngörülebilirlik iyi ama düşük aralığı %85 kadar yukarı çekmek de epey kaygı verici bir şey gibi görünüyor
İyi haber şu ki daha güçlü bir CPU ile dikey ölçekleme yaparsanız Oriole'da daha fazla performans elde edebilirsiniz. Buna karşılık Postgres aynı şekilde ölçeklenmeye devam etmeyecektir
Masaüstü işletim sistemi açısından bakarsanız Postgres sunucusunun boşta kalan zamanını başka şeyler için kullanabilirsiniz ama sunucularda genelde tek bir iş yapılır ve o işe optimize edilmiş bir makine istenir
TPS düşürülürse CPU da orantılı olarak düşecektir; burada amaç ne kadar yükseğe çıkabildiğini göstermek gibi görünüyor
Sistemi %60 CPU ile sınırlandırırsanız toplam rakamlar değişebilir ama aynı kullanımda TPS 1,8 kat ise yine de kazanımdır. Pazarlama hilesinden çok oldukça iyi bir sayı gibi görünüyor
Pahalı bir sunucu CPU'su birim başına X dolar ise ve bunun yalnızca %60'ını kullanabiliyor, pratikte de ancak o kadarını kullanabiliyorsanız, birim başına 0,4X doları yakıyor sayılırsınız
İş yükünü dikey olarak taşıyıp tek bir makineyi %90'a kadar doyurabiliyorsanız, genelde QoS ve izolasyon tekniklerini uygulayarak daha düşük doygunluk ve oransal performansı korumak daha kolaydır. Tersi geçerli değildir. Tüm makine doygunluğunun yalnızca %60'ını kullanabiliyor ve scale-out yapmak zorundaysanız, %90+'a çıkmak için yeniden tasarım gerekir; burada olan da tam olarak bu yeniden tasarım
İyileştirmelerin kümülatif sonucu olarak OrioleDB'nin 5 kat daha yüksek TPS, işlem başına 2,3 kat daha düşük CPU yükü, işlem başına 22 kat daha düşük IOPS ve tabloyla indekslerde şişme olmaması sunduğu söyleniyor
CPU yükünün dalgalanması Postgres'in “ölçeklenmesi” değil, düzenli olarak performans darboğazına girmesidir. Muhtemelen VACUUM çalıştırma ihtiyacından kaynaklanıyor ve bu I/O'ya çok duyarlı
Bu yüzden Postgres sorguları işlemek için I/O kullanmak yerine temizlik işi için I/O harcıyor; TPS ile CPU kullanımı da birlikte sert şekilde düşüyor
Buna karşılık Oriole çok daha yüksek iş hacmini çok daha tutarlı biçimde yönetiyor. Gaza bastığınızda sürekli 100 mph giden bir araba mı, yoksa pedala sonuna kadar basılı olmasına rağmen 40 ile 70 mph arasında şiddetle gidip gelen bir araba mı tercih edersiniz?
Yazıda “Richard Branson'ın PostgreSQL hakkında sevmediği 10 şey” başlıklı oldukça ilginç bir bağlantı var. Meğer o blog yazısını yazan kişi Richard değil, Rick Branson imiş
Aa, o kişi değilmiş