LVS + Keepalivedを利用したリアルサーバのヘルスチェック

· 5 min read
LVS + Keepalivedを利用したリアルサーバのヘルスチェック

前回、LVSを利用したwebサーバのロードバランシングをご紹介しましたが
もし仮に、バックエンドのwebサーバの一つがDOWNしていたとしましょう。

 

生きているwebサーバにバランシングされれば正常にアクセス可能ですが。

DOWNしているサーバに振り分けられてしまうと、この様に閲覧不可に。

この様な事態を防ぐための機能として、Keepalivedがあります。
Keepalivedは転送先サービスの死活監視をすると
そのような状態を回避して、サービスの冗長化をすることができます。

 


構成環境

keepalivedを導入する環境は前回同様、以下の構成となります。

1.LVSの設定をクリア
LVS の設定は Keepalived で制御されるので、まずはipvsadmの設定をクリアします。
これを忘れると設定が競合して、うまくバランシングされないので注意

# ipvsadm -C 
# /etc/rc.d/init.d/ipvsadm save 
ipvsadm: Saving IPVS table to /etc/sysconfig/ipvsadm: [ OK ]

2.keepalivedをインストールする

いつも通りyumでインストールします。

# yum install keepalived

3.Keepalivedの設定を行う
keepalivedの設定ファイルを作ります。
分散方式はラウンドロビン、パケット転送はNATと前回と同様にしていきます。

virtual_server 192.168.1.6 80 { # lvsサーバのeth0のIPを指定します。
  delay_loop 60 # ヘルスチェックの間隔 [秒]
  lvs_sched rr # ロードバランスの方法 (以前はlb_algoでした。分散方式はround robinを使う)
  lvs_method NAT # パケット転送の方法 (以前はlb_kindでした。パケット転送の方法はNAT)
  protocol TCP
# Web 1
  real_server 10.0.0.2 80 {
      weight 1
      inhibit_on_failure # ヘルスチェック失敗時はweightを0にしてバランシングしない。
            HTTP_GET {
            url {
                path /drupal/ # ヘルスチェック用のページ
                status_code 200 #ステータスコード
            }
            connect_timeout 3 # 応答が返ってくるまでのタイムアウト [秒]
         }
     }
# Web 2
  real_server 10.0.0.3 80 {
      weight 1
      inhibit_on_failure
            HTTP_GET {
            url {
                path /drupal/
                status_code 200
            }
            connect_timeout 3
         }
     }
 }

■ 解説

url {
  path /drupal/ # ヘルスチェック用のページ
  status_code 200 #ステータスコード
}

期待するHTTPのレスポンスコードはstatus_codeで指定します。
今回の場合、リアルサーバがhttp://192.168.1.6/drupal/のリクエストに対して
200以外のレスポンスコードを返した場合は、ヘルスチェック失敗となります。

connect_timeout 3 # 応答が返ってくるまでのタイムアウト [秒]

ヘルスチェックのHTTPアクセスのタイムアウトをconnect_timeoutで指定します。
HTTPアクセスを始めてからレスポンスを受け取りきるまで
connect_timeout秒で完了しない場合はヘルスチェック失敗となります。

気をつけて欲しいのは、connect_timeoutのデフォルトはゼロなので
明示的にconnect_timeoutを指定しなかった場合ゼロ秒で
リアルサーバ(バックエンドのサーバ)はレスポンスを返さないといけなくなってしまいます。
ですのでconnect_timeoutは必ず指定しましょう。

inhibit_on_failure  # ヘルスチェック失敗時はweightを0にしてバランシングしない。

inhibit_on_failureを指定しているので
グループから外すときは設定を削除するのではなくweightをゼロにします。
この方がipvsadm -Lnで見たときにどのリアルサーバが外されているか分かりやすいと思います。

  sorry_server 192.168.1.6 80

sorry_serverは全てのリアルサーバがダウンした場合に、パケットが転送されるサーバです。
今回は設定していませんが、実運用ではほかのロードバランサではないサーバを指定した方がよいでしょう。

また、ひとつのreal_serverとsorry_sreverという構成にすれば、
アクティブ/バックアップ構成を作ることができます。

今回の設定内容は最低限の設定だけですが、keepalivedの設定は非常に多岐にわたり
複雑な挙動も設定できるのですが、ここでは記載しきれないので端折ります。
※参考
http://keepalived.cvs.sourceforge.net/keepalived/devel/doc/keepalived.conf.SYNOPSIS?revision=HEAD&view=markup

4.keepalivedを起動する

# /etc/rc.d/init.d/keepalived start
Starting keepalived: [ OK ]

# chkconfig keepalived on

5.挙動確認

[root@lvs ~]# ipvsadm
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.1.6:http rr
  -> 10.0.0.2:http                Masq    1      0          0         
  -> 10.0.0.3:http                Masq    1      0          0   

weight が 1になっていれば正常になっています。
試しにweb1のapacheを停止してみます。

[root@web01 ~]# service httpd stop
httpd を停止中:                                            [  OK  ]

すると、10.0.0.2のweightが0になったことを確認できました。

[root@lvs ~]# ipvsadm
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.1.6:http rr
  -> 10.0.0.2:http                Masq    0      0          0         
  -> 10.0.0.3:http                Masq    1      0          0  

この状態でlvsのipにアクセスしても、応答のないweb1にはバランシングされません。
これがkeepalivedを使用したバランシングしているサーバのヘルスチェック機能になります。


おまけ。

10.0.0.1 - - [12/Feb/2017:12:39:08 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:11 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:14 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:17 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:20 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:23 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:26 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:29 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:32 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:35 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:38 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:41 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:44 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:47 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:50 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:53 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:56 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:39:59 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:40:02 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:40:05 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:40:08 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:40:11 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:40:14 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:40:17 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"
10.0.0.1 - - [12/Feb/2017:12:40:20 +0900] "GET / HTTP/1.0" 403 4961 "-" "KeepAliveClient"

最初keepalivedのヘルスチェック間隔を3秒にしていたのでログがクソでました。
lvsのipアドレスは除外するか、チェック間隔を伸ばしたほうが良いかもしれません。