Teknoloji

ProxySQL ile MySQL Okuma/Yazma Ayrımı ve Bağlantı Havuzu

Bir WooCommerce kampanyasında siparişler artarken stok güncellemeleri, sipariş okumaları ve raporlar veri tabanında aynı anda yük oluşturabilir. ProxySQL ile bu trafiği yönlendirmek, yalnızca kapasite artırmak yerine değerlendirilebilecek bir yaklaşımdır.

ProxySQL ile MySQL okuma/yazma ayrımı ve bağlantı havuzu kurarken ilk karar hangi okumaların gecikmiş veriyi kabul edebileceğidir. Bu rehber ProxySQL 3.0.8, MySQL 8.4 üzerinde geleneksel asenkron birincil–replika yapısı ve Laravel 12 davranışını esas alır. WooCommerce için tüm kritik akışı ana veritabanında tutar; kopyalara okuma açmayı ayrıca doğrulanacak bir uygulama kararı olarak ele alır.

ProxySQL neyi yönetir?

ProxySQL uygulama bağlantılarını kabul eder, MySQL’e açtığı arka bağlantıları havuzlar ve yapılandırılan kullanıcı/kurallara göre sorguları yönlendirir. Hostgroup, birlikte kullanılan veritabanı sunucularının grubudur. Yazma ve okumaların doğru yere gitmesi kendiliğinden oluşmaz; varsayılan grup, etkin kurallar ve işlem durumu birlikte belirleyicidir.

WooCommerce sipariş, stok, kupon, oturum ve raporlama işlemleri; Laravel ise web istekleri, kuyruk işleri ve zamanlanmış görevlerle veritabanını kullanır. Bu işlerin bir bölümünü kopyalara taşımak ana sunucunun yükünü azaltabilir. Kazanç, sorguların maliyetine, çoğaltma yüküne ve doğru yönlendirmeye bağlıdır; ProxySQL tek başına kapasite veya yanıt süresi garantisi vermez.

Tutarlılık sınırı: önce yazıcı, sonra seçilmiş okumalar

Tüm SELECT sorgularını kopyalara gönderen genel bir kural kullanma. SELECT ... FOR UPDATE, FOR SHARE ve eski LOCK IN SHARE MODE kilitli okumalarıdır; yeni yazılmış veriye ihtiyaç duyan sıradan SELECT de ana sunucuda kalmalıdır. Bir sorgunun ilk kelimesi, uygulamanın tutarlılık ihtiyacını açıklamaz. Örnekte app_writer kimliği grup 10’u, yalnızca gecikmeyi tolere eden işler için kullanılan app_reader grup 20’yi seçer.

Asenkron replikada gecikmenin düşük veya sıfır raporlanması, belirli bir yazının o anda görünür olduğunu kanıtlamaz. Sipariş onayı ve stok kontrolü gibi okumalar yazıcıya açıkça gitmelidir. Laravel sticky seçeneği, aynı istek döngüsünde yazma yapıldıktan sonra okumaları yazma bağlantısına yönlendirir; birkaç saniyelik sayaç değildir. Sonraki istek veya başka kuyruk işi bu davranıştan otomatik bir tutarlılık garantisi alamaz.

Ön bağlantılar, arka havuz ve multiplexing

Uygulama yine ProxySQL’e bir ön bağlantı açar; bunun kimlik doğrulama ve varsa TLS maliyeti vardır. ProxySQL’in MySQL tarafındaki arka bağlantıları yeniden kullanması, veritabanına tekrar tekrar bağlanmanın maliyetini azaltabilir. Multiplexing, uygun durumdaki arka bağlantının farklı istemci oturumları için sırayla kullanılmasını sağlar; aynı bağlantıda eşzamanlı sorgu yürütmek değildir.

