Teknoloji

ProxySQL ile MySQL Read/Write Split ve Bağlantı Havuzu: WooCommerce/Laravel İçin Gerçek Dünya Rehberi

Hiç beklenmedik bir cuma akşamı, düğmeye basar gibi siparişlerin patladığı oldu mu? Benim oldu. WooCommerce’te kampanya başladı, sayfalar akıyor, sepetler doluyor, ama bir yerden sonra site ağırlaşıyor, admin sayfası bir açılıyor bir kapanıyor. Klasik hikâye: uygulama yaşıyor, ama veri tabanı nefes nefese. O an düşündüm; bu kadar okuma ve yazma isteği aynı kapıya yığılırsa, kapıyı genişletmek yerine akışı düzenlemek daha mantıklı. İşte o akşam tanışlığımız pekişti: ProxySQL.

Bu yazıda ProxySQL ile MySQL read/write split ve bağlantı havuzu kurup, özellikle WooCommerce ve Laravel projelerinde nasıl daha akışkan bir trafiğe kavuşabileceğimizi konuşacağız. Kuru bir kurulum rehberi değil; sahada karşılaştığım tuhaflıklardan, minik kazalardan, tatlı çözümlerden bahsedeceğim. Mesela şöyle düşünün: bir kafede tek bir kasiyere hem sipariş hem ödeme hem de “menüde ne var?” soruları gidiyor. Kasiyer yorulur. Biz siparişi bir tarafa, ödemeyi diğer tarafa yönlendirip kasiyerin yükünü dengelemekten söz ediyoruz. Hem de uygulama kodunu çok bozmadan.

ProxySQL Nedir ve Neden Araya Girer?

ProxySQL, uygulama ile MySQL/MariaDB arasında duran akıllı bir kapı görevlisi gibi. Bağlantıları havuzlar, hangi sorgunun yazma hangisinin okuma olduğunu anlar, gerektiğinde yazmaları yazıcı düğüme, okumaları okuyucu düğümlere yollar. Uygulama her seferinde veri tabanına sıfırdan bağlanmak yerine, ProxySQL’in sıcak tuttuğu bağlantılardan faydalanır. Sonuç basit: daha az maliyetli bağlantı kurulumu, daha iyi yanıt süresi ve daha dengeli bir yük.

WooCommerce tarafında sipariş akarken, arka planda stok güncellemeleri, sipariş statüleri, meta veriler ve raporlamalar aynı anda hareket eder. Laravel’de ise API’ler, kuyruk işler ve planlı görevler bir orkestrada gibi çalışır. Hepsi veriye dokunur ama her istek yazma yapmak zorunda değil. İşte read/write split tam burada devreye giriyor; yazmalar ana düğüme, okumalar kopyalara. Özetle: yoğunluğu böl, arkadaki makinelerin nefes almasını sağla.

Read/Write Split Mantığı: Sihir Değil, Kurallı Trafik

ProxySQL sorguyu görünce önce cümle yapısına bakar. “INSERT, UPDATE, DELETE, REPLACE” diyorsa hiç uzatmadan yazıcı düğüme yollar. “SELECT” diyorsa, eğer bir işlemin (transaction) içindeyse veya belli bir işaret varsa, yine yazıcıya göndermeyi tercih edebilir. Çünkü bazen bir “SELECT” bile, taze yazdığın veriyi görmek istiyorsundur. Özellikle WooCommerce’te ödeme anında, Laravel’de siparişi yazdıktan hemen sonra okuma yaparken bu tutarlılık önemli.

Buradaki püf nokta şu: replicalarda milisaniyelerle de olsa gecikme olabilir. “Azıcık gecikme ne olacak?” deme. Müşteri siparişi verdi, “siparişiniz bulunamadı” gibi bir şey görmek istemez. ProxySQL’e “yazdıktan sonra şu kadar süre okumalarda da ana düğümü tercih et” dedirtebilirsin. Laravel’de bu, sticky read yaklaşımıyla birkaç saniyeliğine yazıcıya yapışmak gibi. WooCommerce’te ise daha çok akıllı kural yazmak ve replika gecikmesini düşük tutmakla çözülüyor.

