先日、nginxのHTTPでのロードバランシングを試しました。
nginxのHTTPロードバランシングを試す - CLOVER
次は、もっと汎用的にTCPでのロードバランシングをしてみたいと思います。なお、今回はTCPのみで扱いますが、UDPでのロードバランシングも可能なようです。
ドキュメント
主要に利用するモジュール的には、
Module ngx_stream_core_module
と
Module ngx_stream_upstream_module
の2つとなります。
また、こちらのドキュメントも参考にしました。
NGINX Docs | NGINX Load Balancing – TCP and UDP Load Balancer
MySQLへの接続をロードバランシングしてみよう
今回のTCP接続の対象として、MySQLサーバーを持ち出してみます。
MySQLサーバーが、次のように3台起動しているものとします。
- server1 (172.17.0.2)
- server2 (172.17.0.3)
- server3 (172.17.0.4)
別にMySQLのレプリケーションなどがしたいわけではないので、単純にそれぞれ別個で構築します。
で、別々のサーバーにアクセスしていることがわかるように、以下のようにテーブルを作成してデータを登録します。
-- server1 mysql> CREATE TABLE server(name VARCHAR(10), PRIMARY KEY(name)); mysql> INSERT INTO server VALUES('server1'); -- server2 mysql> CREATE TABLE server(name VARCHAR(10), PRIMARY KEY(name)); mysql> INSERT INTO server VALUES('server2'); -- server3 mysql> CREATE TABLE server(name VARCHAR(10), PRIMARY KEY(name)); mysql> INSERT INTO server VALUES('server3');
MySQL側の準備は、これでおしまい。
nginxにTCPロードバランシングの設定をする
では、用意したMySQLに対してロードバランシングするnginxの設定を書いてみます。
HTTPサーバーとして使う時は、httpディレクティブの配下に設定を書いていきますが、今回はstreamディレクティブを使用します。
このnginxは、ローカルで起動しているものとし、MySQLのロードバランシングには3306ポートを使用します。
/etc/nginx/stream-balancer.conf
stream { upstream backends { server 172.17.0.2:3306; server 172.17.0.3:3306; server 172.17.0.4:3306; } server { listen 3306; proxy_pass backends; } }
upstreamディレクティブで名前を付けつつ、serverでバックエンドを設定します。また、そのあとにserverディレクティブのproxy_passでupstreamで決めた名前(ここではbackends)を指定します。
listenは、このバランサのリッスンポートですね。
ちなみにUDPで使う場合は、以下のようにlistenのあとに「udp」って書くみたいです。
listen 53 udp;
今回の稼働環境は、Debian packageインストールしたnginxとなっています。ここは、「/etc/nginx/nginx.conf」にincludeを追加しましょう。
/etc/nginx/nginx.conf
include /etc/nginx/stream-balancer.conf;
これでnginxを再起動します。
確認
それでは、確認してみましょう。
確認用のプログラムは、以下のものを用意。
current-server.groovy
@Grab('mysql:mysql-connector-java:6.0.5') @GrabConfig(systemClassLoader = true) import groovy.sql.Sql Sql.withInstance('jdbc:mysql://localhost:3306/practice?useUnicode=true&characterEncoding=utf-8&characterSetResults=utf-8&useServerPrepStmts=true&useLocalSessionState=true&elideSetAutoCommits=true&alwaysSendSetIsolation=false&useSSL=false', 'kazuhira', 'password') { sql -> sql.eachRow('SELECT name FROM server') { row -> println(row.name) } }
実行。
$ groovy current-server.groovy server1 $ groovy current-server.groovy server2 $ groovy current-server.groovy server3 $ groovy current-server.groovy server1 $ groovy current-server.groovy server2 $ groovy current-server.groovy server3
デフォルトの振り分けアルゴリズムはラウンドロビンなので、アクセスごとに次のサーバーに順次振り分けられます。Least Connection、Hashなどの設定も可能です。
あと、ヘルスチェックなども気になるところですが、こちらは商用機能です(HTTPロードバランシングの時も同じ)。
health_check
アクセスログを出力しよう
ところで、この設定だとロードバランシングはできていますが、ログが残りません。
気になるところなので、設定してみましょう。
設定自体は、こちらを参照。
Module ngx_stream_log_module
stream/upstreamのログフォーマットで使える埋め込み変数は、以下のドキュメントの「Embedded Variables」を参照。
Module ngx_stream_upstream_module
今回は、サンプルに加え接続先を出力する$upstream_addrを使用してみました。
stream { log_format stream-basic '$remote_addr [$time_local] ' '$protocol $status $bytes_sent $bytes_received ' 'upstream->$upstream_addr $session_time'; access_log /var/log/nginx/stream-access.log stream-basic; upstream backends { server 172.17.0.2:3306; server 172.17.0.3:3306; server 172.17.0.4:3306; } server { listen 3306; proxy_pass backends; } }
再起動後、確認してみます。この設定だと、「/var/log/nginx/stream-access.log」にアクセスログが出力されます。
172.17.0.1 [06/Nov/2016:10:17:30 +0000] TCP 200 1295 1169 upstream->172.17.0.2:3306 0.239 172.17.0.1 [06/Nov/2016:10:17:32 +0000] TCP 200 1295 1169 upstream->172.17.0.3:3306 0.195 172.17.0.1 [06/Nov/2016:10:17:35 +0000] TCP 200 1295 1169 upstream->172.17.0.4:3306 0.228 172.17.0.1 [06/Nov/2016:10:17:44 +0000] TCP 200 1295 1169 upstream->172.17.0.2:3306 0.168 172.17.0.1 [06/Nov/2016:10:17:47 +0000] TCP 200 1295 1169 upstream->172.17.0.3:3306 0.188 172.17.0.1 [06/Nov/2016:10:17:49 +0000] TCP 200 1295 1169 upstream->172.17.0.4:3306 0.174
こんなところですかねー。