Aktif işlemler, geçici tablolar, kullanıcı değişkenleri ve bazı kilit/oturum durumları multiplexing’i sınırlayabilir. Uzun yaşayan Laravel işçileri ile kısa PHP istekleri aynı bağlantı davranışına sahip değildir. Multiplexing’in kapanması sorgu yönlendirmesini kapatmaz; başka sunucuya giden sorgu önceki geçici tabloyu göremeyebilir. Havuz ölçümünde kullanılan ve boş arka bağlantıları, ön istemci sayısından ayrı izle.

ProxySQL için deneme yapılandırması

Sunucular, kullanıcılar ve ön koşullar

Örnek yeni ve izole bir kurulum içindir: aynı uygulama sunucusundaki ProxySQL’e 127.0.0.1:6033 üzerinden bağlanılır. db-primary tek yazılabilir MySQL sunucusu, db-replica-1 ve db-replica-2 sağlıklı asenkron kopyalardır; shopdb önceden vardır. Replikalarda read_only/super_read_only korumasını doğrula. Önce uygun resmi paket deposundan ProxySQL’i kurup sürümünü kontrol et; MySQL istemcisiyle mysql -h 127.0.0.1 -P6032 -u admin -p yönetim konsoluna gir. Yönetim erişimini sınırla ve varsayılan parolayı değiştir. Mevcut kurulumda grup, kullanıcı ve kural çakışmalarını incelemeden bu INSERT’leri uygulama.

MySQL tarafında ayrı app_writer, app_reader ve monitor hesaplarını önce oluşturup ilgili her düğümde doğrula. Reader yalnızca gereken SELECT yetkilerini, writer uygulamanın gereken yetkilerini almalı; uygulama hesaplarına CONNECTION_ADMIN veya SUPER verme. Monitor için bağlantı erişimi ve gecikme kontrolüne gereken REPLICATION CLIENT yetkisi gerekir. Hesapların kaynak adresini gerçek ProxySQL adresiyle sınırla. Aşağıdaki yer tutucu parolaları aynı hesapların gerçek sırlarıyla güvenli biçimde değiştir. Arka TLS sertifika/CA yapılandırmasının hazır olduğu varsayılır; use_ssl=1 bunu tek başına kurmaz.

-- ProxySQL admin console: fresh isolated lab only.
INSERT INTO mysql_servers
(hostgroup_id, hostname, port, max_connections, max_replication_lag, use_ssl)
VALUES
(10, 'db-primary', 3306, 200, 0, 1),
(20, 'db-replica-1', 3306, 200, 2, 1),
(20, 'db-replica-2', 3306, 200, 2, 1);

INSERT INTO mysql_replication_hostgroups
(writer_hostgroup, reader_hostgroup, check_type, comment)
VALUES (10, 20, 'read_only', 'Traditional asynchronous replication');

SET mysql-monitor_username='monitor';
SET mysql-monitor_password='REPLACE_WITH_MONITOR_SECRET';
SET mysql-monitor_writer_is_also_reader='false';
LOAD MYSQL VARIABLES TO RUNTIME;
LOAD MYSQL SERVERS TO RUNTIME;
-- Accounts and matching passwords must already exist on MySQL.
INSERT INTO mysql_users
(username, password, active, default_hostgroup, default_schema,
 transaction_persistent, fast_forward, backend, frontend, max_connections)
VALUES
('app_writer', 'REPLACE_WITH_WRITER_SECRET', 1, 10, 'shopdb', 1, 0, 1, 1, 500),
('app_reader', 'REPLACE_WITH_READER_SECRET', 1, 20, 'shopdb', 1, 0, 1, 1, 500);
LOAD MYSQL USERS TO RUNTIME;

mysql_replication_hostgroups burada yazıcı/okuyucu gruplarını read_only durumuyla ilişkilendirir; replikasyon kurmaz. mysql-monitor_writer_is_also_reader=false yazıcıyı okuyucu grubundan ayırır. LOAD ... TO RUNTIME değişiklikleri çalışır duruma alır; kalıcılık için testlerden sonra ilgili SAVE ... TO DISK komutları gerekir. Örnekte başka etkin yönlendirme kuralı bulunmadığı varsayılır; kullanıcıların varsayılan grupları temel yönlendirmeyi sağlar.

