42 puan yazan GN⁺ 14 일 전 | 26 yorum | WhatsApp'ta paylaş
  • Tüm veritabanları sonuçta dosya sistemi üzerindeki yapılandırılmış dosya kümeleridir; bu yüzden erken aşamadaki uygulamalar doğrudan dosya yönetimiyle de yeterli performans elde edebilir
  • Aynı sunucu Go, Bun ve Rust ile uygulanarak dosya tarama, bellek içi map ve disk üzerinde ikili arama olmak üzere üç yaklaşım karşılaştırıldı; sonuçlar, basit dosya erişimiyle bile yüksek iş hacmine ulaşılabildiğini gösteriyor
  • Bellek içi map yaklaşımı en yüksek performansı gösterdi (en fazla 169k req/s); SQLite ise 25k req/s ile kararlı ama ek yük içeriyor
  • Çoğu servis tek bir SQLite dosyasıyla bile 90 milyon DAU seviyesine kadar çalışabilir; bu nedenle ürünün ilk aşamasında ayrı bir veritabanı gerekmeyebilir
  • Veri kümesi RAM'i aştığında veya join, çok koşullu arama, eşzamanlı yazma, transaction gerektirdiğinde veritabanı kullanmak gerekir

Veritabanı Gerçekten Gerekli mi

  • Veritabanı sonuçta bir dosya kümesidir; SQLite tek bir dosyadan, PostgreSQL ise bir dizin ve süreçlerden oluşur
    • Tüm veritabanları dosya sistemine okuma-yazma yapar ve kodda open() çağırmakla aynı temelde çalışır
    • Bu yüzden asıl soru “dosya kullanacak mıyız” değil, “veritabanının dosyalarını mı kullanacağız, yoksa bunları kendimiz mi yöneteceğiz” sorusudur
    • Erken aşamadaki birçok uygulama bunu doğrudan yöneterek de yeterli performans elde edebilir

Deney kurulumu

  • Aynı HTTP sunucusu Go, Bun(TypeScript) ve Rust ile uygulanıp iki depolama stratejisi karşılaştırıldı
    • users.jsonl, products.jsonl, orders.jsonl olmak üzere üç JSONL dosyası kullanıldı
    • Oluşturma için POST /users, sorgulama için GET /users/:id
    • Benchmark yalnızca sorgulama yolu (GET) için yapıldı
  • Yaklaşım 1: Her istekte dosyayı okuma

    • İstek geldiğinde dosya açılıyor, tüm satırlar taranıyor, JSON parse ediliyor ve ID eşleşmesi kontrol ediliyor
    • Ortalama olarak dosyanın yarısını okumak gerektiği için karmaşıklık O(n)
    • Veri büyüdükçe istek işleme hızı keskin biçimde düşüyor
  • Yaklaşım 2: Her şeyi belleğe yükleme

    • Başlangıçta tüm dosya okunup ID tabanlı bir hash map içine yükleniyor
    • Yazmalar hem map'e hem dosyaya yansıtılıyor; okumalar tek map sorgusuyla O(1)
    • Dosya kalıcı depolama görevi görürken map indeks görevi görüyor
    • Go'da sync.RWMutex, Rust'ta RwLock ile paralel okuma destekleniyor
  • Yaklaşım 3: Disk üzerinde ikili arama

    • Tüm veriyi RAM'e almadan hızlı sorgu için bir orta yol
    • ID'ye göre sıralı veri dosyası ve sabit genişlikli bir indeks dosyası (kayıt başına 58 bayt) oluşturuluyor
    • ReadAt ile indeks O(log n) aranıyor, ardından ilgili ofsetten tek kayıt okunuyor
    • Yeni kayıt eklendiğinde sıralama bozulduğu için indeksin periyodik olarak yeniden oluşturulması veya birleştirme gerekiyor
    • Bu birleştirme deseni LSM-tree çalışma mantığına benziyor

Benchmark ortamı

  • Veri kümesi boyutları: 10k, 100k, 1M kayıt
  • Yük aracı: wrk, 10 saniye boyunca 4 thread ve 50 eşzamanlı bağlantıyla rastgele GET istekleri
  • Testler aynı makinede yapıldı: Apple M1 Mac mini, macOS 15, Go 1.26, Bun 1.3, Rust 1.94
  • Go tarafında ayrıca ikili arama (disk) ve SQLite(modernc.org/sqlite) karşılaştırması da yapıldı

