LVS負荷分散構成の実践ガイド

1. LVSの概要

LVS(Linux Virtual Server)は、**Linuxカーネルレベルの四層(TCP/UDP)負荷分散ソリューション**であり、章文嵩博士が1998年に開発し、現在はLinuxカーネルに統合されている。この技術はIP層のディスパッチを通じて、高並列処理と高可用性を持つサーバクラスタを構築する。

1.1 コアアーキテクチャと用語

  • ディレクター(Director):クラスタの入口であり、外部から提供されるVIP(仮想IP)を担当し、リクエストの分配を行う。
  • リアルサーバ(RS):バックエンドでリクエストを処理する実際のサーバで、RIP通信を使用する。
  • DIP:ディレクターとバックエンドとの通信に使用される内部ネットワークIP。
  • ツール:カーネルモジュールはipvs、ユーザー空間管理ツールはipvsadmである。

1.2 三つの主要な動作モード

モード コアアクション 応答パス パフォーマンス 適用シナリオ
DR(直接ルーティング) MACアドレスの書き換え RSがクライアントに直接応答 最高 同じネットワークセグメント、高スループット(推奨)
TUN(IPトンネリング) 新しいIPヘッダのカプセル化 RSがクライアントに直接応答 異なるネットワークセグメント、分散配置されたRS
NAT 宛先/送信元IPの書き換え ディレクターを経由してクライアントに戻る 小規模、統一ゲートウェイ(簡易)

暗記法:DRはMAC変更、TUNはトンネルカプセル化、NATはIP変更;直接応答は高性能、ディレクター経由は互換性が高い。

1.3 一般的なスケジューリングアルゴリズム

  • RR(ラウンドロビン):順序的に割り当て、シンプルで公平。
  • WRR(加重ラウンドロビン):重みに基づいて割り当て、性能差に対応。
  • LC(最少接続):現在の接続数が最も少ないRSを選択。
  • WLC(加重最少接続):重みと接続数を組み合わせ、デフォルト推奨。
  • SH(ソースアドレスハッシュ):同一クライアントを常に同一RSに割り当て、セッション保持を保証。

1.4 主な利点と定位

  • パフォーマンス強化:カーネルモードで処理され、ユーザーモード切り替えのオーバーヘッドなし、数万の同時接続をサポート。
  • 高可用性:**Keepalived**と連携することで、主備切り替えを実現し、単一障害点を回避。
  • コスト削減:オープンソースで無料、高価なハードウェア負荷分散器の代替が可能。

Nginx/HAProxyとの比較:LVSは**四層**であり、純粋なトラフィック分散や高並列処理に適している。一方、Nginx/HAProxyは**七層**(URLルーティング、SSL終端)に優れており、一般的な構成では**LVS+Keepalived(四層)を前方に、Nginx(七層)を後方に配置**する。

2. LVS実践例

1. NATモード(ネットワークアドレス変換)

LVS(Linux Virtual Server)のNATモードは、負荷分散の古典的な実装方法であり、その中心原理は**負荷分散器(VS)がリクエストパケットをネットワークアドレス変換し、後端のリアルサーバ(RS)に転送し、RSの応答を逆変換してクライアントに戻す**ことである。

1.1 NATモードの実践

ノード ネットワークインターフェース/IP設定 役割
VS(vsnode) eth0: 172.25.254.100(パブリック/外部ネットワーク)eth1: 192.168.0.100(プライベート/RSネットワーク) 負荷分散器(LVSノード)
RS1 eth0: 192.168.0.10ゲートウェイ:192.168.0.100 バックエンドリアルサーバ1
RS2 eth0: 192.168.0.20ゲートウェイ:192.168.0.100 バックエンドリアルサーバ2

:RSのデフォルトゲートウェイはVSの内網IP(192.168.0.100)に設定する必要があり、さもないと応答パケットがVSに戻らなくなり、クライアントは結果を受け取れなくなる。

1. フェーズ1:基本ネットワーク環境設定(VSとRS間の通信を確立)
  1. VSノードのネットワーク設定
# eth0(外部ネットワーク)とeth1(内網ネットワーク)を設定し、norouteでルーティングを一時的に設定しない(後でカーネルの転送に任せる)
[root@vsnode ~]# vmset.sh eth0 172.25.254.100 vsnode
[root@vsnode ~]# vmset.sh eth1 192.168.0.100 vsnode noroute

効果:VSに二つのNICを設定し、それぞれ外部クライアントと内部RSクラスタに対応し、クロスネットワーク転送の基盤を構築。

  1. RS1/RS2のネットワーク設定(RS2はIPのみ異なる、論理的には同一)

RS1

# RS1のネットワーク設定
[root@RS1 ~]# vmset.sh eth0 192.168.0.10 RS1 noroute
# ゲートウェイをVSの内網IPに手動設定(必須!)
[root@RS1 ~]# nmcli connection modify eth0 ipv4.gateway 192.168.0.100
[root@RS1 ~]# nmcli connection reload
[root@RS1 ~]# nmcli connection up eth0

