1 puan yazan GN⁺ 2024-07-28 | 1 yorum | WhatsApp'ta paylaş
  • 26 Haziran 2024’te yayınlanan One Million Checkboxes, herkesin aynı 1 milyon onay kutusunu gerçek zamanlı olarak manipüle ettiği bir siteydi ve 2 hafta sonra kapanmadan önce 650 milyondan fazla işaretlemeyi işledi
  • Durumun kendisi yalnızca 1 milyon bit, yani 125KB idi; ancak nginx, Flask/gunicorn ve Redis pubsub ile kurulan ilk yapı beklenmedik trafik karşısında hızla sınırlarına ulaştı
  • Hacker News, Reddit, Mastodon ve Twitter’dan gelen trafikle on binlerce kişi akın edince Redis bağlantı tükenmesi, bant genişliği patlaması, girdi doğrulama eksikliği ve eski güncellemelerin uygulanması sorunları art arda ortaya çıktı
  • Müdahale, sunucu ve Redis ölçeklendirmesi, güncellemeleri toplu işleme, aktarım formatını küçültme, Linux tc tabanlı 250Mbit/s bant genişliği üst sınırı ve süreç yeniden başlatma betiği gibi hızlı uygulanabilecek önlemlere odaklandı
  • Sonrasında backend Go’ya taşınarak istikrara kavuşturuldu ve en sonunda Redis Lua script’i ile onay kutusu dondurma mantığı atomik olarak işlendi; site 11 Temmuz 2024 Doğu Saati ile 4:35 PM’de tamamlandı

Site ve ilk tasarım

  • One Million Checkboxes(OMCB), 26 Haziran 2024’te yayına alınan ve 1 milyon küresel onay kutusu sunan bir web sitesiydi
    • Bir kullanıcı bir onay kutusunu açıp kapattığında bu değişiklik tüm kullanıcıların ekranına anında yansıyordu
    • Yapımı 2 gün sürdü ve beklenen kullanıcı sayısı en fazla birkaç yüz düzeyindeydi
  • Gerçek tepki beklentinin çok üzerindeydi
  • İlk günün erken saatlerine ait bazı loglar elde kalmadı
    • Çünkü başlangıçta günlük logların yalnızca en son 1 milyon adedi saklanıyordu
    • İkinci günden itibaren istikrar sağlanmaya başladı ve o gün 50 milyondan fazla işaretleme yapıldı
    • Site kapanmadan önce toplam işaretleme sayısı 650 milyonu aştı

Redis merkezli ilk mimari

  • Onay kutusu durumu 1 milyon bit ile ifade ediliyordu
    • İşaretli kutu 1, işaretsiz kutu 0 idi
    • Toplam durum boyutu 125KB idi
    • İstemci, bitset’i saklıyor ve render sırasında buna başvuruyordu
  • İstemci, DOM yükünden kaçınacak şekilde yapılandırılmıştı
    • 1 milyon öğenin tamamı DOM’a eklenmiyordu
    • react-window kullanılarak yalnızca ekranda görünen onay kutuları ve küçük bir buffer render ediliyordu
  • Sunucu yapısı, basit yatay ölçeklemeyi dikkate alacak şekilde kurulmuştu
    • nginx statik içeriği sunuyor, API istekleri ile websocket bağlantılarını Flask sunucusuna iletiyordu
    • Flask sunucusu, gunicorn ile çalışan iki instance’tan oluşuyordu
    • Redis hem onay kutusu durumunu saklıyor hem de mesaj kuyruğu görevi görüyordu
  • Redis’in kullanım biçimi de doğrudandı
    • Redis’in bit işleme primitive’leriyle tek tek onay kutularının durumu değiştiriliyordu
    • İstemci bir işaretleme olayı gönderdiğinde Flask, Redis’te ilgili biti çeviriyor ve olayı pubsub’a yazıyordu
    • İki Flask sunucusu da pubsub’ı okuyup kendilerine bağlı istemcilere değişikliği bildiriyordu
  • Tüm durum anlık görüntüsü, kaçırılan güncellemeleri telafi etmek için kullanılan bir mekanizmaydı
    • Arka planda kalan sekmeler yüzünden güncelleme kaçıran istemcileri senkronize etmek için kullanılıyordu
    • İlk uygulamada her 30 saniyede bir tüm durum gönderiliyordu

