1. 程式人生 > >Neutron 理解 (7): Neutron 是如何實現負載均衡器虛擬化的 [LBaaS V1 in Juno]

Neutron 理解 (7): Neutron 是如何實現負載均衡器虛擬化的 [LBaaS V1 in Juno]

學習 Neutron 系列文章:

1. 基礎知識

1.1 負載均衡的概念

  負載均衡(Load Balancing)是將來訪的網路流量在執行相同應用的多個伺服器之間進行分發的一種核心網路服務。它的功能由負載均衡器(load balancer)提供。負載均衡器可以是一個硬體裝置,也可以由軟體實現。它充當反向代理,在多個伺服器之間分發網路或者應用流量。它常用來增加應用的訪問容量(併發使用者數)和可靠性,它也會通過降低伺服器的負載來提高應用的總體效能。

(1)負載均衡器的分類

負載均衡器一般可以分為兩類:第4層負載均衡器和第7層負載均衡器。

第 4 層負載平衡器:基於網路和傳輸層協議(IP,TCP,FTP,UDP等)來均衡負載。

Layer 4 Load Balancing

第7層的負載均衡器:基於應用層協議比如 HTTP, SMTP, SNMP, FTP, Telnet 等均衡負載。比如對 HTTP 來說,第七層的負載均衡器能根據應用的特定資料比如 HTTP 頭,cookies 或者應用訊息中的資料來做進一步的請求分發。

Layer 7 Load Balancing

(2)負載分發演算法

兩種型別的負載均衡器都能接收請求,然後根據特定的演算法將請求分發到特定的伺服器。一些行業標準的演算法是:

  • 輪詢 (Round robin):輪流分發到各個(活動)伺服器
  • 加權輪循 (Weighted round robin):每個伺服器有一定的加權(weight),輪詢時考慮加權。
  • 最少連線 (Least connections):轉發到有最少連線數的伺服器
  • 最少響應時間 (Least response time):轉發到響應時間最短的伺服器

(3)可靠性和可用性

負載均衡器通過監控應用的健康狀態來確保可靠性和可用性,並且只轉發請求到能及時做出響應的服務和應用。

(4)Session persistence (會話保持)

會話保持表示在一個會話期間,轉發一個使用者的請求到同一個後端伺服器。這對購物車或者付款類的請求非常重要。 常用的方法包括:

  • Source IP:相同來源的請求轉發到同一個伺服器
  • HTTP Cookie:該模式下,loadbalancer 為客戶端的第一次連線生成 cookie,後續攜帶該 cookie 的請求會被某個 member 處理
  • APP Cookie:該模式下,依靠後端應用伺服器生成的 cookie 決定被某個 member 處理

(5)常見的開源軟體負載均衡器

  • HAProxy
  • Linux Virtual Servers (LVS) - 包括在許多Linux發行版中的簡單快速的4層負載均衡軟體

  • Nginx - 一個快速可靠的web伺服器也能當作代理和負載均衡器使用。它常常和 HAProxy一起用於快取和壓縮。

1.2 三種部署模式

1.2.1 tow-arms (雙臂)模式

也稱為 in-line 模式,或者 bridge mode 模式,或者 transparent mode。此時,所以前端訪問後端的網路都需要經過 LB,它本身也成為了一種 router。可見,此時的 LB 需要兩個網絡卡,分別連線前端和後端。

來看一個具體的 IP 地址配置示例:

1.2.2 One-arm (單臂)模式

該模式中,LB 不處於前端和後端的通道上,而是在旁邊。此時,LB 只使用一塊網絡卡,而且該網絡卡和後端伺服器處於同一個二層網路中。該 LB 的網絡卡將會被分配一個 virtual load-balanced IP (VIP)。需要注意的是,此時的 LB 需要對進來的網路包做 Source 和 Dest NAT 然後再交給某個後端伺服器,使得後端伺服器返回的網路包將會到達 LB 而不是直接到達前端,再由 LB 轉交給前端。因為使用了 SNAT,因此後端看不到網路包的源IP,這在某些需要審計功能的情況下可能無法滿足要求。

來看一個具體的 IP 地址配置示例:

1.2.3 Direct Server Response 模式

這種模式下,LB 只接收進來的網路包,轉給後端伺服器後,後端伺服器直接將返回包發回給客戶端。這種模式的好處是,可以提高網路的吞吐量,壞處是配置較為複雜。