Bağlantı Havuzu: Her İstek İçin Sıfırdan Tanışmayalım

Her PHP isteğinde yeni bir MySQL bağlantısı kurmanın bedeli var. SSL el sıkışmaları, kimlik doğrulamalar, ağ gecikmesi… Hepsi birikince sayfalar yavaşlıyor. ProxySQL burada büyük kazanım sağlar: o zaten veri tabanıyla konuşuyor ve bağlantıları sıcak tutuyor. Uygulama ise ProxySQL’e bağlanıp “hazır” bir boruya su akıtır gibi akıyor.

Mesela WooCommerce’te kampanya açtın, trafik ikiye katlandı. Eskiden MySQL’de 5000 bağlantı görüp tedirgin olurdun; şimdi ProxySQL bu bağlantıları havuzlayıp makul sayıda tutuyor. Laravel’de de benzer; işçi süreçleri ve kuyruklar yoğunken, havuzun limitlerini doğru ayarladığında, dalgalanmaları çok daha zarif karşılarsın. Burada sihirli ayar yok, ama mantık net: uygulamadan gelen binlerce kısa ömürlü bağlantı yerine, ProxySQL arka tarafta uzun ömürlü ve verimli kanallar açık tutar.

Adım Adım Kurulum: Küçük Bir Prova, Sonra Canlı

Temel Bileşenler

Önce ProxySQL’i kur, sonra veri tabanı düğümlerini ve kullanıcıyı tanıt. Bir ana (yazıcı) ve bir veya birkaç kopya (okuyucu) düğümünü hostgroup mantığıyla etiketle. Uygulama ProxySQL’e bağlanacak, o da sorguya göre doğru hostgruba yönlendirecek.

# Örnek: mysql_servers içine düğümleri eklemek
INSERT INTO mysql_servers(hostgroup_id, hostname, port, max_connections) VALUES
  (10, 'db-writer.internal', 3306, 200),
  (20, 'db-replica-1.internal', 3306, 200),
  (20, 'db-replica-2.internal', 3306, 200);

# Kullanıcıyı tanımla (uygulama ProxySQL'e bu bilgilerle bağlanır)
INSERT INTO mysql_users(username, password, default_hostgroup, transaction_persistent)
VALUES ('appuser', 'sifren', 20, 1);

# Kuralları yaz: yazmaları 10'a, okumaları 20'ye
INSERT INTO mysql_query_rules (rule_id, match_pattern, destination_hostgroup, apply)
VALUES
  (10, '^(?i)(INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|ALTER) ', 10, 1),
  (20, '^(?i)SELECT ', 20, 1);

LOAD MYSQL SERVERS TO RUNTIME; SAVE MYSQL SERVERS TO DISK;
LOAD MYSQL USERS TO RUNTIME;   SAVE MYSQL USERS TO DISK;
LOAD MYSQL QUERY RULES TO RUNTIME; SAVE MYSQL QUERY RULES TO DISK;

Bu çok basit bir iskelet. Gerçekte sağlık kontrollerini, replikasyon gecikmesi ölçümünü ve failover davranışını da yapılandırmak istersin. Ama ilk adımda amaç basitçe trafiği ikiye ayırmak.

Gecikmeye Duyarlı Okuma

Replikasyon gecikmesi artarsa okuma sorgularını otomatik yazıcıya yönlendirmek hayati olabilir. ProxySQL, belirlediğin eşiğin üzerindeki kopyaları geçici olarak devre dışı bırakabilir. Senaryosu net: büyük raporlar çalışıyor, replika ardına bakamıyor; ProxySQL “tamam, seni yormayayım” diyerek o replika için okuma akışını keser.

Bağlantı Havuzu Ayarlarını Dengelemek

Uygulama tarafında yüzlerce kısa bağlantı açmak yerine, ProxySQL’de uygun bir tavan koymak gerekir. Çok düşük olursa kuyruk oluşur, çok yüksek olursa boşuna kaynak yer. Küçük bir test ortamında trafik simüle edip hem ProxySQL istatistiklerine hem de MySQL thread yüküne bakarak birkaç tur ayar yapmak en sağlıklısı.