Ölçekleme ilkeleri

  • Maliyet için üst sınır hesaplanabilir olmalıydı
    • Sınırsız otomatik ölçekleme ile maliyetin patladığı bir yaklaşım özellikle tercih edilmedi
    • Beklenenden fazla yük gelirse sistemin kırılmasına izin verme tarafı seçildi
  • Popülerliğin kısa süreceği varsayıldı
    • Günler veya haftalar sürecek kusursuz çözümler yerine birkaç saat içinde üretilebilecek müdahaleler öne alındı
    • Bu süreçte oluşan teknik borç kabul edildi
  • Teknoloji seçiminde basitlik ve doğrudan işletilebilirlik tercih edildi
    • Sunucuya doğrudan bağlanıp komut çalıştırıp debug edilebilen bir yapı seçildi
    • Ağırlıklı olarak kendi başına işletilebilen ve debug edilebilen bağımlılıklar kullanıldı
  • Sitenin temel deneyimi küresel senkronizasyondu
    • Nereye gidilirse gidilsin değişimin anında görülebilmesi gerekiyordu
    • Kullanıcının gördüğü onay kutularını göndermeye dayalı bir ölçekleme yöntemi seçilmedi

İlk gün: sunucu ekleme ve Redis darboğazı

  • Yayından sonraki 30 dakika içinde yük hızla arttı; site ayaktaydı ama uzun süre dayanması zordu
    • En açık iyileştirme sunucu sayısını artırmaktı
    • nginx, başka bir VM’deki Flask instance’larına kolayca reverse proxy yapabiliyordu ve durum zaten Redis’teydi
  • İkinci sunucu yaklaşık 12:30 PM’de eklendi ve kısa sürede yük %100’e ulaştı
    • Başta bir veya iki ek sunucunun yeterli olacağı düşünülmüştü
    • Gerçekte ise ölçeklendikçe trafik de aynı oranda arttı
    • Site Hacker News’te 1 numaraya çıktı ve Twitter etkinliği de hızla arttı
  • Flask sunucuları ile Redis bağlantıları darboğaz haline geldi
    • Redis connection pool yoktu ve Redis bağlantı sınırına dayanmaya başlamıştı
    • Bunun üzerine güncellemeleri toplu gönderme yaklaşımına geçildi
    • Mevcut istemcilerle geriye dönük uyumluluk gözetilmedi; kullanıcıların sayfayı yenileyeceği varsayıldı
  • Redis connection pool da eklendi ancak gunicorn ve Flask kombinasyonunda temiz çalışmadı
    • Yine de Redis bağlantı sayısını azaltmaya yardımcı olmuş görünüyor
    • Sonrasında bu sorun derinlemesine incelenmeden Go geçişine gidildi
  • Oturum oluşturma rate limit’i kaldırıldı
    • Çünkü rate limit durumu Redis’te tutuluyordu ve Redis bağlantıları tükeniyordu
    • Sorun yeni oturum patlaması değil, tek bir oturumdan çok fazla veri gönderilmesiydi
    • Kısa vadede riskli olsa da kabul edilebilir bir hamle olarak değerlendirildi
  • Redis instance’ı da daha büyük bir yapılandırmaya geçirildi
    • Digital Ocean managed Redis kullanılıyordu
    • 1 shared CPU ve 2GB RAM’li küçük instance’tan 4 dedicated CPU ve 32GB RAM’li instance’a geçildi
    • Yeniden boyutlandırma yaklaşık 30 dakika sürdü

