5 puan yazan GN⁺ 2025-06-07 | 1 yorum | WhatsApp'ta paylaş
  • GitLab, büyük depolar yedeklenirken sürecin çok uzun sürmesi sorununu fark etti ve bunu iyileştirmek için çalışma yaptı
  • Temel neden, 15 yıllık bir Git fonksiyonundaki O(N²) karmaşıklıktı; algoritma optimizasyonuyla performans büyük ölçüde artırıldı
  • Optimizasyon sonucunda, en büyük deponun yedekleme süresi 48 saatten 41 dakikaya düştü
  • İyileştirilen yöntem, kaynak verimliliği ve güvenilirlik sağlarken diğer Git tabanlı araçlar ve topluluk üzerinde de olumlu etki yarattı
  • GitLab 18.0 sürümünden itibaren tüm kullanıcılar ek yapılandırma olmadan bu avantajlardan yararlanabilecek

Depo yedeklemenin önemi ve zorlukları

  • Depo yedekleme, acil durumdan kurtarma stratejisinin temel bileşenlerinden biridir
  • Depo boyutu büyüdükçe güvenilir bir yedekleme sürecinin karmaşıklığı artar
  • GitLab'in kendi Rails deposunun yedeklenmesi 48 saat sürüyordu; bu da yedekleme sıklığı ile sistem performansı arasında zor bir tercih yaratıyordu
  • Büyük depolarda zaman, kaynak, hata riski ve race condition gibi çeşitli sorunlar ortaya çıkar
    • Bu da planlı yedeklemeyi zorlaştırır ve kuruluşların harici araçlara bağımlı olmasına ya da yedekleme sayısını azaltmasına yol açarak tutarsız stratejiler doğurur

Performans darboğazının analizi ve nedenin bulunması

  • GitLab'in yedekleme özelliği, depo snapshot'ı oluşturmak için git bundle create komutunu kullanır
  • Bu komutun uygulanma sürecinde, reference sayısı arttıkça performans darboğazı oluşuyordu
  • Milyonlarca reference içeren büyük depoların yedeklenmesi bazı durumlarda 48 saatten uzun sürüyordu

Neden analizi

  • Komut çalıştırılırken yapılan Flame Graph analiziyle darboğaz bölgesi tespit edildi
  • Reference sayısı 10.000 olduğunda, çalışma süresinin yaklaşık %80'i object_array_remove_duplicates() fonksiyonunda harcanıyordu
  • Bu fonksiyon, 2009'da ilgili commit ile yinelenen reference'ları işlemek amacıyla eklenmişti
    • git bundle create kullanılırken yinelenen reference'lar dahil edilirse ortaya çıkabilecek sorunları önlüyordu
    • Ancak yinelenenleri tespit etme işlemi iç içe geçmiş for döngüleri biçiminde yazıldığı için O(N²) karmaşıklık oluşturuyordu
    • Reference sayısı arttıkça darboğaz daha da ağırlaşıyordu

O(N²)'den verimli eşlemeye geçiş

  • GitLab, iç içe döngüler yerine map veri yapısı kullanan bir yaklaşımı Git'e yama olarak katkı sundu
    • Her reference map'e eklenerek tekrarlar otomatik kaldırıldı ve daha verimli işlendi
  • Bu değişiklikle git bundle create performansı büyük ölçüde iyileşti ve çok sayıda reference bulunan ortamlarda da ölçeklenebilir hale geldi
  • Benchmark sonuçlarına göre, 100 bin reference ölçütünde 6 katın üzerinde performans artışı görüldü

Büyük ölçüde kısalan yedekleme süresi ve etkileri

  • En uzun depo yedekleme süresi 48 saatten 41 dakikaya (%1,4 seviyesine) düştü
  • Depo boyutundan bağımsız olarak tutarlı performans sağlanabilir hale geldi
  • Sunucu yükünün azalması ve yedekleme temelli Git komutlarında genel performans artışı gibi ek kazanımlar elde edildi
  • İlgili yama upstream Git'e uygulandı; GitLab tarafında ise müşterilerin bunu hızla deneyimleyebilmesi için hemen devreye alındı