Laravel ile Uyum: Read/Write Split’i Yapıştırıp Geçmek

Laravel güzel bir avantaj sunuyor: uygulama seviyesinde read/write bağlantı tanımı. ProxySQL’i araya koyduğunda iki yolu var. Birincisi, tüm bağlantıları ProxySQL’e verip kuralları ProxySQL’de yönetmek. İkincisi, Laravel’in native read/write desteğini de kullanıp sticky read gibi tatlı bir dokunuş eklemek. Sipariş yazıldıktan sonraki birkaç saniye boyunca okumalarda da yazıcıya gitmek, “yazdığımı hemen göreyim” hissini güvenli kılar.

// config/database.php içinde basitleştirilmiş örnek
'mysql' => [
  'driver' => 'mysql',
  'host' => env('DB_HOST', 'proxysql.internal'),
  'port' => env('DB_PORT', 6033),
  'database' => env('DB_DATABASE', 'app'),
  'username' => env('DB_USERNAME', 'appuser'),
  'password' => env('DB_PASSWORD', ''),
  'sticky' => true, // Yazdıktan sonra kısa süre yazıcıya yapışır
  'read' => ['host' => 'proxysql.internal'],
  'write' => ['host' => 'proxysql.internal'],
],

Laravel tarafında bu yapı taş gibi işler. Özellikle kuyruk işlerinde ve transaction bloklarında, tutarlılık şüphesini azaltır. Ayrıca uygulama hostunu ProxySQL yaptığında, veri tabanı sertifikalarını ve bağlantı zaman aşımı ayarlarını da ProxySQL tarafında merkezi biçimde yönetme rahatlığı gelir. Laravel dokümantasyonunda bu konu gayet sade anlatılıyor; detaylara Laravel’in read/write bağlantı yönlendirme bölümünden göz atabilirsin.

WooCommerce’te İnce Ayar: Checkout Kırılmadan Nasıl Paylaştırırız?

WordPress dünyası biraz farklı. Uygulama kodunda her sorguya işaret koymak pek mümkün değil. Ama ProxySQL’in kurallarıyla WooCommerce’in kalp atışına uyum sağlayabilirsin. Ödeme ve siparişle ilgili sorguların yazıcıya gitmesi kritik. Sipariş ekranında o an oluşan verinin anında görünmesi gerekir; replikaya düşen gecikme iftira gibi algılanır.

Ben şu yoldan gidiyorum: checkout akışında sık görülen tablo ve örüntülere ufak kurallar. Örneğin “wp_posts içinde shop_order” veya “wp_wc_orders” gibi order depolarına bakan SELECT’leri yazıcıya yönlendirmek. Çok agresif olmaz, ama ödeme anında rahatlatır. Eğer WooCommerce’te High-Performance Order Storage (HPOS) kullanıyorsan, sipariş verisi artık özel tablolarda durduğundan, kuralları bu tablo adlarıyla eşleştirmek daha güvenli. İlgilenenler için HPOS detaylarına WooCommerce’in yüksek performanslı sipariş depolaması rehberinden bakabilir.

Bir de kullanıcı oturumları konusu var. Giriş yaptıktan hemen sonra kullanıcıya “profiliniz güncellendi” gibi bir mesaj gösteriyorsun; bu okuma yazmayı takip ediyor. Burada ya replikasyon gecikmesini çok düşük tutacaksın ya da kritik sayfalarda kısa süreli yazıcı tercihine izin vereceksin. ProxySQL tarafında transaction içinde gelen SELECT’leri yazıcıya göndermek güzel bir emniyet supabı. Checkout ve admin işlemleri çoğunlukla transaction’lı olduğu için bu, hedefi vuruyor.

İzleme, Güncelleme ve Küçük Kazaları Zarifçe Yönetmek