1.3 High Availability Proxy(HAProxy

    HAProxy 是個著名的開源的軟體 TCP(四層)/HTTP(七層) 負載均衡器和代理(proxy)軟體,可以執行在 Linux,Solaris 和 FreeBSD 等系統上。它最常用的用途是通過在多個伺服器(比如 web伺服器,應用,資料庫等)之間分發負載來改善一個伺服器系統的效能和可靠性。目前,它已經被許多大公司採用,包括GitHub, Imgur, Instagram, and Twitter 等。它類似 Nginx 的,採用了單程序和事件驅動模型;它使用的記憶體量低而且穩定,能夠處理大量併發請求。這篇文章 講述了怎樣使用 HAProxy。

主要概念:

  • Frontend:定義請求如何被轉發到 backend。
  • Backend:一組接收轉發的請求的伺服器。其定義包括分發演算法和一組伺服器的地址和埠。

支援的分發演算法:

  • Round robin:平均的將網路流量分發到多個 member。
  • Source IP:從某一個特定 IP 發來的網路請求,總是發到特定的 member。
  • Least connections:將收到的網路請求,發給當前負載均衡池中連線數最少的 member。如果所有的 member 連線數一樣,則遵循 Round robin 的方式。

一個 HAProxy + Keepalived 配置例項:

Health Check(健康檢查):

    HAProxy 使用 Health Check 來確定一個 backend server 能不能接收轉發的請求。這避免了在伺服器不可用時需要手工刪除它。預設的 Health Check 是試著去和一個server 建立一個 TCP 連線,比如,檢查該 backend server 是否在配置的 IP 和 埠上監聽。你可以指定 health check 方法,包括 tcp,http,ping 等。

    當一個 backend server 檢查失敗時,它就無法接受請求了,它就會自動被禁用,請求也不會被轉發到該伺服器上,直到它重新變為可用。如果一個 backend 內的所有伺服器都 health check 失敗,其對應的服務就會變得不可用。

配置檔案:

HAProxy 的核心在於其配置檔案(etc/haproxy/haproxy.cfg)。Neutron 的 LBaas 其實也就是生成了該配置檔案,然後由 HAProxy 去執行。

global #全域性配置,基本不需要修改
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin
        stats timeout 30s
        user haproxy
        group haproxy
        daemon

        # Default SSL material locations
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        # Default ciphers to use on SSL-enabled listening sockets.
        # For more information, see ciphers(1SSL).
        ssl-default-bind-ciphers kEECDH+aRSA+AES:kRSA+AES:+AES256:RC4-SHA:!kEDH:!LOW:!EXP:!MD5:!aNULL:!eNULL

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http

frontend localnodes #where HAProxy listens to connections
    bind *:80              #HAProxy 在所有網絡卡的 80 埠上監聽 HTTP 請求
    mode http              #監聽 HTTP 請求,這時它作為一個七層負載均衡器
    default_backend nodes  #所使用的後端伺服器

backend nodes #Where HAPoxy sends incoming connections
    mode http          #轉發 HTTP 包給後端伺服器
    balance roundrobin #分發演算法
    option forwardfor  #在 HTTP 頭中新增 X-Forwarded-For 頭,使得後端伺服器可以獲取原始請求的來源地址
    http-request set-header X-Forwarded-Port %[dst_port] #在 HTTP 頭中新增 X-Forwarded-Port 頭從而使得後端伺服器可以知道原始的 HTTP Port
    http-request add-header X-Forwarded-Proto https if { ssl_fc } #在使用 SSL 時新增 X-Forwarded-Proto頭
    option httpchk HEAD / HTTP/1.1\r\nHost:localhost #使用 health check 來檢查後端伺服器的可達性
    server web01 127.0.0.1:9000 check #後端伺服器。”check“表示做 health check。
    server web02 127.0.0.1:9001 check
    server web03 127.0.0.1:9002 check

listen stats *:1936 #用於監控 HAProxy
    stats enable
    stats uri /
    stats hide-version
    stats auth someuser:password

 2. Neutron 中的虛擬負載均衡器

    Neutron LBaas (load-balancer-as-a-service)擴充套件(extension)提供向在多個 Nova 虛機中執行的應用提供負載均衡的方法。它還提供 API 來快速方便地部署負載均衡器。 它早在 OpenStack 的 Grizzly 版本就整合到 Neutron 中。自整合到 Neutron 以來,LBaaS 經歷過幾次大的變化。目前,在最新發布的 Kilo 版本中,LBaas 程式碼從 Neutron 中抽離,直接由獨立的專案管理,以及實現了 LBaaS V2。本文是基於 Juno 版本的 LBaas 進行分析。 OpenStack Neutron 預設以 HAProxy 為負載均衡的 driver,同時也支援 A10 network(參考連結)、netscaler、radware (參考文件)等作為 driver。

2.1 LBaas 中的概念

LBaas 可以看做 OpenStack Neutron 對各種物理負載均衡器的虛擬化。它的概念可以和 HAProxy 中的概念進行類比:

HAProxy 的概念 LBaas 的概念 說明
Driver

LBaas 也是採取 driver 模型來支援多種物理的負載均衡器。LBaas 預設實現了 HAProxy driver,同時,它也支援多個其他 Vendor driver。

Frontend VIP(Virturl IP address)

LBaas 對外提供服務的地址。VIP 有自己的 IP 地址,而且一般都能通過公網進行訪問。VIP 負責將網路流量分發到各個 member。

Backend Pool 代表負載後端的虛擬機器池。在以 HAProxy 為 Driver 的情況下,一個 Pool 對應著在一個獨立的 network namespace 中執行的 HAProxy 程序所管理的 backend。目前一個 pool 只能有一個 VIP。
Backend server Member Member 對應的是 pool 裡面處理網路請求的一個 OpenStack Nova 虛機。
Health check Health monitor 它用來監測 pool 裡面 member 的狀態,支援 HTTP, TCP, 和 ping 等多種檢測方法。在 Nuetron 中這是可選的,如果沒有 Health monitor,pool 會一直認為所有的 member 都是 ACTIVE 狀態,這樣所有的 member 會一直出現在 VIP 的分發列表中,哪怕 member 對應的例項不能響應網路請求。這在實際應用中會造成負載均衡的響應異常。

LBaas driver 模型:

 

基本概念:

基本概念之間的聯絡:

LBinstance.png

2.2 LBaas HAProxy 部署例項

    OpenStack 直接採用各種開源可用的負載均衡專案來完成負載均衡的任務,預設使用 HAProxy。LBaaS 所做的任務就是根據使用者提出的負載均衡要求生成符合要求的HAProxy配置檔案並啟動 HAProxy,然後由 HAProxy 進行負載均衡。

2.2.1 安裝

  不同的 LBaas drive 支援不同的部署模式。社群實現 LBaas HAPorxy driver 只支援 one-arm 模式。你可以部署LBaas Agent 在network 節點上,也可以部署在別的節點上。本例項中,將 neutron-lbaas-agent 安裝在 network 節點上。你可以部署多個 LBaas 節點(agent),每個 agent 上執行不同的物理負載均衡器。

Integrating load balancers into the network

網路節點上:

apt-get install neutron-lbaas-agent

apt-get install haproxy

修改 /etc/neutron/lbaas_agent.ini: 

interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver

device_driver = neutron.services.loadbalancer.drivers.haproxy.namespace_driver.HaproxyNSDriver

修改/etc/neutron/neutron.conf

service_plugins = router,lbaas

啟動 service:

service neutron-lbaas-agent restart

lbaas-agent 程序:

neutron  18890     1  5 06:53 ?        00:00:01 /usr/bin/python /usr/bin/neutron-lbaas-agent --config-file=/etc/neutron/lbaas_agent.ini --config-file=/etc/neutron/neutron.conf --log-file=/var/log/neutron/lbaas-agent.log  

Controller 節點上:

修改/etc/neutron/neutron.conf

service_plugins = router,lbaas

service neutron-server restart

修改/etc/openstack-dashboard/local_settings.py: 

OPENSTACK_NEUTRON_NETWORK = {
'enable_router': True,
'enable_quotas': True,
'enable_ipv6': True,
'enable_distributed_router': False,
'enable_ha_router': False,
'enable_lb': True 

2.2.2 配置

(1)Create pool

[email protected]:~$ neutron lb-pool-list
+--------------------------------------+-------+----------+-------------+----------+----------------+--------+
| id | name | provider | lb_method | protocol | admin_state_up | status |
+--------------------------------------+-------+----------+-------------+----------+----------------+--------+
| 3b9d8ebd-9eea-4925-b14e-593a6111ff33 | pool1 | haproxy | ROUND_ROBIN | HTTP | True | ACTIVE |
+--------------------------------------+-------+----------+-------------+----------+----------------+--------+

不太理解建立 pool 時候選的 subnet 是什麼用途。

(2)Create members

[email protected]:~$ neutron lb-member-list
+--------------------------------------+-------------+---------------+--------+----------------+--------+
| id | address | protocol_port | weight | admin_state_up | status |
+--------------------------------------+-------------+---------------+--------+----------------+--------+
| 1f74a288-937d-4804-9ded-472a5d1110dc | 81.1.180.13 | 80 | 1 | True | ACTIVE |
| 944ff4a0-4070-40e4-8189-20f385755113 | 91.1.180.14 | 80 | 1 | True | ACTIVE |
| c5bd3138-9635-4588-889f-d08fcd364ed4 | 81.1.180.12 | 80 | 1 | True | ACTIVE |
+--------------------------------------+-------------+---------------+--------+----------------+--------+

似乎對 member 自身沒什麼限制,只要是 pool 所在的 tenant 內的虛機都可以加入。

(3)Create VIP for pool

[email protected]:~$ neutron lb-vip-list
+--------------------------------------+------+-------------+----------+----------------+--------+
| id | name | address | protocol | admin_state_up | status |
+--------------------------------------+------+-------------+----------+----------------+--------+
| 0c32d37d-f84a-4309-9e01-72d9f0bac69e | vip2 | 81.1.180.81 | HTTP | True | ACTIVE |
+--------------------------------------+------+-------------+----------+----------------+--------+

VIP 的 subnet 也可以和 pool 的subnet 不一致,主要是在指定的 subnet 內建立一個 port。

注意:這裡的 VIP 從字面上看具有一定的迷惑性。VIP (virtual ip) 必須建立在 pool 所在的 subnet 中,所以它本身只是一個和 pool member 的 fixed ip 一樣的 fixed ip address。如果要從外網訪問該 lb pool 的話,則還需要建立一個 floating ip 並且把它關聯到 lb pool 的 vip 上。這也是 one-arm 單臂的由來,也就是說 haproxy 所在的namespace 其實只有一個IP地址,分別接收外部連線以及和成員之間的連線。

從 Horizon 中看建立 VIP 的情景:

(4)Create health monitor

[email protected]:~$ neutron lb-healthmonitor-list
+--------------------------------------+------+----------------+
| id | type | admin_state_up |
+--------------------------------------+------+----------------+
| df1fcdd1-c0b5-4e14-a2fe-2d0789fc26a5 | PING | True |
+--------------------------------------+------+----------------+

(5) associate health monitor with pool

[email protected]:~$ neutron lb-healthmonitor-associate df1fcdd1-c0b5-4e14-a2fe-2d0789fc26a5 3b9d8ebd-9eea-4925-b14e-593a6111ff33
Associated health monitor df1fcdd1-c0b5-4e14-a2fe-2d0789fc26a5

以上步驟後的 pool 的詳細配置:

[email protected]:~$ neutron lb-pool-show 3b9d8ebd-9eea-4925-b14e-593a6111ff33
+------------------------+--------------------------------------------------------------------------------------------------------+
| Field | Value |
+------------------------+--------------------------------------------------------------------------------------------------------+
| admin_state_up | True |
| description | |
| health_monitors | df1fcdd1-c0b5-4e14-a2fe-2d0789fc26a5 |
| health_monitors_status | {"monitor_id": "df1fcdd1-c0b5-4e14-a2fe-2d0789fc26a5", "status": "ACTIVE", "status_description": null} |
| id | 3b9d8ebd-9eea-4925-b14e-593a6111ff33 |
| lb_method | ROUND_ROBIN |
| members | 1f74a288-937d-4804-9ded-472a5d1110dc |
|                | 944ff4a0-4070-40e4-8189-20f385755113 |
|                | c5bd3138-9635-4588-889f-d08fcd364ed4 |
| name      | pool1 |
| protocol   | HTTP |
| provider   | haproxy |
| status      | ACTIVE |
| status_description | |
| subnet_id | 4ec65731-35a5-4637-a59b-a9f2932099f1 |
| tenant_id | 74c8ada23a3449f888d9e19b76d13aab |
| vip_id | 19e16b0b-f48b-4f90-803c-d3afaf26c697 |
+------------------------+--------------------------------------------------------------------------------------------------------+

關於 pool,vip,member 的 subnet,在我的測試環境中,三者之間沒什麼限制,各自都可以處於不同的 subnet 中,只要subnet 之間配置好了 router。這個 ticket 倒是提出來要限制 member 和 vip 都在 pool 的subnet 中,但是有人認為目前沒什麼必要。但是,lb-pool-create 的 help 資訊中,subnet 指 ”The subnet on which the members of the pool will be located.“這個說明就和程式碼實現就有矛盾了。 

2.2.3 驗證

在 vm1 81.1.180.12 上,執行 while true; do echo -e 'HTTP/1.0 200 OK\r\n\r\nserver_151' | sudo nc -l -p 80 ; done 

在 vm2 81.1.180.13 上,執行 while true; do echo -e 'HTTP/1.0 200 OK\r\n\r\nserver_153' | sudo nc -l -p 80 ; done 

在vm3 上使用 wget http://81.1.180.12 和 wget http://81.1.180.13 ,能夠返回結果,顯示上面的命令成功執行。

再在 vm3 兩次使用 wget http://81.1.180.81,結果分別顯示 server_153 和 server_151,顯示輪詢分發成功。

 2.2.4 LBaas 的實現

網路節點上,neutron-lbaas-agent:

(1)為每個帶有 active VIP 的 pool 建立了一個 network namespace,它以 qlbaas-<pool UUID> 命名:ip netns add qlbaas-3b9d8ebd-9eea-4925-b14e-593a6111ff33

[email protected]:/home/s1# ip netns list
qlbaas-3b9d8ebd-9eea-4925-b14e-593a6111ff33

[email protected]:/home/s1# ip netns exec qlbaas-3b9d8ebd-9eea-4925-b14e-593a6111ff33 ip addr
50: tap2d1b74fe-68: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether fa:16:3e:7c:e5:ce brd ff:ff:ff:ff:ff:ff
    inet 81.1.180.81/24 brd 81.1.180.255 scope global tap2d1b74fe-68 #該 interface 的IP 地址為 VIP 的 IP 地址
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fe7c:e5ce/64 scope link
       valid_lft forever preferred_lft forever

該 interface 掛載 OVS br-int 上並被打上了它所在的 network(pool -> subnet -> network) 對應的本地 VLAN ID:

Bridge br-int        
        Port "tap2d1b74fe-68"
            tag: 4
            Interface "tap2d1b74fe-68"
                type: internal 

完整的 network namespace 操作過程為:

ovs-vsctl --if-exists del-port tapd9de9e84-23 --add-port br-int tapd9de9e84-23 --set Interface tapd9de9e84-23 type=internal --set Interface tapd9de9e84-23 external-ids:iface-id=d9de9e84-23ad-4f57-b85a-aea99abf409d --set Interface tapd9de9e84-23 external-ids:iface-status=active --set Interface tapd9de9e84-23 external-ids:attached-mac=fa:16:3e:f4:8f:ae
ip link set tapd9de9e84-23 address fa:16:3e:f4:8f:ae

ip netns add qlbaas-3b9d8ebd-9eea-4925-b14e-593a6111ff33  
ip netns exec qlbaas-3b9d8ebd-9eea-4925-b14e-593a6111ff33 sysctl -w net.ipv4.conf.all.promote_secondaries=1
ip link set tapd9de9e84-23 netns qlbaas-3b9d8ebd-9eea-4925-b14e-593a6111ff33
ip netns exec qlbaas-3b9d8ebd-9eea-4925-b14e-593a6111ff33 ip link set lo up ip link set tapd9de9e84-23 netns qlbaas-3b9d8ebd-9eea-4925-b14e-593a6111ff33 ip netns exec qlbaas-3b9d8ebd-9eea-4925-b14e-593a6111ff33 ip link set tapd9de9e84-23 up ip netns exec qlbaas-3b9d8ebd-9eea-4925-b14e-593a6111ff33 ip addr show tapd9de9e84-23 permanent scope global ip netns exec qlbaas-3b9d8ebd-9eea-4925-b14e-593a6111ff33 ip -4 addr add 91.1.180.180/24 brd 91.1.180.255 scope global dev tapd9de9e84-23 ip netns exec qlbaas-3b9d8ebd-9eea-4925-b14e-593a6111ff33 ip route list dev tapd9de9e84-23 scope link ip netns exec qlbaas-3b9d8ebd-9eea-4925-b14e-593a6111ff33 route add default gw 91.1.180.1 ip netns exec qlbaas-3b9d8ebd-9eea-4925-b14e-593a6111ff33 arping -U -I tapd9de9e84-23 -c 3 91.1.180.180

(2)生成 haproxy 配置檔案

global  #global 中除了 group 都是 hard coded 的
        daemon
        user nobody
        group nogroup  #可以由配置項 user_group 指定,預設為 nogroup
        log /dev/log local0
        log /dev/log local1 notice
        stats socket /var/lib/neutron/lbaas/3b9d8ebd-9eea-4925-b14e-593a6111ff33/sock mode 0666 level user

defaults #都是 hard coded 的 log global retries 3 option redispatch timeout connect 5000 timeout client 50000 timeout server 50000
frontend 0c32d37d-f84a-4309-9e01-72d9f0bac69e option tcplog bind 81.1.180.81:80 #VIP.IP:port mode http #pool1.Protocol default_backend 3b9d8ebd-9eea-4925-b14e-593a6111ff33 maxconn 100 # VIP.ConnectionLimit option forwardfor # 當 mode 為 ”http“時,設定 forwardfor,使得通過 X-Forward-For 頭來儲存原始的源 IP 地址
backend 3b9d8ebd-9eea-4925-b14e-593a6111ff33 mode http #pool.protocol balance roundrobin #pool1.Load_Balancing_Method option forwardfor timeout check 5s # Monitor.timeout(5)當 inter 和 timeout 都設定時,超時時間取兩者中的短者 server 1f74a288-937d-4804-9ded-472a5d1110dc 81.1.180.13:80 weight 1 check inter 5s fall 3 #member1 的配置,包括 ip,port(member 提供服務的埠,因此此時沒有指定check port,因此也是健康檢查的TCP埠),weight;check 指定做健康檢查;inter 指定兩次連續檢查之間的間隔,預設2s (5s);fall 指定Max Retries 或者連續幾次檢查失敗即認為member 是 DOWN 的次數 (3)
server 944ff4a0-4070-40e4-8189-20f385755113 91.1.180.14:80 weight 1 check inter 5s fall 3 #member 2 的配置 server c5bd3138-9635-4588-889f-d08fcd364ed4 81.1.180.12:80 weight 1 check inter 5s fall 3 #member 3 的配置
 

HAProxy 做健康檢查一些別的細節:

  • HAProxy 不支援 PING 做健康檢查。詳細見官網 Health checking
  • TCP port:可以使用 check port 來指定健康檢查 TCP 連線所使用的埠,比如指定 80埠: server srv1 10.0.0.1:443 check port 80;如果不指定的話,則使用負載均衡埠,也就是使用 443:server srv1 10.0.0.1:443。
 option httpchk
 server srv1 10.0.0.1:80 check
 server srv1 10.0.0.1:80 check
  • 還可以使用其它檢查方式,包括
  • Checking a SSL port
    Checking a LDAP service
    Checking a MySql service
    Checking a PgSQL service
    Checking a redis service
    Checking a SMTP service
    Checking any service

Neutron LBaaS HAProxy agent health monitor 的一些細節:

  • 只支援  TCP, HTTP, HTTPS,選擇 PING 等同於選擇 TCP。參見這個 bug
  • TCP 不能顯式指定用於健康檢查的埠,而是使用負載均衡埠。
  • 由 ACTIVE 變為 INACTIVE 狀態的過程需要經過 min(timeout, inter) * fall 時長,也就是需要多次檢查失敗才行。
  • 由 INACTIVE 變為 ACTIVE 狀態的過程,只需要 min(timeout, inter) 時長,也就是一次檢查成功就可以了
  • 一個 Pool 可以關聯多個 health monitor 執行不同型別的檢查。只有當全部的 monitor 認為一個member 是 active 時,該 member 的狀態才是 ACTIVE,否則都會是 INACTIVE。
  • 使用 HTTP 的一個例子
  •         timeout check 3s
            option httpchk GET /
            http-check expect rstatus 200
            server 7015f0d6-12bf-4b68-8455-7c601408dfec 20.0.0.122:80 weight 1 check inter 3s fall 2
  • 使用 HTTPS 的一個例子。與 HTTP 相比,只是增加了 "option ssl-hello-chk"。
  •         timeout check 3s
            option httpchk GET /
            http-check expect rstatus 200
            option ssl-hello-chk
            server 7015f0d6-12bf-4b68-8455-7c601408dfec 20.0.0.122:80 weight 1 check inter 3s fall 2
  • 程式碼(原始碼):
  • server_addon = ' check inter %(delay)ds fall %(max_retries)d' % monitor
        opts = [
            'timeout check %ds' % monitor['timeout']
        ]
    
        if monitor['type'] in (constants.HEALTH_MONITOR_HTTP,
                               constants.HEALTH_MONITOR_HTTPS):
            opts.append('option httpchk %(http_method)s %(url_path)s' % monitor)
            opts.append(
                'http-check expect rstatus %s' %
                '|'.join(_expand_expected_codes(monitor['expected_codes']))
            )
    
        if monitor['type'] == constants.HEALTH_MONITOR_HTTPS:
            opts.append('option ssl-hello-chk')

 一個使用 TCP 健康監視器時一個 member 狀態變化的簡單例子:

  • (0)環境:負載均衡服務為80埠上的 HTTP,使用 TCP health monitor
  • (1)將一個member 加入 pool,在 member 上不啟動 HTTP 服務,則在 neutron lb-member-list 中其狀態為 INACTIVE
  • (2)登入該member,啟動 HTTP 服務,經過很短的時間,member 的狀態變為 ACTIVE
  • (3)再次登入該 member,停止 HTTP 服務,經過相對較長的時間,member 的狀態變為 INACTIVE

(3)在 network namespace 中 啟動了一個 haproxy 程序,使用生成的配置檔案:

ip netns exec qlbaas-3b9d8ebd-9eea-4925-b14e-593a6111ff33 haproxy -f /var/lib/neutron/lbaas/3b9d8ebd-9eea-4925-b14e-593a6111ff33/conf -p /var/lib/neutron/lbaas/3b9d8ebd-9eea-4925-b14e-593a6111ff33/pid

[email protected]:/home/s1# ps -ef | grep haproxy
nobody 22625 1 0 07:29 ? 00:00:02 haproxy -f /var/lib/neutron/lbaas/3b9d8ebd-9eea-4925-b14e-593a6111ff33/conf -p /var/lib/neutron/lbaas/3b9d8ebd-9eea-4925-b14e-593a6111ff33/pid -sf 22365

(4)在 lbaas 的 interface 上抓包,看看幾個機器之間的互動過程

從 81.1.180.14 上 wget 81.1.180.81,VIP 從 81.1.180.12 獲取資料

# 81.1.180.14 通過 ARP 得到 81.1.180.81 的 MAC
10:20:33.070752 fa:16:3e:82:37:03 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Ethernet (len 6), IPv4 (len 4), Request who-has 81.1.180.81 tell 81.1.180.14, length 28
10:20:33.070779 fa:16:3e:7c:e5:ce > fa:16:3e:82:37:03, ethertype ARP (0x0806), length 42: Ethernet (len 6), IPv4 (len 4), Reply 81.1.180.81 is-at fa:16:3e:7c:e5:ce, length 28

#發起 81.1.180.14.41882 到 81.1.180.81.80 的 TCP 連線(三次握手)
10:20:33.073829 fa:16:3e:82:37:03 > fa:16:3e:7c:e5:ce, ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 64, id 24973, offset 0, flags [DF], proto TCP (6), length 60)
    81.1.180.14.41882 > 81.1.180.81.80: Flags [S], cksum 0x380e (correct), seq 2662307254, win 14600, options [mss 1460,sackOK,TS val 62523 ecr 0,nop,wscale 2], length 0
10:20:33.073884 fa:16:3e:7c:e5:ce > fa:16:3e:82:37:03, ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
    81.1.180.81.80 > 81.1.180.14.41882: Flags [S.], cksum 0x0a91 (incorrect -> 0xc0ae), seq 1950187908, ack 2662307255, win 28960, options [mss 1460,sackOK,TS val 19810369 ecr 62523,nop,wscale 7], length 0
10:20:33.078375 fa:16:3e:82:37:03 > fa:16:3e:7c:e5:ce, ethertype IPv4 (0x0800), length 66: (tos 0x0, ttl 64, id 24974, offset 0, flags [DF], proto TCP (6), length 52)
    81.1.180.14.41882 > 81.1.180.81.80: Flags [.], cksum 0x5257 (correct), seq 1, ack 1, win 3650, options [nop,nop,TS val 62525 ecr 19810369], length 0

# HTTP 資料從 81.1.180.14.41882 發到 81.1.180.81.80
10:20:33.079796 fa:16:3e:82:37:03 > fa:16:3e:7c:e5:ce, ethertype IPv4 (0x0800), length 140: (tos 0x0, ttl 64, id 24975, offset 0, flags [DF], proto TCP (6), length 126)
    81.1.180.14.41882 > 81.1.180.81.80: Flags [P.], cksum 0x1a1e (correct), seq 1:75, ack 1, win 3650, options [nop,nop,TS val 62525 ecr 19810369], length 74
10:20:33.079902 fa:16:3e:7c:e5:ce > fa:16:3e:82:37:03, ethertype IPv4 (0x0800), length 66: (tos 0x0, ttl 64, id 51655, offset 0, flags [DF], proto TCP (6), length 52)
    81.1.180.81.80 > 81.1.180.14.41882: Flags [.]^C, cksum 0x0a89 (incorrect -> 0x5f6a), seq 1, ack 75, win 227, options [nop,nop,TS val 19810371 ecr 62525], length 0

#發起 81.1.180.81.49215 > 81.1.180.12.80 的連線
10:20:33.080106 fa:16:3e:7c:e5:ce > fa:16:3e:2b:3e:2a, ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 64, id 49199, offset 0, flags [DF], proto TCP (6), length 60)
    81.1.180.81.49215 > 81.1.180.12.80: Flags [S], cksum 0x0a8f (incorrect -> 0xb04a), seq 2295826540, win 29200, options [mss 1460,sackOK,TS val 19810371 ecr 0,nop,wscale 7], length 0