Başlıca sonuçlar

  • Doğrusal tarama performansı düşüyor: 1M kayıtta Go 23 req/s, Bun 19 req/s seviyesine kadar geriliyor
  • İkili arama (disk): 10k~1M kayıt aralığında 45k→38k req/s ile yalnızca %15 düşüş gösteriyor
    • OS page cache etkisiyle indeksin üst seviyeleri sürekli bellekte kalıyor
  • SQLite: 25k req/s, ortalama 2ms gecikmeyle tutarlı performans sunuyor
  • İkili arama, SQLite'tan yaklaşık 1.7 kat daha hızlı; basit PK sorgularında SQLite'ın ek yükü görülüyor
  • Bellek içi map en yüksek performansı veriyor: 97k~169k req/s, gecikme 0.5ms altı
  • Bun, Go'dan daha hızlı: Bun 106k req/s, Go 97k req/s
    • Bun, JavaScriptCore + Zig(uWebSockets) tabanlı olduğu için libuv'yi baypas ediyor
  • Rust, doğrusal taramada ezici üstünlük gösteriyor: Go'dan 3~6 kat hızlı; bunun JSON parse ve I/O verimliliğinden kaynaklandığı düşünülüyor
  • Kullanım senaryosuna göre en iyi seçim

    • Mutlak en yüksek iş hacmi: Rust bellek içi map (169k req/s)
    • Veriyi RAM'e almadan en iyi sonuç: Go ikili arama (~40k req/s)
    • SQL gerektiğinde: SQLite (25k req/s)
    • En basit uygulama: Go doğrusal tarama (~20 satır kod)

25.000 req/s ne anlama geliyor

  • Tipik web trafiğinde zirve:ortalama = 2:1 oranı varsayılıyor
    • Ortalama 12.500 req/s → zirvede 25.000 req/s
  • Aktif kullanıcıların saatte 10 sorgu yaptığı ve zirvede eşzamanlılık oranının %10 olduğu varsayılıyor
    • Zirve istek formülü: DAU × 0.000278
  • Her yaklaşım için doygunluk DAU hesapları
    • Go doğrusal tarama: 2.8M
    • Go ikili arama: 144M
    • SQLite: 90M
    • Go bellek içi map: 349M
    • Bun bellek içi map: 381M
    • Rust bellek içi map: 608M
  • Çoğu ürün bu seviyelere ulaşmıyor
    • Örnek: 10.000 SaaS müşterisi → 3 req/s, 100.000 DAU uygulama → 30 req/s
  • Sonuç olarak erken aşamadaki çoğu ürünün veritabanına ihtiyacı yok
    • Gerekirse bile tek bir SQLite dosyasıyla 90 milyon DAU seviyesine kadar çıkılabiliyor

Veritabanının gerekli olduğu anlar

  • Veri kümesi RAM'e sığmadığında

    • On milyonlarca kayıtta yalnızca indeksler bile birkaç GB gerektirebilir
    • Veri paging gerekir ve veritabanı bunu otomatik yönetir
  • ID dışındaki alanlarla sorgu gerektiğinde

    • Çok koşullu arama için dosya taraması veya ek map'ler gerekir
    • Birden fazla map tutmak, fiilen kendi query engine'inizi yazmak anlamına gelir
  • Join gerektiğinde

    • Birden çok dosyayı okuyup birleştirmek gerekir; SQL burada daha verimlidir
  • Birden fazla süreç eşzamanlı yazdığında

    • Her instance'ın bellek içi map'i ayrıdır ve tutarlılık kaybolur
    • Dışsal tek bir doğruluk kaynağı gerekir → veritabanının rolü budur
  • Varlıklar arasında atomik yazma gerektiğinde

    • Sipariş oluşturma ile stok düşmenin birlikte başarılı ya da başarısız olması garanti edilmelidir
    • Ayrı bir transaction log uygulamak gerekir; DB bunu ACID ile çözer
    • Bu tür kısıtların olmadığı iç araçlar, yan projeler ve erken aşama ürünler ise
    • tek sunucunun RAM'i içinde rahatlıkla çalışabilir
    • JSONL dosyaları daha sonra veritabanına kolayca migrate edilebilir