Bant genişliği sorunu ve aktarım miktarını azaltma

  • Başlangıçta bant genişliği maliyeti yeterince hesaba katılmamıştı
    • Digital Ocean, ücretsiz bant genişliği aşıldıktan sonra GB başına $0.01 ücret alıyordu
    • Önceki işlerden kalan 1TB ücretsiz bant genişliği vardı ve OMCB’nin bunun üzerinde büyük etkisi olmayacağı düşünülmüştü
  • Tüm durum anlık görüntüleri bant genişliğini çok hızlı tüketebilirdi
    • 1 milyon bit, 1Mbit eder
    • Her 30 saniyede 1.000 kişiye gönderildiğinde dakikada yaklaşık 2GB, saatte 120GB düzeyine çıkıyordu
    • Bu hesap incremental update’leri içermiyordu
  • Bant genişliğini kontrol etme ve maliyet üst sınırı koyma işi nginx kutusunda yapıldı
    • Gönderilen bayt miktarı ip -s link show dev eth0 ile kontrol edildi
    • Tek bir nginx reverse proxy kullanıldığı için bant genişliğinin kaynağını tahmin etmek kolaydı
  • Aktarım miktarını azaltma iki koldan yürüdü
    • Tüm durum anlık görüntülerinin sıklığı düşürüldü
    • Incremental update formatı küçültüldü
  • Toplu güncelleme formatı ciddi biçimde sıkıştırıldı
    • Eski format { "index": 123, "value": true } gibi dict listelerinden oluşuyordu
    • Son format, true index dizileri ile false index dizilerinden oluşan [[123, 125], [124]] çiftiydi
    • Bu yaklaşım ilk uygulamaya göre 5 kat daha kısaydı
  • Maliyet patlamasını önlemek için Linux tc ile hard cap uygulandı
    • Public interface eth0 üzerindeki trafik 250Mbit/s ile sınırlandı
    • Bu, dakikada yaklaşık 2GB ve günde 3TB’ye biraz az kalan bir seviyeye denk geliyordu
    • GB başına $0.01 fiyatla, maliyetin gece boyunca kontrolden çıkma riskinden kaçınıldı

İkinci gün: girdi doğrulama eksikliği ve Redis replica

  • Ertesi sabah site kapalıydı; neden girdi doğrulama eksikliğiydi
    • 1 milyonu aşan index’lerdeki onay kutuları engellenmiyordu
    • Birisi yüz milyonlar seviyesindeki index’lerdeki onay kutularını değiştirdi
    • Bu yüzden işaretli kutu sayısı 1 milyona ulaşmış gibi göründü ve sitenin bittiği düşünüldü
  • Redis verisi de gereksiz yere büyüdü
    • 1 milyoncü bit ile 100 milyonuncu bit arasına milyonlarca 0 eklendi
    • İstemcilere gönderilen veri 100 kat büyüdü
  • Kurtarma hızlı ilerledi
    • nginx durduruldu
    • Eski bitset’in yalnızca ilk 1 milyon biti yeni bir bitset’e kopyalandı
    • Eski bitset debug amacıyla saklandı
    • Kod yeni bitset’e yönlendirildi ve girdi doğrulaması eklendi
  • İlk sayfa yüklemesi de yavaşlamıştı
    • Redis yükü yüksekti ve connection pool bug’ı yüzünden aşırı sayıda bağlantı da açılıyordu
    • Connection pool sorununu debug etmek yerine primary yükünü ve bağlantıları dağıtmak için bir Redis replica eklendi
  • Replica’nın private IP’si elle bulunmak zorunda kaldı
    • Digital Ocean yönergelerindeki gibi public DNS’te replica- öneki çalışıyordu ama private DNS’te çalışmıyordu
    • Public IP kullanılırsa public internet üzerinden geçiş ve bant genişliği ücretlendirmesi riski olduğu düşünüldü
    • Primary ve diğer sunucuların private IP’lerine yakın adresler denenerek üçüncü ya da dördüncü denemede replica private IP’si bulundu
    • Sonrasında bu IP hardcode edildi