10:20:33.080936 fa:16:3e:2b:3e:2a > fa:16:3e:7c:e5:ce, ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
    81.1.180.12.80 > 81.1.180.81.49215: Flags [S.], cksum 0xeeb5 (correct), seq 1301661959, ack 2295826541, win 14480, options [mss 1460,sackOK,TS val 2352200 ecr 19810371,nop,wscale 2], length 0
10:20:33.081056 fa:16:3e:7c:e5:ce > fa:16:3e:2b:3e:2a, ethertype IPv4 (0x0800), length 66: (tos 0x0, ttl 64, id 49200, offset 0, flags [DF], proto TCP (6), length 52)
    81.1.180.81.49215 > 81.1.180.12.80: Flags [.], cksum 0x0a87 (incorrect -> 0x5528), seq 1, ack 1, win 229, options [nop,nop,TS val 19810371 ecr 2352200], length 0

##傳送 HTTP 資料
#資料從 81.1.180.81.49215 發到 81.1.180.12.80
10:20:33.081264 fa:16:3e:7c:e5:ce > fa:16:3e:2b:3e:2a, ethertype IPv4 (0x0800), length 170: (tos 0x0, ttl 64, id 49201, offset 0, flags [DF], proto TCP (6), length 156)
    81.1.180.81.49215 > 81.1.180.12.80: Flags [P.], cksum 0x0aef (incorrect -> 0x06d5), seq 1:105, ack 1, win 229, options [nop,nop,TS val 19810371 ecr 2352200], length 104