Ekler ve kodlar

  • Go, Bun ve Rust sunucu kodları dahil
  • Veri seed etme ve benchmark çalıştırma betiği (run_bench.sh) ayrıca sağlanıyor
  • ZIP dosyasında go-server/, bun-server/, rust-server/, seed.ts bulunuyor
  • Betik üç veri boyutu için seed işlemi yapıyor, ardından wrk ile yük testi çalıştırıp sonlanıyor

DB Pro ile ilgili bilgiler

  • DB Pro**, Mac, Windows ve Linux için** bir veritabanı istemcisi

    • Sorgulama, gezinme ve yönetim özelliklerini bir arada sunuyor
    • İşbirlikçi web platformu ve yerleşik AI desteği var
    • Son sürümde Val Town'ın SQLite veritabanına bağlanma desteği eklendi
    • v1.3.0 ile veritabanı oluşturma, çoklu sorgu editörü ve PlanetScale Vitess bağlantısı özellikleri geldi

26 yorum

 
happing94 13 일 전

Bu ne saçmalık ya
db'nin performans için kullanıldığını mı sanıyorlar

 
unknowncyder 13 일 전

Aynen öyle, belki yeni bir içgörü vardır diye orijinal metne de baktım ama bu da ne böyle...

Bellek pahalı olduğu için disk kullanmaktan, ya da prodüksiyon işletim kararlılığı için, ya da atomiklikten söz edeceklerini sanıyorsunuz. Böyle temel bir giriş yapmak yerine pat diye hız karşılaştırmasına girişince insan ister istemez gülüyor.

'Biz DB satıyoruz ama DB her zaman gerekli değil!' diye bir makale yayımlayıp bunu hiç çekinmeden söylemeleri, pazarlama yapmak istemelerinden mi acaba -_-... Olumlu bakmaya çalışsam da bazen ister istemez sinikleşiyorum.

Hiç değilse bir benchmark edinmiş olduk diyelim.

 
myc0058 6 일 전

Tipik bir laf olsun diye kod yazma durumu.

 
botplaysdice 13 일 전

Bence çok iyi bir yazı. Özellikle böyle 'rakamlar' içeren materyaller çok değerli. Yazdığımız kodun, kullandığımız teknoloji yığınının ne tür ek yükler getirdiğine dair 'kabaca da olsa bir sezgisi olan' geliştiricileri görmenin kolay olmadığı bir dönemdeyiz; keyifle okudum.

 
foriequal0 12 일 전

Ben de katılıyorum. Bence bu, Mechanical sympathy ya da geliştirmede hız-tempo ayarını yaparken önemli sezgiler kazandıran bir kaynak. Tıpkı "Latency Numbers Every Programmer Should Know" gibi.

Ayrıca ben bu yazının belirli bir yönün koşulsuz olarak daha iyi olduğunu söylediği şeklinde okumadım. Aksine, yazıda bahsedilen tüm yaklaşımların gösterdiği rakamlar "çoğu işte fazlasıyla yeterli performans" sunuyor gibi göründüğü için, duruma uygun yöntemi seçelim deniyormuş gibi okudum.

 
botplaysdice 13 일 전

Yanıtlardaki cevherler de cabası.

 
white9s 13 일 전

Bunu yapmayı gerektiren bir neden varsa değerlendirmek gerekebilir, değil mi? Mesela performans kısıtları aşırı derecede ciddiyse.
Ama çoğu durumda bunu özellikle seçmek için gerçekten bir sebep var mı? Sonuçta veritabanının sağladığı avantajlar da yok değil..

 
m00nlygreat 13 일 전

Bence sadece bir bakış açısı değişikliği gibi okunuyor ama herkes çok hassas davranıyor.

 
tazuya 13 일 전

Aynen. Bunu, işin başlangıç aşamasında kullanıcı sayısı henüz azken DB satın almadan ya da sistemi gereksiz yere karmaşıklaştırmadan, sadece temel dosya I/O ile işin oturmasına kadar ilerlenebileceği yönünde bir öneri olarak görmek gerekir.

 
smash8106 13 일 전

