Förmågan att forma trafiken som går till databasen är en av de viktigaste. Under de senaste dagarna hade du inte så mycket kontroll över det - applikationer skickade trafiken till databasen och det är ungefär det. HAProxy, som var vanligt förekommande, har inte heller möjlighet till finkornig kontroll över trafiken. Med introduktionen av SQL-medvetna proxyservrar, som ProxySQL, blev fler möjligheter tillgängliga för databasadministratörer. Låt oss ta en titt på anslutningshanterings- och strypningsmöjligheterna i ProxySQL.
Anslutningshantering i ProxySQL
Som du kanske vet är hur ProxySQL fungerar genom frågereglerna. Det är en lista med regler som varje fråga testas mot och som styr exakt hur ProxySQL kommer att hantera frågan. Från början ansluter applikationen till ProxySQL. Den kommer att autentisera mot ProxySQL (det är därför ProxySQL måste lagra alla användare och lösenordshashar) och sedan kör ProxySQL den genom frågereglerna för att avgöra till vilken värdgrupp frågan ska skickas.
ProxySQL öppnar en pool av anslutningar till backend-servrarna. Det är inte 1-till-1-mappning, som standard försöker den återanvända en backend-anslutning för så många frontend-anslutningar som möjligt. Detta kallas anslutningsmultiplexering. Detaljerna beror på den exakta trafiken som den måste hantera. Varje öppen transaktion måste hanteras inom samma anslutning. Om det finns någon typ av lokal variabel definierad kan denna anslutning inte återanvändas. Att kunna återanvända en enkel backend-anslutning med flera frontend-anslutningar minskar belastningen på backend-databasen avsevärt.
När anslutningen är gjord till ProxySQL, som vi nämnde tidigare, kommer den att behandlas enligt frågereglerna. Här kan trafikformningen ske. Låt oss ta en titt på alternativen
Anslutningsbegränsning i ProxySQL
Låt oss först släppa alla SELECT. Vi kör vår "applikation", Sysbench, på följande sätt:
[email protected]:~# sysbench /root/sysbench/src/lua/oltp_read_only.lua --threads=4 --events=200 --time=0 --mysql-host=10.0.0.101 --mysql-user=sbtest --mysql-password=sbtest --mysql-port=6033 --tables=32 --report-interval=1 --skip-trx=on --table-size=100000 --db-ps-mode=disable --rate=10 run
sysbench 1.1.0-bbee5d5 (using bundled LuaJIT 2.1.0-beta3)
Running the test with following options:
Number of threads: 4
Target transaction rate: 10/sec
Report intermediate results every 1 second(s)
Initializing random number generator from current time
Initializing worker threads...
Threads started!
[ 1s ] thds: 4 tps: 5.97 qps: 103.49 (r/w/o: 103.49/0.00/0.00) lat (ms,95%): 244.38 err/s: 0.00 reconn/s: 0.00
[ 1s ] queue length: 0, concurrency: 4
[ 2s ] thds: 4 tps: 13.02 qps: 181.32 (r/w/o: 181.32/0.00/0.00) lat (ms,95%): 580.02 err/s: 0.00 reconn/s: 0.00
[ 2s ] queue length: 5, concurrency: 4
[ 3s ] thds: 4 tps: 14.99 qps: 228.81 (r/w/o: 228.81/0.00/0.00) lat (ms,95%): 669.89 err/s: 0.00 reconn/s: 0.00
[ 3s ] queue length: 1, concurrency: 4
[ 4s ] thds: 4 tps: 16.99 qps: 232.88 (r/w/o: 232.88/0.00/0.00) lat (ms,95%): 350.33 err/s: 0.00 reconn/s: 0.00
[ 4s ] queue length: 0, concurrency: 3
[ 5s ] thds: 4 tps: 8.99 qps: 99.91 (r/w/o: 99.91/0.00/0.00) lat (ms,95%): 369.77 err/s: 0.00 reconn/s: 0.00
[ 5s ] queue length: 0, concurrency: 1
[ 6s ] thds: 4 tps: 3.99 qps: 55.81 (r/w/o: 55.81/0.00/0.00) lat (ms,95%): 147.61 err/s: 0.00 reconn/s: 0.00
[ 6s ] queue length: 0, concurrency: 1
[ 7s ] thds: 4 tps: 11.06 qps: 162.89 (r/w/o: 162.89/0.00/0.00) lat (ms,95%): 173.58 err/s: 0.00 reconn/s: 0.00
[ 7s ] queue length: 0, concurrency: 2
[ 8s ] thds: 4 tps: 7.99 qps: 112.88 (r/w/o: 112.88/0.00/0.00) lat (ms,95%): 200.47 err/s: 0.00 reconn/s: 0.00
[ 8s ] queue length: 0, concurrency: 2
[ 9s ] thds: 4 tps: 9.01 qps: 110.09 (r/w/o: 110.09/0.00/0.00) lat (ms,95%): 71.83 err/s: 0.00 reconn/s: 0.00
[ 9s ] queue length: 0, concurrency: 0
[ 10s ] thds: 4 tps: 9.99 qps: 143.87 (r/w/o: 143.87/0.00/0.00) lat (ms,95%): 153.02 err/s: 0.00 reconn/s: 0.00
[ 10s ] queue length: 0, concurrency: 1
[ 11s ] thds: 4 tps: 12.02 qps: 177.28 (r/w/o: 177.28/0.00/0.00) lat (ms,95%): 170.48 err/s: 0.00 reconn/s: 0.00
[ 11s ] queue length: 0, concurrency: 1
[ 12s ] thds: 4 tps: 5.00 qps: 70.95 (r/w/o: 70.95/0.00/0.00) lat (ms,95%): 231.53 err/s: 0.00 reconn/s: 0.00
[ 12s ] queue length: 0, concurrency: 2
[ 13s ] thds: 4 tps: 10.00 qps: 137.01 (r/w/o: 137.01/0.00/0.00) lat (ms,95%): 223.34 err/s: 0.00 reconn/s: 0.00
[ 13s ] queue length: 0, concurrency: 1
[ 14s ] thds: 4 tps: 11.01 qps: 143.14 (r/w/o: 143.14/0.00/0.00) lat (ms,95%): 130.13 err/s: 0.00 reconn/s: 0.00
[ 14s ] queue length: 0, concurrency: 0
[ 15s ] thds: 4 tps: 5.00 qps: 100.99 (r/w/o: 100.99/0.00/0.00) lat (ms,95%): 297.92 err/s: 0.00 reconn/s: 0.00
[ 15s ] queue length: 0, concurrency: 4
[ 16s ] thds: 4 tps: 10.98 qps: 122.82 (r/w/o: 122.82/0.00/0.00) lat (ms,95%): 344.08 err/s: 0.00 reconn/s: 0.00
[ 16s ] queue length: 0, concurrency: 0
[ 17s ] thds: 4 tps: 3.00 qps: 59.01 (r/w/o: 59.01/0.00/0.00) lat (ms,95%): 287.38 err/s: 0.00 reconn/s: 0.00
[ 17s ] queue length: 0, concurrency: 2
[ 18s ] thds: 4 tps: 13.01 qps: 165.14 (r/w/o: 165.14/0.00/0.00) lat (ms,95%): 173.58 err/s: 0.00 reconn/s: 0.00
[ 18s ] queue length: 0, concurrency: 0
[ 19s ] thds: 4 tps: 6.99 qps: 98.79 (r/w/o: 98.79/0.00/0.00) lat (ms,95%): 253.35 err/s: 0.00 reconn/s: 0.00
[ 19s ] queue length: 0, concurrency: 1
[ 20s ] thds: 4 tps: 9.98 qps: 164.60 (r/w/o: 164.60/0.00/0.00) lat (ms,95%): 590.56 err/s: 0.00 reconn/s: 0.00
[ 20s ] queue length: 0, concurrency: 3
SQL statistics:
queries performed:
read: 2800
write: 0
other: 0
total: 2800
transactions: 200 (9.64 per sec.)
queries: 2800 (134.89 per sec.)
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
Throughput:
events/s (eps): 9.6352
time elapsed: 20.7573s
total number of events: 200
Latency (ms):
min: 44.36
avg: 202.66
max: 726.59
95th percentile: 590.56
sum: 40531.73
Threads fairness:
events (avg/stddev): 50.0000/0.71
execution time (avg/stddev): 10.1329/0.05
Det är en helt skrivskyddad trafik, den bör ha i genomsnitt 10 transaktioner (140 frågor) per sekund. Eftersom det bara är SELECT kan vi enkelt ändra en av de befintliga frågereglerna och blockera trafiken:
Detta kommer att resultera i följande fel på applikationssidan:
[email protected]:~# sysbench /root/sysbench/src/lua/oltp_read_only.lua --threads=4 --events=200 --time=0 --mysql-host=10.0.0.101 --mysql-user=sbtest --mysql-password=sbtest --mysql-port=6033 --tables=32 --report-interval=1 --skip-trx=on --table-size=100000 --db-ps-mode=disable --rate=10 run
sysbench 1.1.0-bbee5d5 (using bundled LuaJIT 2.1.0-beta3)
Running the test with following options:
Number of threads: 4
Target transaction rate: 10/sec
Report intermediate results every 1 second(s)
Initializing random number generator from current time
Initializing worker threads...
Threads started!
FATAL: mysql_drv_query() returned error 1148 (SELECT queries are not allowed!!!) for query 'SELECT c FROM sbtest25 WHERE id=83384'
FATAL: `thread_run' function failed: /usr/local/share/sysbench/oltp_common.lua:426: SQL error, errno = 1148, state = '42000': SELECT queries are not allowed!!!
Nu är det här uppenbarligen hårt. Vi kan vara mer artiga och bara öka fördröjningen för SELECT-frågorna.
Detta påverkar naturligtvis prestandan för frågorna när 10 millisekunder läggs till till varje SELECT som körs.
SQL statistics:
queries performed:
read: 2800
write: 0
other: 0
total: 2800
transactions: 200 (5.60 per sec.)
queries: 2800 (78.44 per sec.)
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
Throughput:
events/s (eps): 5.6030
time elapsed: 35.6952s
total number of events: 200
Latency (ms):
min: 622.04
avg: 7957.01
max: 18808.60
95th percentile: 15934.78
sum: 1591401.12
Threads fairness:
events (avg/stddev): 50.0000/36.01
execution time (avg/stddev): 397.8503/271.50
Vi ställer in fördröjningar för varje SELECT-fråga, vilket inte nödvändigtvis är meningsfullt annat än att visa att du kan göra det. Vanligtvis skulle du vilja använda fördröjningen på vissa stötande frågor. Låt oss säga att vi har en fråga som är mycket tung och den lägger till betydande belastning på databasens CPU. Vad värre är, det har introducerats av den senaste kodändringen och det kommer från alla applikationsvärdar. Visst, du kan vänta på att utvecklarna återställer ändringen eller driver en fix men med ProxySQL kan du ta kontrollen i dina egna händer och bara antingen blockera frågan eller minska dess påverkan till och med ganska avsevärt.
Låt oss anta att vår databas går bra vidare när varningsklockorna börjar ringa.
En snabb titt på statistiken visar att antalet frågor som körs av ProxySQL går ner medan CPU-användningen går upp. Vi kan titta på de vanligaste frågorna i ProxySQL för att se om vi kan märka något ovanligt.
Ovanligt är det verkligen - en ny fråga som inte är en del av regelbunden frågeblandning vi observerade på vårt system. Vi kan använda alternativet för att skapa frågeregeln.
Vi lägger till en 50 sekunders fördröjning till frågan genom att ställa in Delay till 50000 ms.
Vi kan bekräfta att frågeregeln används och att frågor träffar den .
Efter en kort stund kan vi också märka att belastningen minskar och antalet av exekverade frågor är återigen inom det förväntade intervallet. Naturligtvis, istället för att lägga till förseningen i frågan, kunde vi helt enkelt blockera den. Det skulle ha varit ännu enklare för oss att åstadkomma, men att helt blockera frågan kan få betydande inverkan på applikationen.
Vi hoppas att det här korta blogginlägget ger dig lite insikt i hur ProxySQL kan hjälpa dig att forma din trafik och minska prestandaträffen som introduceras av skenande frågor.