Read/write split kurduk, havuzları ayarladık. Şimdi spor saatini takma zamanı: ölç, gözle, düzelt. ProxySQL’in query digest istatistikleri, hangi sorguların ne kadar süre aldığını ve hangi hostgruba gittiğini fısıldar. Replikaların gecikmesini izleyip eşik koyduğunda, gece yarısı patlayan raporlar bile can sıkmaz. MySQL tarafında da yavaş sorgu logunu hafifçe açıp, uzun yaşayan sorguları sıkıştırmak güzel bir temizliktir.

Canlıya alırken sıfır kesinti hedefi aklında olsun. ProxySQL’in arada olması burada avantaj, çünkü arka tarafta düğüm değiştirmek, yükü kademeli dağıtmak daha kolay. Eğer dağıtım ve DNS tarafında süreçleri otomatikleştirmek hedefin varsa, şu bakış açısı işine yarayabilir: Terraform ile otomasyon ve sıfır kesinti dağıtımı bir araya getirmek güzel bir çerçeve sunuyor.

Uygulama gözleminin tadını artırmak için uçtan uca izler kurmak şahane. Laravel’de önemli endpoint’lerin DB çağrılarını da izlediğinde, ProxySQL’in elinden geçen sorguların nasıl dolaştığını daha iyi anlarsın. Bu sayede “checkout neden bazen uzuyor?” sorusunu sayılarla konuşur hale getirirsin.

Gerçek Dünyada Karşılaştığım Tıkanmalar ve Çözümler

En çok gördüğüm sıkıntı: read-your-write tutarlılığı. Yazdıktan hemen sonra okuduğunda, replika arkadan gelirse hayal kırıklığı. Çözüm olarak üç dokunuş öneriyorum. Birincisi, kritik akışlarda transaction kullan ve transaction içindeki SELECT’leri yazıcıya yönlendir. İkincisi, Laravel’de sticky özelliğini aç; yazıdan sonra birkaç saniye aynı düğümde kal. Üçüncüsü, WooCommerce’te checkout’la ilgili SELECT’leri yazıcıya yönlendirecek kurallar yaz; abartma, nokta atışı yap.

İkinci yaygın konu: havuz doyması. Özellikle kısa ömürlü yoğun PHP isteklerinde ProxySQL’in arka bağlantı havuzu tavanı iyi ayarlanmazsa kuyruklar oluşur. Burada küçük bir yük testi altın değerinde. Az az artır, grafiklere bak, “aha” dediğin noktayı bul. Uygulama tarafındaki eşzamanlılık ile arka bağlantı tavanını uyumlu tut.

Üçüncü başlık: uzun yaşayan SELECT’ler. Rapor, dışa aktarma, büyük JOIN’ler… Replikanın ritmini bozar. Bu sorguları ya zamanlayıp sakin saatlere al ya da kaynakları bol bir replika ayır. ProxySQL’de belirli sorgu kalıplarını özel bir okuyucu gruba göndermek hayat kurtarır. Bir de indeks temizlikleri, sorgu planlarını tazelemek, şişkin tablo sorunlarını sakin sakin çözmek uzun vadede kan basıncını düşürür.

Güvenlik ve Dayanıklılık: Sessiz Kahramanlar

Uygulama ve ProxySQL arasına TLS koymak, özellikle farklı ağlar arasında konuşuyorsan, içini rahatlatır. ProxySQL, arka tarafa giden bağlantıda da TLS konuşabilir; sertifikaları düzenli yenilemek ve süreleri takip etmek önemli. Kimlik doğrulamada uygulamaya özel bir DB kullanıcısı verip, ProxySQL içinde en az yetkiyle çalıştırmak iyi bir alışkanlık.

Failover senaryolarında ProxySQL’in kalp atışı kontrolleri devreye girer. Yazıcı çökerse, kontrolü ele alıp uygun düğümü yazıcı yapman gerekir; burada otomasyon iyidir ama aceleci davranan otomasyon bazen fazla cesur olabilir. Önce replikanın güncel olduğundan emin olmak, sonra yazıcı atamasını yapmak, en sonunda ProxySQL’e “oyunu buna kur” demek daha güvenli bir ritim.

