haproxy的stick table复制,haproxysticktable


在上一篇文章中,分析了haproxy的stick table特性和用法,其中特性之一也是很实用的特性是stick table支持在haproxy多个节点之间进行复制(replication)。

本文仅讨论如何配置实现stick table的复制功能,不考虑在什么环境下实现它,以及它的双主模型如何配置。

本文实验环境:

1.stick table复制特性

只要设置好haproxy的节点组,haproxy就会自动将新插入的、刚更新的stickiness记录通过TCP连接推送到节点组中的非本地节点上。这样一来,stickiness记录不会丢失,即使某haproxy节点出现了故障,其他节点也能将客户端按照粘性映射关系引导到正确的后端服务器上。

由于每条stickiness记录占用空间都很小(平均最小50字节,最大166字节,由是否记录额外统计数据以及记录多少来决定占用空间大小),使得即使在非常繁忙的环境下多个节点之间推送都不会出现压力瓶颈和网络阻塞(可以按节点数量、stickiness记录的大小和平均并发量来计算每秒在网络间推送的数据流量)。

它不像被人诟病的session复制(copy),因为session复制的数据量比较大,而且是在各应用程序服务器之间进行的。而一个稍大一点的核心应用,提供服务的应用程序服务器数量都不会小,这样复制起来很容出现网络阻塞。

此外,stick table还可以在haproxy重启时,在新旧两个进程间进行复制,这是本地复制。当haproxy重启时,旧haproxy进程会和新haproxy进程建立TCP连接,将其维护的stick table推送给新进程。这样新进程不会丢失粘性信息,和其他节点也能最大程度地保持同步,使得其他节点只需要推送该节点重启过程中新增加的stickiness记录就能完全保持同步。

如果后端使用了session共享,在大多数情况下没必要在代理层实现会话保持。如果此时使用stick table,一般只是为了收集统计数据进行采样调查,但这样的状态统计数据无需在各节点之间进行复制。

2.如何定义haproxy节点成员

haproxy提供了peers指令,用于定义节点组,peer指令用于定义节点组中的成员。

例如,定义本文测试环境的节点组:

peers my_peers    # 节点组名
    peer haproxy1 192.168.100.59:12138  # 定义对端名称,以及和对端建立tcp连接的端口,用于推送stickiness记录
    peer haproxy2 192.168.100.54:12138
    peer haproxy3 192.168.100.42:12138

然后在stick-table指令中引用节点组。例如:

stick-table type ip size 100k expire 5m peers my_peers

注意,应当让每个haproxy节点的节点组内容一致,然后使用haproxy命令的"-L"选项指定本地节点成员,这样方便管理每个节点和本地节点。

haproxy -D -L haproxy1 -f /etc/haproxy/haproxy.cfg

如果不指定"-L",则在解析配置文件时将默认以主机名作为本地节点名进行解析,但很可能它不会定义在peers中,因此会报错。

因此,如果要实现stick table的复制,还想使用sysV或systemctl管理haproxy服务,需要修改这些服务管理脚本,在启动、重启和语法检查项上加上"-L"选项。例如,systemd的haproxy服务管理脚本改为如下内容:

[root@xuexi ~]# cat /usr/lib/systemd/system/haproxy.service 
[Unit]
Description=HAProxy Load Balancer
After=syslog.target network.target

[Service]
EnvironmentFile=/etc/sysconfig/haproxy
ExecStartPre=/usr/sbin/haproxy -L haproxy2 -f /etc/haproxy/haproxy.cfg -c -q
ExecStart=/usr/sbin/haproxy-systemd-wrapper -L haproxy2 -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid $OPTIONS
ExecReload=/usr/sbin/haproxy -L haproxy2 -f /etc/haproxy/haproxy.cfg -c -q
ExecReload=/bin/kill -USR2 $MAINPID
KillMode=mixed

[Install]
WantedBy=multi-user.target

另外个人建议,每个节点要么完全使用sysV、systemctl管理haproxy的启动、停止,要么完全使用haproxy命令手动管理服务的启动和停止,否则可能会出现记录不同步的现象。至今没找到会出现这个问题的原因。

3.完成配置

如下,是每个haproxy节点的配置文件内容。

global
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     20000
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/run/haproxy.sock mode 600 level admin
    spread-checks 2

    peers mypeers 
        peer haproxy1 192.168.100.59:12138
        peer haproxy2 192.168.100.54:12138
        peer haproxy3 192.168.100.42:12138
defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    timeout http-request    2s
    timeout queue           3s
    timeout connect         1s
    timeout client          10s
    timeout server          2s
    timeout http-keep-alive 10s
    timeout check           2s
    maxconn                 18000 