Replika gecikmesi ve okuyucu kalmaması

max_replication_lag, mysql_servers satırında bulunur. Örnekte okuyucular için 2 saniye yalnızca bir deneme eşiğidir; uygulamanın kabul edeceği eskilikle karıştırma. Monitor eşiği aşan kopyayı kullanımdan çıkarabilir, fakat ölçüm aralığı ve hatalar da izlenmelidir. Grup 20’de uygun okuyucu kalmazsa bu yapılandırma yazıcıya otomatik geçiş sağlamaz; okuma bekleyebilir veya hata alabilir. Uygulamanın kontrollü olarak yazıcı kimliğine dönmesi ve yazıcının bu yükü kaldırması ayrıca tasarlanmalıdır.

Bağlantı sınırlarını ölçmek

Sunucu satırındaki max_connections=200 arka bağlantı tavanıdır; kullanıcıdaki max_connections=500 ön istemci sınırıdır. İkisi de örnek değerdir. Tüm ProxySQL örneklerinin aynı MySQL sunucusuna açacağı havuzları, doğrudan yönetim bağlantılarını ve MySQL kapasitesini birlikte bütçele. Sınırı artırmak yavaş sorguyu düzeltmez; eşzamanlı PHP işçileri, kuyruklar, işlem süreleri, bekleme ve bağlantı hatalarıyla birlikte yük testi yap.

Laravel 12: ayrı okuma ve yazma kimlikleri

Aynı ProxySQL adresini kullanırken iki farklı kullanıcı seçmek, Laravel’in yazma PDO’suna geçen sorgunun gerçekten yazıcı hostgroup’unda kalmasını sağlar. Aşağıdaki bölüm mevcut config/database.php bağlantı dizisine uyarlanır. DB_WRITE_PASSWORD ve DB_READ_PASSWORD önceden oluşturulan hesaplarla eşleşmelidir. Başlangıçta tüm trafik yazıcıda doğrulanmalı; aşağıdaki read bölümü ancak gecikmeyi tolere eden okuma yolları ayrıldıktan sonra etkinleştirilmelidir.

// Merge into the existing config/database.php connections array.
'mysql' => [
    'driver' => 'mysql',
    'host' => '127.0.0.1',
    'port' => 6033,
    'database' => env('DB_DATABASE', 'shopdb'),
    'username' => 'app_writer',
    'password' => env('DB_WRITE_PASSWORD'),
    'unix_socket' => '',
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'read' => [
        'username' => 'app_reader',
        'password' => env('DB_READ_PASSWORD'),
    ],
    'write' => [
        'username' => 'app_writer',
        'password' => env('DB_WRITE_PASSWORD'),
    ],
    'sticky' => true,
],

sticky=true aynı bağlantının mevcut istek döngüsündeki yazma durumuna bakar. Laravel işlemi içindeki okumalar yazma PDO’sunu kullanır; ayrı istek, ayrı bağlantı veya başka iş için süre temelli bir garanti yoktur. Uzun yaşayan işçilerin bağlantı yaşam döngüsünü ve yapılandırma değişikliğinden sonra yeniden yüklenmesini ayrıca doğrula. İstemci–ProxySQL ile ProxySQL–MySQL TLS ve zaman aşımı ayarları ayrıdır. Bağlantı seçenekleri Laravel’in read/write belgelerinde açıklanır.

WooCommerce: checkout akışını yazıcıda tutmak

WooCommerce’in normal veritabanı bağlantısını app_writer ile ProxySQL’e yönlendir; DB_HOST yerel örnekte 127.0.0.1:6033 olur. Böylece sipariş, ödeme, stok, kupon, yönetim ve oturum sorguları aynı yazıcı yolu üzerinden çalışır. Yalnızca bağlantı adresini değiştirmek, güvenli bir replica-read entegrasyonu oluşturmaz; gecikmeye dayanıklı ayrı rapor veya okuma entegrasyonu ayrıca geliştirilip sınanmalıdır.

