1 puan yazan GN⁺ 4 시간 전 | 1 yorum | WhatsApp'ta paylaş
  • ClickHouse Managed Postgres, tek iş parçacıklı PgBouncer'ın tek bir CPU çekirdeğine takılı kalma sınırını aşmak için, çekirdek sayısıyla orantılı çok süreçli bir filoyu varsayılan yapılandırma olarak çalıştırıyor
  • Tüm süreçler so_reuseport ile aynı porta bağlanıyor ve çekirdek yeni bağlantıları dağıttığı için, istemci tarafında tek bir endpoint gibi görünüyor
  • Ayrı bir bağlantı üzerinden gelen Postgres iptal istekleri, oturumu elinde tutmayan bir sürece ulaşabildiğinden, süreç eşleme ile gerçek oturum sahibine iletiliyor
  • 16-vCPU c7i.4xlarge üzerinde tek süreç yaklaşık 87.000 TPS'de tepe yaparken, 16 süreçlik filo yaklaşık 336.000 TPS'ye çıkarak yaklaşık 4 kat işlem hacmi kaydetti
  • Bağlantı az olduğunda tek süreç benzer veya biraz daha hızlı olabilir, ancak yüksek eşzamanlılıkta tek çekirdek darboğaz haline geldiği için bağlantı bütçesini filonun geneline bölerek Postgres'i aşırı bağlantıya boğmadan işlem hacmi ve bağlantı üst sınırı ölçeklenmeli

Tek sürecin yarattığı CPU darboğazı

  • PgBouncer tek iş parçacıklı olduğu için, sistemdeki CPU sayısından bağımsız olarak bir süreç yalnızca tek çekirdek kullanır
  • 16-vCPU'lu bir sunucuda bile bağlantı havuzlama işi tek bir çekirdekte yoğunlaşır ve kalan 15 çekirdek boşta kalır
    • Bu nedenle, Postgres'in işleme kapasitesi tükenmeden önce havuzlayıcı toplam işlem hacmini sınırlar
  • ClickHouse Managed Postgres, kullanılabilir çekirdek sayısıyla orantılı olarak PgBouncer süreç sayısını belirleyen bir süreç filosu çalıştırır

so_reuseport ile bağlantı dağıtımı

  • Filodaki tüm süreçler so_reuseport etkinleştirilmiş halde aynı porta bağlanır
  • Çekirdek gelen bağlantıları süreçlere dağıttığı için, istemci tek bir endpoint'e bağlanır ve arka planda birden fazla PgBouncer çalıştığını bilmek zorunda kalmaz
  • PgBouncer belgeleri de birden fazla çekirdeği kullanmak için birden çok tek iş parçacıklı süreç çalıştırma yöntemi olarak so_reuseport kullanımını öneriyor

Sorgu iptalini garanti eden süreç eşleme

  • Postgres'in iptal isteği, çalışan sorgu bağlantısından ayrı yeni bir bağlantı üzerinden iptal anahtarıyla birlikte gelir
  • so_reuseport kullanıldığında çekirdek, yeni iptal bağlantısını ilgili oturumu tutan süreç yerine başka bir sürece yönlendirebilir
    • İsteği alan süreç ilgili sorguyu tanımıyorsa iptal gerçekleşmez
  • PgBouncer süreçleri arasında eşleme yapılırsa, yanlış sürece ulaşan istek gerçek oturum sahibi olan sürece iletilebilir
  • Böylece isteği hangi süreç alırsa alsın, sorgu iptali filonun tamamında düzgün çalışır

Transaction pooling ve bağlantı bütçesi

  • Havuzlama transaction modunda çalışır ve transaction commit edilir edilmez sunucu bağlantısı yeniden havuza döner
  • max_client_conn ve max_db_connections, süreç sayısına bölünerek her sürece tahsis edilir
  • Bağlantı bütçesini bölmek, filonun toplam bağlantı sayısını Postgres'in güvenli sınırları içinde tutarken toplam bağlantı üst sınırını yükseltmeyi sağlar
  • Tek süreç, kendi max_client_conn sınırını aşan yeni istemcileri şu hatayla reddeder
    • FATAL: no more connections allowed (max_client_conn)

Aynı donanım üzerinde benchmark

  • İki yapılandırma da aynı AWS EC2 ortamında ölçüldü
    • Havuzlayıcı sunucu: 16-vCPU c7i.4xlarge
    • Postgres: ayrı bir sunucu
    • Yük üretici: üçüncü bir sunucuda pgbench
    • İş yükü: salt okunur (select-only), transaction pooling modu
  • Karşılaştırma, PgBouncer tek süreç ile 16 süreçli filo arasında yapıldı; instance tipi, Postgres ve iş yükü aynıydı
  • İstemci bağlantıları 8'den 256'ya çıkarılırken işlem hacmi ve 16 çekirdekli sunucunun CPU kullanımı ölçüldü
İstemci Tek süreç TPS Tek süreç sunucu CPU Filo TPS Filo sunucu CPU
8 8,910 0.8% 6,450 2.9%
32 54,203 5.2% 64,244 12.3%
64 86,570 8.3% 219,439 31.9%
128 83,463 8.1% 320,547 45.9%
256 76,893 7.7% 336,469 48.9%

