İçindekiler
- 1 Bir Akşamüstü Trafik Fırtınası ve Aklıma Düşen HAProxy
- 2 L4 mü L7 mi? Yol Ağzında Durup Yön Soranların Hikayesi
- 3 Health Check: Sunucunun Nabzını Parmak Ucunda Hissetmek
- 4 Sticky Sessions: Ziyaretçiyi Tanıyan Kapıcı
- 5 TLS Termination ve TLS Passthrough: Hangi Kapıda Paltomuzu Çıkaracağız?
- 6 Sıfır Kesinti: Dağıtımı Sahne Arkasında Değiştirirken Işıklar Hiç Sönmesin
- 7 Gerçek Dünya Akışları: Web, API, WebSocket ve gRPC
- 8 Gözlem, Log ve Küçük İpuçları: Sorun Çıkmadan Önce Görmek
- 9 Küçük Konfigürasyon Tarifleri: Tadında ve Yeterince
- 10 Kapanış: Trafiği Sakinleştirmek ve Günü Güzel Bitirmek
Bir Akşamüstü Trafik Fırtınası ve Aklıma Düşen HAProxy
Hiç başınıza geldi mi? Trafik sanki sözleşmiş gibi aynı anda yükselir, destek ekibi nefesini tutar, herkes monitöre yapışır. Benim için öyle bir akşamüstüydü. Siparişler artıyor, kullanıcılar koşturuyor, bir yandan yeni versiyon dağıtımı için dakikalar sayılıyor. Tam o sırada düşündüm: “Bu akışı kim sakince yönetiyor?” Cevap aslında bir süredir hayatımızdaydı: HAProxy ile L4/L7 yük dengeleme. Kibar bir trafik polisi gibi, hem sokaklar arası yönlendirme yapıyor, hem de kim nereye gidecek, kim yorulmuş, kim dinç anlıyor. Üstelik doğru kurarsak, tüm bu dans sıfır kesintiyle akıp gidiyor.
Bu yazıda, L4 ve L7 yük dengelemeyi bir hikaye gibi ele alacağız. Health check ile sunucuların nabzını nasıl tuttuğumuzu, sticky sessions ile ziyaretçiyi nasıl tanıyıp aynı uygulama sunucusuna “nazikçe” yönlendirdiğimizi konuşacağız. Sonra TLS termination ve TLS passthrough arasındaki farkı, günlük hayattan örneklerle açacağız. Son olarak da “sıfır kesinti” dağıtımın nasıl gerçek bir şey olduğunu, küçük püf noktalarıyla anlatacağım. Hazırsanız, birlikte o akşamüstü paniğini sakin bir akışa çevirelim.
L4 mü L7 mi? Yol Ağzında Durup Yön Soranların Hikayesi
Bir Katman Masalı: Kapıda mı, lobide mi karşılarsın?
Yük dengelemede L4 demek, biraz kapıdaki güvenlik görevlisi gibi. Kim geldi, hangi porta girmek istiyor, IP’si ne, o kadar. Hızlı karar verir, dosdoğru uygun kapıya yönlendirir. L7 ise lobideki danışma gibi; gelenin ne istediğini daha iyi anlar. URL nedir, başlıklar ne diyor, çerezi var mı, belki dil tercihi bile… L4 hızlı ve masrafsızdır, L7 ise daha “akıllı” yönlendirmeler yapar. Şimdi bunu günlük hayata taşıyalım. Mesela şöyle düşünün: Bir e-ticaret sitesinde bazı istekler dosya indirmeye gidiyor, bazıları sepete. Dosya indirmeyi L4 ile hızlıca bir node’a atmak isteyebilirsin, sepet ve ödeme gibi daha hassas akışları L7’nin ince ayarıyla ele alabilirsin.
Benim pratikte sevdiğim yaklaşım, dışarıda L4’ün gücünü kullanıp kritik uygulamalarda L7’nin zekasına başvurmak. Bu sayede hem hız hem esneklik dengesi kuruluyor. Aşağıda çok ufak bir tat:
# Basit L4 (TCP) terminasyonu olmadan geçiş - TLS passthrough örneği
frontend fe_tls
bind :443
mode tcp
tcp-request inspect-delay 5s
use_backend bk_api if { req.ssl_sni -i api.example.com }
use_backend bk_www if { req.ssl_sni -i www.example.com }
backend bk_api
mode tcp
balance roundrobin
server api1 10.0.0.11:443 check
server api2 10.0.0.12:443 check
backend bk_www
mode tcp
balance roundrobin
server www1 10.0.0.21:443 check
server www2 10.0.0.22:443 check
Burada L4’teyiz; TLS’i çözmeden sadece SNI’ya bakıp trafiği ilgili arka uca yolluyoruz. Eğer L7 ile işleri daha renkli yapmak isterseniz, TLS’i burada sonlandırıp HTTP seviyesinde karar alabilirsiniz:
# L7 (HTTP) - TLS termination ve akıllı yönlendirme
frontend fe_https
bind :443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
mode http
option forwardfor
http-request set-header X-Forwarded-Proto https
use_backend bk_static if { path_beg /assets/ }
default_backend bk_app
backend bk_static
mode http
balance roundrobin
http-response set-header Cache-Control max-age=600
server cdn1 10.0.0.31:80 check
server cdn2 10.0.0.32:80 check
backend bk_app
mode http
balance leastconn
server app1 10.0.0.41:8080 check
server app2 10.0.0.42:8080 check
Gördüğünüz gibi, L7 ile daha ince kararlar alabiliyoruz. Statikleri bir yere, uygulamayı başka yere alırken, üstüne ufak önbellek başlıkları bile ekleyebiliyoruz. Düz konuşalım: İş ihtiyacına göre karışık kullanmak oldukça doğal ve işe yarıyor.
Health Check: Sunucunun Nabzını Parmak Ucunda Hissetmek
“İyi misin?” demenin otomatik yolu
Bir kullanıcı 404 görünce moral bozulur, 500 görünce güven bozulur. Sağlık kontrolü tam burada sahneye çıkar. HAProxy arka uçlardaki sunuculara düzenli “iyisin, değil mi?” sorusu sorar. Bu sadece ping atmak değildir; bazen belirli bir URL’den, belirli bir yanıt beklemek gerekir. Mesela uygulama sağlıklıysa “OK” yazan bir endpoint verir, HAProxy de onu arar. Eğer iki defa üst üste kötü cevap alırsa, o sunucuyu trafikten çıkarır; sonra düzelince tekrar oyuna alır.
Basit ve anlaşılır bir yapı için şöyle düşünebilirsiniz: Uygulamanızda /healthz gibi hafif bir kontrol noktası açın. Veritabanına, dış servislere gerek duymadan “ayaktayım” desin. HAProxy buna bakar, yükü güvende tutar. Küçük bir örnek:
backend bk_app
mode http
option httpchk GET /healthz
http-check expect status 200
default-server inter 2s fall 3 rise 2
server app1 10.0.0.41:8080 check
server app2 10.0.0.42:8080 check
“Fall 3, rise 2” gibi ayarlar, düşmeden önce kaç kez tökezledi, toparlanmak için kaç iyi cevap verdi, bunu anlatır. Bu sayede tek seferlik bir takılma yüzünden sunucular hemen oyundan düşmez. L4’teyseniz tcp-check kullanarak port seviyesinde nabız tutabilirsiniz. Daha karmaşık senaryolarda birden fazla kontrol yapmak, hatta kritik bağımlılıkları ayrı bir “/readyz” endpoint’i ile kontrol etmek iyi hissettirir.
Sticky Sessions: Ziyaretçiyi Tanıyan Kapıcı
“Bu ziyaretçi hep aynı masayı istiyor” durumu
Kimi uygulamalar, özellikle oturum tabanlı olanlar, kullanıcıyı hep aynı sunucuda görmek ister. Neden? Çünkü sunucu belleğinde oturum bilgisi duruyordur, paylaşımlı bir oturum deposu yoktur ya da henüz buna hazır değilsinizdir. Sticky sessions, bu ziyaretçiyi nazikçe aynı arka uca yönlendirir. Çerezle, IP ile, hatta özel kurallarla yapılabilir. En pratik olanı çerez yöntemidir.
Mesela şöyle düşünün: Giriş yapan kullanıcı sepetini dolduruyor. Sunucu 1’de oluşan sepet bellekte duruyor. Eğer kullanıcı akış içinde bir anda Sunucu 2’ye düşerse, sepet sanki kaybolmuş gibi olur. Bunu engellemek için HAProxy ile çerez ekleyip, bir kere bağlanan kullanıcıyı aynı sunucuya taşırız:
backend bk_app
mode http
balance roundrobin
cookie SRV insert indirect nocache
server app1 10.0.0.41:8080 cookie s1 check
server app2 10.0.0.42:8080 cookie s2 check
Bu yapı, ziyaretçiye görünmez bir not veriyor gibi. “Bu arkadaş s1 masasında oturuyordu” diyor. Alternatif olarak IP tabanlı tutarlılık da kullanabilirsiniz. Bu daha kaba bir yöntemdir ama bazen iş görür:
backend bk_api
mode http
balance source
hash-type consistent
server api1 10.0.0.11:8080 check
server api2 10.0.0.12:8080 check
Sticky sessions sihirli değnek değil. Eğer uygulama sunucusunu yeniden başlatırsanız, bellekteki oturumlar uçabilir. O yüzden orta vadede paylaşımlı bir oturum deposu ya da stateless tasarıma geçmek hep içi ferahlatır. Bu arada, veri katmanında tutarlılık ve dağıtım dendi mi, ben backend dünyasında ProxySQL ile read/write akışını tatlı tatlı ayırmanın uygulama deneyimini nasıl rahatlattığını çok gördüm; uygulama katmanı ile veri katmanını birlikte düşünmek güzel akış yaratır.
TLS Termination ve TLS Passthrough: Hangi Kapıda Paltomuzu Çıkaracağız?
Bazen kapıda çözersin, bazen içeri alırsın
TLS, trafiği şifreleyen paltomuz. Bu paltoyu HAProxy’de çıkarabilirsiniz (termination), ya da hiç dokunmadan arka uca iletebilirsiniz (passthrough). Termination olduğunda HAProxy içeriği görür; yönlendirme, WAF, başlık düzenleme gibi akıllı işler yapar. Passthrough’da ise HAProxy paltosuna karışmaz, sadece SNI’a bakarak nereye gideceğini söyler, şifre çözme işi arka uca kalır.
Hangi durumda neyi seçelim? Eğer L7 kararlarına ihtiyacınız varsa, TLS’i önde kırmak çok iş görüyor. Ancak regülasyon, güvenlik politikası ya da performans sebebiyle şifre çözmeyi uygulama sunucularına bırakmak istiyorsanız, passthrough doğru seçim. SNI yönlendirmesiyle birden fazla domain’i tek noktada taşıyabilirsiniz. Sertifika yönetimi tarafında ben genelde otomasyonu severim; örneğin Let’s Encrypt belgelerinde anlatılan ACME akışı ile sertifika yenilemeyi script’lerle rüzgâr gibi döndürmek mümkün.
Bir not: Arka uçta servisleriniz birbirini doğrulasın isterseniz, mTLS yani karşılıklı sertifika doğrulama akışı çok şık duruyor. Bu konuyu ayrı bir dünyada, mTLS ile mikroservisleri nasıl kale gibi sağlamlaştırabileceğinize dair rehberde detaylı konuşmuştuk. HAProxy önde TLS’i sonlandırırken, içeride servisler arası trafiği mTLS ile korumak içimizi rahatlatır.
Sıfır Kesinti: Dağıtımı Sahne Arkasında Değiştirirken Işıklar Hiç Sönmesin
“Hitless reload” ve yumuşak geçişler
Bir gerçek: Konfigürasyonlar değişir, sertifikalar yenilenir, yeni sürümler gelir. Önemli olan bunlar olurken kullanıcı akışının takılmaması. HAProxy’nin güzelliği, doğru kurduğunuzda yeniden yüklemeyi trafiği kesmeden yapabilmesi. Master-worker modeli ve “hitless reload” yaklaşımıyla, yeni süreç ayağa kalkarken eskisi işini bitirene kadar bekler. Ben pratikte şu yaklaşımı seviyorum: Control socket ile sunucuları nazikçe “drain” moduna alıp, yeni istek almalarını engellemek, var olan isteklerin bitmesini beklemek; sonra yeni sürümü koyup geri almak. Bu, bebek uyurken oda değiştirmek gibi sakince yapılmalı.
HAProxy tarafında bunu desteklemek için “stats socket” açmak iyi bir alışkanlık. Böylece komutla “şu sunucuyu geçici olarak devre dışı bırak, ağırlığını düşür” gibi hamleler yapabiliyorsunuz. Konfigürasyonu tekrar yüklerseniz de stick-table ve bağlantıların nazik aktarımı gibi detaylar işinizi kolaylaştırır. Bu konuda seamless reloads anlatımının yapıldığı rehber zahmetsiz geçişin mantığını çok güzel anlatır.
Dağıtımı daha da tatlandırmak isterseniz, mavi-yeşil gibi iki ortam kurup, trafiği yavaşça yenisine kaydırabilirsiniz. DNS tarafında da otomasyonla destek verince, iş iyice pürüzsüz olur. Biz bunu anlatırken, Terraform, Cloudflare ve sıfır kesinti dağıtımın nasıl birleştiğine dair yazıda DNS’i de oyuna dahil ederek anlatmıştık; HAProxy ile bu orkestrasyon çok uyumlu çalışıyor.
Gerçek Dünya Akışları: Web, API, WebSocket ve gRPC
“Mesela şöyle düşünün…”
Bir WordPress e-ticaret sitem var diyelim; kampanya sırasında trafik patlıyor. L7 ile statik dosyaları hafif sunuculara, PHP isteklerini ise daha güçlü düğümlere yönlendiriyorum. Health check ile yorulanı kenara çekiyorum. Sticky session ile sepet karışmıyor. Bir de önbellek başlığı takviyesiyle sayfa akışı hızlanıyor. Benzer bir durumda, kenarda küçük bir mikro önbellek bile hava açar; Nginx tarafında bu konuya merakınız varsa, mikro önbelleklemenin PHP uygulamalarını nasıl uçurduğunu anlattığım rehber hoşunuza gider.
API’lerde ise L7’nin yetenekleri parlıyor. Belirli endpoint’leri farklı havuzlara atmak, limit koymak, başlık düzenlemek katkı sağlar. Bazı ekipler WebSocket ya da gRPC kullanıyor; orada bağlantılar uzun süre açık kalır, kalp atışları önemlidir. Zaman aşımlarını özenle ayarlayın. Eğer uçta bir CDN veya proxy katmanınız da varsa, oradaki bekleme ayarlarının HAProxy ile uyumlu olduğundan emin olmak gerekir. Bu konuda, WebSocket ve gRPC akışını canlı tutmanın sırlarını paylaştığım yazıdaki ipuçları HAProxy’nin arkasında da işinize yarar.
İç servisler arası iletişimde güven tarafı ayrı bir keyifli konu. Bazı ekipler önde HAProxy ile L7 kararlarını alıp, içeride servisler arası konuşmayı mTLS ile güvene alıyor. Böylece içerideki trafik şifreli ve kimlik doğrulanmış oluyor. Üstelik sertifika yenileme ve dağıtım, küçük bir otomasyonla günlük işler arasına karışıyor. Yeri gelmişken, HAProxy yapılandırmasını öğrenirken HAProxy’nin resmi dokümantasyonundaki yapılandırma kılavuzu hayat kurtarır; ihtiyaç duyduğunuzda sayfayı bir işaretleyin, aradığınız direktif anında önünüze gelir.
Gözlem, Log ve Küçük İpuçları: Sorun Çıkmadan Önce Görmek
İzle, ölç, küçük düzeltmeler yap
Benim en sevdiğim anlardan biri, bir grafikte ufak bir diş görüp “Aha, burada bir şey var” demek. HAProxy loglarını anlaşılır tutmak, başlıklarla IP ve gerçek istemciyi not düşmek, yavaş istekleri işaretlemek büyük fark yaratır. Ardından uygulama tarafında ayrıntılı izler toplamak, uçtan uca safları sıklaştırır. Bu konuda, “ne nerede gecikiyor” sorusuna dair merakınızı OpenTelemetry ile izlenebilirlik rehberinde gerçeğe dönüştürecek örnek akışlar var; HAProxy önünde koşan uygulamalarda bu çok işe yarıyor.
Ufak ama önemli bir not: Zaman aşımı değerleri. İstemci, HAProxy ve arka uç arasında bu değerlerin uyumlu olması, gereksiz kopmaları önler. WebSocket/gRPC gibi uzun soluklu bağlantılarda bu ayarlar adeta emniyet kemeri. Sertifika yenileme tarafında da otomasyonu unutmayın; bir gece yarısı sertifikanın süresi bitmiş, tarayıcı bağırıyorsa can sıkıcı olur. Otomasyon için basit bir ACME istemcisi ve “hitless reload” çok iş görür.
Küçük Konfigürasyon Tarifleri: Tadında ve Yeterince
Bir tutam socket, bir çimdik drain
Bazen minimallik en iyisidir. Aşağıdaki örnekte, hem socket üzerinden kontrol, hem de yumuşak dağıtım pratikleri bir arada:
global
log /dev/log local0
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
master-worker
defaults
log global
mode http
option httplog
timeout connect 5s
timeout client 50s
timeout server 50s
frontend fe_https
bind :443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
default_backend bk_app
backend bk_app
balance leastconn
option httpchk GET /healthz
default-server inter 2s fall 3 rise 2
server app1 10.0.0.41:8080 check
server app2 10.0.0.42:8080 check
Dağıtım öncesi, aşağıdaki gibi sunucuyu nazikçe sahneden çekebilirsiniz. Bu komutlar, aktif bağlantıları koparmadan “yeni misafir alma, eskileri uğurla” demek oluyor:
echo "set server bk_app/app2 state drain" | socat stdio /run/haproxy/admin.sock
# Yeni sürüm app2'ye, sağlık kontrolü yeşil, sonra geri al:
echo "set server bk_app/app2 state ready" | socat stdio /run/haproxy/admin.sock
Konfigürasyonu güncelledikten sonra “reload” verdiğinizde bağlantılar hit almadan geçiş yapar. Bu tekniğin ince noktalarını öğrenmek için yine hitless reload yaklaşımına dair açıklamaları okumak oldukça faydalı.
Kapanış: Trafiği Sakinleştirmek ve Günü Güzel Bitirmek
Yanınıza alacağınız küçük notlar
HAProxy ile L4/L7 yük dengeleme, doğru kurulduğunda trafiği sakinleştiriyor. Health check ile sunucuların nabzını tutuyor, sticky sessions ile kullanıcı deneyimini dengede tutuyor, TLS termination ya da passthrough ile güvenliği ve esnekliği yerli yerine koyuyoruz. Üstüne bir de sıfır kesinti dağıtım pratikleri eklenince, gece yarısı alarm kurma ihtiyacı azalıyor. Bu işin sırrı, küçük adımlar, tutarlı otomasyon ve düzenli gözlem. Bir de sade, anlaşılır konfigürasyonlar.
Pratik bir rota çizeyim: Önce basit bir health endpoint’i açın, HAProxy’de kontrol edin. Ardından sticky ihtiyacınızı çerezle mi, IP ile mi çözeceğinize karar verin. TLS’te nerede sonlandıracağınız hem güvenlik politikanıza hem de yönlendirme ihtiyaçlarınıza bağlı. Yenileme işini otomatikleştirin; isterseniz Let’s Encrypt dokümanlarından ilhamla başlayın. İş çoğalınca otomasyon ve orkestrasyon kaçınılmaz; burada Terraform ile DNS ve altyapıyı birlikte ele alan pratikleri gözden geçirin. İşi bütünsel görmek rahatlatır.
Umarım bu rehber, akşamüstü paniğini güneş batarkenki o tatlı dinginliğe çevirir. Bir gün yine yoğun bir dağıtım anında, HAProxy konfigürasyonunuzu güvenle “reload” ederken aklınıza bu satırlar gelsin. Sorularınız, merak ettikleriniz olursa paylaşın. Bir dahaki yazıda görüşmek üzere, trafiğiniz hep akıcı, kesintiniz sıfır olsun.