Süreç yeniden başlatma ve stale update düzeltmesi

  • Flask süreçleri çökmeye devam etti ve bunun nedeninin Redis bağlantı eksikliği olduğu düşünüldü
    • Ayrıntılı debug yerine, çalışan Flask süreçlerinin sayısını kontrol eden bir bash script’i yazıldı
    • Çalışan süreç sayısı 3’ün altına inerse systemd unit’i yeniden başlatıyordu
    • Script crontab’e eklendi
  • nginx yapılandırması da buna uygun şekilde ayarlandı
    • Düşen sunucuların geçici olarak rotation dışına alınması sağlandı
    • Bu değişiklikten sonra site istikrara kavuştu
  • İstemci durum senkronizasyonunda bir stale update bug’ı vardı
    • İstemci hem incremental update hem de full-state snapshot alıyordu
    • Bu iki güncellemede timestamp olmadığı için istemci yeni bir snapshot aldıktan sonra eski bir incremental update uygulayabiliyordu
    • Sonuç olarak bir sonraki full-state snapshot gelene kadar tamamen yanlış bir durum görülebiliyordu
  • Timestamp tabanlı bir hafifletme eklendi
    • Full-state snapshot’a timestamp eklendi
    • Redis pubsub’a yazılan her update’e de timestamp eklendi
    • İstemciye gönderilen batch içine, kapsadığı incremental update’ler arasındaki en büyük timestamp kondu
    • İstemci artık son full-state snapshot’tan daha eski batch’leri atıyordu
  • Bu çözüm kusursuz değildi
    • Batch içindeki update’lerden yalnızca biri bile yeniyse, çoğu eski olsa da batch uygulanabiliyordu
    • Yine de önceki duruma göre büyük bir iyileşmeydi

Go ile yeniden yazım ve istikrar

  • Ertesi sabah site ayaktaydı ve sonrasında odak backend’in yeniden yazımına kaydı
    • Bu sırada Washington Post’tan da bir e-posta gelmişti
    • Siteyi nasıl kapatacaklarına dair plan da aynı anda düşünülüyordu
  • Kapanış planı, işaretli kutuların hızlıca kaldırılmaması halinde donması üzerine kuruluydu
    • Bu değişiklik etkinlikte yeni bir patlamaya ve ek sunucu çalışmasına yol açabilirdi
    • Mevcut Flask tabanlı yapının bunu kaldırıp kaldıramayacağından emin değillerdi
  • Arkadaşı Eliot ile birlikte backend Go ile yeniden yazıldı
    • Pazar günü 2 PM’den 2 AM’e kadar uygulama konuşulup tüm backend port edildi
    • Yapı büyük ölçüde değiştirilmeden taşındı
    • En güncel protokolü destekleyen bir Go socketio kütüphanesi bulmak gibi noktalar engel oluşturdu
  • Performans artışı çok büyüktü
    • Sistem o kadar iyi ölçeklenmeye başladı ki botlar aşırı trafik yükleyebilir hale geldi
    • Daha iyi bir rate limit ihtiyacı ortaya çıktı
  • Pazar gecesi bir DDoS da yaşandı
    • Site Cloudflare arkasına alınarak ve nginx ayarları biraz değiştirilerek buna yanıt verildi

Siteyi kapatma mantığı

  • Go ile yeniden yazımdan sonra site istikrarlı çalıştı
    • Sonraki bir hafta boyunca röportajlar ve yoğun ilgiyle ilgilenildi
    • Ardından siteyi kapatma işine geçildi
  • Kapanış yöntemi onay kutularının donmasıydı
    • İşaretli bir kutu hızla kaldırılmazsa frozen durumuna geçiyordu
    • Zaman ilerledikçe tüm site tamamen frozen hale geliyordu
  • Redis’e ek durum bilgisi eklendi
    • Her onay kutusunun en son ne zaman işaretlendiğini tutan bir hashtable eklendi
    • Bu durum istemciye göndermek için büyük olsa da Redis’te saklamak için uygundu
    • time_to_freeze değeri de saklandı
  • Donma kararı uncheck anında veriliyordu
    • now - last_checked > time_to_freeze ise uncheck yapılmıyordu
    • Bunun yerine frozen_bitset güncellenerek ilgili onay kutusunun frozen olduğu işaretleniyordu
    • frozen_bitset, checked durumu gibi istemcilere dağıtılıyordu
    • İstemci, frozen biti açık olan onay kutularını devre dışı bırakıyordu
  • Kimse uncheck yapmasa da donmanın gerçekleşmesi için ayrı bir iş eklendi
    • Periyodik olarak donması gereken ama henüz işaretlenmemiş bitler bulunup frozen durumuna geçiriliyordu
    • İlgili mantık Redis Lua script’ine konarak atomik biçimde çalıştırıldı
    • Böylece race condition’lardan kaçınmak kolaylaştı
  • Kapanış değişikliği yayına alındıktan 2 hafta 1 gün sonra uygulandı
    • 11 Temmuz 2024 Doğu Saati ile 4:35 PM’de 491915 numaralı kutu işaretlendi ve site tamamlandı

