Daha hızlı SQLite arayışı
(avi.im)- Sunucusuz ve edge ortamlarda birden fazla SQLite örneği birlikte çalıştırıldığında senkron I/O beklemesi kuyruk gecikmesini artırıyor; Helsinki ve Cambridge araştırmacıları bunu asenkron I/O ve depolama ayrıştırmasıyla azaltma yöntemini denedi
- Linux io_uring, gönderim kuyruğu ve tamamlama kuyruğu üzerinden I/O istekleri sırasında uygulamanın başka işleri sürdürmesini sağlayarak thread bloklanmasını azaltan bir temel sunuyor
- SQLite,
sqlite3_step()çalışırken gereken B-Tree sayfası önbellekte yoksa POSIXread()gibi senkron I/O ile diski okuyor; I/O bitene kadar thread duruyor - Araştırmacılar yalnızca POSIX çağrılarını değiştirmek yerine, Rust tabanlı yeniden yazım projesi Limbo içinde VM ve BTree’yi asenkron yürütme modeline uyacak şekilde değiştirdi
- Benchmark’larda p999 kuyruk gecikmesi en fazla 100 kat azaldı; ancak p90 ve p99 SQLite ile neredeyse aynı, çoklu reader/writer değerlendirmesi ise gelecekteki çalışma olarak kalıyor
SQLite’ı daha hızlı yapmaya yönelik araştırma
- University of Helsinki ve Cambridge araştırmacıları, “Serverless Runtime / Database Co-Design With Asynchronous I/O” çalışmasında SQLite’a asenkron I/O ve depolama ayrıştırması uygulama yöntemini ele alıyor
- Bu makale, Rust tabanlı SQLite yeniden yazım projesi Limbo için temel oldu
- Bir workshop makalesi olduğu için kısa; odak noktası sunucusuz ve edge computing
- Temel fikir şu: SQLite’ın kendisi zaten hızlı olsa bile, çok kiracılı ortamlardaki kuyruk gecikmesi yürütme modeli değiştirilerek daha da azaltılabilir
io_uring’in azalttığı I/O beklemesi
- Linux çekirdeğindeki io_uring, asenkron I/O arayüzü sağlar
- Adı, kullanıcı alanı ile çekirdek alanı tarafından paylaşılan ring buffer’dan gelir ve iki alan arasındaki buffer kopyalama ek yükünü azaltır
- Uygulama bir I/O isteği gönderdikten sonra, OS tamamlandığını bildirene kadar başka işleri paralel yürütebilir
- Çalışma akışı şöyledir
io_uring_setup()sistem çağrısıyla gönderim kuyruğu ve tamamlama kuyruğu adlı iki bellek alanı ayarlanır- Uygulama, gönderim kuyruğuna I/O isteğini koyar ve
io_uring_enter()ile OS’ye işlemeyi başlatmasını bildirir read()vewrite()gibi thread’i bloklamadan denetimi kullanıcı alanına geri verir- Uygulama başka işler yaparken, I/O tamamlanmasını kontrol etmek için tamamlama kuyruğunu periyodik olarak poll eder
SQLite sorgu yürütmesinde senkron I/O darboğazı
- SQLite uygulaması, veritabanı dosyasını
sqlite3_open()ile açar; bu süreçte POSIXopengibi düşük seviyeli OS I/O çağrılır sqlite3_prepare(),SELECT,INSERTgibi SQL ifadelerini bir bytecode komutları dizisine dönüştürürsqlite3_step(), sorgunun okuyacağı satırı üretinceye veya yürütme bitinceye kadar bytecode komutlarını çalıştırır- Okunacak satır varsa
SQLITE_ROWdöndürür - İfade tamamlandığında
SQLITE_DONEdöndürür
- Okunacak satır varsa
- Yürütme sırasında backend pager çağrılır ve tablolar ile satırları temsil eden B-Tree dolaşılır
- Gereken B-Tree sayfası SQLite sayfa önbelleğinde yoksa disk erişimi gerçekleşir
- SQLite, POSIX
readgibi senkron I/O ile sayfa içeriğini diskten belleğe okur - Bu sırada
sqlite3_step()çekirdek thread’ini bloklar - I/O beklerken eşzamanlı iş yapmak için uygulamanın daha fazla thread kullanması gerekir
- SQLite, POSIX
Sunucusuz ve edge’de SQL’i gömme nedeni
- Sunucusuz computing edge’de çalıştığında ve veritabanı bulut ortamında olduğunda, sunucusuz fonksiyon ile bulut arasında ağ gidiş-dönüş maliyeti oluşur
- Veriyi edge’e birlikte yerleştirme yöntemi de var; ancak daha iyi bir yaklaşım olarak veritabanını edge runtime içine gömmek öneriliyor
- Cloudflare Workers zaten bu biçimi sağlıyor, fakat KV arayüzü sunuyor
- KV her problem alanına iyi uymaz
- Tablo biçimli verileri KV modeline eşlemek geliştirici deneyimini kötüleştirir
- Serileştirme ve deserileştirme maliyeti de oluşur
- SQL daha uygun olabilir; SQLite gömülü bir veritabanı olduğundan sunucusuz runtime’a doğrudan dahil edilebilir
SQLite’ı basitçe io_uring’e geçirmek neden zor
- SQLite, geleneksel POSIX
read()vewrite()tabanlı senkron I/O kullanır - Küçük uygulamalarda büyük sorun olmasa da, tek bir sunucuda yüzlerce SQLite veritabanı çalıştırıldığında darboğaz olabilir
- Sunucu kaynak kullanımının maksimize edilmesi gereken ortamlarda senkron I/O bir kısıt haline gelir
- SQLite’ta eşzamanlılık ve çok kiracılık sorunları var
- I/O senkron ve bloklayıcı olduğu için aynı makinedeki uygulamalar kaynaklar için rekabet eder
- Sonuç olarak gecikme artar
- POSIX I/O çağrılarını basitçe io_uring ile değiştirmek zordur
- Bloklayıcı I/O kullanan uygulamaların io_uring’in asenkron I/O modeline uyacak şekilde yeniden tasarlanması gerekir
- SQLite kütüphanesi, I/O devam ederken denetimi uygulamaya geri verebilmelidir
- Araştırmacılar SQLite’ın yalnızca bazı çağrılarını değiştirmek yerine, SQLite’ı Rust ile yeniden yazıp io_uring kullanma yaklaşımını seçti
Limbo’nun asenkron yürütme modeli
- Limbo, SQLite’ın Rust ile yeniden yazıldığı bir projedir; VM ve BTree bileşenleri asenkron I/O destekleyecek şekilde değiştirildi
- Senkron bytecode komutları, asenkron karşılıklarıyla değiştirildi
- Örneğin
Nextkomutu imleci ilerletir ve gerekirse sonraki sayfayı getirir- Mevcut senkron sürümde disk I/O oluşursa, sayfayı okuyup çağırana döndürünceye kadar bloklanır
- Asenkron sürümde
NextAsyncgönderildikten sonra hemen döner - Çağıran taraf daha sonra bloklanabilir veya başka işler yapabilir
- Asenkron I/O bloklamayı ortadan kaldırır ve eşzamanlılığı iyileştirir
- Kaynak kullanımını daha da artırmak için sorgu motoru ile depolama motorunu ayıran depolama ayrıştırması da öneriliyor
- İlgili açıklama olarak Disaggregated Storage - a brief introduction da bağlantılanmış
Benchmark sonuçları ve kalan sorular
- Benchmark, çok kiracılı sunucusuz runtime’ı simüle ediyor
- Her kiracının kendi gömülü veritabanına sahip olduğu bir kurulum kullanılıyor
- Kiracı sayısı 1’den 100’e kadar 10’luk adımlarla değiştiriliyor
- SQLite, her kiracı için ayrı thread kullanıyor ve ölçüm her thread’de sorgu çalıştırılarak yapılıyor
- Çalıştırılan sorgu
SELECT * FROM users LIMIT 100ve 1000 kez tekrarlanıyor - Limbo da aynı deneyi yürütüyor, ancak Rust coroutine’leri kullanıyor
- Sonuç olarak p999’da kuyruk gecikmesi en fazla 100 kat azaldı
- SQLite sorgu gecikmesi, thread sayısının artmasıyla kademeli biçimde kötüleşmedi
- Çalışma hâlâ sürüyor ve makalede birkaç açık soru kalıyor
- Future Work bölümünde birden fazla reader ve writer içeren ek benchmark’lar ele alınıyor
- Fayda yalnızca p999 sonrasında belirginleşiyor
- p90 ve p99 performansı SQLite ile neredeyse aynı
- Limbo kodu açık kaynak olarak yayımlanmış durumda
- Limbo şu anda resmi bir Turso projesi ve tanıtım yazısı da yayımlandı
Henüz yorum yok.