frontend http-in
    bind             *:80
    mode             http
    log              global
    default_backend  dynamic_group

backend dynamic_group
    stick-table type string len 32 size 5k expire 5m peers mypeers
    stick on req.cook(PHPSESSID)
    stick store-response res.cook(PHPSESSID)
    balance roundrobin
    option http-server-close
    option httpchk     GET /index.php
    option redispatch
    http-check expect  status 200
    server app1 192.168.100.60:80 check rise 1 maxconn 3000 
    server app2 192.168.100.61:80 check rise 1 maxconn 3000

然后分别在3个节点上启动haproxy,注意加上"-L"选项。

haproxy -D -L haproxy1 -f /etc/haproxy/haproxy.cfg    # exec on haproxy1
haproxy -D -L haproxy2 -f /etc/haproxy/haproxy.cfg    # exec on haporxy2
haproxy -D -L haproxy3 -f /etc/haproxy/haproxy.cfg    # exec on haproxy3

分别在haproxy1、haproxy2、haproxy3上监控stick table。如果下面命令执行失败,见查看stick table信息。

watch -n 1 'echo "show table dynamic_group" | socat unix:/var/run/haprox.sock -'

由于上面的配置文件中,stick table中存储和匹配的记录是响应报文中名为PHPSESSID的cookie,因此在浏览器上测试时,能实现会话粘性。但如果使用curl命令进行测试,由于curl每次执行结束进程就退出,无法缓存cookie,因此curl的每次请求都是新连接。此处正好利用curl这一点特性,来生成多个stickiness记录,方便观察stick table记录推送的情况。

找一台Linux主机,分别对三个haproxy节点进行5次curl请求。

ip1=192.168.100.59
ip2=192.168.100.54
ip3=192.168.100.42
for i in $ip1 $ip2 $ip3;do
    for j in `seq 1 5`;do 
        curl http://$i/index.php &>/dev/null
        usleep 500000
    done
done

以下是截取自三个节点的stick table内容。

###################### haproxy1 ########################
# table: dynamic_group, type: string, size:5120, used:15
0x1551cc4: key=1t1lr3s5s7pm4tuu3476c40jk3 use=0 exp=286311 server_id=2
0x1551f04: key=3m3o6qkfvk8l4lenk0k8to2bd6 use=0 exp=288500 server_id=2
0x1551904: key=8bg6ej7md7453sp0rrgi5vsiu7 use=0 exp=281350 server_id=1
0x1552144: key=9c4lf1tncd290mjl7vnjafnqe2 use=0 exp=287418 server_id=2
0x1552744: key=b3gqn2i3emi43rfh3i8t0jhln4 use=0 exp=283523 server_id=1
0x15519c4: key=cskoqa8vbb7fbac4eko27hnk70 use=0 exp=281897 server_id=2
0x1550c54: key=ejjgpe1j99nv7hqmnlpib5osq6 use=0 exp=286867 server_id=1
0x1550fc4: key=immqb6ocsq8m5982o28hatk6c2 use=0 exp=285187 server_id=2
0x1550e44: key=lg78n74u0dj51m3cvkn9qhce66 use=0 exp=287953 server_id=1
0x15522c4: key=livn0t62bthpfvp5motknhb934 use=0 exp=284620 server_id=1
0x1551b44: key=mhkh0c4lpisr9kgdb3ggmplpk1 use=0 exp=285745 server_id=1
0x1552384: key=ovfoprd6p91sjbf22qo5jjd4u0 use=0 exp=289035 server_id=1
0x1552204: key=rvt3fnhr51sfrqu1aefjceqlu4 use=0 exp=282978 server_id=2
0x1550d84: key=snkm72pvasr36ut39qopd3jmb1 use=0 exp=282442 server_id=1
0x1552084: key=ucj2pkve527nt39mejp1n7jdu5 use=0 exp=284084 server_id=2