Ben de katılıyorum. Hizmetlerde veritabanına gerekenden fazla önem atfedildiği durumlar zaman zaman oluyor; bazen de normalizasyon bozulursa çok büyük bir sorun olacakmış gibi aşırı düzeyde tasarım yatırımı yapılıyor, değil mi?
Mesele veritabanı kullanmayalım demek değil; neden kullanıyorduk ve hizmetin asıl temeli gerçekten nedir diye düşünceyi tazelemek açısından bakmak bile bence fazlasıyla iyi olur.
Her zaman denge önemlidir.

 
cafedead 13 일 전

SQLite’ı prodüksiyon sunucusu için seçtiğiniz andan itibaren, ne zaman başka bir şeye geçmeniz gerektiğini sürekli düşünmek zorunda kalırsınız.
Eskiden veritabanının kendisinin maliyeti (sunucu satın alma, IDC, lisans maliyetleri vb.) yüksek olduğu için bunu düşünmeye değerdi,
ancak bugünlerde sözde tek tıkla kurulum yapılabiliyorken gerçekten bunu dert etmeye gerek var mı?

 
roxie 8 일 전

Şu anda da DB pahalı.

 
csjune 12 일 전

Elbette "erken aşamadaki projeler veya ölçeği küçük uygulamalar" için veritabanı gerekmeyebilir. Sadece veritabanı değil, diğer unsurlarda da aşağı yukarı herhangi bir şeyle idare edilebilir. Sorun ölçek büyüdüğünde ortaya çıkıyor. Bu da sadece eğlencesine rakamlara bakan bir yazı.

 
carnoxen 13 일 전

https://hackers.pub/@gnh1201/2025/…

Bazen ayrı bir veritabanı kurulumu gerekmeyebilir. Yalnızca Windows için geçerli olsa da...

 
roxie 8 일 전

Başlığı görünce kahkaha attım.

 
kuthia 13 일 전

Bazen, temel varlıkların kalıcılığının gerçekten RDBMS aracılığıyla güvence altına alınması gerekip gerekmediğini düşünüyorum. Sonuçta SSOT sağlamak için kullanılabilecek epeyce alternatif(?) teknoloji de var.

 
neptune 13 일 전

Sqlite bozulursa yapacak bir şey kalmaz..

 
okxrr 13 일 전

