- CGI programlama ile bile günde 200 milyondan fazla web isteğini işlemek mümkün
- Son dönemdeki donanım performansı artışı sayesinde CGI yaklaşımının dezavantajları büyük ölçüde azaldı
- Go ve SQLite kullanan bir CGI programı, 16 iş parçacıklı bir CPU üzerinde olağanüstü performans gösterdi
- CGI, birden fazla CPU çekirdeğini kullanma konusunda özellikle uygun bir yapı sunuyor
- Modern teknoloji sayesinde geçmişteki web uygulaması geliştirme yöntemleri bugün de yeterince pratik olabilir
CGI'nin geçmişi ve bugünü
- 1990'ların sonlarında yazar, web geliştirmeye CGI ile başladı ve o dönemde NewsPro gibi sistemler kullandı
- CGI, her web isteğinde yeni bir süreç başlatıp sonlandırdığı için yüksek ek yük oluşturuyordu
- Bu nedenle daha verimli PHP, FastCGI gibi alternatif teknolojiler geliştirildi
Donanım performansındaki gelişim
- Son 20 yılı aşkın sürede bilgisayar hızı ve performansı büyük ölçüde arttı
- 2020'de yazar, Go ve Rust ile geliştirilen araçları (
ripgrep gibi) kullanırken süreç çalıştırma yaklaşımının pratikliğini yeniden fark etti
Modern CGI yaklaşımının avantajları
- Go ve Rust gibi hızlı çalışan dillerle CGI geliştirildiğinde, eski tip CGI'nin dezavantajlarının çoğu ortadan kalkıyor
- CGI programları, her istek için ayrı bir süreçte çalıştığı için çok çekirdekli CPU kullanımına son derece uygun
- Örneğin 16 iş parçacıklı bir ortamda saniyede 2400'den fazla istek = günde 200 milyon+ istek işleme potansiyeli doğrulandı
- Büyük sunucular 384 veya daha fazla CPU iş parçacığı sunabiliyor
Geliştirme kültürüne dair içgörüler
- Bugün Go ve Rust gibi dillerin yaygınlaşmasıyla 1990'lardaki CGI yaklaşımı yeniden anlam kazanabilir
- Yine de bu yöntem hâlâ her ortam için uygun değil ve ana akım bir yaklaşım olarak önerilmiyor
- Önemli nokta, bugün CGI'nin eskisi kadar verimsiz bir çözüm olmadığının deneysel olarak gösterilmesi
Sonuç
- Modern donanım ve hızlı dillerin desteğiyle CGI programlama, geçmişle kıyaslanamayacak bir performans sergiliyor
- Çoklu süreç yaklaşımının avantajlarını en üst düzeye çıkaran bir örnek olarak, web geliştiriciler için ilgi çekici çıkarımlar sunuyor
1 yorum
Hacker News görüşleri
Günümüzde Python ile bile CGI oldukça hızlı hissettiriyor
CGI betiği başlangıçta CPU’da 400 milisaniye harcasa bile, sunucuda 64 çekirdek varsa saniyede 160 istek işlenebilir; bu da sunucu başına günde 14 milyon trafiği kaldırmak demek
Günlük yüz milyonlar seviyesindeki trafiklerde bile (statik varlıklar hariç) CGI süreç başlangıcı darboğaz olmak zorunda değil
Eskiden bu tür teknolojilerin "sıkıcı derecede istikrarlı teknoloji" olduğu için Python standart kütüphanesinde hep bulunduğunu düşünürdüm, ama günümüzde Python bakımcıları istikrar ve geriye dönük uyumluluğa daha olumsuz bakıyor
Bu yüzden fazla 'sıkıcı ve istikrarlı' modüller standart kütüphaneden çıkarılıyor; nitekim
cgimodülü 3.13 sürümünde silindiYaklaşık 25 yıldır Python’ı prototipleme için kullanma alışkanlığım yüzünden ama artık pişmanım
Şu sıralar JS ile Lua arasında kararsızım
cgi'nin kaldırılmasıyla ilgili resmi açıklama bağlantısı: PEP 594 cgiBu bağlantı 2000 yılında (25 yıl önce) yazılmış PEP 206 belgesine gidiyor; orada bile "
cgipaketi kötü tasarlanmış ve üzerinde çalışması zor" deniyorjackrosenthal/legacy-cgi deposunda standart kütüphane modülünün bire bir yerine geçebilen bir drop-in replacement görülebilir
Python geliştiricileri sadece
cgiadlı modülü çıkardıCGI betiği uygulaması hâlâ
http.servermodülündekiCGIHTTPRequestHandlerile destekleniyorAslında
cgimodülünde HTML form verisini ayrıştıran birkaç işlevden fazlası yoktuPython’da
cgimodülünün standart kütüphaneden çıkmasını eleştirmek anlaşılır, ama örnek gösterilen JS zaten baştan standart kütüphaneye sahip değilLua’nın da stdlib içinde bir CGI modülü olmadığına dikkat çekiliyor
Ben kişisel olarak PHP ya da JS tercih ederim
Bu tür durumlarda kutudan çıktığı gibi JIT gelmesi kullanışlı
Python’ı 1.6’dan beri kullanıyorum ama çoğunlukla sadece OS betikleme için
Eskiden Tcl’yi Apache veya IIS modülleriyle entegre edip modülleri sürekli C ile yeniden yazdığım bir dönem yaşamıştım (1999~2003)
Bir CGI betiği 400 milisaniye CPU kullanıyorsa, o endpoint’in yanıt süresi de en az o kadar olur; bu da kullanılabilirliği etkiler
Kısa süre önce 350 dolarlık mini bir sunucuya golang binary’si, rabbitmq, redis ve MySQL kurup aynı sunucuda sürdürülebilir biçimde 5.000 req/s işledim
24 saatte bu, 400 milyon istek kapasitesi demek
Günümüzde ücretsiz araçların ne kadar harika olduğunu bir kez daha hissettim
Yine de bulut maliyetlerinin çok yüksek olduğunu düşünüyorum
Elbette bire bir karşılaştırma zor, ama geliştirme ve tuning işlerini evin bodrumundaki sunucuda doğrudan yapabilmiş olmak ayrıca tatmin ediciydi
Kubernetes tabanlı mikroservis yığınları kullanıp geliştirme hızını 10 kat yavaşlatan durumlar da var
Pek çok kişi sunucuların saniyede sadece 1 istek işleyen makineler olmadığını bilmiyor
Sırf Google yapıyor diye peşinden gidip aşırı overhead ödüyoruz
Ben de ekibimde çok iyi işleyen 'modüler monolitik' mimari hakkında bir şeyler yazmam gerektiğini düşünüyorum
Yan projelerimi evde barındırmayı denedim ama elektrik kesintisi, ISP kesintisi, uzaktan erişim sorunu, disk arızası gibi riskler büyük
Sonunda kendi zaman maliyetini de katınca ekonomik faydası belirsiz kalıyor
Bulut hizmetleri ölçek ekonomisinden faydalandığı için pratikte makul bir seçim olabiliyor
Bulut şart değil; bir hosting sağlayıcısından dedicated server kiralamak da mümkün
Tabii bant genişliği/trafik sınırları oluyor
Bulutun ana akım olmasının nedeni, VC’lerin ve yatırımcıların bu şirketlerde pay sahibi olması ya da "ya sınırsız trafik patlarsa" kaygısı
Bulut satış uzmanları yatırımcıların bu kaygısını ustaca kullanıyor
Herkes illa bulut kullanmıyor
Gerçek hizmetlerde VM maliyetinin yüksek olmasının nedeni yüksek performanslı compute değil, devasa yerel disk kapasitesi ihtiyacı
Çok güçlü hesaplama gerekmiyor; 20TB’lık 4 disk ve makul bir CPU ile bile harika bir servis tasarlanabilir
Bulutta böyle bir kombinasyon bulmak neredeyse imkânsız
cgi-biniçinden DB’ye erişmek gerektiğinde, her seferinde sürecin yeniden DB bağlantısı kurması can sıkıcıKod bellekte çalışıyorsa (
fastcgigibi), sadece başlangıç süresi kısalmaz; aynı zamanda DB connection pool ya da thread başına kalıcı bağlantı tutmak da mümkün olurBüyük ölçekte çalıştırınca DB bağlantı sayısı fazla artıp veritabanını zorlayabiliyor
"Python tek iş parçacıklı, o yüzden çok süreç; Python yavaş, o yüzden daha çok süreç" mantığıyla çok sayıda süreç işletiliyor
Sonunda shared connection pool’u (
pg bouncergibi) Python süreçlerinin dışına taşımak ve çeşitli tuning yapmak gerekiyorEn sonunda da daha yönetilebilir bir dille (çok iş parçacığı desteği olan ve performansı daha iyi bir dille) yeniden yazınca sistem çok daha basit hâle gelmişti
Bu yüzden CGI sonunda istekler arasında bilgi tutabilen bir modele (
fastcgigibi) evrildiGeleneksel olarak ayrı bir daemon kaldırıp proxy görevi verdikleri de olurdu; ayrıca Unix soketleri kullanıldığında TCP/IP’ye göre çok daha verimli olurdu
UDP kullanılması gerektiğini söyleyen bir görüş
Benim için
inetddoğrudan CGI’nin kendisiBu sayede internet çok daha eğlenceli gelirdi
Bir zamanlar
inetdile çeşitli shell betikleri, hatta sadece Bash ile yazılmış HTTP bile çalıştırmıştımEski VPS’ler, yedek ya da sürüm kontrolü olmayan dizüstüler artık yok ama güzel anılar kaldı
Dağıtım da
Makefile + scpile basitti; testler denetcatvegrepile yazılmış Bash betikleriyle yapılabiliyorduGerçekten yaşaması güzel bir çağdı
Bir
hello worlduygulamasının 2400 rps’ye ulaşmasının günümüz donanımına göre pek etkileyici olmadığı izlenimi varKod da daha basit hâle gelmemişken, ne uğruna performanstan vazgeçildiği sorgulanıyor
2000 rps’den fazlasına ihtiyaç yoksa bu zaten sorun değil
Böyle bir trafiğe ihtiyaç duyan sitelerin çok az olduğu savunuluyor
Sayı olarak çok yüksek görünmeyebilir ama pratikte birçok ortam için yeterli
HN geliştiricilerinin söz ettiği 'hug of death' (belirli bir anda ani trafik patlaması) durumlarına bile dayanabilecek bir seviye
Bizim şirkette hâlâ
cgi-bindizini üzerinden basit iç web uygulamalarını hızlıca ayağa kaldırma yöntemi kullanılıyorBasit tutulduğunda geliştirme verimliliği çok yüksek
CGI olsa bile
http/1.0'ı doğrudanprintetmek gerekmiyor; Python’ınwsgiref.handlers.CGIHandleraracıyla herhangi bir WSGI uygulaması CGI betiği olarak çalıştırılabiliyorFlask örnek kodu da aşağıdaki kadar basit
İş ortamında betikleri
uwsgi'nin CGI eklentisiyle çalıştırıyoruzApache ya da lighttpd üzerinde
mod_cgiçalıştırmaktan çok daha basit ve daha esnek hissettiriyoruwsgisistem düzeyinde çalıştığı içinsystemd’nin tüm hardening ve sandboxing imkânlarından yararlanabiliyorAyrıca
uwsgi’nin CGI işleyişinde her dosya türü için ayrı interpreter belirtilebiliyorİlk baytın gönderilmesine kadar 250~350 ms sürüyor; bizim kullanımımız için gayet kabul edilebilir
uwsgi CGI belgeleri
wsgiref.handlers.CGIHandleraracının henüz deprecated olmamış olması faydalı bir bilgiDün tartışılan ilgili başlık bağlantı
Son dönemde yan projelerde Apache kullanırken
.htaccessözelliğini faydalı bulduğum olduHerhangi bir dizine sadece bir
.htaccessdosyası koyarak her istekte ek sunucu ayarlarının yüklenmesini sağlayabiliyorsunuzhtaccess resmi belgeleri
Eskiden her istekte disk erişimi overhead’i yarattığı için performans açısından
.htaccesskullanımından kaçınılması ve mümkünse ana yapılandırmaya taşınması önerilirdiAma artık SSD’ler ve RAM yeterince güçlü; elbette performanstan çok az kaybettiriyor ama CPU’lar da yeterince iyi olduğu için çoğu durumda göz ardı edilebilir
[StaticPatch projem][https://github.com/StaticPatch/StaticPatch/tree/main] içinde de bunu uygulayarak kullanıyorum
PHP’nin yaratıcısı Rasmus Lerdorf’tan ünlü bir söz
"Ben gerçek bir programcı değilim, sadece çalışmasını sağlar ve yoluma devam ederim. Gerçek programcılar 'bunda ciddi bir bellek sızıntısı var, düzeltilmeli' der. Ben ise Apache’yi her 10 istekte bir yeniden başlatırım"
PHP o günden sonra uzun bir yol kat etti; ilk hatalarını aşarak büyük ölçüde gelişti
"PHP 8’de kodum ne kadar azsa o kadar iyi" dediğine dair bir anekdot da var
Apache neden dosya sistemini izleyip sadece değiştiğinde okumuyor da, her istekte gereksiz disk erişimi yaptırıyor anlamıyorum
Sonuç olarak HTTP isteklerinin %99,99’unu yavaşlatıyor deniyor
Son zamanlarda hızlı prototipleme için bu tür bir yapıyı iş akışımda düşünmeye başladım
JIT dillerde
fastcgibenzeri bir yapı yoksaimportdarboğaz olabiliyorKullandığım
h2oweb sunucusundamrubyvefast-cgihandler ayar dosyalarının basit olması, yerel script işleri için çok uygunh2o fastcgi belgeleri
Bir başka avantaj da, müşterilerin kendi özel kodlarını ekleyebilmesi için yerel yazılımı genişletmek gerektiğinde işe yaraması
Örneğin eskiden genişletme için MCP kullanmak gerekirdi ama artık CGI ile yapılandırılmış istekleri uygulamak yeterli
Son kullanıcı ortamında MCP ön ucu olarak CGI programlarını bağlamak da ilginç bir fikir olabilir
MCP hizmetlerinin de pekâlâ CGI ile uygulanabileceği düşünülüyor
Spesifikasyona daha yakından bakma isteği var
fastcgikullanınca CGI’nin avantajlarının neredeyse hepsinin kaybolduğu sorgulanıyorGeçmişte C programları ile CGI kombinasyonunu bizzat kullandım
O zamanlar 100’den fazla çekirdek ya da bol RAM yoktu; en fazla 1GB bellekle bile çalışıyordu
O günlerde yapılabildiyse, bugün çok daha kolay olması gerekir diye düşünüyorum
Yük dengeleme gereksinimi doğduktan sonra ölçekleme zorlaştı ama öncesinde gayet iyi çalışıyordu
Bu arada front-end ve back-office için ayrı iki çalıştırılabilir dosya vardıydı