More than 1 year has passed since last update.


ロードバランサとは

ロードバランサは、複数のバックエンドサーバがあるときに、リクエストを分散させるための仕組み。

image.png


DNSラウンドロビン

似たような負荷分散の仕組みとしてDNSラウンドロビンがある。

これはバックエンドサーバのIPアドレスをDNSレコードとして登録し、DNSの問い合わせ時にバックエンドサーバのIPアドレスを順番に返事することで負荷分散する。


DNSラウンドロビンでは対応できないこと


  • DNSの問い合わせ結果はクライアント側でキャッシュされるため


    • 負荷が偏る可能性がある

    • サーバダウンした時に、即座に切り替えられないクライアントがいる



  • パーシステンス機能がない(クライアントごとに同一のサーバに割り振れない)

上記に対応したいときに、ロードバランサが使われる。


L7ロードバランサ


  • L7レベルでロードバランシングする


    • クライアントから見たときの接続先IPアドレスはLBのIPアドレスになる

    • バックエンドサーバから見たときの接続元IPアドレスはLBのIPアドレスになる



  • HTTPの情報を用いた、高度な制御ができる


    • Cookieを利用したスティッキーセッション

    • X-Forwarded-Forヘッダー を利用したクライアントのIPアドレス保持



  • HTTP情報を取得するために、LBでTCPコネクションが終端する


    • クライアントとLB

    • LBとバックエンドサーバ




パケットの流れ

image.png


L4ロードバランサ


  • L4以下のレベルでロードバランシングする

  • IPレベルでのセッションパーシステンスができる


    • 接続元IPが同じなら同じバックエンドサーバに送れる



  • IPアドレス変換方式(NAT方式) と MACアドレス変換方式(DSR方式) がある

  • ロードバランサでTCPコネクションは終端しない


IPアドレス変換方式(NAT方式)


  • NATを利用してL4レベルでロードバランシングする


    • クライアントから見たときの接続先IPアドレスはLBのIPアドレスになる

    • バックエンドサーバから見たときの接続元IPアドレスはLBのIPアドレスになる



  • NAT変換のために全ての通信がLBを経由する


パケットの流れ

image.png


MACアドレス変換方式(DSR方式)


  • 宛先MACアドレスを差し替えてロードバランシングする


    • ロードバランサとバックエンドサーバは同一セグメントに置く必要がある

    • クライアントから見たときの接続先IPアドレスはLBのIPアドレスになる

    • バックエンドサーバから見たときの接続元IPアドレスはクライアントのIPアドレスになる



  • バックエンドサーバの戻りパケットが、ロードバランサを経由せずにクライアントと直接通信する

  • レスポンスの接続元IPアドレスをロードバランサに見せかける必要がある


    • ロードバランサのIPアドレスをバックエンドサーバのループバックIPアドレスに設定する

    • ループバックIPアドレスはARPに答えないように設定する




パケットの流れ

image.png


構築してみる


L7ロードバランサ

構成図は以下のとおり。

image.png

今回はLBとして、nginx を利用する。


設定

リファレンスを参考に、nginxの設定をする。


http {
...
upstream myapp1 {
server 10.133.1.2;
server 10.133.1.3;
}
...
server {
...
location / {
proxy_pass http://myapp1;
}
}
...
}


パケットキャプチャ

次に、バックエンドサーバでhttpdを起動し、クライアントからHTTPリクエストを投げる。

LBのeth0(クライアント側NIC)のパケットをキャプチャする。

# tcpdump port 80 -i eth0 -w eth0.pcap

image.png

LBのeth1(バックエンド側NIC)のパケットをキャプチャする。

# tcpdump port 80 -i eth1 -w eth1.pcap

image.png

上記から各ethごとにTCPハンドシェイクを行っており、TCPコネクションが2本張られていることがわかる。また、クライアントからLBにHTTPリクエストが送られた後に、LBからバックエンドサーバにTCPコネクションを張っているのがわかる。


接続元IPアドレスをバックエンドサーバに伝える

クライアントの接続元IPアドレスをバックエンドサーバが知りたい場合は、X-Forwarded-Forヘッダーをnginx側で付与すればよい。リファレンス

すると以下のように、HTTPヘッダーに接続元IPアドレスが付与される。



# tcpdump -A port 80 -i eth1
...
.*.{.).
GET / HTTP/1.0
X-Forwarded-for: 192.168.11.104
Host: myapp1
Connection: close
Cache-Control: max-age=0
...


IPアドレス変換方式(NAT方式)

構成図は以下のとおり。

image.png

以下を参考に、LBとしてipvsadm を利用する。

http://dsas.blog.klab.org/archives/50664843.html


設定

LBでipvsadmの設定をする。

# ipvsadm -C

# ipvsadm -A -t 192.168.11.107:80 -s lc
# ipvsadm -a -t 192.168.11.107:80 -r 10.133.1.2 -m
# ipvsadm -a -t 192.168.11.107:80 -r 10.133.1.3 -m
# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.11.107:80 lc
-> 10.133.1.2:80 Masq 1 0 0
-> 10.133.1.3:80 Masq 1 0 0

次に、バックエンドサーバでhttpdを起動し、クライアントからHTTPリクエストを投げる。


パケットキャプチャ

LBのeth0(クライアント側NIC)のパケットをキャプチャする。

# tcpdump port 80 -i eth0 -w eth0.pcap

image.png

LBのeth1(バックエンド側NIC)のパケットをキャプチャする。

# tcpdump port 80 -i eth1 -w eth1.pcap

image.png

上記から、LBで接続元IPや接続先IPの変換はするものの、TCPコネクションが1本しか張られていないことがわかる。(接続元のエフェメラルポート番号がそのまま接続先に渡されており、また、時刻から、LBはパケットを横流ししているようになっている)


MACアドレス変換方式(DSR方式)

構成図は以下のとおり。

image.png

以下を参考に、LBとしてipvsadm を利用する。

http://momijiame.tumblr.com/post/71390424576/centos-65-%E3%81%A7-lvs-ipvs-%E3%81%AE-direct-server-return


設定

LBでipvsadmの設定をする。

]# iptables -L

]# ipvsadm -A -t 192.168.11.107:80 -s lc
]# ipvsadm -a -t 192.168.11.107:80 -r 192.168.11.108:80 -g
]# ipvsadm -L
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.11.107:http lc
-> 192.168.11.108:http Route 1 0 0

次に、バックエンドサーバでhttpdを起動し、クライアントからHTTPリクエストを投げる。


パケットキャプチャ

LBのパケットをキャプチャする。

# tcpdump port not 22 -w lb.pcap

戻りパケットがLBを経由しないため、Wiresharkがパケットが欠けてると警告を出している。

image.png

バックエンドサーバのパケットをキャプチャする。

# tcpdump port 80 -w backend.pcap

接続先IPアドレスがLBのIPアドレスになっている。また、接続元IPアドレスがクライアントのアドレスになっている。

image.png

上記から、戻りパケットだけはLBを経由せずにクライアントにダイレクトに返っていることがわかる。まさにDirect Server Return…


参考