- SQLite'ın tek yazarlı yapısı ve gömülü niteliğinin aslında ölçeklenebilirlik ve performansı artıran etkenler olduğu deneylerle gösterildi
- Aynı koşullarda Postgres ağ gecikmesi olduğunda 348 TPS'ye kadar düşerken, SQLite ağın ortadan kalkmasıyla 44.096 TPS'ye ulaştı
- Tek yazarlı modelden yararlanan batch işleme ve SAVEPOINT tabanlı ayrıntılı transaction'larla en fazla 186.157 TPS, kararlı yapılandırmada ise 102.545 TPS kaydedildi
- Amdahl yasası, ağ tabanlı veritabanlarındaki darboğazı açıklarken, SQLite bunu aşarak yüksek verimliliği koruyor
- Bu sonuçlar, yerel ortamda SQLite kullanımının potansiyelini ve ağ darboğazını ortadan kaldırmanın önemini vurguluyor
SQLite'ın yapısı ve deney ortamı
- SQLite MVCC kullanmıyor ve yalnızca tek bir yazara izin veriyor, ancak bu yapı ironik biçimde yüksek ölçeklenebilirliği mümkün kılıyor
- Gömülü bir veritabanı olduğundan ağ ek yükü yok
- Benchmark, Apple M1 Pro, 16 GB bellekli MacBook Pro (2021) ortamında yürütüldü
- Deney, kusursuz optimizasyonu hedeflemekten çok, genel koşullarda da yüksek yazma throughput'una ulaşılabildiğini göstermek amacıyla yapıldı
TPS tanımı ve transaction örneği
- TPS, basit bir yazma hızı değil, etkileşimli transaction (Interactive Transaction) anlamına geliyor
- Örnek: Hesaplar arasında para transferinde birden fazla sorgu ve uygulama kodu tek bir transaction içinde çalışır
- Transaction'lar hata oluştuğunda durumu geri alabilir; bu yüzden tutarlılığın korunmasında kritik rol oynar
Benchmark yapısı
- Büyük ölçekli eşzamanlı istekleri simüle etmek için Clojure tabanlı virtual threads kullanıldı
- Postgres, HikariCP tabanlı connection pool ile yapılandırılırken, SQLite tek yazar ve çekirdek sayısı kadar okuma bağlantısı kullandı
- Her iki veritabanında da id, balance alanlarına sahip basit bir
account tablosu kullanıldı ve 1 milyar satır eklendi
- Kullanıcı etkinliği power law dağılımını (0.9995) izliyor ve yaklaşık 100 bin aktif kullanıcı bulunuyor
Ağ tabanlı veritabanı (Postgres) performansı
- Aynı sunucuda Postgres 13.756 TPS elde etti
- 5 ms ağ gecikmesi eklendiğinde 1.214 TPS'ye, 10 ms'de ise 702 TPS'ye sert biçimde düştü
- Serialization isolation level uygulandıktan sonra 660 TPS'ye, ek sorgular dahil edildiğinde ise 348 TPS'ye geriledi
- Bu, Amdahl yasasına göre ağ darboğazının toplam performansı sınırladığını gösteriyor
- Ağ gecikmesi arttıkça transaction lock çekişmesi yoğunlaşıyor ve sistem ölçeklenemiyor
SQLite'ın gömülü olmasının avantajı
- Ağ ortadan kaldırıldığında SQLite 44.096 TPS'ye ulaştı
- Ağ darboğazı kaybolduğu için Amdahl yasasının etkisi en aza indi
- Tek yazarlı yapıdan yararlanılarak batch processing uygulandığında değer 186.157 TPS'ye kadar çıktı
- Dinamik batch boyutu ayarıyla latency ve throughput otomatik olarak optimize edildi
SAVEPOINT ile ayrıntılı transaction'lar
- Batch içindeki tekil transaction hatalarının tüm işlemi bozmasını önlemek için SAVEPOINT kullanan iç içe transaction'lar uygulandı
- Hata durumunda yalnızca ilgili transaction geri alınıyor, tüm batch korunuyor
- Bu yöntemle de 121.922 TPS korundu
Okuma/yazma karma yük testi
- Tüm isteklerin %75'i okuma, %25'i yazma olarak yapılandırıldı
- Ayrı bir okuma thread pool kullanılarak okuma isteklerinin yazmaları engellememesi için ayrıştırma yapıldı
- Sonuç olarak 102.545 TPS elde edildi
Performans karşılaştırması özeti
| Koşul |
Postgres |
SQLite |
| Ağ yok |
13.756 |
44.096 |
| 5 ms gecikme |
1.214 |
n/a |
| 10 ms gecikme |
702 |
n/a |
| 10 ms + serialization |
660 |
n/a |
| Batch işleme |
n/a |
186.157 |
| Batch + SAVEPOINT |
n/a |
121.922 |
| Batch + SAVEPOINT + okuma |
n/a |
102.545 |
Sonuç
- SQLite, tek yazarlı model ve gömülü yapı sayesinde ağ tabanlı veritabanlarına kıyasla çok daha yüksek TPS elde etti
- Amdahl yasasının işaret ettiği ağ darboğazı sınırını aşarak verimliliği en üst düzeye çıkardı
- Tüm kod GitHub'da açıklandı ve ilgili başlıklar kapsamında Amdahl yasası, power law, SQLite ölçeklendirme örnekleri gibi kaynaklar da sunuldu
- SQLite, yerel ortamda yüksek performanslı transaction işleme için son derece etkili bir seçenek
2 yorum
Harici sunucuya gitmeden yalnızca yerel ortamda kullanılacaksa, ağ diye bir vergi ödemeye gerek var mı demek oluyor. (VFS vs Socket)
Hacker News yorumu
SQLite tabanlı hibrit protobuf ORM/CRUD sunucusu geliştiriyorum
Kod ve açıklamalar GitHub - accretional/collector üzerinde
Gerçek zamanlı yedeklemede 5~15 ms kesinti, yüzlerce okuma/yazma isteğinin kuyruklanması, CRUD genel gecikmesinde yaklaşık 1 ms ve WAL tabanlı streaming yedekleme bile mümkün
Eskiden yalnızca Postgres ve Spanner kullanıyordum; Collector'a bölümleme özelliği eklenirse muhtemelen bir daha Postgres kullanmam
Dezavantajı, tüm veri ve işlemlerin tek bir makineye sığmak zorunda olması
AWS'nin u-24tb1.112xlarge instance'ı (448 vcore, 24 TB RAM, 64 TB EBS) kullanılırsa oldukça geniş bir alan var
Yazı SQLite'ın verimliliğini vurguluyor ama karşılaştırma ölçütünün belirsiz olduğunu düşünüyorum
Çünkü baştan ayrı sunucu mimarisi varsayılmış, sonra da yerel gömülü veritabanı performansı ölçülmüş
Aynı koşullarda yerel Postgres tuning ile de benzer performans elde edilebilir
Postgres bağlantı sayısını 8 ile sınırlamak bir darboğaz olabilir
CPU ve thread kullanımını da paylaşıp, daha büyük bir connection pool ile yeniden test etmek iyi olur
64 bağlantıya çıkarılırsa throughput 8 kat artabilir. Sınıra ulaşana kadar istemci ayarlarını ölçeklemek gerekir
Asıl nokta, network gecikmesinin darboğaz olup olmadığını fark etmek
Birçok iş yükünde sıradan bir yerel veritabanı, mükemmel bir uzak veritabanından daha hızlıdır
Önemli olan “hangi veritabanı en iyisi” değil, “network sınırını geçmek zorunda mısınız” sorusudur
Network tipi veritabanları, uygulamayı yeniden dağıtmayı kolaylaştırma avantajına sahip
Yeni bir instance açıp eskisini kapatarak neredeyse kesintisiz dağıtım yapmak mümkün
SQLite aynı instance üzerinde olursa değişim sırasında veritabanını da yeniden ayağa kaldırmak gerekir; bu da daha karmaşık hale gelir. Gerçek operasyonda böyle bir sorun yaşanıp yaşanmadığını merak ediyorum
Migration sırasında kesinti olabilir. Litestream sayesinde artık replikasyon ve yedekleme daha kolay
Yazar
PRAGMA synchronous="normal"ayarını kullanmış; bu, her seferinde fsync yapılmadığı anlamına gelirAdil bir karşılaştırma için
"full"olarak ayarlanması gerekir"normal"de kabul edilebilir. Güç kaybında dayanıklılık kaybedilir ama transaction tutarlılığı korunurSQLite için HA (yüksek erişilebilirlik) yapılandırmasının nasıl olduğunu merak ediyorum
En azından otomatik failover yapılabilecek bir düzey olmalı
Ben şu anda Postgres ile SQLite (litestream dahil) arasında kararsızım.
Uygulamam bir miktar kesintiyi tolere edebildiği için, tek kutuda dikey ölçekleme daha basit ve daha ucuz
Marmot GitHub üzerinde gossip tabanlı replikasyon mekanizması yeni eklendi
SQLite'ı gerçekten production'da sınırlarına kadar zorlayan örnekler olup olmadığını merak ediyorum
Tipik bir web uygulaması veya e-ticaret ortamında SQLite ile Postgres arasında kullanıcı sayısı sınırının yaklaşık nerede olduğunu merak ediyorum
SQLite son güncellemelerle eşzamanlı okumayı destekliyor ama hâlâ yalnızca tek yazmaya izin veriyor
Bunun hangi durumlarda sorun olduğunu ve ölçekleme düşünülüyorsa baştan Postgres ile başlamanın daha doğru olup olmadığını sormak isterim