ProxySQL Kurallarıyla İnce İşçilik: WooCommerce ve Laravel İçin Örnekler

Küçük ama etkili birkaç kural fikri bırakayım. Checkout’ta sipariş tabanlı SELECT’leri yazıcıya gönder:

INSERT INTO mysql_query_rules (rule_id, match_pattern, destination_hostgroup, apply)
VALUES
  (30, '^(?i)SELECT .* FROM (wp_wc_orders|wp_posts).*shop_order', 10, 1);

LOAD MYSQL QUERY RULES TO RUNTIME; SAVE MYSQL QUERY RULES TO DISK;

Transaction içindeki SELECT’leri yazıcıya göndererek tutarlılığı güçlendir:

UPDATE mysql_query_rules SET 
  flagIN = 1, 
  destination_hostgroup = 10
WHERE rule_id = 20 AND match_pattern = '^(?i)SELECT ' AND log = 0 AND apply = 1;

-- Not: flagIN ve transaction_persistent ayarlarıyla birlikte düşün.

Laravel’de kritik iş akışlarını transaction ile çepeçevre sar:

DB::transaction(function () {
    $order = Order::create([...]);
    // Buradaki SELECT'lerin yazıcıda kalması için transaction koruması yeterli olur
    $summary = Order::where('id', $order->id)->first();
});

Bunlar birer iskelet. Üretimde kurcalayıp kendi sorgu desenlerine göre inceltmek gerekir. Zorlamadan, ölçerek, adım adım.

Dokümantasyon ve Ufak Yol Arkadaşları

Detaylara dalmak istediğinde, ProxySQL’in resmi dokümantasyonu yol gösterici. Laravel cephesinde read/write bağlantılarını küçücük bir dokunuşla etkinleştirmek için resmi dokümanın ilgili bölümü çok net. WooCommerce’te ise sipariş depolamasını HPOS’a taşıdıysan, yüksek performanslı sipariş depolaması rehberi işini kolaylaştırır.

Kapanış: Sakin Trafik, Mutlu Siparişler

Özetle şunu gördüm: ProxySQL araya girince, MySQL ile uygulama arasındaki iniş çıkışlar daha yumuşak oluyor. Read/write split ile yazmaları güvenli limana, okumaları ferah denize yolluyoruz. Bağlantı havuzu sayesinde “her istekte yeniden tanışma” derdinden kurtuluyoruz. WooCommerce’te checkout nefes alıyor, Laravel’de kuyruklar daha az sürpriz yapıyor.

Pratik öneri olarak; önce küçük bir test ortamında kural ve havuz ayarlarını dene, sonra kademeli canlı al. Transaction’ları kritik yerlerde aç, Laravel’de sticky’yi çekinmeden kullan, WooCommerce’te checkout’a özgü SELECT’leri yazıcıya yönlendir. Replika gecikmesini izle, eşiği geçeni dinlendir. Ve en önemlisi, ölçmeden karar verme. Umarım bu rehber elini rahatlattı; soruların olursa, bırak konuşalım. Bir dahaki yazıda görüşmek üzere.

Sıkça Sorulan Sorular

Doğru kuralla güvenli. Checkout ve siparişle ilgili SELECT sorgularını yazıcıya yönlendir, replikasyon gecikmesini izle ve kritik akışlarda transaction kullan. Böylece “yazdığımı görmüyorum” sürprizi yaşamazsın.

Hayır, çoğu zaman gerekmez. Laravel’in read/write bağlantı desteğini etkinleştirip ProxySQL’i tek uç olarak tanımlaman yeterli. Sticky özelliğini açarsan yazma sonrası kısa süreli okumalarda da yazıcıya gitmeyi garanti edersin.

Küçük bir yük testi yap, eşzamanlı istek sayına göre ProxySQL arka bağlantı tavanını kademeli artır. Çok düşükse kuyruk, çok yüksekse kaynak israfı olur. Replika gecikmesini ve sorgu sürelerini izleyerek tatlı noktayı bul.