İşlem hacmi ve CPU kullanım sonuçları

  • Tek süreç yaklaşık 87.000 TPS'de tepe yaptıktan sonra yük arttıkça performansı düştü ve 256 istemcide yaklaşık 77.000 TPS kaydetti
  • 16 süreçli filo daha fazla çekirdek kullanarak yaklaşık 336.000 TPS'ye çıktı ve tek sürece göre yaklaşık 4 kat işlem hacmi sağladı
  • pidstat ölçümünde tek PgBouncer süreci yük altında CPU'nun yaklaşık %97'sini kullanarak bir çekirdeği tamamen doldurdu, ancak 16-vCPU'lu sunucunun toplam kullanım oranı %10'un altında kaldı
  • Filo işi sunucunun geneline dağıtarak yaklaşık 8 çekirdek kullandı; Postgres ve yük üretici sınıra ulaştığında bile ek kapasite kalmıştı
  • 256 istemcinin korunduğu ölçümde tek süreç sunucu yaklaşık %9, filo sunucu ise sürekli yaklaşık %52 CPU kullandı
  • EC2 CloudWatch üzerinden alınan dış ölçümde tek süreçli instance'ın ortalama CPUUtilization değeri yaklaşık %16, filo için ise yaklaşık %60 oldu
    • CloudWatch rakamları misafir sistem içi ölçümlerden biraz daha yüksek olsa da, tek PgBouncer'ın 16-vCPU'nun büyük kısmını kullanamadığı gerçeği değişmiyor

Eşzamanlılığa göre yapılandırma seçimi

  • Bağlantı sayısı az olduğunda paralelleştirilecek iş olmadığından ve filonun bağlantıları birden çok sürece dağıldığından, tek süreç yeterli olabilir veya biraz daha hızlı olabilir
    • 8 istemcide tek süreç 8.910 TPS, filo ise 6.450 TPS kaydetti
  • Eşzamanlılık arttığında tek sürecin kapladığı tek çekirdek işlem hacminin tavanı olur ve filoyla arasındaki performans farkı büyür
  • Postgres'in PgBouncer'dan önce sınıra ulaştığı ortamlarda tek süreç de uygun bir varsayılan seçimdir
  • Havuzlayıcı işlem hacmini sınırlamaya başladığında, çekirdek sayısına uygun süreç filosu, so_reuseport tabanlı port paylaşımı ve süreç eşleme birlikte kullanılmadan darboğaz giderilemez
  • Tüm ClickHouse Managed Postgres sunucuları bu yapılandırmayı varsayılan olarak sunuyor

