2015年3月9日

HAProxy

Server提供網路服務時,面臨到一台 Server 的 capacity 瓶頸,這時候,就可以用 L4 Load Balancer 或是 HAProxy 來進行網路分流與 load balance。

HAProxy 目前主要支援兩種 traffic,http 以及一般的 tcp,http traffic 是最主要支援的部份,HAProxy 可深入到 HTTP Traffic 的封包內容,並根據設定的條件修改封包資料。

安裝

我們可以選擇直接用 yum 安裝,目前的版本為 haproxy-1.5.2-2.el6.i686

yum install haproxy

安裝完成後,執行檔會放在 /usr/sbin 目錄中。

也可以選擇直接從 source code 編譯。

tar -zxvf haproxy-1.5.11.tar.gz
cd haproxy-1.5.11

make clean

#  linux 核心為 2.6.x 可以用使用 TARGET=linux26 參數進行最佳化,如果真的不知道可以用 TARGET=generic 即可
make TARGET=linux26 USE_OPENSSL=1 ADDLIB=-lz
make install

安裝完成後,執行檔會裝在 /usr/local/sbin 目錄中。

自行編譯後,還需要製作 service 啟動檔,這也是從 yum 安裝的 haproxy 抄來的,改一下執行檔的路徑就可以用了。

vi /etc/init.d/haproxy

#!/bin/sh
#
# haproxy
#
# chkconfig:   - 85 15
# description:  HAProxy is a free, very fast and reliable solution \
#               offering high availability, load balancing, and \
#               proxying for TCP and  HTTP-based applications
# processname: haproxy
# config:      /etc/haproxy/haproxy.cfg
# pidfile:     /var/run/haproxy.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

exec="/usr/local/sbin/haproxy"
prog=$(basename $exec)

[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog

lockfile=/var/lock/subsys/haproxy

check() {
    $exec -c -V -f /etc/$prog/$prog.cfg
}

start() {
    $exec -c -q -f /etc/$prog/$prog.cfg
    if [ $? -ne 0 ]; then
        echo "Errors in configuration file, check with $prog check."
        return 1
    fi

    echo -n $"Starting $prog: "
    # start it up here, usually something like "daemon $exec"
    daemon $exec -D -f /etc/$prog/$prog.cfg -p /var/run/$prog.pid
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    # stop it here, often "killproc $prog"
    killproc $prog 
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    $exec -c -q -f /etc/$prog/$prog.cfg
    if [ $? -ne 0 ]; then
        echo "Errors in configuration file, check with $prog check."
        return 1
    fi
    stop
    start
}

reload() {
    $exec -c -q -f /etc/$prog/$prog.cfg
    if [ $? -ne 0 ]; then
        echo "Errors in configuration file, check with $prog check."
        return 1
    fi
    echo -n $"Reloading $prog: "
    $exec -D -f /etc/$prog/$prog.cfg -p /var/run/$prog.pid -sf $(cat /var/run/$prog.pid)
    retval=$?
    echo
    return $retval
}

force_reload() {
    restart
}

fdr_status() {
    status $prog
}

case "$1" in
    start|stop|restart|reload)
        $1
        ;;
    force-reload)
        force_reload
        ;;
    check)
        check
        ;;
    status)
        fdr_status
        ;;
    condrestart|try-restart)
      [ ! -f $lockfile ] || restart
    ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|try-restart|reload|force-reload}"
        exit 2
esac

設定

設定檔會放在 /etc/haproxy/haproxy.cfg,設定內容有兩大部份,global 以及 proxy,而 proxy 中,有四個主要項目:defaults, listen, frontend 以及 backend 的部份。

global

範例

global
    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
    nbproc        1

    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats

此區塊可使用的設定項目

  • chroot
  • daemon
    以 daemon 的方式運行
  • nbproc
    daemon mode 才能使用,設定 process 的數量
  • user/uid
  • group/gid
  • log
  • pidfile
  • stats

  • maxconn
    可接受最大的連線數量

  • noepoll
    不使用 linux 的 epoll
  • nokqueue
    不使用 BSD 的 kqueue polling
  • debug
    將所有訊息顯示到 console
  • quiet
    不顯示任何訊息

獨立的 haproxy logfile

我們必須調整一些 rsyslog 的設定,才能將 haproxy 的 log 放到獨立的 logfile 裡面。

vi /etc/rsyslog.conf

# 把這兩行的註解刪除
# Provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514

# 限制 rsyslog UDP 只會用在 127.0.0.1
$UDPServerAddress 127.0.0.1

新增一個檔案 /etc/rsyslog.d/haproxy.conf

vi /etc/rsyslog.d/haproxy.conf

local2.*    /var/log/haproxy/haproxy.log

也可以用這個方式,將 log file 區分不同的 log level,要不然就放在同一個 log file 裡面就好了。

local2.=info     /var/log/haproxy-info.log
local2.notice    /var/log/haproxy-allbutinfo.log

重新啟動系統 log 記錄器

service rsyslog restart

編輯 haproxy.logrotate,讓 haproxy.log 檔案每天產生一個,然後保留 120 天的資料。