Sipariş depolaması eski wp_posts/wp_postmeta yapısında veya HPOS’un özel tablolarında olabilir; wp_wc_orders yalnızca örnek addır, gerçek tablo önekini kontrol et. HPOS’ta hangi deponun yetkili olduğu ve uyumluluk eşitlemesi önemlidir. Salt tablo adı regex’i tüm checkout akışını kapsamaz. Sipariş erişiminde depolama biçimini bilen WooCommerce CRUD API’sini tercih et; ayrıntılar HPOS depolama rehberinde yer alır.

Profil güncellemesi, ödeme dönüşü ve yeni siparişin okunması farklı HTTP isteklerine dağılabilir. Bütün bu akışı otomatik olarak tek transaction kabul etme. Yazıcıdan okuma replica gecikmesini ortadan kaldırır; uygulamanın stok kilitlemesi, eşzamanlılık kontrolü, ödeme tekrarları ve önbellek geçersizleştirmesi yine doğru uygulanmalıdır. Sadece son sipariş SELECT’ini işaretlemek bu sorumlulukların yerini tutmaz.

Yönlendirme ve havuz davranışını izlemek

Yönetim konsolunda kullanıcı, hostgroup, sorgu digest’i ve arka havuz durumunu birlikte incele. Ortalama süre aşağıda mikrosaniyeden milisaniyeye çevrilir; proxy içindeki beklemeyi de kapsayabilir. Kural vuruş sayısı tek başına belirli bir isteğin tüm yolunu kanıtlamaz.

-- SQL only: run inside the ProxySQL admin console.
SELECT hostgroup, srv_host, srv_port, status, ConnUsed, ConnFree, ConnERR, Queries
FROM stats_mysql_connection_pool ORDER BY hostgroup, srv_host;

SELECT username, hostgroup, digest, digest_text, count_star,
       ROUND(sum_time / NULLIF(count_star, 0) / 1000.0, 2) AS avg_ms
FROM stats_mysql_query_digest ORDER BY sum_time DESC LIMIT 20;

SELECT rule_id, hits FROM stats_mysql_query_rules ORDER BY rule_id;
SELECT hostname, port, repl_lag, error
FROM monitor.mysql_server_replication_lag_log
ORDER BY time_start_us DESC LIMIT 10;

Dağıtımı küçük trafik dilimleriyle yap; hata oranı, checkout başarısı ve p95/p99 yanıt sürelerini önceki durumla karşılaştır. Düğüm değiştirmek aktif bağlantıların kesilmeyeceği anlamına gelmez. Altyapı değişikliklerini kayda almak için Terraform ile VPS ve DNS otomasyonu yaklaşımı kullanılabilir; veritabanı devri ve uygulama geri dönüşü ayrıca planlanmalıdır.

Uygulama izleriyle bir checkout isteğini SQL kayıtları ve MySQL yavaş sorgu verileriyle ilişkilendir. Sayaçların yeniden başlatma veya sıfırlama sonrası değiştiğini hesaba kat; karşılaştırmada aynı zaman aralığını kullan. Sorgu kayıtları kişisel veri ve sır içerebilir, bu yüzden ayrıntılı günlükleri ihtiyaç duyulan kapsam ve süreyle sınırla.

Üç yaygın darboğazı ayırmak

Yazdıktan sonra okuyamama: Önce okumanın kullandığı kullanıcı ve hostgroup’u doğrula. Kritik okuma yazıcı PDO’suna gitmeli; önceki isteğin sticky durumuna güvenme. İşlem yazıcıda başlatılmalıdır. transaction_persistent=1 işlemi başladığı hostgroup’ta tutar; okuyucuda başlamış bir işlemi yazıcıya taşımaz.