Maliyet ve çıkarılan dersler

  • Siteyi işletmenin maliyeti yaklaşık $850 oldu
    • Bağışlar bu maliyete oldukça yaklaştı
    • Sonuçta büyük bir zarar olmadığı değerlendirildi
  • Redis ve nginx seçiminden memnun kalındı
    • Redis ve nginx çok faydalı teknolojiler olarak değerlendirildi
    • Doğrudan işletildikleri için debug ve düzeltme kolay oldu
    • Ancak managed Redis instance üzerinde tam kontrol olmaması biraz rahatsız ediciydi
  • Başından itibaren uzun süreli büyük ölçek tasarımı yapmama kararı olumlu değerlendirildi
    • İnternette neyin başarılı olacağını öngörmenin zor olduğu düşünülüyor
    • En başta haftalarca scale üzerine düşünülseydi muhtemelen site hiç yayımlanamayacaktı
    • Çok sayıda kullanıcının gelmesi, bakım motivasyonu ve öncelik belirleme açısından yardımcı oldu
  • Sınırlı anonim etkileşime yönelik talep de doğrulandı
    • İnsanların yabancılarla sınırlı biçimde etkileşime girilen sitelere ilgi gösterdiği görüldü
    • Bu tür siteleri yapmaya devam etme konusunda güven arttı