GitLab müşterileri için gerçek değişim

  • Kurumsal müşteriler artık art arda gece boyunca yapılan yedeklemeleri, geliştirme iş akışlarıyla çakışmadan çalıştırabiliyor
  • Recovery Point Objective (RPO) süresinin kısalması sayesinde, afet durumlarında veri kaybı riski ciddi ölçüde azaldı
  • Kaynak tüketimi, bakım süresi ve bulut maliyetleri dahil olmak üzere operasyonel yük de düştü
  • Depo ölçeği büyüse bile artık yedekleme sıklığı ile sistem performansı arasında seçim yapmak gerekmiyor
  • Artık tüm GitLab kullanıcıları yapılandırma değişikliği olmadan bu avantajlardan yararlanabiliyor

Sonraki adımlar ve anlamı

  • Bu iyileştirme, GitLab'in ölçeklenebilir kurumsal düzeyde Git altyapısı kurmaya yönelik sürekli çabasının bir parçası
  • GitLab'in katkı sunduğu değişiklikler upstream Git projesine de yansıtıldı ve sektör geneli ile açık kaynak topluluğu üzerinde olumlu bir etki yarattı
  • Bu tür altyapı iyileştirme çalışmaları, diğer kritik performans iyileştirmeleri için de model haline geliyor

GitLab'in performans yaklaşımına dair daha derin bir anlatım, GitLab 18 virtual launch etkinliğinde görülebilir