# ネットワーク確認:route -nでデフォルトゲートウェイが192.168.0.100であることを確認し、RSの応答がVSに戻ることを保証
[root@RS1 ~]# route  -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.0.100   0.0.0.0         UG    100    0        0 eth0
192.168.0.0     0.0.0.0         255.255.255.0   U     100    0        0 eth0

RS2

# ネットワーク設定
[root@RS2 ~]# vmset.sh eth0 192.168.0.20 RS1 noroute
# ゲートウェイをVSの内網IPに手動設定(必須!)
[root@RS2 ~]# nmcli connection modify eth0 ipv4.gateway 192.168.0.100
[root@RS2 ~]# nmcli connection reload
[root@RS2 ~]# nmcli connection up eth0
[root@RS2 ~]# route  -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.0.100   0.0.0.0         UG    100    0        0 eth0
192.168.0.0     0.0.0.0         255.255.255.0   U     100    0        0 eth0
  1. RSの業務展開(HTTPサービス)

httpdのインストールと起動し、差別化されたページ(RS1/RS2を区別)を作成

# RS1
[root@RS1 ~]# dnf install httpd -y
[root@RS1 ~]# systemctl enable --now httpd
[root@RS1 ~]# echo RS1 - 192.168.0.10 > /var/www/html/index.html

# RS2
[root@RS2 ~]# dnf install httpd -y
[root@RS2 ~]# systemctl enable --now httpd
[root@RS2 ~]# echo RS2 - 192.168.0.20 > /var/www/html/index.html
  1. VSでのテスト接続性

curl 192.168.0.10/curl 192.168.0.20で対応するページが返却されれば、VSとRSの内網通信は正常。

[root@vsnode ~]# curl  192.168.0.10
RS1 - 192.168.0.10
[root@vsnode ~]# curl  192.168.0.20
RS2 - 192.168.0.20
2. フェーズ2:LVS NATモードのコア設定(VSノード)
  1. カーネルIP転送の有効化(NATモード前提)

LVS NATはカーネルのパケット転送に依存し、有効化が必要:

[root@vsnode ~]# echo net.ipv4.ip_forward=1 >> /etc/sysctl.conf
[root@vsnode ~]# sysctl  -p
net.ipv4.ip_forward = 1     # 設定が有効になり、net.ipv4.ip_forward = 1が出力される

原理:IP転送が無効の場合、VSはRSからの応答パケットをクライアントに転送できず、NATプロセスが中断する。

  1. ipvsadm規則の設定(負荷分散コア)

ipvsadmはLVSの管理ツールで、コアパラメータの解説:

  • -C:古いルールをクリア;
  • -A -t 172.25.254.100:80 -s wrr:仮想サービス(VIP:172.25.254.100、ポート80)を作成し、スケジューリングアルゴリズムはwrr(加重ラウンドロビン);
  • -a -t VIP:ポート -r RS_IP:ポート -m -w 重み:リアルサーバを追加し、-mはNATモード(マスカレード)、-wは重み;
[root@vsnode ~]# ipvsadm -C  # ルールをクリア
# 仮想サービスの作成(VIP+ポート+スケジューリングアルゴリズム)
[root@vsnode ~]# ipvsadm -A -t 172.25.254.100:80 -s wrr
# RS1の追加、重み1、NATモード
[root@vsnode ~]# ipvsadm -a -t 172.25.254.100:80 -r 192.168.0.10:80 -m  -w 1
# RS2の追加、重み1、NATモード
[root@vsnode ~]# ipvsadm -a -t 172.25.254.100:80 -r 192.168.0.20:80 -m  -w 1

ルールの確認:ipvsadm -LnでRSリストと設定が見られ、ルールが有効であることが確認できる。