1 yorum

 
GN⁺ 2024-07-28
Hacker News yorumları
  • Dağıtık sistemlerin tarihsel bilgisiyle birlikte öğrenilecek çok şey olan bir yazıydı.
    Depolama alanı hariç neredeyse her tür kesinti ve arıza noktasını yaşamış gibi görünüyor; çözüm sürecini görebilmek güzeldi.
    Redis'in Lua desteklediğini bilmiyordum; bunu görünce alternatif bir durum deposu olarak denemek istedim.
    Bant genişliği, bulut servislerindeki en büyük şikâyetlerimden biri. Çünkü aşırı ücretlendirmeyi engelleyecek sert bir limit yok.

    • Depolama alanını da sıkıcı bir şekilde yaşadım. logrotate ayarı düzgün değildi, disk neredeyse dolmuştu; box-check loglarını Redis'e gönderirken Redis patlamasın diye eski logları diske indiren bir düzenek yapmak zorunda kaldım.
      Ama ikisi de büyük sorun değildi; depolama alanının anlamlı bir sorun olmadığı bir proje görmek epey ilginçti. Benim için yeni bir deneyimdi.
      Bant genişliği gerçekten baş ağrıttı. Yaklaşık iki gün boyunca sürekli tetikte kalıp NIC'in gönderilen baytlarını kontrol ettim, hesapları tekrar yaptım; hard cap olmaması korkutucuydu. Digital Ocean'ın fiyatları oldukça makul sayılmasına rağmen böyleydi.
      Popüler sunucusuz servisleri kullanmadım ama oralarda bant genişliği maliyetinin epey sert vurduğunu anlıyorum.
      Ayrıca Redis içindeki Lua gerçekten güçlü; biraz performans kaybını göze alabiliyorsanız zor ve yarış koşulu bol birçok problemi atlayabiliyorsunuz, çalışması da keyifliydi.
  • Harika bir yazıydı; web sitesi de tebriki hak ediyor.
    Ama kişisel olarak en çok gurur duyulacak kısmın bu yazılmış metin olduğunu düşünüyorum.

    • Siteyi yayına almadan önce yapmaya harcadığım zamandan yazıyı yazmaya çok daha fazla zaman harcadım; bu bana oldukça komik geliyor.
  • “Ölçeklenebilirliği neredeyse hiç önemsemeden siteyi iki günde yapmanın iyi bir seçim olduğu” kısmının öz olduğunu düşünüyorum.
    Özellikle kariyerinin başındaki mühendislerin öğrenmesi gereken bölüm bu. Ölçeklenebilirlik, sorun olana kadar sorun değildir.
    Sorun olduğu noktada ise aslında iyi bir sorundur ve düzeltmesi sanıldığından zor da değildir.

    • Bu ancak “o yüzden sistemi basit ve temel tutun” kısmıyla birlikte kabul edildiğinde doğru.
      Ölçekleme ya da ekip ayrımı gerektiği için değil, geliştiriciler sadece öyle yapmak istediği için mikroservislerin “bariz seçim” olduğu çok sistem gördüm.
      Böyle sistemleri ölçeklemek gerçekten eziyet.
  • Yakın tarihli ilgili yazı: One Million Checkboxes - https://news.ycombinator.com/item?id=40800869 - Haziran 2024, 305 yorum

  • Böyle projeler eğlenceli.
    Yaklaşık 6 yıl önce Android'de Pixmap'i çıkarmıştım; 1024x1024 gibi daha büyük ızgaraları destekleyen küçük bir iş birliğine dayalı piksel düzenleme uygulamasıydı.
    Her olayı bir PNG görüntüsüne uygulayan bir kuyruk vardı; istemci bağlandığında ilk PNG'yi yüklüyor, sonrasında her piksel çizme olayı için yalnızca küçük bir nesne alıyordu.
    Böylece ilk yüklemede görüntü sıkıştırmasından yararlanabiliyorsunuz, sonraki değişiklik kümeleri ise çok küçük oluyor. Ayrıca tüm olaylar logda saklandığı için görüntüyü “geri sarabiliyorsunuz” [0]
    [0] 22mb: https://blog.winricklabs.com/images/pixmap-rewind-demo.gif

    • Güzelmiş. Birden çok web istemcisine piksel düzeyinde güncellemeler gönderme konusunda benzer bir fikre baktım ama yapmak istediğim yöntemle bant genişliği ve depolamayı fazla tüketecek gibi görünüyordu.
      Bu yüzden API çağrısıyla adreslenebilen bir tuval üzerinde kurcalıyorum.
      https://x.com/RussTheMagic/status/1816749136487588311
  • İyi yazıydı. Sonunda maliyetin ne kadar tuttuğunu merak ediyorum.

    • Bunu eklemeliydim.
      Toplam maliyet yaklaşık 850 dolar oldu ve bağışlarla neredeyse karşılandı.
      Go'ya geçtikten sonra altyapıyı düzgün kapatmama hatası yaptım; ayrıca açtığım ikinci Redis replikasını da kaldırabilirdim. Maliyete odaklansaydım yarıya indirebilirdim diye düşünüyorum.
      Ama bağışlar maliyeti neredeyse karşılıyordu ve başka çok iş vardı, bu yüzden buna fazla odaklanmadım.
      Siteyi kapattıktan sonra da grafik hazırlığı vb. için altyapıyı bir süre açık tuttum, bu yüzden biraz daha para gitti; şu anda az da olsa zarardayım ama büyük bir tutar değil.
  • Backend'i yeni öğrenen biri olarak, bu proje için daha basit bir alternatif mimari var mı merak ediyorum.
    1 milyon bitlik durumu barındırmanın ve istemcilerle senkronize etmenin daha kolay bir yolu olsa iyi olurdu. Yazıdaki çözümlerin bir kısmını anlamak zordu.
    Yazarın projeleri harika.

    • Yazının bazı kısımları zorduysa kusura bakmayın.
      Kullandığım teknolojileri daha uzun açıklamak istedim ama yazı zaten çok uzundu, daha fazlasını eklemek zor geldi.
      Sorunuz varsa memnuniyetle yanıtlarım.
      Dürüst olmak gerekirse mimariyi çok daha basitleştirmenin yolunu pek bilmiyorum. Bu amaçla kullanılabilecek servisler vardır, ama bu daha çok karmaşıklığı başka birine devretmek gibi olur.
      Sonuçta gerekenler şunlar: işaretlenmiş kutuları takip eden bir veritabanı, veriyi veritabanına koyma yöntemi, mevcut durumu istemciye bildirme yolu, istemci bir kutuyu işaretlediğinde sunucuya haber verip durumu güncelleme yolu, kutu işaretlendiğinde ya da işareti kaldırıldığında istemcilere bildirme yolu ve her zaman 1 milyon DOM öğesi render etmeme yöntemi.
      Burada işaret durumunu Redis ile sakladım; basitlik için 1 milyon biti olduğu gibi tuttum ve istemcilere 1 milyon bitin tamamını gönderdim. Verinin çok büyük olmaması iyiydi.
      Flask ve WebSocket ile işaretleme olaylarını ve güncellemeleri ele aldım; hem tekil kutu güncellemelerini hem de 1 milyon kutunun tamamına ait güncellemeleri gönderdim, render sorununu da react-window ile önledim.
      Geri kalan nginx statik içerik ve reverse proxy çoğunlukla ölçeklemeyi kolaylaştırmak için vardı; bu ayrıntılar olmadan da uygulamak ve siteyi çalıştırmak mümkün. Sadece aynı yükü kaldıramaz.
    • Yazıdaki her şeyi tek bir sürece de tıkabilirsiniz.
      Veritabanı yerine bit kümesini bir dosyada saklayıp mmap edersiniz. Reverse proxy yerine uygulama içinde HTTP isteklerini ve WebSocket bağlantılarını doğrudan işleyebilirsiniz.
    • Açıkçası bu hâliyle neredeyse en basitlerinden biri.
      Arkasında cache ve publish/subscribe kuyruğu olan birkaç web sunucusu düzeni.
      Büyük bir host üzerinde hepsini bellek içinde de işleyebilirdiniz ama talebi karşılayamazsa ya da herhangi bir nedenle başarısız olursa tamamen tıkanırsınız.
    • Dürüst olmak gerekirse bundan çok daha basitleşmesi zor gibi.
      Backend API ile aynı süreç içinde 1 milyon boolean'dan oluşan global liste tutmak gibi ölçeklenemez bir yöntem hariç tabii.
    • Aynı duruma sahip checkbox bloklarının tamamını (checked, start_x, start_y, end_x, end_y) tuple'ları olarak özetlemek için dörtlü ağaç kullanırsınız. Çok bariz bir yöntem değil mi?
  • Harika.
    Bir sonraki yazının hangi checkbox'ların en az ya da en çok işaretlendiğine dair istatistiksel analiz olup olmayacağını merak ediyorum.
    Epey aşağı kaydırıp seçtiğim checkbox'ın neredeyse anında kaldırıldığını hatırlıyorum; biraz üzülmüştüm.

    • Yakında ham veriyi paylaşacağım.
      Ondan önce siteyle ilgili anlatmam gereken bir hikâye daha var.
  • Oyunun hâlâ canlı olup olmadığını merak ediyorum.
    https://onemillioncheckboxes.com/ adresine girince hiçbir şey işaretli görünmüyor ve JS konsolunda sadece şunu görüyorum:
    {"total":0,"totalGold":0,"totalRed":0,"totalGreen":0,"totalPurple":0,"totalOrange":0,"recentlyChecked":false}

    • Orijinal metne göre “siteyi 2 hafta sonra kapatmadan önce 650 milyonu geçti” deniyor.
  • Ölçeklenebilir bir uygulamanın tam zıttı örnek olarak, 1000 karakterden kısa 1 milyon checkbox uygulaması var. Deno sürümü.
    https://gist.github.com/jeff-hykin/4cdebafd8698298d021f103e2...