1 yorum

 
GN⁺ 4 시간 전
Hacker News yorumları
  • https://github.com/yandex/odyssey kullanmak yeterli. Odyssey, ölçeklenebilir bir PgBouncer

    • En doğrulanmış ve PostgreSQL’e doğal olarak uyan çözüm olan PgBouncer önce düzgün şekilde ayarlanıp kullanıldı; prepared statement desteği gibi uzun süredir duran sorunlar da çözüldü ve çok iyi çalışıyor
      PostgreSQL bağlantılarını 10 binin üzerine ölçekleyen çok sayıda müşteri var ve ileride Odyssey ya da pgdog gibi alternatifler de değerlendirilecek. Yine de kişisel olarak PostgreSQL’de 10 binden fazla bağlantı bulundurmayı tercih etmiyorum; birkaç yüz bağlantıyla da yeterince ölçeklenebileceğini düşünüyorum
    • Bununla ilgili ilginç bir bilgi olarak, ClickHouse da aslında Yandex tarafından geliştirilmişti
    • Yandex bir Rus şirketi olduğu için kullanmamanın daha iyi olduğunu düşünüyorum
  • Kubernetes üzerinde PgBouncer çalıştırıyorsanız, tek bir makinede birden çok süreç başlatmak da kolay, birden çok makineye dağıtmak da
    Azure, VM bakımı sırasında tüm sunucu grubunda art arda kesintilere yol açabildiği için çok makineli kurulum özellikle faydalı

    • PgBouncer ile PostgreSQL arasına bir ek ağ atlaması girdiğinde bunun throughput üzerinde ne etkisi olduğunu merak ediyorum. Farkın küçük olmasını bekliyorum ama doğrulamaya değer
  • Burada sözü edilen peering kavramını anlıyorum ama PostgreSQL’de bunu hiç kullanmadım
    A) PostgreSQL’de bunu kolayca yapılandırmaya yarayan bir mod ya da ayar var mı? İptal isteğinin hata alınmayana kadar eşlere sırayla iletildiği ya da yanlış sürecin doğru süreci belirleyebilmesi için iptal isteğinde metadata taşındığı bir yapı hayal ediyorum
    B) Tüm PostgreSQL süreçleri istemci isteklerini so_reuseport ile alıyorsa, eşler arası iletişim için ayrıca bir process inter communication (IPC) mekanizması gerekecek gibi görünüyor; pratikte hangi mekanizma kullanılıyor?

  • pgdog kullanıyorum ve ihtiyaç duyduğum kullanım senaryosuna çok iyi uyuyor

    • Pgdog, Instacart’ın uzun zaman önce karşılaştığı PgBouncer eksiklerini gidermek ve PostgreSQL’i yatay ölçeklemek için daha sağlam bir temel, yani sharding sağlamak amacıyla oluşturuldu
    • İleride pgdog sunmayı da değerlendireceğiz. PgBouncer’ı neden seçtiğimiz https://news.ycombinator.com/item?id=48873867 bağlantısında daha ayrıntılı anlatılıyor
    • Son zamanlarda PostgreSQL reverse proxy projeleri sırayla gündeme geliyor. Pgdog’un neden yapıldığını burada görebilirsiniz: https://news.ycombinator.com/item?id=48819308
  • PgBouncer’ın neden iptal istekleriyle bile ilgilenmesi gerektiğini merak ediyorum. Bunları doğrudan PostgreSQL’e iletse ve PostgreSQL iptal edilen sorguya normal yanıt yerine hata döndürse, o bağlantıyı yöneten PgBouncer bunu ele alsa yeterli olmaz mı?

    • Sorgu iptali, mevcut sorgu bağlantısından ayrı iletildiği için PgBouncer’ın isteği doğru sunucuya ve bağlantıya göndermesi gerekir
      PgBouncer istemciye sahte ama izlenebilir bir iptal PID’si ve gizli değer verir; iptal isteği geri geldiğinde gerçek sunucu/süreç PID’sini ve gizli değeri bulup iletir. Ayrıca istemci sorgunun hâlâ çalıştığını sanarken PgBouncer bunun zaten bittiğini ve bağlantının yeniden kullanıldığını biliyor olabilir; bu yüzden o bağlantı ve PID’nin gerçekten hâlâ o sorguyu çalıştırıp çalıştırmadığını doğrulaması gerekir
  • Bu, mikroservislerde PostgreSQL sunucusuna erişimi bağlantı havuzu üzerinden kontrol etmek için mi kullanılıyor? Monolitik bir backend ise gerekli görünmüyor
    Düzgün çoğu backend framework’ünde bağlantı havuzu zaten yerleşik gelir ve mikroservis gerektirmeyen ya da önerilmeyen kullanım durumlarının %98’i bununla çözülür

    • Arka uç uygulaması her hostta tek bir büyük binary olarak çalışıyorsa doğru. Ancak backend, durumu paylaşmayan çok sayıda fork edilmiş süreçten oluşuyorsa buna kesinlikle ihtiyaç var
  • PgBouncer harika bir yazılım. Çok kullanıyorum ve veritabanı operasyonlarını oldukça basitleştiriyor

  • so_reuseport terimini ilk kez görüyorum, ilginçmiş. Kurulumun anahtarı bununla birlikte peering gibi görünüyor; peering PgBouncer’a gömülü mü ve yapılandırması kolay mı?

  • Kubernetes’te de peering kullanılabiliyor mu? Bu ortamda port yeniden kullanımı gerekmeyecek gibi duruyor; ayrıca her Pod’un ayrı bir bağlantı havuzuna sahip olup bağımsız mı çalıştığını merak ediyorum

  • Şu an 46 yaşındayım ve 23 yaşımdayken PostgreSQL’in ağır bağlantı modelini görüp şok olduğumu hatırlıyorum. O zamandan beri bu konuda hiç iyileşme olmadı mı?

    • Oldukça iyileşti ve artık binlerce bağlantıyı da epey iyi kaldırıyor: https://techcommunity.microsoft.com/blog/adforpostgresql/imp...
      Yine de bağlantı havuzu kullanılmıyorsa PostgreSQL’in süreç fork etmesi gerektiğinden, yeni bağlantı oluşturmanın maliyeti her zaman onlarca milisaniye ya da daha fazlası oluyor. Bağlantı havuzu olmadan yazılmış uygulamalar ideal değil ama yaygın
      Uygulama framework’leri de değişti; serverless mimariler PostgreSQL’in zorlanmaya başladığı on binlerce bağlantı üretebiliyor. Ben kişisel olarak birkaç yüzün üzerindeki bağlantıları tercih etmiyorum ama bugünlerde bu durum gayet gerçekçi
    • O dönemde birçok şirket, Java’nın ortaya koyduğu threading modeline ilk kez işe yarar cevaplar vermeye başlıyordu. Bu model, Windows’un yaklaşımına ek yetenekler katıyordu; Solaris bile Java yükünü taşımakta zorlanıyordu, HP-UX daha da kötüydü ve SGI’ın HP’den daha iyi olup olmadığını hatırlamıyorum
      Java uyumluluğunu sağlama sürecinde birçok şirket eşzamanlılık işleme yöntemini ciddi biçimde değiştirmek zorunda kaldı. PostgreSQL ve SQLite da benzer dönemde tasarlandı, ancak bu threading tartışmaları ortaya çıkmadan önce bile yüksek yüklü sistemleri devreye almış sektörün deneyimli isimleri tarafından, eski donanım kullanıcılarını da destekleyecek şekilde geliştiriliyordu