[root@vsnode ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.25.254.100:80 wrr
  -> 192.168.0.10:80              Masq    1      0          0
  -> 192.168.0.20:80              Masq    1      0          0
3. フェーズ3:負荷分散効果のテスト
  1. 基本テスト(重み1:1)
[root@vsnode ~]# for i in {1..10};do curl 172.25.254.100;done
RS2 - 192.168.0.20
RS1 - 192.168.0.10
RS2 - 192.168.0.20
RS1 - 192.168.0.10
RS2 - 192.168.0.20
RS1 - 192.168.0.10
RS2 - 192.168.0.20
RS1 - 192.168.0.10
RS2 - 192.168.0.20
RS1 - 192.168.0.10

出力はRS1 - 192.168.0.10RS2 - 192.168.0.20が交互に表示され、wrr(重み1:1)のラウンドロビンロジックに従っている。

  1. 重み調整テスト(重み2:1)

RS1の重みを2に変更:

# 重み変更
[root@vsnode ~]# ipvsadm -e -t 172.25.254.100:80 -r 192.168.0.10:80 -m  -w 2
[root@vsnode ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.25.254.100:80 wrr
  -> 192.168.0.10:80              Masq    2      0          5
  -> 192.168.0.20:80              Masq    1      0          5

再度テスト:

[root@vsnode ~]# for i in {1..10};do curl 172.25.254.100;done
RS2 - 192.168.0.20
RS1 - 192.168.0.10
RS1 - 192.168.0.10
RS2 - 192.168.0.20
RS1 - 192.168.0.10
RS1 - 192.168.0.10
RS2 - 192.168.0.20
RS1 - 192.168.0.10
RS1 - 192.168.0.10
RS2 - 192.168.0.20

出力ではRS1の出現回数がRS2の約2倍(RS2、RS1、RS1、RS2…)となり、wrr加重スケジューリングの効果が検証された。

4. フェーズ4:LVSルールの永続化(再起動時に失われないように)

実験中に別のシェルを開き、監視コマンドを実行して観察する。

  1. カスタムファイルによる永続化
# カスタムファイルで永続化
[root@vsnode ~]# ipvsadm-save -n
-A -t 172.25.254.100:80 -s wrr
-a -t 172.25.254.100:80 -r 192.168.0.10:80 -m -w 2
-a -t 172.25.254.100:80 -r 192.168.0.20:80 -m -w 1
[root@vsnode ~]# ipvsadm-save -n > /mnt/ipvs.rule    # ルールをファイルにエクスポート
[root@vsnode ~]# ipvsadm -C                          # ルールをクリア(再起動を模倣)
[root@vsnode ~]# ipvsadm-restore < /mnt/ipvs.rule    # ルールを復元
  1. システムサービスによる永続化(推奨)
# デーモンサービスでルールを永続化
[root@vsnode ~]# ipvsadm-save -n > /etc/sysconfig/ipvsadm   # デフォルト設定ファイルにエクスポート
[root@vsnode ~]# ipvsadm -C
[root@vsnode ~]# systemctl enable --now ipvsadm.service     # サービスを起動し、自動的にルールをロード
Created symlink /etc/systemd/system/multi-user.target.wants/ipvsadm.service → /usr/lib/systemd/system/ipvsadm.service.

1.2 NATモードのコア原理(パケットフロー)

  1. クライアントリクエスト:クライアントが172.25.254.100:80(VSのVIP)にアクセスし、パケットの宛先IP=VIP、宛先ポート=80;
  2. VS転送:VSはipvsadmルールにより、パケットの宛先IPを特定のRSのIP(例:192.168.0.10)に変更し、宛先ポートは変更せず、送信元IPはクライアントIPのまま、その後RSに転送;
  3. RS応答:RSはパケットを受け取り、リクエストを処理し応答を生成し、ゲートウェイがVSであるため、応答パケットの宛先IP=VSの内網IP(192.168.0.100)、送信元IP=RS自身のIP;
  4. VS応答パケット:VSはRSの応答を受け取り、パケットの送信元IPをVIP(172.25.254.100)に変更し、宛先IPをクライアントIPに戻し、クライアントに転送;
  5. クライアント受信:クライアントは応答を受け取り、VIPからの応答であることを認識し、バックエンドRSの存在を知らずに利用。

1.3 NATモードの特徴まとめ

利点 欠点
設定が簡単、RSに特別な設定不要 VSが単一障害点(すべてのパケットがVSを通過)
RSは任意のOSを使用可能 TCP/UDPのみサポート、複雑なプロトコルには非対応
重みで柔軟なスケジューリング可能 転送効率はDR/TUNモードより低い

1.4 注意事項

  1. RSのデフォルトゲートウェイはVSの内網IPに設定すること、さもないと応答パケットが戻らない;
  2. VSはip_forwardを有効にする必要があり、さもないとパケットを転送できない;
  3. NATモードでは、VSのVIPは外部に公開(クライアントがアクセス可能)し、RSはVSの内網とのみ通信すればよく、パブリックIPは不要;
  4. スケジューリングアルゴリズムwrr(加重ラウンドロビン)はRSの性能に応じて重みを調整し、高性能なRSには高い重みを設定。

この実験により、LVS NATモードの「ネットワークの確立」→「ルール設定」→「負荷テスト」→「ルール永続化」の全プロセスを完全に検証し、コアは「アドレス変換」と「パケット転送」のロジック、およびRSのゲートウェイがVSを指すという重要な要件を理解した。

2. DRモード

LVS(Linux Virtual Server)のDR(Direct Routing、直接ルーティング)モードは、LVSの三つのコアモード(NAT/DR/TUN)の一つであり、その主な特徴はリクエストはディレクターを経由し、応答はリアルサーバ(RS)から直接クライアントに戻ることで、ディレクターがボトルネックになるのを回避し、高性能な負荷分散に使用される。

2.1 DRモードの実践

役割 ネットワークインターフェース/IP設定 主な役割
ルーター(router) eth0:172.25.254.100 eth1:192.168.0.100 クロスネットワーク転送(172.25.254.0/24 ↔ 192.168.0.0/24)、IP転送とSNATの有効化
ディレクター(vsnode) eth0:192.168.0.50 lo:192.168.0.200(VIP) LVSディレクター、VIP(仮想IP)を保持し、リクエストをRSに分配
クライアント(client) eth0:172.25.254.99 リクエストを発信する端末、VIP(192.168.0.200)にアクセス
リアルサーバ(RS1) eth0:192.168.0.10 lo:192.168.0.200(VIP) 実際の業務を処理し、VIPを保持(loループのみ)
リアルサーバ(RS2) eth0:192.168.0.20 lo:192.168.0.200(VIP) RS1と同様、負荷分散の冗長性を実現

コアネットワークロジック

  • クライアントは172.25.254.0/24ネットワークセグメントにあり、ルーターのeth0口のみ直接アクセス可能;
  • ルーターはeth1口で192.168.0.0/24ネットワークセグメント(VS、RS1、RS2)に接続し、クロスネットワーク転送を実現;
  • VIP(192.168.0.200)はクライアントのアクセス先であり、VSのlo口とすべてのRSのlo口に設定(コア設計)。
1. ルーター設定:クロスネットワーク転送+SNAT
# ipvsadmサービスを無効化(LVSと競合を避ける)
[root@router ~]# systemctl disable --now ipvsadm.service
Removed "/etc/systemd/system/multi-user.target.wants/ipvsadm.service".
[root@router ~]# ipvsadm -C    # ipvsadmルールをクリア

# 二つのNICのIPを設定:eth0(172.25.254.100)、eth1(192.168.0.100)
[root@router ~]# vmset.sh eth0 172.25.254.100 vsnode
[root@router ~]# vmset.sh eth1 192.168.0.100 vsnode noroute

# カーネル転送を有効化(コア:クロスネットワークデータパケット転送)
[root@router ~]# echo net.ipv4.ip_forward=1 >> /etc/sysctl.conf
[root@router ~]# sysctl  -p
net.ipv4.ip_forward = 1

# SNATポリシー:172.25.254.0/24ネットワークのデータパケットがeth1から出るとき、送信元IPを192.168.0.100に変換
[root@router ~]# iptables -t nat -A POSTROUTING -o eth1 -j SNAT --to-source 192.168.0.100
# 逆SNAT:192.168.0.0/24ネットワークのデータパケットがeth0から出るとき、送信元IPを172.25.254.100に変換
[root@vsnode ~]# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 172.25.254.100

主な役割

  • IP転送を有効化し、クライアント(172.25.254.99)のリクエストが192.168.0.0/24ネットワークセグメントのVSに届くように;
  • SNAT変換によりクロスネットワーク通信における送信元IPの正当性を解決し、RSの応答がクライアントに原路線で戻るように。
2. 負荷分散器(vsnodeディレクター)設定:VIPバインド+ルート設定
# eth0のIPとゲートウェイを設定(ルーターeth1に設定)
[root@vsnode ~]# vmset.sh  eth0 192.168.0.50 vsnode  noroute
[root@vsnode ~]# vim /etc/NetworkManager/system-connections/eth0.nmconnection
[connection]
id=eth0
type=ethernet
interface-name=eth0

[ipv4]
method=manual
address1==192.168.0.50/24,192.168.0.100

[root@vsnode ~]# cd  /etc/NetworkManager/system-connections/
# loループバックにVIP(192.168.0.200/32)をバインド
[root@vsnode system-connections]#  cp -p eth0.nmconnection lo.nmconnection
[root@vsnode system-connections]# vim lo.nmconnection
[connection]
id=lo
type=loopback
interface-name=lo

[ipv4]
method=manual
address1==127.0.0.1/8
address2=192.168.0.200/32    # VIPはlo口にのみバインドし、ARPブロードキャスト衝突を避ける

# ネットワーク設定を再読込し、確認
[root@RS1 system-connections]# nmcli connection reload
[root@RS1 system-connections]# nmcli connection up eth0
接続が正常にアクティブ化されました(D-Bus アクティブパス:/org/freedesktop/NetworkManager/ActiveConnection/7)
[root@RS1 system-connections]# nmcli connection up  lo
接続が正常にアクティブ化されました(D-Bus アクティブパス:/org/freedesktop/NetworkManager/ActiveConnection/8)
# 確認
root@vsnode system-connections]# route  -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.0.100   0.0.0.0         UG    100    0        0 eth0
192.168.0.0     0.0.0.0         255.255.255.0   U     100    0        0 eth0
192.168.0.0     0.0.0.0         255.255.255.0   U     100    0        0 eth0
[root@vsnode system-connections]# ip a
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet 192.168.0.200/32 brd 192.168.0.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0:  mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:41:e5:8b brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    altname ens160
    inet 192.168.0.50/24 brd 192.168.0.255 scope global secondary noprefixroute eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::e40:8975:6b9:fea8/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

コア設計

  • VSのeth0は通信入口のみ、VIP(192.168.0.200)はlo口にバインドされる理由は、DRモードではVSはクライアントリクエストのみを受け取れば良く、VIPをARPブロードキャストに参加させない(RSのVIPと衝突を避ける);
  • ルートはルーター(192.168.0.100)に設定し、VSがクライアントのクロスネットワークリクエストを受信できるように。
3. クライアント設定:ゲートウェイ指定+VIPアクセス
# eth0のIP(172.25.254.99)とゲートウェイ(ルーターeth0:172.25.254.100)を設定
[root@client ~]# vmset.sh  eth0 172.25.254.99 client
[root@client ~]# vim /etc/NetworkManager/system-connections/eth0.nmconnection
[connection]
id=eth0
type=ethernet
interface-name=eth0

[ipv4]
method=manual
address1=172.25.254.99/24,172.25.254.100  # ゲートウェイはルーター
dns=8.8.8.8;

[root@client ~]# nmcli connection reload
[root@client ~]# nmcli connection up eth0
接続が正常にアクティブ化されました(D-Bus アクティブパス:/org/freedesktop/NetworkManager/ActiveConnection/3)
[root@client ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.25.254.100  0.0.0.0         UG    100    0        0 eth0
172.25.254.0    0.0.0.0         255.255.255.0   U     100    0        0 eth0

# 確認:VIP(192.168.0.200)にping
[root@client ~]# ping 192.168.0.200
PING 192.168.0.200 (192.168.0.200) 56(84) ビットのデータ。
64 ビット、192.168.0.200から:icmp_seq=1 ttl=128 時間=1.08 ミリ秒

コアロジック

  • クライアントのデフォルトゲートウェイはルーターであり、192.168.0.200(VIP)へのリクエストはルーターに最初に送られ、その後VSに転送される;
  • VIPにpingが通ればクロスネットワーク転送とVSのVIPバインドが有効であることを示す。
4. リアルサーバ(RS1/RS2)設定:VIPバインド+ARP抑止+ルート設定

RS1(RS2の設定は完全に同じ、IPのみ異なる)

# eth0のIP(192.168.0.10)とゲートウェイ(ルーターeth1:192.168.0.100)を設定
[root@RS1 ~]# vmset.sh eth0 192.168.0.10 RS1 noroute
[root@RS1 ~]# nmcli connection modify eth0 ipv4.gateway 192.168.0.100
[root@RS1 ~]# nmcli connection reload
[root@RS1 ~]# nmcli connection up eth0
[root@RS1 ~]# route  -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.0.100   0.0.0.0         UG    100    0        0 eth0
192.168.0.0     0.0.0.0         255.255.255.0   U     100    0        0 eth0

# lo口にVIP(VSのVIPと一致:192.168.0.200/32)をバインド
[root@RS1 ~]# cd /etc/NetworkManager/system-connections/
[root@RS1 system-connections]# cp -p eth0.nmconnection lo.nmconnection
[root@RS1 system-connections]# vim lo.nmconnection
[connection]
id=lo
type=loopback
interface-name=lo

[ethernet]

[ipv4]
address1=127.0.0.1/8
address2=192.168.0.200/32  # コア:RSのlo口にVIPをバインド
method=manual
[root@RS1 system-connections]# nmcli connection reload
[root@RS1 system-connections]# nmcli connection up lo
接続が正常にアクティブ化されました(D-Bus アクティブパス:/org/freedesktop/NetworkManager/ActiveConnection/6)

[root@RS1 system-connections]# ip a   # lo口に192.168.0.200/32のIPが見える
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet 192.168.0.200/32 scope global lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
       
 # 重要な:ARP抑止(VIP衝突問題の解決)
[root@rs1 ~]# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
[root@rs1 ~]# echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
[root@rs1 ~]# echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
[root@rs1 ~]# echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce

確認:

  • ARP抑止のコア原理

DRモードでは、すべてのRSとVSが同じVIP(192.168.0.200)をバインドしており、ARP抑止をしない場合:

  • スイッチ/ルーターがARP要求「誰が192.168.0.200?」を送信すると、すべてのRSとVSが応答し、ARP衝突が起こり、リクエスト分配が混乱する;
  • arp_ignore=1:目的IPがローカルNIC(eth0/lo)に設定されたIPであるARP要求のみ応答し、VIPのARP要求は拒否(VIPはlo口にあり、ローカル専用);
  • arp_announce=2:ARPパケットを送信する際、送信元IPが所属するNICのIPをARPパケットの送信元として使用し、RSがVIPのMACアドレスを外部にブロードキャストしない。
  • ルート設定の役割

RSのデフォルトゲートウェイはルーター(192.168.0.100)に設定され、RSがリクエストを処理した後、応答パケットを直接クライアントに送信できる(VSを経由しない)。

2.2 LVS DRモードのコア動作フロー

実験環境を基に、クライアントがVIP(192.168.0.200)にアクセスする完全なフロー:

  1. クライアントリクエスト発信:クライアント(172.25.254.99)がVIP(192.168.0.200)にリクエストを送信し、ゲートウェイがルーター(172.25.254.100)であるため、最初にルーターeth0に到着;
  2. ルーターでのリクエスト転送:ルーターはIP転送機能により、リクエストをeth1(192.168.0.100)から192.168.0.0/24ネットワークセグメントのVS(192.168.0.50)に転送;
  3. VSでのリクエスト分配:VSはリクエストを受け取り、LVS DRモードのスケジューリングアルゴリズム(rr、wrrなど)により、リクエストを**MACアドレスのみ変更**(宛先MACを特定RSのMACに変更)し、対応するRS(例:RS1:192.168.0.10)に転送(コア:VSはデータリンク層のMACのみ変更、IP層の送信元(クライアント)、宛先(VIP)は変更なし);
  4. RSでのリクエスト処理:RSはリクエストを受け取り、lo口にVIP(192.168.0.200)がバインドされているため、リクエストが自分宛だと判断し、リクエストを処理し応答データパケットを生成;
  5. RSによるクライアント直接応答:RSの応答データパケットの送信元IPはVIP(192.168.0.200)、宛先IPはクライアント(172.25.254.99)、デフォルトゲートウェイ(ルーター192.168.0.100)を通してクライアントに戻る;
  6. コア利点:応答データパケットはVSを経由せず、VSはリクエストの分配のみを行い、VSの負荷を大幅に低減し、全体のスループットを向上。

2.3 実験の重要な注意事項

  1. VIPのバインド場所:VSとすべてのRSのVIPはloループバックにバインドし、/32(ホストルート)に設定し、ARPブロードキャスト衝突を避ける;
  2. ARP抑止は必須:RSがarp_ignore/arp_announceを設定しない場合、VIPのARP応答が衝突し、リクエスト分配が失敗する;
  3. IP転送は必須:ルーターとVS/RSのカーネルIP転送(net.ipv4.ip_forward=1)は有効化し、さもないとクロスネットワーク通信が失敗;
  4. ルートの正しい設定:すべてのノードのデフォルトゲートウェイはルーターの対応ネットワークIPに設定(クライアント→172.25.254.100、VS/RS→192.168.0.100)。

2.4 DRモードの利点と適用シナリオ

  1. 利点
  • 極めて高いパフォーマンス:VSはリクエストの分配のみ(MAC変更)、応答パケットはRSから直接クライアントに戻るため、VSに帯域幅のボトルネックがない;
  • 接続数制限なし:VSはTCP接続を維持せず(パケット転送のみ)、大量の同時リクエストをサポート;
  • 互換性良好:RSのオペレーティングシステムに特別な要件はなく、VIPバインドとARP抑止のみ設定可能。
  1. 適用シナリオ
  • 高並列・高スループットの業務(例:ECサイトのセール、ライブコメント、静的リソース配信);
  • 低遅延・高可用性のTCP/UDPサービス(例:データベース読み込み分離、APIゲートウェイ)。

総括:今回の実験はLVS DRモードのコア設定とネットワークロジックを完全に再現し、キーポイントはVIPのlo口バインド、ARP抑止、クロスネットワーク転送、直接ルーティング応答であり、これらの詳細を理解することでDRモードのコア原理を習得できる。

3. ファイアウォールマーキングによるラウンドロビン誤りの解決

3.1 背景と問題の核心

このケースはLVS(Linux Virtual Server)負荷分散に関わるもので、主な課題は「HTTP(80ポート)とHTTPS(443ポート)の独立したラウンドロビンにより、リクエストが重複割り当てされる」問題である。

まずコアコンポーネントを明確化:

  • VSNode:LVS負荷分散器(ディレクター)、VIP(仮想IP)は192.168.0.200;
  • RS1/RS2:リアルサーバ(バックエンドノード)、IPはそれぞれ192.168.0.10、192.168.0.20;
  • Client:テストクライアント、VIPを検証するためにアクセスする;
  • スケジューリングアルゴリズム:`rr`(ラウンドロビン)、リクエストは順番に後端ノードに割り当てられる。

3.2 初期設定と問題分析

  1. rsホストでHTTPとHTTPSの両方のプロトコルを同時に開始
# RS1とRS2でHTTPSを有効化
[root@RS1+RS2 ~]# dnf install mod_ssl -y
[root@RS1+RS2 ~]# systemctl restart httpd
[root@RS1+RS2 ~]# systemctl restart httpd
  1. vsnodeでHTTPSのラウンドロビンポリシーを追加

VSNode上で80と443ポートにLVSルールを設定:

  • 80ポートの仮想サービスを作成し、RS1:80、RS2:80にラウンドロビンで割り当て;
  • 443ポートの仮想サービスを作成し、RS1:443、RS2:443にラウンドロビンで割り当て;
[root@vsnode boot]# ipvsadm -A -t 192.168.0.200:80  -s rr
[root@vsnode boot]# ipvsadm -a -t 192.168.0.200:80 -r 192.168.0.20 -g
[root@vsnode boot]# ipvsadm -a -t 192.168.0.200:80 -r 192.168.0.10 -g
[root@vsnode boot]# ipvsadm -A -t 192.168.0.200:443 -s rr
[root@vsnode boot]# ipvsadm -a -t 192.168.0.200:443 -r 192.168.0.10:443 -g
[root@vsnode boot]# ipvsadm -a -t 192.168.0.200:443 -r 192.168.0.20:443 -g
[root@vsnode boot]# 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.0.200:80 rr
  -> 192.168.0.10:80              Route   1      0          0
  -> 192.168.0.20:80              Route   1      0          0
TCP  192.168.0.200:443 rr
  -> 192.168.0.10:443             Route   1      0          0
  -> 192.168.0.20:443  
[root@vsnode ~]# systemctl restart ipvsadm
  1. ラウンドロビンエラーの表示
# クライアントテスト:2回のリクエスト(80+443)はすべてRS2に割り当てられた
[root@client ~]# curl  192.168.0.200;curl -k https://192.168.0.200
RS2 - 192.168.0.20
RS2 - 192.168.0.20

# 上記設定後、httpとhttpsは独立したサービスとなり、ラウンドロビンで重複が発生する
  1. 問題の根本

LVSにおいて、**80ポートと443ポートは完全に独立した「仮想サービス」**:

  • HTTPリクエスト(80)は「80ポートのラウンドロビンキュー」を通り、HTTPSリクエスト(443)は「443ポートのラウンドロビンキュー」を通り;
  • 二つのキューは独立してカウントされ、HTTPとHTTPSリクエストが同じRSに割り当てられ、期待される「ラウンドロビン均等割り当て」が破られる。

3.3 解決策:ファイアウォールマーキング(MARK)+マーキングに基づくLVSスケジューリング

  1. コアアイデア:**VIPの80/443ポートのすべてのデータパケットに統一されたマーキングを付与し、LVSが「ポート」ではなく「マーキング」でラウンドロビンを行う**ことで、80と443のリクエストを同じラウンドロビンキューにまとめる。

80/443データパケットにマーキングを付与(iptables mangleテーブル)

[root@vsnode boot]# iptables -t mangle -A PREROUTING -d 192.168.0.200 -p tcp -m multiport --dports 80,443 -j MARK --set-mark  6666

解説

  • t mangle:「mangleテーブル」を操作(データパケットのマーキング/TTLなどの属性変更専用);
  • A PREROUTING:「PREROUTINGチェーン」(データパケットが本機に入る前の処理)にルールを追加;
  • d 192.168.0.200:宛先IPはVIP(負荷分散VIPへのデータパケットのみマッチ);
  • p tcp:プロトコルはTCP;
  • m multiport --dports 80,443:宛先ポートが80または443のデータパケットをマッチ;
  • j MARK --set-mark 6666:マッチしたデータパケットに「6666」のマーキングを付与。
  1. マーキングに基づくLVS仮想サービスを作成
[root@vsnode boot]# ipvsadm -A -f 6666 -s rr

解説

  • ipvsadm:LVSのコア設定ツール;
  • -A:仮想サービスを追加(Add);
  • -f 6666:「ファイアウォールマーキング(fwmark)6666」に基づいて仮想サービスを作成(以前の「ポート+IP」を置き換え);
  • -s rr:スケジューリングアルゴリズムはラウンドロビン(Round Robin)。
  1. 後端RSをマーキングサービスにバインド
[root@vsnode boot]# ipvsadm  -a -f 6666 -r 192.168.0.10 -g
[root@vsnode boot]# ipvsadm  -a -f 6666 -r 192.168.0.20 -g

解説

  • -a:仮想サービスに後端リアルサーバを追加(Add);
  • -f 6666:マーキング6666の仮想サービスに関連付け;
  • -r 192.168.0.10/20:後端リアルサーバのIPを指定;
  • -g:転送モードは「Gateway」(DRモード、直接ルーティング)、LVSの最も一般的で効率的な転送モード(データパケットはVSノードを介さず直接戻る)。
  1. クライアントでのテスト結果
[root@client ~]# curl  192.168.0.200;curl -k https://192.168.0.200
RS2 - 192.168.0.20
RS1 - 192.168.0.10

HTTP(80)リクエストはRS2、HTTPS(443)リクエストはRS1に割り当てられ、クロスポートの統一ラウンドロビンが実現された。

下位原理

  • VIP:80とVIP:443へのすべてのデータパケットはiptablesにより6666マーキングされる;
  • LVSは80/443ポートを区別せず、「マーキング6666」を基準にラウンドロビンを行う;
  • 80と443のリクエストは同じラウンドロビンキューに入り、順番にRS1、RS2に割り当てられ、「独立ポートラウンドロビンによる重複割り当て」問題が解決。

3.4 総括

このケースのコアは「ファイアウォールマーキング(MARK)により複数ポートリクエストを正規化し、LVSがマーキングに基づいて負荷分散をスケジュールする」ことで、HTTP/HTTPSの独立ラウンドロビンによる割り当て重複問題を解決する。コアステップ:

  1. VIPの80/443データパケットに統一マーキングを付与;
  2. マーキングに基づくLVS仮想サービスを作成;
  3. 後端RSをマーキングサービスにバインド;
  4. クロスポートの統一ラウンドロビンスケジューリングを実現。

4. 持続接続によるセッション保持

4.1 コア背景

セッション保持(セッション永続性)は負荷分散における重要な要件であり、同一クライアントの複数リクエストを同一のバックエンドサーバに固定転送することを意味し、IPVSのpersistent(永続接続)パラメータで実現可能で、ファイルでは具体的なコマンドとテストによりその機能を検証した。

4.2 設定

  1. IPVSスケジューリング戦略の設定
[root@vsnode ~]# ipvsadm -A -f 6666 -s rr -p 1

解説

  • -A:新しい仮想サービスを追加;
  • -f 6666:ファイアウォールマーキング(fwmark)6666に基づいて仮想サービスを定義(従来のIP+ポートに依存しない);
  • -s rr:スケジューリングアルゴリズムはrr(ラウンドロビン、Round Robin);
  • -p 1:永続接続を有効化し、タイムアウト時間は1秒(つまり1秒以内の同一クライアントリクエストは同一バックエンドサーバに固定)。
[root@vsnode ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
FWM  6666 rr persistent 1
  -> 192.168.0.10:0               Route   1      0          0
  -> 192.168.0.20:0  

出力解釈

  • FWM 6666:ファイアウォールマーキング6666に基づく仮想サービス;
  • rr persistent 1:ラウンドロビンスケジューリング+1秒の永続接続;
  • 後端ノード:192.168.0.10192.168.0.20(二つのリアルサーバRS)、転送モードはRoute(ルーティングモード)、重みWeight=1(スケジューリング優先度同等)。
  1. セッション保持効果のテスト
[root@client ~]# curl  192.168.0.200
RS1 - 192.168.0.10
[root@client ~]# curl  192.168.0.200
RS1 - 192.168.0.10

操作:クライアントが仮想サービスIP(192.168.0.200)を複数回アクセス;

結果:二回のリクエストともにRS1 - 192.168.0.10を返し、永続接続が有効であることを示す—つまり、スケジューリングアルゴリズムがラウンドロビンでも、1秒以内の同一クライアントリクエストは192.168.0.10というバックエンドサーバに固定され、セッション保持が検証された。

  1. IPVS接続状態の観察
[root@vsnode ~]# watch -n 1 ipvsadm -Lnc
IPVS connection entries
pro expire state       source             virtual            destination
TCP 01:56  FIN_WAIT    172.25.254.99:42420 192.168.0.200:80   192.168.0.20:80
IP  00:57  ASSURED     172.25.254.99:0    0.0.26.10:0        192.168.0.20:0
TCP 01:54  FIN_WAIT    172.25.254.99:46216 192.168.0.200:80   192.168.0.20:80
TCP 01:55  FIN_WAIT    172.25.254.99:46222 192.168.0.200:80   192.168.0.20:80

出力解釈

  • pro:プロトコル(TCP/IP);
  • expire:接続の有効期限(例:01:56は1分56秒後に期限切れ);
  • state:接続状態(FIN_WAITは閉鎖段階、ASSUREDは安定接続);
  • source:クライアントIP+ポート(172.25.254.99);
  • virtual:仮想サービスIP+ポート(192.168.0.200:80);
  • destination:バックエンドサーバIP+ポート(192.168.0.20:80);
  • 核心結論:クライアントの複数接続は同一バックエンドサーバを指しており、セッション保持の効果が検証された。

4.3 総括

IPVS永続接続ルールの設定→アクセス効果のテスト→接続状態の観察の流れにより、IPVSのpersistentパラメータによるセッション保持の実現方法を示した:

  1. ファイアウォールマーキングで仮想サービスを定義し、具体的なIP+ポートに依存しない;
  2. ラウンドロビンスケジューリングと短時間(1秒)の永続接続を組み合わせ、同一クライアントのリクエストを同一バックエンドに固定;
  3. テストと接続状態観察の両面からセッション保持効果を検証。

タグ: linux LVS load-balancing NAT dr

6月22日 16:22 投稿