vi /etc/logrotate.d/haproxy.logrotate

/var/log/haproxy/haproxy.log {
    missingok
    notifempty
    sharedscripts
    rotate 120
    daily
    compress
    postrotate
        reload rsyslog >/dev/null 2>&1 || true
    endscript
}

proxy

proxy 設定是由 defaults, listen, frontend, backend 組成。

  • defaults name
    設定所有其他區塊的預設參數,如果設定檔中,後面又多了一塊 defaults 設定,後面的設定會覆蓋掉前面的設定。

  • frontend name
    描述接受 client 端 request 的 listening sockets。

  • backend name
    描述 proxy 會將 frontend 接收的 request 連線 forward 到後端的一組 servers。

  • listen name
    定義完整的 proxy,包含了 frontend 與 backend,這個部份的定義,通常用在設定一般的 TCP-only traffic。

proxy 定義的名稱 name ,必須要使用這些字元 upper and lower case letters, digits,
'-' (dash), '_' (underscore) , '.' (dot) and ':' (colon)。

HTTP traffic

HAProxy 針對 http traffic 提供了五種 mode

  • KAL: keep alive ("option http-keep-alive")
    這是預設值,所有處理中的 request, response 以及 connection 都會持續 idle 並保持連線。

  • TUN: tunnel ("option http-tunnel")
    只會處理第一個 request 與 response,其他封包都會直接 forward,不進行任何分析與處理,目前建議不使用這個模式,因為會對 logging 以及 HTTP processing 造成問題。

  • PCL: passive close ("option httpclose")
    就跟 tunnel mode 一樣,在處理完第一個封包後,會雙向加上 "conneciton: close",讓連線結束。

  • SCL: server close ("option http-server-close")
    在收到最後的 response 時,就會 close server-facing connection,但仍然持續保留 client-facing connection。

  • FCL: forced close ("option forceclose")
    在收到最後的 response 之後,就會關閉連線。

在一個 http connection 經過 frontend 與 backend 設定之後,可能會有兩段 proxy mode 的設定,最終這個 connection 的 mode 是由下表的規則決定,keep-alive 是最弱的設定值,而 force close 是最強的設定值。KAL < TUN < PCL < SCL < FCL

                          Backend mode

                | KAL | TUN | PCL | SCL | FCL
            ----+-----+-----+-----+-----+----
            KAL | KAL | TUN | PCL | SCL | FCL
            ----+-----+-----+-----+-----+----
            TUN | TUN | TUN | PCL | SCL | FCL
 Frontend   ----+-----+-----+-----+-----+----
   mode     PCL | PCL | PCL | PCL | FCL | FCL
            ----+-----+-----+-----+-----+----
            SCL | SCL | SCL | FCL | SCL | FCL
            ----+-----+-----+-----+-----+----
            FCL | FCL | FCL | FCL | FCL | FCL
defaults

這個區塊的參數,是設定檔後面所有參數的預設設定值,下面的設定值會蓋掉上面的。

範例

defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

此區塊可使用的設定項目

  • balance
    選擇使用那一種 algorithm 來執行 load balance。
  • mode { tcp|http|health } (defaults 為 http)
  • log global
  • option httplog
    Enable logging of HTTP request, session state and timers
  • option http-server-close
    Enable or disable HTTP connection closing on the server side
  • option forwardfor except 127.0.0.0/8
    因為 X-Forwarded-For header 裡面會有 client 的 IP,HAProxy 會利用此 header,所以增加此設定,可讓 X-Forwarded-For header 都轉送到 後端的 server
  • option redispatch
    當 client 連到掛掉的機器時, 可重新再分配
  • retries 3
    失敗重試次數
  • timeout http-request 10s
    Set the maximum allowed time to wait for a complete HTTP request,等待 HTTP Request 完成的 timeout 時間
  • timeout queue 1m
    Set the maximum time to wait in the queue for a connection slot to be free,等待 queue 釋放空間的 timeout 時間
  • timeout connect 10s
    Set the maximum time to wait for a connection attempt to a server to succeed.
  • timeout client 1m
    Set the maximum inactivity time on the client side. 當有 long polling 時,這個參數在 frontend 要調長到 long polling 最大的等待時間
  • timeout server 1m
    Set the maximum inactivity time on the server side. 當有 long polling 時,這個參數在 backend 要調長到 long polling 最大的等待時間
  • timeout http-keep-alive 10s
    Set the maximum allowed time to wait for a new HTTP request to appear
  • timeout check 10s
    Set additional check timeout, but only after a connection has been already established.
  • maxconn 3000
    連線到某個 server 的最大連線數
backend balance mode