###################### haproxy2 ########################
# table: dynamic_group, type: string, size:5120, used:15
0x7fa77ec4c8a4: key=1t1lr3s5s7pm4tuu3476c40jk3 use=0 exp=278032 server_id=2
0x7fa77ec4d4e4: key=3m3o6qkfvk8l4lenk0k8to2bd6 use=0 exp=280404 server_id=2
0x7fa77ec4c2a4: key=8bg6ej7md7453sp0rrgi5vsiu7 use=0 exp=272658 server_id=1
0x7fa77ec4c424: key=9c4lf1tncd290mjl7vnjafnqe2 use=0 exp=279232 server_id=2
0x7fa77ec4be24: key=b3gqn2i3emi43rfh3i8t0jhln4 use=0 exp=275012 server_id=1
0x7fa77ec4c4e4: key=cskoqa8vbb7fbac4eko27hnk70 use=0 exp=273251 server_id=2
0x7fa77ec4c724: key=ejjgpe1j99nv7hqmnlpib5osq6 use=0 exp=278635 server_id=1
0x7fa77ec4d2a4: key=immqb6ocsq8m5982o28hatk6c2 use=0 exp=276814 server_id=2
0x7fa77ec4c964: key=lg78n74u0dj51m3cvkn9qhce66 use=0 exp=279812 server_id=1
0x7fa77ec4d664: key=livn0t62bthpfvp5motknhb934 use=0 exp=276201 server_id=1
0x7fa77ec4d7e4: key=mhkh0c4lpisr9kgdb3ggmplpk1 use=0 exp=277418 server_id=1
0x7fa77ec4c1e4: key=ovfoprd6p91sjbf22qo5jjd4u0 use=0 exp=280984 server_id=1
0x7fa77ec4d724: key=rvt3fnhr51sfrqu1aefjceqlu4 use=0 exp=274422 server_id=2
0x7fa77ec4c664: key=snkm72pvasr36ut39qopd3jmb1 use=0 exp=273842 server_id=1
0x7fa77ec4d424: key=ucj2pkve527nt39mejp1n7jdu5 use=0 exp=275620 server_id=2


###################### haproxy3 ########################
# table: dynamic_group, type: string, size:5120, used:15
0x1372c24: key=1t1lr3s5s7pm4tuu3476c40jk3 use=0 exp=276198 server_id=2
0x1372e64: key=3m3o6qkfvk8l4lenk0k8to2bd6 use=0 exp=278387 server_id=2
0x1372864: key=8bg6ej7md7453sp0rrgi5vsiu7 use=0 exp=271237 server_id=1
0x1373964: key=9c4lf1tncd290mjl7vnjafnqe2 use=0 exp=277304 server_id=2
0x1373f64: key=b3gqn2i3emi43rfh3i8t0jhln4 use=0 exp=273410 server_id=1
0x1372924: key=cskoqa8vbb7fbac4eko27hnk70 use=0 exp=271784 server_id=2
0x13723e4: key=ejjgpe1j99nv7hqmnlpib5osq6 use=0 exp=276753 server_id=1
0x13726e4: key=immqb6ocsq8m5982o28hatk6c2 use=0 exp=275073 server_id=2
0x1372564: key=lg78n74u0dj51m3cvkn9qhce66 use=0 exp=277840 server_id=1
0x1373ae4: key=livn0t62bthpfvp5motknhb934 use=0 exp=274507 server_id=1
0x1372aa4: key=mhkh0c4lpisr9kgdb3ggmplpk1 use=0 exp=275631 server_id=1
0x1373ba4: key=ovfoprd6p91sjbf22qo5jjd4u0 use=0 exp=278922 server_id=1
0x1373a24: key=rvt3fnhr51sfrqu1aefjceqlu4 use=0 exp=272865 server_id=2
0x13724a4: key=snkm72pvasr36ut39qopd3jmb1 use=0 exp=272330 server_id=1
0x13738a4: key=ucj2pkve527nt39mejp1n7jdu5 use=0 exp=273971 server_id=2

结果符合预期目标,每个表都有15条stickiness,且它们的key和对应的server_id完全相同。

有了stick table的复制功能,在没有session共享的情况下,为架构设计多提供了几种方案。至于如何选择,需要考虑与其配合的软件特性。特别适用的一种情况是,在haproxy前端使用LVS代理时,由于LVS只能4层负载,很可能将同一客户端调度到不同的haproxy节点上,如果使用stick table复制,就不用担心haproxy不能将客户端引导到同一后端服务器上的问题。另一种使用stick table复制的场景是结合keepalived实现双主模型代理不同服务时,为了会话保持也高可用,可以使用stick table的复制保证粘性记录不丢失。

 

回到Linux系列文章大纲:http://www.cnblogs.com/f-ck-need-u/p/7048359.html
回到网站架构系列文章大纲:http://www.cnblogs.com/f-ck-need-u/p/7576137.html
回到数据库系列文章大纲:http://www.cnblogs.com/f-ck-need-u/p/7586194.html
转载请注明出处:http://www.cnblogs.com/f-ck-need-u/p/8565998.html

注:若您觉得这篇文章还不错请点击右下角推荐,您的支持能激发作者更大的写作热情,非常感谢!

相关内容

    暂无相关文章