データベースに送られるトラフィックを形成する機能は、最も重要な機能の1つです。過去数日間、あなたはそれをそれほど制御できませんでした-アプリケーションはトラフィックをデータベースに送信しました、そしてそれはそれについてです。一般的に使用されていたHAProxyには、トラフィックをきめ細かく制御するオプションもありません。 ProxySQLのようなSQL対応プロキシの導入により、データベース管理者はより多くの可能性を利用できるようになりました。 ProxySQLでの接続処理とスロットルの可能性を見てみましょう。
ProxySQLでの接続処理
ご存知かもしれませんが、ProxySQLが機能する方法は、クエリルールを使用することです。これは、すべてのクエリがテストされ、ProxySQLがクエリを処理する方法を正確に管理するルールのリストです。最初から、アプリケーションはProxySQLに接続します。 ProxySQLに対して認証され(これがProxySQLがすべてのユーザーとパスワードハッシュを保存する必要がある理由です)、ProxySQLはクエリルールを実行して、クエリの送信先を決定します。
ProxySQLは、バックエンドサーバーへの接続のプールを開きます。これは1対1のマッピングではなく、デフォルトでは、1つのバックエンド接続をできるだけ多くのフロントエンド接続に再利用しようとします。これは接続多重化と呼ばれます。詳細は、処理する必要のある正確なトラフィックによって異なります。開いているすべてのトランザクションは、同じ接続内で処理する必要があります。ある種のローカル変数が定義されている場合、この接続は再利用できません。複数のフロントエンド接続で単一のバックエンド接続を再利用できるため、バックエンドデータベースの負担が大幅に軽減されます。
前述のように、ProxySQLへの接続が確立されると、クエリルールに従って処理されます。ここで、トラフィックシェーピングが発生する可能性があります。オプションを見てみましょう
ProxySQLでの接続スロットリング
まず、すべてのSELECTを削除しましょう。 「アプリケーション」であるSysbenchを次のように実行しています。
[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
これは完全に読み取り専用のトラフィックであり、平均して1秒あたり10トランザクション(140クエリ)になるはずです。これらはSELECTのみであるため、既存のクエリルールの1つを簡単に変更して、トラフィックをブロックできます。
これにより、アプリケーション側で次のエラーが発生します:
[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!!!
今、これは明らかに厳しいです。より丁寧になり、SELECTクエリの遅延を増やすことができます。
これは、10ミリ秒が追加されるため、明らかにクエリのパフォーマンスに影響します。実行されるすべてのSELECTに。
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
すべてのSELECTクエリに遅延を設定しましたが、これは、実行できることを示す以外に必ずしも意味がありません。通常、問題のあるクエリで遅延を使用します。非常に重いクエリがあり、データベースのCPUにかなりの負荷がかかるとします。さらに悪いことに、最近のコード変更によって導入され、すべてのアプリケーションホストから提供されています。もちろん、開発者が変更を元に戻すか修正をプッシュするのを待つことはできますが、ProxySQLを使用すると、自分で制御を取得して、クエリをブロックするか、その影響を大幅に減らすことができます。
メトリックをざっと見ると、によって実行されたクエリの数がわかりますCPU使用率が上がる間、ProxySQLは下がります。 ProxySQLの上位クエリを調べて、何か異常なことに気付くことができるかどうかを確認できます。
珍しいことですが、実際には、その一部ではない新しいクエリです。システムで観察された通常のクエリミックス。このオプションを使用して、クエリルールを作成できます。
Delayを50000に設定して、クエリに50秒の遅延を追加しますミリ秒。
クエリルールが使用中であり、クエリがそれにヒットしていることを確認できます。
しばらくすると、負荷が低下し、数が減少することがわかります。実行されたクエリの数は、再び期待される範囲内にあります。もちろん、クエリに遅延を追加する代わりに、単にブロックすることもできます。それは私たちにとってさらに簡単だったでしょうが、クエリを完全にブロックすると、アプリケーションに大きな影響を与える可能性があります。
この短いブログ投稿が、ProxySQLがトラフィックを形成し、暴走クエリによってもたらされるパフォーマンスへの影響を減らすのにどのように役立つかについての洞察を提供することを願っています。