10:20:33.093515 fa:16:3e:2b:3e:2a > fa:16:3e:7c:e5:ce, ethertype IPv4 (0x0800), length 66: (tos 0x0, ttl 64, id 11584, offset 0, flags [DF], proto TCP (6), length 52)
    81.1.180.12.80 > 81.1.180.81.49215: Flags [.], cksum 0x4781 (correct), seq 1, ack 105, win 3620, options [nop,nop,TS val 2352200 ecr 19810371], length 0

#資料從 81.1.180.12.80 發到 81.1.180.81.49215
10:20:33.110793 fa:16:3e:2b:3e:2a > fa:16:3e:7c:e5:ce, ethertype IPv4 (0x0800), length 96: (tos 0x0, ttl 64, id 11585, offset 0, flags [DF], proto TCP (6), length 82)
    81.1.180.12.80 > 81.1.180.81.49215: Flags [P.], cksum 0xcc98 (correct), seq 1:31, ack 105, win 3620, options [nop,nop,TS val 2352207 ecr 19810371], length 30
10:20:33.110904 fa:16:3e:7c:e5:ce > fa:16:3e:2b:3e:2a, ethertype IPv4 (0x0800), length 66: (tos 0x0, ttl 64, id 49202, offset 0, flags [DF], proto TCP (6), length 52)
    81.1.180.81.49215 > 81.1.180.12.80: Flags [.], cksum 0x0a87 (incorr