Havuz doyması: Kullanılan arka bağlantıları ve sorgu/işlem sürelerini incele; ön istemci sınırı ile arka sunucu tavanını ayır. Limit dolduğunda bekleme ve zaman aşımı oluşabilir. PHP veya kuyruk eşzamanlılığını artırmadan önce sorgu planını, kilitleri ve MySQL kaynaklarını ölç.

Uzun raporlar: Gecikmiş veriyi kabul eden dışa aktarımları ayrı okuyucu kimliği ve gerekirse ayrı hostgroup ile çalıştır. Uzun transaction ve akış halinde sonuç okumak bağlantıyı uzun süre tutabilir. Sayfalama, uygun indeksler, sorgu planı incelemesi ve zamanlama; yalnızca havuz tavanını artırmaktan farklı sorunları çözer.

TLS, yetkiler ve devralma sınırları

Yerel ön bağlantı örneği yalnızca loopback TCP içindir; şifreli olduğunu varsayma. Ayrı sunuculara geçerken istemci–ProxySQL TLS’ini yapılandırıp gerekli kullanıcılarda mysql_users.use_ssl=1 ile zorunlu kıl. Arka bağlantıda mysql_servers.use_ssl=1 ve ilgili CA/sertifika ayarları ayrıca gerekir. TLS açmak, doğru karşı taraf kimliğinin doğrulandığını tek başına göstermez: geçersiz CA/sertifika denemelerini de içeren bağlantı testleri yap. Yetkiler gerçek MySQL hesaplarında uygulanır; ProxySQL’e kullanıcı eklemek GRANT işlemi değildir.

ProxySQL sağlığı ve read_only durumunu izler; eski yazıcıyı yalıtıp replikayı güvenli biçimde terfi ettiren bir failover yöneticisi değildir. Devralmada eski yazıcının yeni yazı kabul etmesini engelle, adayın uygulanmış işlem durumunu ve olası veri kaybını değerlendir, ardından tek yazılabilir düğümü ve yönlendirmeyi doğrula. Sadece read_only bayrağını değiştirmek sıfır veri kaybını veya çift yazıcı oluşmamasını kanıtlamaz.

Kullanıcıya bağlı kurallar ve açık yazıcı okuması

Yeni deneme kural kümesinde aşağıdaki erken ve sonlandırıcı kural, app_writer trafiğinin grup 10’da kalmasını açık hale getirir. active=1 gereklidir; kural tablosunda varsayılan değer 0’dır. Gerçek kurulumda daha erken kuralları ve ID çakışmalarını incele; bu örnek mevcut tüm kuralları silmeyi gerektirmez.

-- Fresh rule set; verify rule IDs and ordering before adapting.
INSERT INTO mysql_query_rules
(rule_id, active, username, destination_hostgroup, apply)
VALUES (1, 1, 'app_writer', 10, 1);
LOAD MYSQL QUERY RULES TO RUNTIME;

İsteğe bağlı aşağıdaki kural, app_reader kullanıcısının başında /* to:master */ bulunan ham sorgusunu yazıcı grubuna gönderir; reader hesabı o sunucuda da gerekli SELECT yetkilerine sahip olmalıdır. Yorum kendiliğinden tanınan bir tutarlılık özelliği değildir. Aktif ve okuyucuya sabitlenmiş işlemi taşımaz; kritik uygulama akışında doğrudan writer bağlantısını tercih et. flagIN/flagOUT kural zinciri içindir, transaction algılamaz.

-- Optional: explicitly marked reads by app_reader may use the primary.
INSERT INTO mysql_query_rules
(rule_id, active, username, match_pattern, destination_hostgroup, apply)
VALUES (2, 1, 'app_reader',
'^[[:space:]]*[/][*][[:space:]]*to:master[[:space:]]*[*][/]', 10, 1);
LOAD MYSQL QUERY RULES TO RUNTIME;