1 yorum

 
GN⁺ 2025-06-07
Hacker News görüşleri
  • GitLab’ın Git’e katkı olarak sunduğu performans iyileştirme kodunun v2.50.0 sürümünde yayımlanmasının planlandığı bilgisi paylaşılıyor. ilgili commit bağlantısı

  • Kendi deneyimlerinden yola çıkarak, yazdığı kodda n^2 işlemlerini ortadan kaldırmanın her zaman doğru seçim olduğunu vurguluyor. Özel bir algoritma yazmadan bile, problemin çok küçük n değerlerinde bile kolayca ortaya çıkmasına şaşırdığını söylüyor.

    • Bruce Dawson’ın birinci bilişim yasasına atıf yapıyor: O(n^2), en kötü ölçeklenebilirlik sorunlarının başladığı nokta. Prodüksiyonda yeterince hızlı görünür, ama dağıtıma çıktıktan sonra ölümcül performans düşüşlerine yol açar. ilgili yazı bağlantısı

    • O(N^2) zaman karmaşıklığının testlerde hızlı görünüp prodüksiyonda ciddi sorunlara yol açtığı durumları defalarca gördüğüne dair kişisel deneyimini paylaşıyor.

    • Kendi deneyimine göre sorunların büyük kısmında (%80–90), karmaşık algoritmalara ihtiyaç duyuluyorsa bu genelde veri modelinin baştan doğru kurulmadığının işaretidir. Derleyiciler, veritabanı iç yapıları, rota planlama gibi bazı özel alanlar dışında karmaşık algoritmaların özünde gerekli olduğunu düşünmüyor.

    • Yalnızca n değerinin 10’dan küçük kaldığı, donanım açısından sınırlı durumları istisna olarak anıyor (CAN arayüzü gibi). Eğer donanım değişmeden n büyüyebiliyorsa n^2 işlemlerinden mutlaka kaçınılması, ya tasarımda sınır konulması ya da önceden tespit edilip yeniden tasarım gereksiniminin fark edilmesi gerektiğini öneriyor.

    • Kendisinin de n^3 işlem yüzünden yalnızca 10.000 öğede darboğaz yaşadığını, ama henüz bir çözüm bulamadığını söyleyerek sıkıntısını dile getiriyor.

  • Bunun ilginç bir bulgu olduğunu söylüyor, ancak yazının uzunluğunun onda biri kadar olsa bile yeterince etkili iletişim kurulabileceğini düşünüyor. Yine de video içerik olmaması sayesinde göz gezdirmenin kolay olmasını olumlu buluyor.

    • Yazıyı henüz okumamış olanlar için, flame graph bölümünden sonra backport konusuna gelinmeden önce okumayı bırakmanın özünü kavramak açısından en verimli nokta olduğunu söylüyor.

    • Yazının genel üslubunun, sanki bir LLM (büyük dil modeli) tarafından üretilmiş gibi hissettirecek kadar uzun olduğunu ve bunun aklında kaldığını belirtiyor.

    • Yazı daha uzun olsaydı bile sorun etmeyeceğini, ancak neden yedekleme bundle’ının iki ref olarak oluşturulduğunu hâlâ merak ettiğini söylüyor.

  • 48 saatin, birkaç GB büyüklüğündeki bir git klasörünü sıkıştırmak için çok uzun olduğunu; hatta 41 dakikanın bile uzun sayıldığını düşünüyor. Tüm git deposu neden doğrudan snapshot/archive olarak alınmıyor da özellikle git bundle kullanılıyor, bunu sorguluyor. git bundle’ın düzenli yapılan ZFS yedeklemelerine kıyasla ne gibi bir avantajı olduğunu merak ediyor.

    • Git’in resmi SSS belgesine göre, bu tür yöntemler Git’in normal bütünlük kontrol süreçlerini baypas ettiği için risk taşıyor. Bu durumda koleksiyon bütünlüğünü doğrulamak için git fsck öneriliyor. Bireysel kullanımda Syncthing ve Btrfs snapshot’larının tek başına yeterince hızlı ve güvenilir olduğunu söylüyor. ilgili belge

    • ZFS snapshot’larını S3 gibi ZFS tabanlı olmayan harici hedeflere yedeklemenin kısıtları olduğunu belirtiyor. git bundle’ın daha az bilinen bir özelliği olarak, git clone --bundle-uri ile bir konum belirtilebildiğini; sunucunun istemciye bundle konumunu söylemesi hâlinde istemcinin bundle’ı indirip hızlıca açacağını ve yalnızca delta güncellemelerini sunucudan alacağını, böylece büyük depoların kopyalanmasındaki yükün ciddi biçimde azalacağını anlatıyor.

    • Sonuçta burada yapılmış şeyin, önbellekleme gereken yere önbellek eklemek gibi göründüğünü söylüyor. Normalde git depolarının dağıtık sistem yapısı gereği başka depolara mirror edilip dosya sistemi snapshot/yedek araçlarıyla yönetilmesinin yeterli olması gerekmez mi diye soruyor. Asıl önemli olanın, kritik sürüm kontrol bilgisinin kendisinin dağıtık biçimde tutulması olduğunu vurguluyor.

  • Git yedekleme konusunda çok tecrübeli olmadığını, ama yerel repodan doğrudan yedek alınırken neden race condition oluştuğunu merak ettiğini belirtiyor.

  • Eğer üst katman veri protokolü yüzünden iş bu kadar zahmetli hâle geliyorsa, neden doğrudan blok seviyesinde snapshot kullanılmadığını sorguluyor. Git’te WAL (Write Ahead Logging) benzeri bir yapı olmamasını engel olarak görüyor, ancak SQLite’ta yalnızca WAL modu ekleyerek blok snapshot stratejisini gerçek servis ortamında sorunsuz kullandığını söylüyor. Git’te de böyle bir mimari olsaydı çok daha sağlam yedekleme stratejileri mümkün olabilirdi diye düşünüyor.

    • Git’te WAL benzeri bir mekanizma olmamasından kaynaklanan sorunu anladığını, sadece snapshot’a güvenerek yapılan yedeklemenin geri yükleme sırasında deponun bozulmasına yol açtığı kritik bir sorun yaşadığını paylaşıyor. Kurtarmanın mümkün ama çok uğraştırıcı olduğunu ekliyor.

    • SQLite için son dönemde daha iyi bir seçenek olarak sqlite3_rsync çözümünün çıktığını hatırlatıyor.

    • GitLab’ın yalnızca basit bir managed service değil, kullanıcıların kendilerinin kurup çok farklı ortamlarda çalıştırabildiği bir ürün olduğunu; dolayısıyla her kullanıcının dosya sistemi, snapshot desteği ve işletim sistemi koşullarının farklı olabileceğini açıklıyor. Bu yüzden GitLab açısından, her ortamda genel geçer şekilde çalışacak bağımsız bir yedekleme sistemi istemenin mantıklı olduğunu söylüyor.

  • “Algoritma değişikliğiyle yedekleme süresi üstel olarak (Exponentially) azaltıldı” ifadesini görünce, bunun O(n^2)’den O(n^2/2^n)’e düşürüldüğü anlamına gelip gelmediğini sorguluyor. Gerçekte öyle olmadığını tahmin ediyor.

    • Düzeltilen fonksiyonun algoritmik karmaşıklığının gerçekte 6 kat hızlandığını; diğer kullanım bağlamlarında ise toplam çalışma süresinin %1’e düştüğü kadar dramatik sonuç verdiğini, bu yüzden bu durumda “üstel iyileşme” ifadesinin pazarlama açısından kabul edilebilir olduğunu söylüyor. Kesin karmaşıklık sınıflandırmasının burada çok anlamlı olmadığını ekliyor.

    • Günlük konuşmada exponential kelimesinin matematiksel olarak tam kesin bir anlamda değil, daha çok “muazzam ölçüde iyileşti” anlamında mecazi şekilde kullanıldığını açıkça belirtiyor.

    • Kendi yorumuna göre bunun n’den log(n)’e düşüş anlamına gelebileceğini düşünüyor. Kuantum Fourier dönüşümünün klasik DFT’ye göre üstel derecede daha hızlı olduğunun sıkça söylenmesine benzer şekilde, karmaşıklığın n^2’den nlogn’e geçtiği durumu anıyor.

    • n^2 bir algoritma log(n) arama yaklaşımıyla değiştirildiğinde hızın üstel olarak artmış sayılabileceğini, ama pratikte bunun çoğu zaman hash map erişimi gibi O(1) seviyesine kadar gittiğini ve dolayısıyla daha da hızlı olduğunu söylüyor.

    • Bu tartışmanın kendisini verimsiz bir laf kalabalığı olarak gördüğünü ifade ediyor.

  • C ile yazılmış olmanın tek başına performans garantisi vermediğini, veri yapıları ve algoritmaların daha önemli olduğunu gösteren iyi bir örnek olduğunu söylüyor.

    • C’de uygun container’ları uygulamanın çok zor olması nedeniyle bu tür performans sorunlarının daha sık yaşandığını belirtiyor. C++ veya Rust’ta unordered_set/HashSet gibi yerleşik veri yapıları sayesinde geliştiricilerin basit bir for döngüsüyle geçiştirmek yerine daha doğal biçimde optimize etme eğiliminde olduklarını söylüyor. Bu örnekte de Git’te string set olsa bile standart bir yapı olmadığı için ilk yazanın bunu bilmiyor olabileceğini düşünüyor.
  • Erken optimizasyon ile öngörücü (anticipatory) optimizasyon arasında denge gerektiği dersini çıkarıyor. Genel olarak erken optimizasyondan kaçınmak gerekse de, çok sık çağrılan fonksiyonlarda bariz ve kolay optimizasyonların önceden uygulanmasının iyi bir kural olabileceğini öneriyor.

    • Uygulama yazıldığı dönemde kullanılan kaynak dilde string set yapısı yerleşik olsaydı, ilk geliştiricinin de bu optimizasyonu kolayca uygulayabileceğini tahmin ediyor. Sonuçta bu tür problemlerin C gibi container bakımından zayıf dillerin yapısal sınırlamalarından kaynaklandığını düşünüyor.
  • İlgili commit’i, yani algoritma iyileştirmesinin yapıldığı değişikliği doğrudan paylaşıyor. ilgili commit bağlantısı