這是 balance 設定值可選填的 algorithm 項目。

  • roundrobin
    每個 server 依據權值 weight 依序選擇 servers,這是最快的 algorithm,server weight 會根據 instance slow start 的狀況而隨時變動。這個 algorithm 在每個 backend 最多可處理 4095 個 active server nodes。如果有個 server node 在 down 之後馬上又變成 active,可能會需要數百個 requests 之後,才會再 join 這個 server farm。

  • static-rr
    每個 server 根據 weight 依序選擇 server,類似 roundrobin,但權值 weight 是固定的。沒有 active server node 的處理數量上限。

  • leastconn
    目前處理最少連線數量的 server,作為下一個 connection 轉向的 server。建議在較長 tcp session 的服務中使用這個演算法,例如 LDAP, SQL, etc...,不適合用在類似 HTTP 這種短 sesion time 的 protocol。

  • first
    server nodes 之中,選擇第一個可使用的 server,當這個 server 連線處理數量達到 maxconn 時,就會選擇下一個 server,所以設定檔中一定要有 maxconn 設定值。

  • source
    source IP address 會 hashed 並除以 total weight of running serer,用這個結果來決定要選擇那一個 server,這可確保同一個 client IP 的 traffic 會連到同一個 server。如果 server nodes 數量改變了,就會因為重新計算 hash,造成 clients 連線到不同的 servers。

  • uri
    可用 uri 的 ? 前面的部份,或是整個 uri 進行 hash,可確保同一個 uri 會轉給同一個 server。這個設定通常用在 proxy caches 與 anti-virus proxyies,用以提高 cache hit rate。

    有兩個 optinal parameter: len 與 depth。len 就是使用 uri 裡面幾個字元,但因為 uri 通常是 / 開頭,所以不要將 len 設定為 1。

    depth 表示計算 hash 的 maxmimum directory depth,出現一個 / 代表多了一層 depth。

  • url_param
    使用 HTTP Get request URL 裡面的參數,如果用到了 "check_post",就會使用 POST request 裡面的參數。

  • hdr(name)
    會尋找名稱為 name 的 HTTP header 欄位。

    optonal 參數 "use_domain_only" 可用在指定 header 為 Host 的時候,如果 Host 為 "haproxy.1wt.eu" 就只會考慮 "1wt"

  • rdp-cookie, rdp-cookie(name)
    尋找設定的 cookie,通常就是 session ID,如果沒有 session ID 就會使用 roundrobin algorithm。

一些設定的參考範例

範例 1:雖然這個是 listen 區塊,但實際上是設定一個網頁 service,提供一個 HAProxy 網頁監控界面。

# HAProxy 網頁管理界面
listen stats *:2000
    mode http
    stats enable
    stats hide-version
    stats realm Haproxy\ Statistics
    stats uri /
    # 帳號密碼
    stats auth username:password
    stats refresh 10s

範例 2:

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
    bind *:80
    mode http
    default_backend nodes

backend nodes
    mode http
    balance roundrobin
    option forwardfor
    http-request set-header X-Forwarded-Port %[dst_port]
    http-request add-header X-Forwarded-Proto https if { ssl_fc }
    option httpchk HEAD / HTTP/1.1\r\nHost:localhost
    server web01 127.0.0.1:9000 check
    server web02 127.0.0.1:9001 check
    server web03 127.0.0.1:9002 check

範例 3:

defaults
    log    global
    mode    http
    option    httplog
    option    dontlognull
    retries    3
    option redispatch
    option httpclose
    maxconn    32768
    contimeout    5000
    clitimeout    50000
    srvtimeout    50000

listen www-balancer
    bind 0.0.0.0:80
    balance         roundrobin
    server          w1 192.168.1.10:80 weight 3 check
    server          w2 192.168.1.20:80 weight 3 check
    option          httpchk GET /robots.txt
    option          forwardfor

範例 4: DB1 與 DB2 設定為 Master-Master Replication

defaults
    mode tcp
    option redispatch   #連前當前配置失敗時,允許重新配發到他台機器
    option abortonclose
    timeout connect 5000ms
    timeout client 30000ms
    timeout server 30000ms
    log 127.0.0.1 local0
    balance roundrobin   #使用輪替演算法,分散主機流量

listen proxy
    bind *:3306  #綁定192.168.11.180的3306 Port為運行主機端口
    mode tcp
    server db1 192.168.1.10:3306  weight 1 check  

    #後端主機.178,179,權重值配置

    server db2 192.168.1.20:3306  weight 2 check  

    #check 參數檢查改主機是否Live

範例 5:

defaults
    timeout server 86400000
    timeout connect 86400000
    timeout client 86400000
    timeout queue   1000s

# [HTTP Site Configuration]
listen  http_web 192.168.10.10:80
    mode http
    balance roundrobin  # Load Balancing algorithm
    option httpchk
    option forwardfor
    server server1 192.168.1.10:80 weight 1 maxconn 512 check
    server server2 192.168.1.20:80 weight 1 maxconn 512 check

# [HTTPS Site Configuration]
listen  https_web 192.168.10.10:443
    mode tcp
    balance source# Load Balancing algorithm
    reqadd X-Forwarded-Proto:\ http
    server server1 192.168.1.10:443 weight 1 maxconn 512 check
    server server2 192.168.1.20:443 weight 1 maxconn 512 check

References

富人用 L4 Switch,窮人用 Linux HAProxy!

使用 HAProxy 完成 網站分流, 平衡負載

[FreeBSD & Linux]網站分流:簡易架設 HAProxy 伺服器

使用 Haproxy 搭建高可用與負載平衡叢集