Laravel’de işlemi adı açıkça seçilmiş mysql bağlantısında başlat. Aşağıdaki örnek mevcut Order modelini, doğrulanmış $orderData verisini ve orders tablosunu varsayar; ödeme veya stok algoritması değildir. Sonraki istek veya işte bilinen sipariş ID’siyle yapılan kritik okuma useWritePdo() kullanır.

use Illuminate\Support\Facades\DB;

// Existing Order model uses the mysql connection; $orderData is validated.
$order = DB::connection('mysql')->transaction(function () use ($orderData) {
    $order = Order::on('mysql')->create($orderData);
    return Order::on('mysql')->whereKey($order->id)->firstOrFail();
});

// A critical read in a later request/job must choose the writer explicitly.
$fresh = DB::connection('mysql')->table('orders')
    ->useWritePdo()->where('id', $order->id)->first();

Önce yazıcı/okuyucu oturumlarını, bir yazma sonrası okumayı, kilitli okumayı ve tüm okuyucuların kullanılamadığı durumu deneme ortamında doğrula. Uygulama sonuçları ile hostgroup istatistikleri uyuşunca ilgili yapılandırma modüllerini diske kaydet. Geri dönüş için önceki satırları ve uygulama bağlantı ayarını sakla; eski değerleri ilgili modüle geri yükleyip runtime’a al, doğrula ve kalıcılaştır. Yeniden başlatmayı genel geri alma yöntemi sayma.

-- After routing, authentication, TLS and failure tests pass:
SAVE MYSQL VARIABLES TO DISK;
SAVE MYSQL SERVERS TO DISK;
SAVE MYSQL USERS TO DISK;
SAVE MYSQL QUERY RULES TO DISK;

Resmi kaynaklar ve sürüm uyumu

Ayarların sürümüne uygun şemasını ProxySQL resmi belgelerinden kontrol et. Bu örnek geleneksel MySQL asenkron replikasyon içindir; Group Replication veya Galera hostgroup tablolarının sütunlarını buraya taşıma. Laravel ve HPOS bağlantıları yukarıdaki ilgili bölümlerde yer alır.

Canlıya geçiş için kabul ölçütleri

Yazıcı kimliğinin kritik işlemler boyunca grup 10’da kaldığı, reader kimliğinin yalnızca gecikmeyi tolere eden yollarda kullanıldığı ve okuyucu kaybında uygulamanın beklenen davranışı gösterdiği doğrulanmalıdır. Bağlantı bütçesi, TLS/yetki testleri ve geri dönüş adımları da kayıtlı olmalıdır. Performans kazanımını ancak aynı iş yükünde ölçülmüş sonuçlarla değerlendirmek mümkündür.

Sıkça Sorulan Sorular

Tutarlılık uygulamanın okuma yollarına bağlıdır. Bu rehber WooCommerce’in normal bağlantısını yazıcıda tutar. Yalnızca gecikmeyi tolere eden, ayrıca doğrulanmış bir entegrasyon okuyucuya açılır. Sipariş tablosu regex’i veya düşük replika gecikmesi tek başına checkout tutarlılığını sağlamaz.

Önce yalnızca yazıcı bağlantısıyla başlanabilir. Okuma ayrımı için read/write tarafında farklı ProxySQL kullanıcıları ve kritik okumalar için açık yazıcı seçimi gerekir. Sticky aynı istek döngüsünde yazma sonrası çalışır; saniyelik süre veya sonraki istek ve kuyruk işi için garanti değildir.

Ön istemci bağlantılarıyla arka MySQL bağlantılarını ayrı ölçün. Tüm ProxySQL örneklerinin aynı MySQL sunucusuna açacağı havuzları, doğrudan bağlantıları ve uygulama eşzamanlılığını birlikte bütçeleyin. Kullanılan bağlantılar, bekleme, hata oranı ve işlem süreleriyle yük testi yapın.
↑