之前的blog中提到了HAProxy中的gpc0这个计数器,当时理解的不是很清楚。
后来又google了一下,找到了一篇相当有用的文档,我把我的理解写下来,希望对大家有点用处。
我们来看如下一个示例配置:
001 global
002 log 127.0.0.1 local0
003 log 127.0.0.1 local1 notice
004 stats socket /var/run/haproxy.stat mode 600 level operator
005 maxconn 4096
006 user haproxy
007 group haproxy
010 daemon
011
012 defaults
013 log global
014 mode http
015 option httplog
016 option dontlognull
017 retries 3
020 option redispatch
021 maxconn 2000
022 contimeout 5000
023 clitimeout 50000
024 srvtimeout 50000
025
026 frontend http
027 bind *:2550
030 stick-table type ip size 200k expire 10m store gpc0
031 # check the source before tracking counters, that will allow it to
032 # expire the entry even if there is still activity.
033 acl whitelist src 192.168.1.154
034 acl source_is_abuser src_get_gpc0(http) gt 0
035 use_backend ease-up-y0 if source_is_abuser
036 tcp-request connection track-sc1 src if !source_is_abuser
037
040 acl is_test1 hdr_sub(host) -i test1.com
041 acl is_test2 hdr_sub(host) -i test2.com
042
043 use_backend test1 if is_test1
044 use_backend test2 if is_test2
045
046 backend test1
047 stick-table type ip size 200k expire 30s store conn_rate(100s),bytes_out_rate(60s)
050 acl whitelist src 192.168.1.154
051 # values below are specific to the backend
052 tcp-request content track-sc2 src
053 acl conn_rate_abuse sc2_conn_rate gt 3
054 acl data_rate_abuse sc2_bytes_out_rate gt 20000000
055
056 # abuse is marked in the frontend so that it's shared between all sites
057 acl mark_as_abuser sc1_inc_gpc0 gt 0
060 tcp-request content reject if conn_rate_abuse !whitelist mark_as_abuser
061 tcp-request content reject if data_rate_abuse mark_as_abuser
062 server local_apache localhost:80
063
064 backend test2
065 stick-table type ip size 200k expire 1m store conn_rate(100s),bytes_out_rate(60s)
066 acl whitelist src 192.168.1.154
067 # values below are specific to the backend
070 tcp-request content track-sc2 src
071 acl conn_rate_abuse sc2_conn_rate gt 5
072 acl data_rate_abuse sc2_bytes_out_rate gt 20000000
073
074 # abuse is marked in the frontend so that it's shared between all sites
075 acl mark_as_abuser sc1_inc_gpc0 gt 0
076 tcp-request content reject if conn_rate_abuse !whitelist mark_as_abuser
077 tcp-request content reject if data_rate_abuse mark_as_abuser
100 server local_apache localhost:80
101
102 backend ease-up-y0
103 mode http
104 errorfile 503 /etc/haproxy/errors/503rate.http
整个配置实现如下目的:
1.根据主机头判断是test1.com还是test2.com,然后发到对应的backend服务器
2.来自192.168.1.154的访问不受访问速率限制
3.如果100秒之内平均连接速率或者发送的字节数速率超过限制,则使用ease-up-y0这个backend处理,将持续返回503错误给用户。
下边来解说一下我们关注的限速部分的配置,我将按照逻辑的顺序说明,而不是配置文件中的位置。
1.针对backend test1,我们定义一个stick-table,key类型是ip地址,表项最多200K个,表项自动过期时间3分钟,存储2个数据: 100秒内本IP新建connection的速率,60秒内本IP向外发送数据大小的比率
047 stick-table type ip size 200k expire 3m store conn_rate(100s),bytes_out_rate(60s)
stick-table中每个IP表项有50bytes大小,加上connection rate和bytes out rate各12bytes。
所以每个表项占用74bytes内存,742001024/1024*1024 ~= 14.11MBytes
所以整个stick-table占用14Mbytes内存。
- 将请求的源ip地址作为key,存入当前stick-table的sc2计数器内(官方的建议是sc0用于frontend,sc1用于backend)
052 tcp-request content track-sc2 src
如果100秒内新建连接速率大于3,则标记acl conn_rate_abuse
如果60秒内发送数据的数量大于20000000 bytes,则标记acl data_rate_abuse
053 acl conn_rate_abuse sc2_conn_rate gt 3
054 acl data_rate_abuse sc2_bytes_out_rate gt 20000000
3.接下来这段真正执行这些规则。
057 acl mark_as_abuser sc1_inc_gpc0 gt 0
060 tcp-request content reject if conn_rate_abuse !whitelist mark_as_abuser
061 tcp-request content reject if data_rate_abuse mark_as_abuser
这段配置比较晦涩难懂,但并不复杂。
gpc0是一个通用计数器,sc1_inc_gpc0是gpc0计数器增量(我们在frontend配置中使用)
060 tcp-request content reject if conn_rate_abuse !whitelist mark_as_abuser
这一行说明,无论用户违反了连接速率或者发送byte速率的限制,而且用户不在白名单中,则frontend中的gpc0计数器的值会增加。
sc1_inc_gpc0永远返回真值,根据短路求值的原则,如果conn_rate_abuse或data_rate_abuse不为真值,则mark_as_abuser规则不会被触发执行。
4.上边的gpc0计数器,会在frontend中被处理
030 stick-table type ip size 200k expire 10m store gpc0
031 # check the source before tracking counters, that will allow it to
032 # expire the entry even if there is still activity.
033 acl whitelist src 192.168.1.154
034 acl source_is_abuser src_get_gpc0(http) gt 0
035 use_backend ease-up-y0 if source_is_abuser
036 tcp-request connection track-sc1 src if !source_is_abuser
在frontend我们声明了一个stick-table,用于存储per source ip的通用计数器。如果这个计数器的值被backend增加了(大于0)
则使用ease-up-y0这个backend服务器,用户会被返回一个503错误页面。
一旦用户触发了规则,则这个source ip将不会再被跟踪,也就是说这个source ip会一直被返回503错误。
直到这个source ip表项过期,本例中是10分钟(expire 10m)。
参考文档:
http://blog.serverfault.com/2010/08/26/1016491873/