sqlite bozulduğu durumlar var mı? Merak ediyorum. Anormal dosya taşıma veya silme durumları hariç.

 
GN⁺ 14 일 전
Hacker News görüşleri
  • Bu yazıyı gerçekten çok beğendim. Bilgisayarların ne kadar hızlı olduğunu çok iyi gösteriyor.
    Ancak son bölümdeki sonuca katılmıyorum. Yazar, “birden fazla sürecin aynı anda yazması gerekiyor” kısıtının pek çok uygulama için geçerli olmadığını söylemiş ama pratikte erken aşamadaki ürünlerde bile cron ya da message queue gibi ayrı worker'ların eşzamanlı yazma yapması gereken durumlar sık görülüyor.
    Bunu sadece ana sunucunun yazacağı şekilde tasarlayabilirsiniz ama bu da mimari karmaşıklığı artırır.
    Bu yüzden saf ölçek açısından yazara katılsam da, daha geniş bakınca veritabanı kullanmanın daha iyi olduğunu düşünüyorum. Özellikle SQLite makul bir seçim.
    Ölçek ihtiyacı olursa sık erişilen verileri bellekte cache'leyebilirsiniz. Benim kullandığım kombinasyon SQLite + bellek içi cache.

    • Ben de benzer durumlarla sık karşılaşıyorum. Tek bir sunucu yeterli olsa bile sunucu yedekliliği gerektiği anda ağ depolaması gerekiyor ve sonunda ağ üzerinden erişilebilen bir DB'ye yöneliyorsunuz.
      S3 bazen iş görüyor ama hâlâ tam bir alternatif olarak kullanılmasında çok sayıda kısıt var.
    • Bugünlerde yeni bir projeye başlarken varsayılan olarak SQLite kullanıyorum. Performansı çok yüksek ve ileride ölçek büyürse Postgres'e geçmek de kolay.
      Ayrı bir DB sunucusu yönetmek ya da yedek almak gerekmediği için çok daha basit ve ucuz.
    • Rust 1M benchmark'ını gördükten sonra, bilgisayarların ne kadar hızlı olduğunu tekrar fark ettim.
  • SQLite'ı gerçekten seviyorum ama her sorunun cevabı olmadığını da öğrendim.
    İstemci tarafında bir sözlük uygulaması yaparken SQLite wasm portunu denedim ama DB dosyası beklediğimden büyüktü, iyi sıkışmıyordu ve yüklenmesi de yavaştı.
    Sonunda orijinal TSV dosyasından doğrudan indeks oluşturup zstd ile sıkıştırılmış halde tutmaya, wasm içinde de her seferinde açmaya geçtim. Bu, SQLite'tan çok daha hızlıydı.
    Modül boyutu da 800KB'den 52KB'ye düştü ve aynı anda birden fazla instance çalıştırmak da sorun olmadı.
    Metin araması için stringzilla kullandım; inanılmaz hızlı.
    SQLite harika ama her durumda doğru cevap değil.

  • SQLite benchmark'ı yeterince optimize edilmemiş.
    Sadece

    db.SetMaxOpenConns(runtime.NumCPU())
    db.SetMaxIdleConns(runtime.NumCPU())
    

    bunu eklemek bile benim makinemde performansı 27,700 r/s'den 89,687 r/s'ye çıkardı.
    prepared statement ya da timestamp'i int'e çevirmeyi de denedim ama büyük bir fark olmadı.

  • Yazı fena değildi ama “tüm DB'ler dosya sistemine open() ile erişir” kısmı doğru değil.
    SQLite gibi uygulamalar, dosyayı doğrudan bellek alanına eşlemek için mmap kullanır. Bu yöntem syscall'ları atlar ve çok daha hızlı erişim sağlar.
    Yazının ilerleyen kısmında tüm dosyanın belleğe okunma süreci anlatılıyor; mmap kullanılsaydı daha iyi olurdu gibi geliyor.

    • Yazının DB'nin IO'sunu basitleştirerek anlattığı doğru.
      Yine de mmap'in her zaman daha iyi olduğunu söylemek zor. Bazıları OS API'lerine bağımlı olmak yerine bunu uygulama mantığında doğrudan yönetmeyi tercih ediyor.
      İlgili çalışma için CMU'nun mmap araştırmasına bakılabilir.
    • mmap'in kullandığı backend store da sonuçta dosya sistemindeki bir dosya.
      “open() gibi çalışır” ifadesi biraz basitleştirilmiş ama teknik olarak yanlış değil.
  • Uzun zaman önce Perl ile küçük bir satış web uygulaması yapmıştım; ISP sunucusuna hiçbir şey kuramadığım için dosya tabanlı bir hash kullandım.
    Müşteri bunu 20 yıldan fazla aynı şekilde kullandı, sonra vefat etti ve ailesi devralınca Wordpress'e geçti.
    Son kontrol ettiğimde sipariş sayısı yüz binleri bulmuştu ama performans hâlâ iyiydi.
    Donanımdaki gelişmeler sayesinde bu hack işi gibi duran yapı beklediğimden çok daha uzun dayandı. Bugün yapsam muhtemelen SQLite da fazlasıyla yeterli olurdu.

    • Sitede ne tür ürünler satıldığını merak ettim.
  • Depolamayı kendiniz uygulamaya çalışırsanız DB'nin nasıl çalıştığını anlayabilirsiniz.
    İndeksleri ve veri yapılarını verimli şekilde ele almak zorunda kalıyorsunuz ve sonunda “bu iş oyuncak değilse en baştan DB kullanmalıydım” sonucuna varıyorsunuz.

  • Relational Databases Aren’t Dinosaurs, They’re Sharks
    Küçük uygulamalarda elde edilen sınırlı faydaya kıyasla, tekerleği yeniden icat etmek için harcanan zaman çok daha büyük bir kayıp.

    • Köpekbalığı vs dinozor benzetmesi gerçekten çok yerinde.
      Kretase döneminde köpekbalıkları zaten bugünkü hallerine çok yakındı ve sonrasında da büyük değişim geçirmeden hayatta kaldılar.
      Buna karşılık dinozorlar, pterosaurlar ve mosasauruslar yok oldu ama köpekbalıkları, timsahlar ve büyük yılanlar optimize edilmiş tasarımları sayesinde neredeyse aynı şekilde bugüne kadar geldi.
      İlişkisel DB'lerin de böyle olduğunu düşünüyorum.
  • Böyle yazılar okumak keyifli.
    Yine de ben hâlâ vakaların %99'unda SQL ve transaction desteği olan bir DB kullanıyorum.
    Ama yakın zamanda kişisel bir projede veriyi YAML dosyalarına dayalı basit bir dosya sistemiyle yönettim ve benim ölçeğimde hiç performans sorunu yaşamadım.
    İnsan tarafından okunabilir olması ve diff alınabilmesi, performanstan daha önemliydi.
    Yine de çoğu durumda sorgu dili ve garanti edilmiş tutarlılık sunan bir DB seçerim.

  • Sonunda her zaman DB özelliklerine ve ACID garantilerine ihtiyaç duyuluyor.
    Ne zaman eski tip düz dosya tabanlı bir store kullanmam gerekse, tutarlılık, transaction ve sorgu dilini sonradan yamamaya çalışırken zorlanıyorum. Sonuçta yine tekerleği yeniden icat etmiş oluyorsunuz.

  • Atomiklik gereken anda DB şart.
    Dosya sistemi üzerinde atomik yazma uygulamak çok kırılgan bir iş.
    Bu yüzden birçok DB crash durumunda veri bozulması sorunları yaşadı. Bir zamanlar Windows üzerindeki RocksDB de bunlardan biriydi.

    • Dosya üzerinde atomik değişiklik gerekiyorsa ben doğrudan SQLite kullanırdım.
      Bunu kendin uygulamak bana delilik gibi geliyor. OS API'lerini kullanarak güvenli yazmayı öğrenmek elbette iyi olur ama bugünlerde bu fazla niş bir beceri.
      Üstelik sonraki geliştiricinin bunu bakımını yapamama ihtimali de yüksek. Sonunda yine DB'ye geçilir.
    • Yazıdaki kod bir gün elektrik kesilirse boş dosyayla sonuçlanacak.
      En azından aynı dosya sistemi içinde geçici bir dosyaya yazıp, fsync yaptıktan sonra rename ile değiştirmek gerekir.
    • Basit durumlarda o kadar da kırılgan değil.
      Tüm DB'yi geçici bir dosyaya yazıp flush ettikten sonra move ile değiştirirseniz, Unix'te bu atomiktir.
      Ama bunun hiç ölçeklenmediği de açık. Küçük bir güncellemede bile tüm dosyayı yeniden yazmanız gerekir ve lock yönetimi de gerekir. ACID'in sadece bir kısmını çözmüş olursunuz.
    • Böyle bakınca zaten ACID'in A'sıyla uğraşıyor oluyorsunuz.
      Bu arada OLAP DB olan DuckDB, out-of-core iş yüklerinde de çok iyi çalışıyor.
    • 2025 itibarıyla Linux + ext4, tek ve çok bloklu atomik yazma desteği sunuyor.
      resmî doküman bağlantısı
 
mstorm 14 일 전

Buzdolabı olmadan da yaşayabilirsiniz ama bazı zorluklar olur.
Buzdolabı kullanabiliyorken kullanmamak için bir sebep yok.

 
foobarman 12 일 전

Yoksa sen Ilbe’ci misin?

 
alfenmage 5 일 전

"Hayır" deyince herkes Ilbe mi oluyor? Ben Gyeongsang-do'luyum da?

 
foobarman 5 일 전

Şikayet etmek istiyorum ama nasıl şikayet edeceğimi bilmiyorum, ah.

 
okxrr 13 일 전

Bu yorum, Koreli geliştiricilerin ne kadar kalıplaşmış düşündüğünü ve GeekNews’in seviyesini gösteriyor gibi görünüyor.

 
alfenmage 5 일 전

O seviyenin tam olarak ne olduğunu, seviyeyi değerlendirme nedeninin ne olduğunu, mantık/fakt/bilim/istatistikten en az ikisini kullanarak söyle bakalım, evet evet

 
foobarman 5 일 전

Haha, sadece kelimelere bakınca bile DC Inside, Ilbe, Ppomppu tayfasından olduğu belli; aldırmayın.