首页
About Me
推荐
weibo
github
Search
1
linuxea:gitlab-ci之docker镜像质量品质报告
49,451 阅读
2
linuxea:如何复现查看docker run参数命令
23,046 阅读
3
Graylog收集文件日志实例
18,582 阅读
4
linuxea:jenkins+pipeline+gitlab+ansible快速安装配置(1)
18,275 阅读
5
git+jenkins发布和回滚示例
18,181 阅读
ops
Openvpn
Sys Basics
rsync
Mail
NFS
Other
Network
HeartBeat
server 08
Code
Awk
Shell
Python
Golang
virtualization
KVM
Docker
openstack
Xen
kubernetes
kubernetes-cni
Service Mesh
Data
Mariadb
PostgreSQL
MongoDB
Redis
MQ
Ceph
TimescaleDB
kafka
surveillance system
zabbix
ELK Stack/logs
Open-Falcon
Prometheus
victoriaMetrics
Web
apache
Tomcat
Nginx
自动化
Puppet
Ansible
saltstack
Proxy
HAproxy
Lvs
varnish
更多
互联咨询
最后的净土
软件交付
持续集成
gitops
devops
登录
Search
标签搜索
kubernetes
docker
zabbix
Golang
mariadb
持续集成工具
白话容器
elk
linux基础
nginx
dockerfile
Gitlab-ci/cd
最后的净土
基础命令
gitops
jenkins
docker-compose
Istio
haproxy
saltstack
marksugar
累计撰写
690
篇文章
累计收到
139
条评论
首页
栏目
ops
Openvpn
Sys Basics
rsync
Mail
NFS
Other
Network
HeartBeat
server 08
Code
Awk
Shell
Python
Golang
virtualization
KVM
Docker
openstack
Xen
kubernetes
kubernetes-cni
Service Mesh
Data
Mariadb
PostgreSQL
MongoDB
Redis
MQ
Ceph
TimescaleDB
kafka
surveillance system
zabbix
ELK Stack/logs
Open-Falcon
Prometheus
victoriaMetrics
Web
apache
Tomcat
Nginx
自动化
Puppet
Ansible
saltstack
Proxy
HAproxy
Lvs
varnish
更多
互联咨询
最后的净土
软件交付
持续集成
gitops
devops
页面
About Me
推荐
weibo
github
搜索到
12
篇与
的结果
2019-06-14
linuxea: HAproxy1.9 Docker 镜像
在此前的几篇文章在中,简单的记录了haproxy在1.9之后的一些变化(部分来自谷歌翻译),这其中包括多线程,Runtime API, ACL,配置文件,以及日志和统计页面和map。在这篇文章中,我将简单叙述haproxy的docker配置,我重构了haproxy的docker配置,作为简单的使用中,可以重载配置文件。这借用了supervisor与inotifywait的配置。一旦配置文件发生改变,就会自动进行reloadDockerfile我们在原本的dockerfile中安装inotify-tools supervisor socat。并且创建用户和编译halog,如果你阅读过此前的文章,相信你已经知道这些的作用了FROM alpine:3.9 ENV HAPROXY_VERSION 1.9.8 ENV HAPROXY_URL https://www.haproxy.org/download/1.9/src/haproxy-1.9.8.tar.gz ENV HAPROXY_SHA256 2d9a3300dbd871bc35b743a83caaf50fecfbf06290610231ca2d334fd04c2aee ENV USER=haproxy ENV USID=401 # entrypoint.sh start scripts And supervisord.conf file ADD entrypoint.sh /bin/entrypoint.sh ADD supervisord.conf /etc/supervisord.conf # see https://sources.debian.net/src/haproxy/jessie/debian/rules/ for some helpful navigation of the possible "make" arguments RUN set -x \ \ && apk add --no-cache --virtual .build-deps \ ca-certificates \ gcc \ libc-dev \ linux-headers \ lua5.3-dev \ make \ openssl \ openssl-dev \ pcre-dev \ readline-dev \ tar \ zlib-dev \ py-pip \ \ && addgroup -g ${USID} -S ${USER} \ && adduser -HDu ${USID} -s /sbin/nologin -g 'haproxy server' -G ${USER} ${USER} \ && wget -O haproxy.tar.gz "$HAPROXY_URL" \ && echo "$HAPROXY_SHA256 *haproxy.tar.gz" | sha256sum -c \ && mkdir -p /usr/src/haproxy /usr/local/haproxy /var/run \ && tar -xzf haproxy.tar.gz -C /usr/src/haproxy --strip-components=1 \ && rm haproxy.tar.gz \ \ && makeOpts=' \ TARGET=linux2628 \ USE_LUA=1 LUA_INC=/usr/include/lua5.3 LUA_LIB=/usr/lib/lua5.3 \ USE_GETADDRINFO=1 \ USE_OPENSSL=1 \ USE_PCRE=1 PCREDIR= \ USE_ZLIB=1 \ PREFIX=/usr/local/haproxy \ ' \ && make -C /usr/src/haproxy -j "$(getconf _NPROCESSORS_ONLN)" all $makeOpts \ && make -C /usr/src/haproxy install-bin $makeOpts \ && make -C /usr/src/haproxy/contrib/halog halog \ \ && mkdir -p /usr/local/etc/haproxy \ && cp -R /usr/src/haproxy/examples/errorfiles /usr/local/etc/haproxy/errors \ && cp /usr/src/haproxy/contrib/halog/halog /bin/halog \ && rm -rf /usr/src/haproxy \ && ln -s /usr/local/haproxy/sbin/haproxy /bin/haproxy \ \ && runDeps="$( \ scanelf --needed --nobanner --format '%n#p' --recursive /usr/local \ | tr ',' '\n' \ | sort -u \ | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ )" \ && apk add --virtual .haproxy-rundeps $runDeps inotify-tools supervisor socat bash \ && pip install supervisor-stdout \ && apk del .build-deps \ && rm -rf /var/cache/apk/* \ && chmod +x /bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"]Supervisord在Supervisord守护进程中,使用-w -s启动command=/bin/sh -c "exec haproxy -W -S /var/run/haproxy.sock -f /etc/haproxy/haproxy.cfg -db"并且监控配置文件变化,如果变化则进行reloadcommand=sh -c 'while inotifywait -q -r -e create,delete,modify,move,attrib --exclude "/\." /etc/haproxy/haproxy.cfg; do echo "reload" |socat /var/run/haproxy.sock -; done'haproxy.cfgglobal log /dev/log local0 chroot /usr/local/haproxy stats socket /var/run/haproxy.sock mode 600 level admin stats timeout 2m maxconn 4096 ###每个进程的最大连接数,默认4000 user haproxy #用户组 group haproxy daemon ###创建1个进程进入deamon模式运行。此参数要求将运行模式设置为"daemon" nbproc 1 #设置启动进程数,默认是1 nbthread 4 #4个线程 cpu-map auto:1/1-4 0-3 # 绑定cpu profiling.tasks on defaults mode http ###默认的模式mode { tcp|http|health },tcp是4层,http是7层,health只会返回OK log global ###采用全局定义的日志 option dontlognull ###不记录健康检查的日志信息,日志不会记录空连接 option httpclose ###每次请求完毕后主动关闭http通道 option httplog ###访问日志类别http日志格式 option forwardfor ###如果后端服务器需要获得客户端真实ip需要配置的参数,可以从Http Header中获得客户端ip option abortonclose #当服务器负载很高的时候,自动结束掉当前队列处理比较久的链接 option redispatch ###当使用了cookie时,haproxy将会将请求的后端服务器的server id插入到cookie中,以保证会话的session持久性,而此时,如果后端服务器宕机,但是客户端的cookie是不会刷新的,如果设置此参数,将会将客户的请求强制定向到另外一个后端的server上继续会话。 timeout connect 5000ms #default 10 second timeout if a backend is not found timeout client 500000 ###客户端连接超时 timeout server 500000 ###服务器返回的响应时间 maxconn 100000 ###最大连接数 retries 3 ###。重试时间。3次连接失败就认为服务不可用,也可以通过后面设置 listen stats mode http bind *:1080 #监听端口 stats refresh 30s #统计页面自动刷新时间 stats uri /stats #统计页面url stats realm Haproxy Manager #统计页面密码框上提示文本 stats auth admin:admin #统计页面用户名和密码设置 stats hide-version #隐藏统计页面上HAProxy的版本信息 #--------------------------------------------------------------------- frontend frontend-web.com bind *:2379 mode http option httplog acl in_network src 10.0.0.0/8 acl is_map_add path_beg /map/add http-request set-map(/etc/haproxy/maps/hosts.map) %[url_param(domain)] %[url_param(backend)] if is_map_add in_network http-request deny deny_status 200 if { path_beg /map/ } stick-table type binary len 8 size 1m expire 10s store http_req_rate(10s) http-request track-sc0 base32+src http-request set-var(req.rate_limit) path,map_beg(/etc/haproxy/maps/rates.map) http-request set-var(req.request_rate) base32+src,table_http_req_rate(frontend-web.com) acl rate_abuse var(req.rate_limit),sub(req.request_rate) lt 0 http-request deny deny_status 429 if rate_abuse acl is_static path -i -m beg /static use_backend %[str(active),map(/etc/haproxy/maps/hosts.map)] log global default_backend A-backend-linuxea.com log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r" #--------------------------------------------------------------------- frontend tcp_app default_backend C-backend-linuxea.com mode http bind *:2380 backend A-backend-linuxea.com option forwardfor header X-REALL-IP #获取后端ip option httpchk HEAD / HTTP/1.0 http-check expect rstatus (2|3)[0-9][0-9] http-check disable-on-404 default-server inter 3s fall 3 rise 2 balance roundrobin #负载均衡算法:roundrobin:轮询 source:源ip hash leastconn:最小连接数 server etcd1 172.25.6.37:81 check server etcd2 172.25.10.245:81 check server etcd3 172.25.50.250:81 check backend B-backend-linuxea.com option forwardfor header X-REALL-IP option httpchk HEAD / HTTP/1.0 balance roundrobin server etcd2 172.25.10.35:83 check inter 2000 rise 30 fall 15 backend C-backend-linuxea.com option tcp-check balance roundrobin server redis 172.25.8.23:6379 check port 6379 server mysql 172.25.8.23:3306 check port 3306docker-compose.yml而后编辑haproxy的compose文件即可version: '3.7' services: haproxy: image: marksugar/haproxy:1.9.8 container_name: haproxy #privileged: true restart: always network_mode: "host" volumes: - /etc/localtime:/etc/localtime:ro - /etc/haproxy:/etc/haproxy ports: - "2379:2379" - "1080:1080" logging: driver: "json-file" options: max-size: "1G"快速部署curl -Lks https://raw.githubusercontent.com/marksugar/dockerMops/master/docker-haproxy/haproxy-1.9.8/deploy-1.9.8.sh |bash延伸阅读linuxea:haproxy 1.9中的多线程linuxea:haproxy1.9 了解四个基础部分linuxea:haproxy1.9日志简介linuxea: 使用HAproxy 1.9 Runtime API进行动态配置linuxea: 探索 HAproxy 1.9 统计页面linuxea: HAproxy 1.9 ACL简介
2019年06月14日
2,914 阅读
0 评论
0 点赞
2019-06-12
linuxea: HAproxy Maps简介 蓝绿部署
HAProxy映射文件存储键值对,并且是一些创造性行为的起点,包括动态速率限制和蓝绿色部署。字典。Map。哈希值。关联数组。这些列为HAProxy负载均衡器的广泛功能集。它们被称为map。想要设置蓝绿色部署?也许你想通过URL路径设置速率限制?如何动态切换哪些后端服务器用于域?这一切都是用map完成的!在本文中,你将学习如何创建map文件,将其存储在系统中,在HAProxy配置中引用它,并实时更新。你还将看到一些有用的场景,可以充分利用你的新知识。入门在考虑使用Map文件可以做的有趣事情之前,让我们围绕Map文件进行思考。map file一切都始于创建一个map文件。创建名为hosts.map的文件。然后添加以下行:[root@www.linuxea.com ~]# mkdir /etc/haproxy/maps/[root@www.linuxea.com ~]# cat /etc/haproxy/maps/hosts.map static.linuxea.com be_static www.linuxea.com be_static linuxea.com be_static api.linuxea.com be_api有关此文件结构的一些注意事项:这是纯文本每行一个Key一个value出现在一个键之后,由至少一个空格隔开(例如be_static)单词之间的空行和额外空格将被忽略注释必须以#号开头,并且必须在各自的行开头映射文件存储键值对。 HAProxy将它们用作查找表,例如根据Host标头的值找出将客户端路由到哪个后端。将此关联存储在文件而不是HAProxy配置本身的好处是能够动态更改这些值。接下来,将此文件传输到服务器测试,并将其放入你选择的目录中。 HAProxy启动时会加载映射文件,但正如你将看到的那样,它们可以在运行时修改而无需重新加载Map Converters为了更好的了解可以对映射文件执行的操作,让我们看一下使用一个来查找应该发送用户的正确后端服务器池。你将使用先前创建的hosts.map文件来查找应根据给定域名使用哪个后端。首先编辑haproxy.cfg文件。正如你将看到的,你将添加一个读取map文件并返回后端名称的Map Converters。 use_backend %[str(linuxea.com),map(/etc/haproxy/maps/hosts.map)]将linuxea.com作为键的hosts.map中的第一行将返回其值。注意输入str(linuxea.com)如何从表达式开始并用逗号分隔转换器。在运行时计算此表达式时,它将转换为use_backend be_static行,该行将请求定向到be_static服务器池。当然,你可以发送HTTP标头或URL参数的值,而不是传递像linuxea.com这样的硬编码字符串。下一个示例使用Host标头的值作为输入。use_backend %[req.hdr(host),lower,map(/etc/haproxy/maps/hosts.map,be_static)]map converters最多需要两个参数。第一个是map文件的路径。第二个可选参数声明了一个默认值,如果找不到匹配的键,将使用该值。所以,在这种情况下,如果没有匹配,be_static将被使用。如果输入匹配Map文件中的多个项目,HAProxy将返回第一个项目。map converters在文件中查找完全匹配,但有一些变体为部分匹配提供了机会。这里总结了最常用的:|-------------------------------------------------------------------------------------------------------------------------------------- |map_beg :在Map文件中查找与输入开头匹配的条目(例如,“abcd”的输入将匹配文件中的“a”)。 |map_end :在映射文件中查找与输入结尾匹配的条目(例如,“abcd”的输入将匹配文件中的“d”)。 | 与其他匹配模式不同,这不执行ebtree查找,而是检查每一行。 |-------------------------------------------------------------------------------------------------------------------------------------- |map_sub :在映射文件中查找构成样本子字符串的条目(例如,“abcd”的输入将与文件中的“ab”或“c”匹配)。 | 与其他匹配模式不同,这不执行ebtree查找,而是检查每一行。 |-------------------------------------------------------------------------------------------------------------------------------------- |map_ip :这将输入作为IP地址并在Map中查找。如果Map中有掩码(例如192.168.0.0/16),则该范围内的任何IP都将匹配它。 | 如果输入类型是IP地址,则这是默认值。 |-------------------------------------------------------------------------------------------------------------------------------------- |map_reg :这会将Map中的样本作为正则表达式读取,如果正则表达式匹配则匹配。与其他匹配模式不同,这不会执行ebtree查找,而是检查每一行。 |map_str :别名map。这将一个字符串作为输入,匹配整个键,并返回一个值作为字符串 |--------------------------------------------------------------------------------------------------------------------------------------修改值map file的好处在于更新他们,比如从一个后端更改到另外一个后端来进行维护。其中有四种方法修改。1 ,直接编辑文件。但是需要重新加载haproxy(1.8已经引入了无中断重载),假如你使用的是puppet或ansible,那么这将会是一个不错的选择2,企业版haproxy支持lb-update3,Runtime API修改,无需重新加载haproxy4,使用http-request set-map配置文件的指令。这使你有机会根据请求中的URL参数更新映射条目。很容易将其转换为方便的基于HTTP的界面,以便从远程客户端进行Map文件更改。在这里重点介绍Runtime API编辑使用Runtime API进行编辑回顾我们之前的博客文章,使用HAProxy Runtime API动态配置,你将看到有几种API方法可用于更新现有的映射文件。API方法 描述 show map :列出可用的Map文件或显示Map文件的内容。 get map :报告与给定输入匹配的键和值。 set map :修改Map条目。 add map :添加Map条目。 del map :删除Map条目。 clear map :删除映射文件中的所有条目。没有任何参数,show map列出加载到内存中的映射文件。如果给它指向特定文件的路径,它将显示其内容。在以下示例中,我们使用它来显示hosts.map中的键值对。[root@www.linuxea.com ~]# echo "@1; show map /etc/haproxy/maps/hosts.map"| socat stdio /var/run/haproxy.sock 0x14381b0 static.linuxea.com be_static 0x1438c20 www.linuxea.com be_static 0x1438ca0 linuxea.com be_static 0x1438d20 api.linuxea.com be_api第一列是条目的位置,通常被忽略。第二列是要匹配的键,第三列是值。我们可以通过Runtime API轻松添加和删除条目。要从Map文件中删除条目,请使用del map。请注意,这只会将其从内存中删除,而不是从实际文件中删除。[root@www.linuxea.com ~]# echo "@1; del map /etc/haproxy/maps/hosts.map linuxea.com"| socat stdio /var/run/haproxy.sock [root@www.linuxea.com ~]# echo "@1; show map /etc/haproxy/maps/hosts.map"| socat stdio /var/run/haproxy.sock 0x14381b0 static.linuxea.com be_static 0x1438c20 www.linuxea.com be_static 0x1438d20 api.linuxea.com be_api你还可以删除所有条目clear map:[root@www.linuxea.com ~]# echo "@1; clear map /etc/haproxy/maps/hosts.map "| socat stdio /var/run/haproxy.sock [root@www.linuxea.com ~]# echo "@1; show map /etc/haproxy/maps/hosts.map"| socat stdio /var/run/haproxy.sock [root@www.linuxea.com ~]# 添加新密钥和值add map:[root@www.linuxea.com ~]# echo "@1; add map /etc/haproxy/maps/hosts.map linuxea.com be_stats "| socat stdio /var/run/haproxy.sock [root@www.linuxea.com ~]# echo "@1; show map /etc/haproxy/maps/hosts.map"| socat stdio /var/run/haproxy.sock 0x1438d20 linuxea.com be_stats 更改现有条目set map:[root@www.linuxea.com ~]# echo "@1; set map /etc/haproxy/maps/hosts.map linuxea.com dev "| socat stdio /var/run/haproxy.sock [root@www.linuxea.com ~]# echo "@1; show map /etc/haproxy/maps/hosts.map"| socat stdio /var/run/haproxy.sock 0x1438d20 linuxea.com dev [root@www.linuxea.com ~]# 使用show map,我们可以获取文件的内容,使用awk将其过滤到第二和第三列,然后将内存中的表示保存回磁盘:[root@www.linuxea.com ~]# echo "@1; show map /etc/haproxy/maps/hosts.map"| socat stdio /var/run/haproxy.sock | awk '{print $2" "$3}' > /etc/haproxy/maps/hosts.map [root@www.linuxea.com ~]# cat /etc/haproxy/maps/hosts.map linuxea.com dev操作也可以用分号链接在一起,这样可以轻松编写更改脚本并保存结果:[root@www.linuxea.com ~]# echo "@1; clear map /etc/haproxy/maps/hosts.map; add map /etc/haproxy/maps/hosts.map bar.linuxea.com be_foo; add map /etc/haproxy/maps/hosts.map foo.linuxea.com be_baz" | socat stdio /var/run/haproxy.sock[root@www.linuxea.com ~]# echo "@1; show map /etc/haproxy/maps/hosts.map"| socat stdio /var/run/haproxy.sock 0x1438d20 bar.linuxea.com be_foo 0x14381b0 foo.linuxea.com be_baz如果你通过多个进程分配HAProxy,则nbproc需要为每个进程配置一个套接字,然后运行循环以单独更新每个进程。使用多线程时这不是问题使用http-request set-map假设你不想手动编辑文件或使用Runtime API。相反,你希望能够使用特定的URL参数发出HTTP请求,并更新你的Map文件。在那种情况下,http-request set-map是你的首选。这允许使用fetches,converters和ACL来决定何时以及如何在运行时更改映射条件。除了set-map,还有del-map,它允许你以相同的方式删除map条目。与Runtime API一样,这些更改也仅适用于请求最终执行的进程。将map文件的路径传递给set-map,并使用要添加或更新的键和值(用空格分隔)。 key和value都支持日志格式表示法,所以你可以将它们指定为普通字符串或使用提取和转换器。例如,要向hosts.map文件添加新条目,但前提是源地址属于在192.168.122.0/24范围内,你可以使用如下配置:frontend linuxea.com bind :80 acl in_network src 192.168.122.0/24 acl is_map_add path_beg /map/add http-request set-map(/etc/haproxy/maps/hosts.map) %[url_param(domain)] %[url_param(backend)] if is_map_add in_network http-request deny deny_status 200 if { path_beg /map/ } use_backend %[req.hdr(host),lower,map(/etc/haproxy/maps/hosts.map)]这将允许你发出Web请求,例如http://192.168.122.64/map/add?domain=example.com&backend=be_static,以便快速轻松地更新maps。如果该条目已存在,则将更新。请注意,你可以使用http-request deny deny_status 200来阻止请求转到后端服务器。http-request del-map命令后跟要从映射文件中删除的密钥acl is_map_del path_beg /map/delete http-request del-map(/etc/haproxy/maps/hosts.map) %[url_param(domain)] if is_map_del in_network使用你之前看到的show map技术,你可以安排一个cron作业来每隔几分钟保存一次Map文件。但是,如果你需要跨HAProxy的多个实例复制这些更改,使用其他方法之一将是一个更好的选择。控制何时设置或删除条目的另一种方法是检查请求的方法,然后设置条目(如果它是POST或PUT)。如果是DELETE,则删除条目。测试下:[root@www.linuxea.com ~]# echo "@1; show map /etc/haproxy/maps/hosts.map"| socat stdio /var/run/haproxy.sock 0x9d74a0 linuxea.com dev我们更新一个http://172.25.10.245:2379/map/add?domain=linuxea.com&backend=B-backend-linuxea.com[root@www.linuxea.com ~]# echo "@1; show map /etc/haproxy/maps/hosts.map"| socat stdio /var/run/haproxy.sock 0x9d74a0 linuxea.com B-backend-linuxea.com在做一次测试配置修改如下: acl in_network src 10.0.0.0/8 acl is_map_add path_beg /map/add http-request set-map(/etc/haproxy/maps/hosts.map) %[url_param(domain)] %[url_param(backend)] if is_map_add in_network http-request deny deny_status 200 if { path_beg /map/ } use_backend %[str(active),map(/etc/haproxy/maps/hosts.map)]reload[root@www.linuxea.com ~]# echo "reload" | socat stdio /var/run/haproxy.sockhaproxy的配置如下:backend A-backend-linuxea.com option forwardfor header X-REALL-IP #获取后端ip option httpchk HEAD / HTTP/1.0 balance roundrobin #负载均衡算法:roundrobin:轮询 source:源ip hash leastconn:最小连接数 server etcd1 172.25.6.37:81 check inter 2000 rise 30 fall 15 server etcd2 172.25.10.245:81 check inter 2000 rise 30 fall 15 server etcd3 172.25.50.250:81 check inter 2000 rise 30 fall 15 backend B-backend-linuxea.com option forwardfor header X-REALL-IP option httpchk HEAD / HTTP/1.0 balance roundrobin server etcd2 172.25.10.35:83 check inter 2000 rise 30 fall 15修改下:http://172.25.10.245:2379/map/add?domain=active&backend=B-backend-linuxea.com现在active的是 B-backend-linuxea.com[root@www.linuxea.com ~]# echo "@1; show map /etc/haproxy/maps/hosts.map"| socat stdio /var/run/haproxy.sock 0x1e6b450 linuxea.com dev 0x7f748c027820 active B-backend-linuxea.com蓝绿部署假设你希望实施蓝绿部署,其中你可以将Web应用程序的新版本部署到一组临时服务器上,然后将它们与一组生产服务器交换。你可以创建一个名为bluegreen.map的文件并添加一个条目[root@www.linuxea.com ~]# cat /etc/haproxy/maps/bluegreen.map active A-backend-linuxea.com在这种情况下,A-backend-linuxea.com backend包含你当前活动的生产服务器集。这是HAProxy配置文件:backend A-backend-linuxea.com option forwardfor header X-REALL-IP #获取后端ip option httpchk HEAD / HTTP/1.0 balance roundrobin server etcd1 172.25.6.37:81 check inter 2000 rise 30 fall 15 server etcd2 172.25.10.245:81 check inter 2000 rise 30 fall 15 server etcd3 172.25.50.250:81 check inter 2000 rise 30 fall 15 backend B-backend-linuxea.com option forwardfor header X-REALL-IP option httpchk HEAD / HTTP/1.0 balance roundrobin server etcd2 172.25.10.35:83 check inter 2000 rise 30 fall 15将新版本的应用程序部署到A-backend-linuxea.com服务器并对其进行测试后,可以使用Runtime API将活动A-backend-linuxea.com服务器与B-backend-linuxea.com服务器交换,从而使B-backend-linuxea.com服务器在生产中变为活动状态。将业务修改到B-backend-linuxea.com19332> set map /etc/haproxy/maps/bluegreen.map active B-backend-linuxea.com观察。现在,你的流量将从A-backend-linuxea.com服务器转移到B-backend-linuxea.com服务器。与滚动部署不同,这可确保你的所有用户同时迁移到新版本的应用程序。[root@www.linuxea.com ~]# while true;do curl 172.25.10.245:2379 && sleep 1;done 172.25.50.250 172.25.6.37 172.25.10.245 172.25.50.250 172.25.6.37 172.25.10.245 172.25.50.250 172.25.10.35 is ok 172.25.10.35 is ok 172.25.10.35 is ok 172.25.10.35 is ok 172.25.10.35 is ok 172.25.10.35 is ok 172.25.10.35 is ok按URL路径限制速率对于此示例,你将为你的网站设置速率限制。使用映射文件可以为不同的URL设置不同的限制。例如,与开始的URL /api/old可以允许比那些与开始了更高的要求速度/api/new。添加名为rates.map的Map文件并添加以下条目:/api/old 40 /api/new 20[root@www.linuxea.com ~]# mkdir /etc/haproxy/maps/ -p [root@www.linuxea.com ~]# cat > /etc/haproxy/maps/rates.map << EOF /api/old 40 /api/new 20 EOF正常情况下你将分别看到172.25.10.35 old 172.25.10.35 new考虑以下内容frontend,其中每个客户端的当前请求率在10秒内测量。像/api/old这样的URL路径每秒最多允许四个请求(40个请求/ 10秒= 4个rps)。frontend frontend-web.com bind :80 default_backend A-backend-linuxea.com # Set up stick table to track request rates # 设置跟踪请求率 stick-table type binary len 8 size 1m expire 10s store http_req_rate(10s) # Track client by base32+src (Host header + URL path + src IP) # 通过base32 + src跟踪客户端(主机头+ URL路径+ src IP) http-request track-sc0 base32+src # Check map file to get rate limit for path # 检查映射文件以获取路径的速率限制 http-request set-var(req.rate_limit) path,map_beg(/etc/haproxy/maps/rates.map) # Client's request rate is tracked # 跟踪客户的请求率 http-request set-var(req.request_rate) base32+src,table_http_req_rate(frontend-web.com) # Subtract the current request rate from the limit # If less than zero, set rate_abuse to true #从限制中减去当前请求率 #如果小于零,则将rate_abuse设置为true acl rate_abuse var(req.rate_limit),sub(req.request_rate) lt 0 # Deny if rate abuse # 拒绝率滥用 http-request deny deny_status 429 if rate_abuse这里,stick-table定义记录十秒钟内的客户请求率。请注意,我们使用base32 + src fetch方法跟踪客户端,该方法是Host头,URL路径的组合,URL路径和源IP地址。这允许我们基于每个路径跟踪每个客户端的请求率。 base32 + src值作为二进制数据存储在base32+src中。然后,使用http-request set-var设置两个变量。第一个req.rate_limit设置为rates.map文件中当前路径的预定义速率限制。第二个req.request_rate设置为客户端的当前请求率ACL rate_abuse进行计算以查看客户端的请求率是否高于此路径的限制。它通过从请求限制中减去请求率并检查差异是否小于零来完成此操作。如果是,则http-request deny指令以429 Too Many Requests响应/api/old/[root@www.linuxea.com ~]# while true;do curl 172.25.10.245:2379/api/old/ ; done 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old 172.25.10.35 old <html><body><h1>429 Too Many Requests</h1> You have sent too many requests in a given amount of time. </body></html> <html><body><h1>429 Too Many Requests</h1> You have sent too many requests in a given amount of time. </body></html> <html><body><h1>429 Too Many Requests</h1> You have sent too many requests in a given amount of time. </body></html> <html><body><h1>429 Too Many Requests</h1> /api/new[root@www.linuxea.com ~]# while true;do curl 172.25.10.245:2379/api/new/ ; done 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new 172.25.10.35 new <html><body><h1>429 Too Many Requests</h1> You have sent too many requests in a given amount of time. </body></html> <html><body><h1>429 Too Many Requests</h1> You have sent too many requests in a given amount of time. </body></html> <html><body><h1>429 Too Many Requests</h1> You have sent too many requests in a given amount of time.延伸阅读linuxea:haproxy 1.9中的多线程linuxea:haproxy1.9 了解四个基础部分linuxea:haproxy1.9日志简介linuxea: 使用HAproxy 1.9 Runtime API进行动态配置linuxea: 探索 HAproxy 1.9 统计页面linuxea: HAproxy 1.9 ACL简介
2019年06月12日
3,779 阅读
0 评论
0 点赞
2019-06-11
linuxea: HAproxy 1.9 ACL简介
通过HAProxy ACL,你可以定义用于阻止恶意请求,选择后端,重定向到HTTPS以及使用缓存对象的自定义规则。当相关人员将负载均衡器添加到他们的基础架构中时,他们正在寻找能够扩展其网站和服务,获得更好的可用性以及获得更多宁静的夜晚,因为他们知道他们的关键服务不再是单点故障。然而,不久之后,他们意识到使用像HAProxy 这样的负载均衡器,他们可以智能的来检查传入的流量并在运行中做出决策。例如,你可以限制谁可以访问各种端点,将非https流量重定向到https,检测并阻止恶意机器和扫描程序,以及定义添加HTTP标头,更改URL或重定向用户的条件HAProxy中的访问控制列表或ACL允许你测试各种条件并根据这些测试执行给定操作。这些条件几乎涵盖了请求或响应的任何方面,例如在其中搜索字符串或模式,检查它们来自的IP,最近的请求率(via stick tables),TLS状态等。你采取的操作可以包括制作路由决策,重定向请求,返回静态响应等等。在使用逻辑运算符(AND,OR,NOT)在其他代理解决方案可能会很麻烦,HAProxy的ACL包含它们以形成更复杂的条件。格式化ACL有两种指定ACL的方法 - 命名ACL和匿名或内联ACL第一种形式是命名ACL:acl is_static path -i -m beg /static我们从acl关键字开始,后跟名称,后跟条件。这里我们有一个名为is_static的ACL。然后,此ACL名称可以与if和unless语句一起使用,例如use_backend be_static if is_static。当你要将给定条件用于多个操作时,建议使用此表单acl is_static path -i -m beg /static use_backend be_static if is_static他的条件,路径-i -m beg / static,检查URL是否以/ static开头。你将在本文后面看到它如何与其他类型的条件一起使用use_backend be_static if { path -i -m beg /static }这与上面两行所做的相同,只是在一行中。对于内联ACL,条件包含在花括号内。在这两种情况下,你可以将多个条件链接在一起。 ACL之间一个接一个地列出,其间没有任何内容将被认为是和一个和。如果两个ACL都为真,则整体条件才为真。http-request deny if { path -i -m beg /api } { src 10.0.0.0/16 }这将阻止10.0.0.0/16子网中的任何客户端访问以/ api开头的任何内容,同时仍能访问其他路径。添加感叹号会反转条件:http-request deny if { path -i -m beg /api } !{ src 10.0.0.0/16 }现在只允许10.0.0.0/16子网中的客户端访问以/ api开头的路径,而禁止所有其他路径。也可以从文件导入IP地址:http-request deny if { path -i -m beg /api } { src -f /etc/haproxy/blacklist.acl }在blacklist.acl中,你将使用CIDR表示法列出单个或一系列IP地址,如下所示:192.168.122.3 192.168.122.0/24你还可以使用||定义一个条件可以为真的ACL:http-request deny if { path -i -m beg /evil } || { path -i -m end /evil }这样,每个请求的路径以/evil开头(例如/evi/foo)或以/ evil结尾(例如/foo/evil)将被拒绝你也可以执行相同的操作来组合命名ACL:acl starts_evil path -i -m beg /evil acl ends_evil path -i -m end /evil http-request deny if starts_evil || ends_evil对于命名ACL,多次指定相同的ACL名称将导致条件的逻辑OR,因此最后一个块也可以表示为:acl evil path_beg /evil acl evil path_end /evil http-request deny if evil这允许你组合AND和OR(以及命名和内联ACL)来构建更复杂的条件,例如:http-request deny if evil !{ src 10.0.0.0/16 }如果路径以/evil开头或结尾,这将阻止请求,但仅限于不在10.0.0.0/16子网中的客户端。诸如弹性二叉树或EB树等保持ACL有着高性能特征。 例如,字符串和IP地址匹配依赖于EB树,这些EB树允许ACL处理数百万个条目,同时保持HAProxy最佳性能和效率。从我们到目前为止看到的情况来看,每个ACL条件分为两部分 - 信息源(或获取),例如path和src以及它匹配的字符串。在这两个部分的中间,一个可以指定Flags(例如-i用于不区分大小写的匹配)和匹配方法(例如,请求在字符串的开头匹配)。 ACL的所有这些组件将在以下部分中进行扩展Fetches现在你已了解格式化ACL的基本方法,你可能希望了解可用于制定决策的信息源。 HAProxy中的信息源称为fetch,这些允许ACL获取要处理的信息以下是一些更常用的Fetches:src : 返回发出请求的客户端IP地址 path : 返回客户端请求的路径 url_param(foo) : 返回给定URL参数的值 req.hdr(foo) : 返回给定HTTP请求标头的值(例如,User-Agent或Host) ssl_fc : 如果连接是通过SSL进行的,则返回true的布尔值,HAProxy在本地解密它Converters通过Fetches获得一条信息后,你可能希望对其进行转换。Converters由逗号分隔,如果你有多个Converters,则可以与其他Converters分隔,并且可以多次链接在一起。某些Converters(例如lower和upper)由它们自己指定,而其他Converters则传递给它们。如果需要参数,则在括号中指定。例如,要获取从/static的路径的值,删除,你可以使用带有正则表达式和替换的regsub Converters作为参数:path,regsub(^/static,/)与Converters一样,有各种各样的Converters,但下面是一些比较流行的Converters:lower :将示例的大小写更改为小写 upper :将示例的大小写更改为大写 base64 :Base64对指定的字符串进行编码(适用于匹配二进制样本) field :允许你Fetches类似于awk的字段。例如,如果你将“a | b | c”作为样本并在其上运行字段(|,3),则将留下“c” bytes :给定偏移量和长度作为参数,从输入二进制样本中Fetches一些字节 map :在指定的映射文件中查找示例并输出结果值Flags你可以在单个ACL中放置多个Flags,例如:path -i -m beg -f /etc/haproxy/paths_secret.acl这将基于路径的开头执行不区分大小写的匹配,并与存储在指定文件中的模式进行匹配。没有像获取/Converters类型那样多的Flags,但是有很多种类。以下是一些常用的:-i :执行不区分大小写的匹配(因此FoO的样本将匹配Foo的模式) -f :而不是匹配字符串,匹配ACL文件。此ACL文件可以包含IP,字符串,正则表达式等列表。只要列表不包含正则表达式,该文件就会被加载到b-tree格式中,几乎可以立即处理数百万个项目的查找 -m :指定匹配类型。这将在下一节中详细介绍。如果从文档的ACL Basics部分向下滚动,你会发现其他几个Matching methods现在你有一个来自Converters和fetches的示例,例如通过路径请求的URL路径,以及通过硬编码路径/evil匹配的内容。要将前者与后者进行比较,你可以使用几种匹配方法中的一种。和以前一样,有很多匹配方法,你可以通过向下滚动(除了Flags之外)在文档的ACL Basics部分中查看完整列表。以下是一些常用的匹配方法:str :执行精确的字符串匹配 beg :使用模式检查字符串的开头,因此“foobar”的样本将匹配“foo”但不是“bar”的模式。 end :检查带有模式的字符串的结尾,因此foobar的样本将匹配bar的模式但不匹配foo。 sub :子串匹配,因此foobar的样本将匹配模式foo,bar,oba。 reg :将模式作为样本的正则表达式进行比较。警告:与其他匹配方法相比,这是CPU饥饿,除非没有其他选择,否则应该避免。 found :这是一个根本不采用模式的匹配。与之匹配的是true如果发现样品,false否则。这可用于(作为一些常见示例)查看是否存在header(),是否设置了cookie(),或者是否找到了map()中的样本。req.hdr(x-foo) -m foundcook(foo) -m foundsrc,map(/etc/hapee-1.8/ip_to_country.map-m len :返回样本的长度(所以带有-m len 3的foo样本将匹配)到目前为止,你可能已经注意到使用path -m beg /evil比较我们的预期路径/evil与我们使用匹配方法检查的样本的开头beg。在许多地方,你可以使用在一个参数中组合样本获取和匹配方法的速记。在这个例子中path_beg /foo并且path -m beg /foo完全相同,但前者更容易键入和读取。并非所有Fetches都具有内置匹配方法的变体(事实上,大多数都没有),并且存在一个限制,即如果使用Converters链接Fetches,则必须使用Flags指定它(除非链上的最后一个Converters)有匹配变体,大多数没有)。如果没有所需匹配方法的获取变体,或者如果使用Converters,则可以使用-m上一节中提到的Flags来指定匹配方法。关于ACL让我们快速了解可以由ACL控制的HAProxy中的常见操作。这并不是为了给你提供这些规则可以使用的所有条件或方法的完整列表,而是为你在遇到ACL可以提供帮助的内容时提供想象力。使用http请求重定向重定向此规则有许多变体,所有这些变量都会向客户端返回301/302响应,告诉他们在另一条路径下请求。所有这些都允许使用%[]语法指定的日志格式规则在字符串中使用以允许动态重定向。该命令http-request redirect location设置整个URI。例如,要将非www域重定向到其www,你可以使用:http-request redirect location http://www.%[hdr(host)]%[capture.req.uri] unless { hdr_beg(host) -i www }在这种情况下,我们的ACL hdr_beg(host) -i www确保客户端被重定向,除非它们的Host HTTP头已经以www开头。该命令http-request redirect scheme改变了请求的方案,而其余部分则保留了其余部分。这允许简单的http-to-https重定向行:redirect scheme https if !{ ssl_fc }在这里,我们的ACL !{ ssl_fc }检查请求是否未通过https进入。该命令http-request redirect prefix允许你指定将请求重定向到的前缀。例如,下面的行会导致没有一个URL路径的所有请求与开始/foo被重定向到/foo/ {original URI here}:http-request redirect prefix /foo if !{ path_beg /foo }对于这些中的每一个,可以添加代码参数以指定响应代码。如果未指定,则默认为302。支持响应代码是301,302,303,307,和308。例如:redirect scheme code 301 https if !{ ssl_fc }这会将http请求重定向到https并告诉客户端他们不应该继续尝试http。或者对于更安全的版本,你可以通过注入Strict-Transport-Security标头http-response set-header。使用use_backend选择后端在HTTP模式下该use_backend行允许你指定使用另一个后端的条件。例如,要将HAProxy统计信息网页的流量发送到统计信息后端,你可以use_backend与ACL一起检查URL路径是否以/ stats开头:use_backend be_stats if { path_beg /stats }为了更加有趣,后端名称可以是动态的日志格式规则。在下面的示例中,我们将路径放在地图中并使用它来生成后端名称:use_backend be_%[path,map_beg(/etc/haproxy/paths.map)]如果文件paths.map包含/api api作为键值对,则流量将被发送到be_api,将静态be_与字符串api组合。如果没有任何映射条目匹配,并且你已将可选的第二个参数(默认参数)指定给map函数,则将使用该默认值use_backend be_%[path,map_beg(/etc/haproxy/paths.map, mydefault)]在这种情况下,如果映射文件中没有匹配项,则将使用后端be_mydefault。否则,流量将自动通过此规则搜索use_backend匹配的另一个规则或为default_backend行的配置。在TCP模式下我们还可以为TCP模式流量做出路由决策,例如,如果流量是SSL,则将流量定向到特殊后端:tcp-request inspect-delay 10s use_backend be_ssl if { req.ssl_hello_type gt 0 }请注意,对于tcp级路由决策,当需要来自客户端的数据(例如需要检查请求)时,该inspect-delay语句需要避免HAProxy在没有来自客户端的任何数据的情况下传递阶段。除非客户端保持静止10秒钟,否则它不会等待整整10秒钟。一旦它可以决定缓冲区是否具有某种类型的SSL消息,它就会继续前进。使用http-request set-header设置HTTP标头向请求添加HTTP标头有多种选择(对客户端透明)。将此与ACL组合使我们只能在给定条件为真时设置标头add-header :添加新标头。如果客户端发送了相同名称的标头,则会忽略它,添加同名的第二个标头。 set-header :将以相同的方式添加新标头add-header,但如果请求已经具有相同名称的标头,则将覆盖该标头。适用于客户端可能想要篡改的安全敏感标记。 replace-header :应用指定标头的正则表达式替换(例如,将假cookie注入cookie标头) del-header :从请求中删除指定名称的任何标头。在添加新标头(或其中使用的任何自定义标头名称)之前删除x-forwarded-for标头很有option forwardfor用。使用http-request set-path更改URL这允许HAProxy修改客户端请求的路径,但对客户端透明。它的值接受日志格式规则,因此你可以使请求的路径动态化。例如,如果你想在不通知客户端的情况下向所有请求添加/foo/(如上面的重定向示例),请使用:http-request set-path /foo%[path] if !{ path_beg /foo }还有set-query,它改变了查询字符串而不是路径,并且set-uri将路径和查询字符串设置在一起,这是变体。使用http-response set-map更新map file这些操作并不经常使用,但在动态调整HAProxy映射方面开辟了有趣的可能性。这可以用于诸如让登录服务器告诉HAProxy从那时起将客户端(在这种情况下是会话cookie)请求发送到另一个后端的任务:http-request set-var(txn.session_id) cook(sessionid) use_backend be_%[var(txn.session_id),map(/etc/haproxy/sessionid.map)] if { var(txn.session_id),map(/etc/haproxy/sessionid.map) -m found } http-response set-map(/etc/haproxy/sessionid.map) %[var(txn.session_id)] %[res.hdr(x-new-backend)] if { res.hdr(x-new-backend) -m found } default_backend be_login现在,如果后端在响应中设置x-new-backend头,HAProxy将使用客户端的sessionid cookie将后续请求发送到指定的后端。变量被用作,否则,响应阶段HAProxy无法访问请求cookie - 你可能需要记住HAProxy在启动期间会警告的其他类似问题的解决方案还有与del-map基于ACL条件删除映射条目有关。与大多数操作一样,http-response set-map有一个相关的操作http-request set-map。这作为伪API可用于允许后端添加和删除映射条目。使用http请求缓存使用缓存HAProxy 1.8的新功能是小对象缓存,允许基于ACL缓存资源。这与http-response cache-store一起允许你在HAProxy的缓存系统中存储选择请求。例如,鉴于我们已经定义了一个名为icons的缓存,以下内容将存储以/icons开头的路径的响应,并在将来的请求中重用它们http-request set-var(txn.path) path acl is_icons_path var(txn.path) -m beg /icons/ http-request cache-use icons if is_icons_path http-response cache-store icons if is_icons_path使用ACL来阻止请求现在你已经简单的了解了ACL,现在是时候做一些请求阻止了!该命令http-request deny向客户端返回403并立即停止处理请求。这经常用于DDoS/Bot缓解,因为HAProxy可以在不打扰Web服务器的情况下拒绝大量请求。类似于此的其他响应包括http-request tarpit(保持请求挂起,直到超时tarpit到期,然后返回500 - 通过重载连接表来减慢访问的速度,http-request silent-drop(让HAProxy停止处理请求)但是告诉内核不要通知客户端 - 从客户端角度打开连接,但是从HAProxy角度关闭;要注意状态防火墙)。使用deny和tarpit,你可以添加deny_statusFlags来设置自定义响应代码,而不是使用开箱即用的默认403/500。例如,使用http-request deny deny_status 429将导致HAProxy 使用错误429:Too Many Requests响应客户端。在以下小节中,我们将提供许多静态条件,阻塞流量可能对其有用。HTTP协议版本许多攻击使用HTTP 1.0作为协议版本,因此如果是这种情况,使用内置ACL很容易阻止这些攻击HTTP_1.0http-request deny if HTTP_1.0用户代理字符串的内容我们还可以检查User-Agent标头并拒绝它是否与指定的字符串匹配http-request deny if { req.hdr(user-agent) -m sub evil }如果-m sub用户代理请求标头的一部分包含字符串evil,则该行将拒绝该请求。删除-m sub,留下你req.hdr(user-agent) evil作为条件,它将是一个完全匹配而不是substring。用户代理字符串的长度一些攻击者将尝试使用随机md5sum绕过正常的用户代理字符串,这可以通过长度识别并立即阻止:http-request deny if { req.hdr(user-agent) -m len 32 }攻击者的攻击可能会有很多不同,因此你可以依赖合法用户代理更长的事实,同时将其设置为最小长度:http-request deny if { req.hdr(user-agent) -m len le 32 }然后,这将阻止任何具有短于32个字符的用户代理标头的请求。路径如果攻击者滥用合法客户端没有的特定URL,则可以根据路径阻止:http-request deny if { path /api/wastetime }或者,你可以阻止攻击者访问隐藏文件或文件夹:http-request deny if { path -m sub /. }延伸阅读linuxea:haproxy 1.9中的多线程linuxea:haproxy1.9 了解四个基础部分linuxea:haproxy1.9日志简介linuxea: 使用HAproxy 1.9 Runtime API进行动态配置linuxea: 探索 HAproxy 1.9 统计页面
2019年06月11日
3,952 阅读
0 评论
0 点赞
2019-06-10
linuxea: 探索 HAproxy 1.9 统计页面
在之前的博客文章HAProxy Logging简介中,你了解了如何利用HAProxy的强大功能,通过日志记录将可观察性提高到负载均衡器和服务的状态。HAProxy还附带一个名为HAProxy Stats页面的仪表板,该页面向你显示涵盖服务器运行状况,当前请求率,响应时间等的大量指标。这些指标为你提供了基于每个前端,后端和服务器的精细数据。你只需要添加一个stats enable指令,该指令通常放在它自己的frontend部分中。frontend stats bind *:8404 stats enable stats uri /stats stats refresh 10s stats admin if { src 127.0.0.1 }该bind行设置你将用于访问仪表板的地址和端口。可选stats uri行更改URL的路径。该stats refresh行配置仪表板在浏览器中自动刷新的频率。你还可以使用此screen将服务器置于维护模式或从中排出流量。为此,你将添加该stats admin行并限制谁可以通过ACL语句访问这些函数。你也可以将其设置stats admin if TRUE为绕过限制。(可选)添加stats auth <username:password> 一行以强制执行基本身份验证。listen stats mode http bind *:1080 #监听端口 stats refresh 30s #统计页面自动刷新时间 stats uri /stats #统计页面url stats realm Haproxy Manager #统计页面密码框上提示文本 stats auth admin:admin #统计页面用户名和密码设置 stats hide-version #隐藏统计页面上HAProxy的版本信息有了这个,你可以访问端口上的/stats URL以查看仪表板:HAProxy Stats页面为你提供近乎实时的信息提要,你可以使用这些信息对代理服务进行故障排除,获取有关流量的信息,并观察服务器上的负载。但是,度量标准使用简写名称和前缀进行标记。在充分利用它们之前,你需要了解它们的含义。在这篇博客文章中,你将浏览统计信息页面并了解每个部分显示的内容。Frontend Statistics在第一部分中,我们将探索与前端相关的统计数据。一个前端就是一个客户端连接到。当请求进入负载均衡器时 - 并且当响应返回给客户端时 - 它们通过前端。因此,它可以访问包含整个请求/响应生命周期的端到端计时,消息大小和运行状况指示器。在第一部分中,我们将探索与前端相关的统计数据。前端是客户端连接的内容。当请求进入负载均衡器时 - 并且当响应返回给客户端时 - 它们通过前端。因此,它可以访问包含整个请求/响应生命周期的端到端时序,消息大小和运行状况指示器Session Rate会话率该会话速率部分-->Session rate,在前端的情况下,描述了其客户端连接到HAProxy的速度。Cur列显示正在创建客户端会话或客户端与服务器之间完全建立的连接的当前速率。如果将鼠标悬停在此字段上,该页面将显示以下向下钻取指标:Current connection rate: :1/s Current session rate: :1/s Current request rate: :1/s 如下图:对应Current connection rate per second 当前每秒的连接速率 客户端连接到HAProxy的速率(尚未创建完整会话) Current session rate per second 当前每秒会话速率 正在创建会话的速率,这些会话是保持端到端连接状态的实体(客户端到HAProxy和HAProxy到后端服务器) Current request rate per second 当前每秒请求率 通过已建立的连接接收HTTP请求的速率Max列显示同时使用的大多数会话。如果将鼠标悬停在此字段上,该页面将显示以下向下钻取指标:Max connection rate: 10/s Max session rate: 10/s Max request rate: 10/s如下图:对应Max connection rate per second 每秒最大连接速率 客户端连接到HAProxy的最高速率(尚未创建完整会话) Max session rate per second 每秒最大会话速率 客户端建立会话的最高速率,这些会话是保持端到端连接状态的实体(客户端到HAProxy和HAProxy到后端服务器) Max request rate per second 每秒最高请求率 通过已建立的连接收到HTTP请求的最高速率“ Limit”列显示前端将接受的每秒最大会话数,由rate-limit sessions设置设置。如果超出此限制,则套接字的积压(在系统缓冲区中)中的其他连接将保持挂起状态Sessions.在frontend的上下文中,“Sessions”部分计算负载均衡器上使用的会话数或完整的客户端到服务器连接数。Cur列显示已建立会话的当前数量。 Max列显示同时建立的大多数会话。“Limit”列显示允许的最多同时会话,由frontend中的maxconn设置定义。达到此限制时,该特定frontend将停止接受新连接。如果未设置maxconn,则Limit与配置的global部分中的maxconn值相同。如果未设置,则该值基于你的系统。将鼠标悬停在“Total”列上时,该页面将显示以下向下钻取指标:Cum. connections: 1027 Cum. sessions: 1027 Cum. HTTP requests: 1027 - HTTP 1xx responses: 0 - HTTP 2xx responses: 523 Compressed 2xx: 0 (0%) - HTTP 3xx responses: 0 - HTTP 4xx responses: 0 - HTTP 5xx responses: 503 - other responses: 0 Intercepted requests: 524 Cache lookups: 0 Cache hits: 0 (0%) Failed hdr rewrites: 0如下图:对应Cum. connections 自上次重新加载HAProxy以来建立的累积连接数。 Cum. sessions 自上次重新加载以来建立的累积会话数(端到端连接)。 Cum. HTTP requests 自上次重新加载以来累积的HTTP请求数。 HTTP 1xx responses 收到1xx响应的HTTP请求总数。 HTTP 2xx responses 收到2xx响应的HTTP请求总数。 Compressed 2xx 如果已启用压缩,则压缩的2xx响应总数。它还显示已压缩的请求的百分比。 HTTP 3xx responses 收到3xx响应的HTTP请求总数。 HTTP 4xx responses 收到4xx响应的HTTP请求总数。 HTTP 5xx responses 收到5xx响应的HTTP请求总数。 Other responses 收到其他指标未涵盖的响应的HTTP请求总数。 Intercepted requests 截获并重定向到HAProxy Stats页面的请求总数。 Cache lookups 检查资源的缓存的总次数。 Cache hits 返回缓存资源的总次数。 Failed hdr rewrites 由于缓冲区中没有足够的空间,无法添加或设置HTTP标头的总次数。尝试增加tune.maxrewrite或tune.bufsize。 该LbTot和最后列在本节不使用Bytes在前端的上下文中,“ Bytes”部分显示HAProxy和下游客户端之间发送和接收的累积数据量。In列显示接收的总字节数,Out列显示发送的总字节数Denied"Denied"部分显示因安全问题而被拒绝的请求和响应数。Req列显示由于frontend或listen部分中放置的以下任何配置指令而被拒绝的请求数:http-request denyhttp-request rejecthttp-request silent-drophttp-request tarpithttp-response silent-droptcp-request connection silent-droptcp-request content rejecttcp-request content silent-dropRESP列显示的是通过一个拒绝响应的数目http-response deny,它被放置在该指令frontend或listen。Errors在前端的上下文中, Errors部分中仅使用 Req列。它显示了遇到错误的请求数。可能的原因包括:提前终止客户来自客户端的读取错误客户超时了客户端关闭了连接客户端发送了格式错误的请求请求是tarpittedServer"Server"部分中应用于前端的唯一字段是“ 状态”字段。当状态为OPEN时,前端正常运行并准备接收流量。你可以禁用前端,通过执行disable frontend Runtime API命令,它将其状态更改为STOP。以下是调用该命令的示例:echo "disable frontend website" | socat stdio /var/run/haproxy.sock使用enable frontend命令将前端的状态更改回OPENBackend StatisticsBackend是负载平衡服务器池。 HAProxy将请求发送到后端,然后从其中一个活动服务器接收响应。此处的统计信息包括有关每台服务器的运行状况,与排队,连接和获取响应相关的计时以及请求率的信息Queue“Queue”部分仅适用于后端,并显示客户端等待服务器可用的时间。使用maxconn设置时,HAProxy能够对连接进行排队。这减少了后端服务器的压力。Cur列显示当前已排队但尚未分配给服务器的客户端连接数。 Max列显示一次排队的最多连接数。“limit”列显示允许排队的最大连接数,由每个服务器行上的maxqueue设置定义。设置可以排队的连接数的最大限制是确保客户端不会排队等待太长时间的一种方法。你还可以设置超时队列,以设置客户端在HAProxy返回错误响应之前保持排队的时间长度。Session Rate在后端服务器的上下文中,会话与连接相同。这些统计信息显示了与服务器建立连接的速率。Cur列显示每秒与服务器建立连接的当前速率。 Max列显示与给定服务器建立连接的最高速率。不使用limit列Sessions在后端的上下文中,“ Sessions”部分显示与任何活动服务器的当前连接数。Cur列列出了服务器的活动连接数。 Max列显示同时为给定服务器建立的最多连接。“limit”列显示服务器允许的最大连接数,由服务器行上的maxconn参数设置。后端行显示limit的fullconn值,如果未设置,则使用以下公式:路由到此后端的前端的会话限制值的总和除以10.因此,如果你有两个前端,每个都有1000的限制,它们的总和将是2000.除以10得到该后端的限制值200。"total"列显示已使用给定服务器的累积连接数。将鼠标悬停在此字段上时,下拉列表会显示以下向下钻取指标:如下:Cum. sessions : 建立到此服务器的累积连接数。 New connections : 建立新连接的次数,而不是重用现有连接。 Reused connections : 重用现有连接的次数。 Cum. HTTP responses : 从此服务器收到的累积HTTP响应数。 HTTP 1xx responses : 此服务器的HTTP 1xx响应总数。 HTTP 2xx responses : 此服务器的HTTP 2xx响应总数。 HTTP 3xx responses : 此服务器的HTTP 3xx响应总数。 HTTP 4xx responses : 此服务器的HTTP 4xx响应总数。 HTTP 5xx responses : 此服务器的HTTP 5xx响应总数。 Other responses : 其他指标未涵盖的HTTP响应总数。 Failed hdr rewrites : 由于缓冲区中没有足够的空间,无法添加或设置HTTP标头的总次数。尝试增加tune.maxrewrite或tune.bufsize。 Queue time : 在等待连接到服务器的连接时,连接保持排队的时间量(以毫秒为单位),在过去1024次成功连接中取平均值。 Connect time : 成功连接到服务器所花费的时间(以毫秒为单位),在过去1024次成功连接中取平均值。 Response time : 服务器响应时间(以毫秒为单位),在过去1024次成功连接中取平均值。 Total time : 总会话时间(以毫秒为单位),在过去1024次成功连接中取平均值。LbTot列显示选择给定服务器以提供请求的总次数。这可能是由于正常的负载平衡或由于故障服务器的重新分配造成的。Last列显示自上次连接以来的时间。在本节的底部,以灰色显示,度量标准将汇总并报告后端整体Bytes在后端的上下文中,“ Bytes”部分显示HAProxy与上游服务器之间发送和接收的数据量。In列显示发送到服务器的字节数。 Out列显示收到的字节数。底行显示了所有服务器的后端总数Denied"Denied"部分显示因安全问题而被拒绝的请求和响应数。Req列仅适用于整个后端。它显示了后端中任何以下配置指令拒绝的请求数:http-request denyhttp-request rejecthttp-request silent-drophttp-request tarpithttp-response silent-droptcp-request content rejecttcp-request content silent-droptcp-response content silent-dropResp列显示由于backend中的任何以下配置指令而拒绝任何给定服务器的响应数http-response denytcp-response content reject底行显示了这些单独服务器指标的总和ErrorsErrors显示与后端服务器通信相关的错误数。不使用Req列。 Conn列显示尝试连接到服务器时遇到错误的请求数。例如,如果在HAProxy已经开始连接时关闭服务器,那么你会看到此数字上升。运行状况检查最终会从轮换中删除服务器。Resp列显示获取响应时遇到的错误。例如,关闭tcp-response内容关闭的连接将增加此计数Warnings后端的"Warnings"部分显示重试次数和重新分配次数。如果你已向后端添加了retries重试指令,则Retr列将显示重试连接的总次数。Redis列显示HAProxy无法与服务器建立连接并将其重新分配到另一台服务器的次数。这要求你添加了一个选项redispatch指令。Server在后端的上下文中,“ Server”部分显示有关每个服务器的状态,运行状况和权重的各种详细信息“ status”列显示服务器当前是否已启动以及启动时间。它可以显示以下任何状态:up :服务器报告为健康。 DOWN :服务器报告为不健康且无法接收请求。 NOLB :你已将http-check disable-on-404添加到后端,并且运行状况检查的URL已返回HTTP 404响应。 MAINT :服务器已被禁用或进入维护模式。 DRAIN :服务器已进入排水模式。 no check :未对此服务器启用运行状况检查。LastChk列显示的值为L7OK / 200,单位为1ms。该特定值意味着执行了第7层健康检查;它返回了一个HTTP 200 OK响应,它在1毫秒内完成。或者,如果你在0ms内看到L4OK,则表示HAProxy能够与服务器建立第4层连接。Wght列显示它将接受的流量比例,由服务器行上的weight参数设置。Act列显示服务器是处于活动状态(标记为Y)还是备份(标记为 - )。密切相关的Bck列显示服务器是备份(标记为Y)还是活动(标记为 - )Chk列显示失败的运行状况检查的数量。 Dwn列显示从UP到DOWN的转换次数。 Dwntme列显示服务器已关闭多长时间。如果已向服务器行添加了slowstart参数,则在禁用并稍后启用该服务器时,Thrtle列显示服务器将接受的流量百分比。在你设定的期间内,百分比将逐渐上升至100%。延伸阅读linuxea:haproxy 1.9中的多线程linuxea:haproxy1.9 了解四个基础部分linuxea:haproxy1.9日志简介linuxea: 使用HAproxy 1.9 Runtime API进行动态配置linuxea: 关于HAproxy无缝重载
2019年06月10日
5,234 阅读
0 评论
0 点赞
2019-06-09
linuxea: 关于HAproxy无缝重载
HAProxy Technologies的研发部门发布了一个补丁集,可以在不丢弃数据包的情况下实现HAProxy的无缝重新加载。该补丁集最早合并到HAProxy 1.8开发分支中,而后在每个版本持续支持。这项工作是HAProxy Technologies更大的路线图计划的一部分,以支持更多的微服务用例,因为我们看到这些用例变得越来越频繁。这个特定的修复应该很好地解决大型环境,其中多个服务都共享相同的HAProxy服务器,或者微服务编排系统比传统的负载平衡设置更频繁地添加/删除服务,或者许多其他用例需要频繁的HAProxy重载。让我带你了解问题的历史以及我们如何达成最终解决方案。本章节来自谷歌翻译,如有雷同,纯属巧合。原链接1.什么是无缝重装用户经常称之为“无缝”或“无中断”的重新加载是在不影响用户体验的情况下执行的配置更新或服务升级。配置更新可能需要某些服务的停止/启动序列,导致临时中断并使管理员在执行它们或尝试尽可能长时间推迟之前担心很多。使用今天的微服务和非常频繁的重新加载,在配置更新或服务升级期间丢失任何单个连接是不可接受的。服务升级更为重要,因为虽然某些产品是从落地考虑设计的,无需重新加载即可支持配置更新,但如果没有停止/启动序列,则无法进行升级。因此,管理员会留下在生产中运行的那些软件组件的虚假版本,因为它永远不是正确的时间。HAProxy不区分配置更新和服务升级。在每种情况下,新的可执行文件都与新配置一起使用,因此服务升级与配置更新一样透明。但是,随着时间的推移,情况已经发生变化,在haproxy 1.2.11实现了软重载机制。基于新进程尝试绑定到所有侦听端口如果失败,它会向旧进程发送一个信号,要求它暂时释放端口新流程再次尝试如果失败,它会放弃并发出旧进程的信号,以继续处理传入的连接如果成功,则表示它在完成现有连接服务后可以退出的旧进程应该注意的是,在步骤2和3之间存在一个小的“black hole”,其中端口不受任何过程的约束。在2006年,我们在现场看到的负载大约是每秒几百个连接的数量级,并且在重新加载期间(短于一毫秒)正确着陆的任何连接的风险足够低,可以忽略。同年,OpenBSD系统支持SO_REUSEPORT,这是一个套接字选项,允许将新套接字绑定到与前一个套接字相同的端口。好处是,在OpenBSD上它允许我们跳过第2步和第3步,并且没有“black hole”。这是在同年的HAProxy 1.2.14版本中实现的,并且曾经是HAProxy中第一个真正无缝的重新加载。然而在旧版本linux内核也支持过SO_REUSEPORT,但是从2.4开发期间就丢弃了,然而这将被重新打补丁使用。但是主线的linux内核并不接受。因此,这个补丁被保存,直到6.0版本(2.6.32)与此同时,一个新的,更好的SO_REUSEPORT实现被带到Linux内核3.9,允许负载智能地分布在多个套接字上。HAProxy可以立即受益于这一新的改进。但它带来了一个问题,部分源于其可扩展性。套接字队列是独立的,人们逐渐开始报告在HAProxy重新加载期间在负载下观察到偶尔的RST。haproxy团队在实验室中以非常高的负载重现了这一点。重新加载期间发出的RST速率约为每次重新加载2-3个连接。起初它看起来很低,但微服务和云环境彻底改变了观点。有些服务每隔几秒就会重新加载一次。在Linux 4.9下以每秒55,000个连接运行并且每秒重新加载10次的haproxy服务,在180次重新加载之后,可能会在100万个连接中达到155次连接失败:2.尝试解决阻止SYN大约在2010年,当用户开始报告此问题时,重新加载操作期间阻止SYN数据包(这应该非常快)。它最终阻止了在重新加载期间建立新连接,导致一些客户端重新传输它们丢弃的SYN数据包并使它们无法经历重置。但是,尽管在某些低延迟环境中,在重新加载期间偶尔会导致额外的200ms-3s延迟是不可接受的套接字服务器在2011年初,在发布HAProxy版本1.5-dev4之后,Simon Hormans尝试通过使用套接字服务器实现master-worker模型以完全不同的方式解决该问题想法是,不是让HAProxy重新加载,而是一个进程保持活动状态,它会处理所有套接字并在重新加载时将它们传递给每个新进程。遗憾的是,这项工作在当时公布了HAProxy的许多内部限制,如果不对HAProxy的信号处理,内存管理和流程管理进行大规模的重新设计,就没有办法让它可靠地工作。因此,这个补丁集从未合并过,但它确实很有趣,这些重点已经转移到改进HAProxy内部,以便在以后使这种架构成为可能延迟SYN在2015年,Yelp的Joe Lynch仍然不满意“阻塞SYN”方法造成的额外延迟,他发现了一种很好的方法来显着改善它。他没有丢弃SYN数据包,而是使用Linux排队规则(qdisc)来延迟它们。删除qdisc后,排队的数据包会自动释放,并且只有在HAProxy重新加载新配置文件时才会延迟额外的延迟。该脚本最终变得有点复杂,但是一旦编写完就没有必要再触摸它了,大多数用户认为这种方法是最佳的更改套接字的分数在Joe Lynch和他的同事Josh Snyder的帮助下,我们考虑了其他各种选项,例如在关机期间删除SO_REUSEPORT选项并使这些套接字得分更低,将套接字积压设置为零,在关闭之前关闭插座并具有drain mode和其他类似机制。恰巧在同一时间,Tolga Ceylan提出了类似的设计来解决影响Nginx的同样问题。在此期间,建议尝试eBPF使用eBPF将SYN转移到某些队列试图实施eBPF导致失败。简而言之,原则是为传入的数据包分配一个不同的队列,这样它们就不会落入退出进程的队列中。这种方法的一个问题是无法知道剩余进程的队列号,如果重新加载比旧进程的平均生命周期更频繁,那么这些数字也可能在旧进程的生命周期内发生变化(相当微服务中的常见问题)。所以我们基本上能做的就是接受或拒绝流量套接字服务器在2016年,GitHub(也使用HAProxy)在master-worker模型中提出了与套接字服务器非常相似的东西,但它的侵入性要小得多,它使用HAProxy将已绑定套接字重用为侦听套接字的能力。他们的服务器被称为“multibinder”,在这里描述:https://githubengineering.com/glb-part-2-haproxy-zero-downtime-zero-delay-reloads-with-multibinder/其他讨论了各种其他想法,例如将侦听套接字的绑定更改为错误的接口,或者如果已经绑定它以取消绑定以降低其在compute_score()函数中的分数(它确定将传入连接发送到哪个队列) 。所有这些想法都带来了不可接受的缺点(例如暂时将敏感套接字暴露给不安全的接口)并且没有实现预期的缺陷完善3.制定长期解决方案在尝试基于eBPF实现某些功能失败之后,在短期内无法在内核中获得一个很好的解决方案。此外,每天受这个问题影响的所有用户(以及运行企业Linux发行版的用户)都很少有机会将必要的内核更新反向移植到他们的生产系统。所以我认为唯一剩下的可接受的短期解决方案是回到“套接字服务器”方法(旧进程和新进程之间的文件描述符传输),以便永远不会关闭套接字。但是,我们不是依赖于复杂的主工作者模型,而是尝试使用HAProxy CLI套接字,该套接字通常是UNIX套接字,并且最重要的是可以使用SCM_RIGHTS传输文件描述符。SCM_RIGHTS是UNIX套接字的一个鲜为人知的功能,它允许一个进程将一个或多个文件描述符传输到另一个进程。另一个进程以它们所处的相同状态(通常使用不同的FD编号)接收它们,就好像它们是使用dup()复制一样haproxy团队Olivier Houchard讨论了这个问题,他对此非常感兴趣,他立即开始研究HAProxy中需要改变的内容以支持它。与此同时,开始进行彻底的分析4. 分析问题在2017年之前,在7年多的时间里HAProxy Technologies没有人想出一个很好的解决方案来解决这个问题。当旧版本的haproxy运行在双核系统的笔记本上,每秒重新加载haproxy10次,在压力测试中,每40000个链接大概有一个错误。每秒reload 10次,每秒运行80,000个连接!将负载生成器连接到与haproxy相同的CPU,超过一个小时和1.5亿个连接没有任何单个错误。在网络上运行了相同的测试,发现当HAProxy绑定到与网络中断相同的CPU时没有一个错误,并且只有在HAProxy进程位于不同的CPU上时才会发生错误。这解释了为什么这些年来情况发生了变化。多年来,由于HAProxy的资源使用非常有限,我们大多数人都在廉价的单CPU机器上运行,而且默认情况下不会出现问题。然后,当haproxy开始部署在SMP机器上时,问题再一次避开了我们 - 许多这些SMP系统配备了单队列NIC,默认情况下内核的调度程序倾向于自动将接收进程移动到与收到中断。这是我们通常手动禁用以获得更高性能的东西,但由于绝大多数用户没有更改默认设置,因此它们仍未受影响。实际原因是由于一个简单的错误,使用参数“-F”和“-c”启动了我的负载生成器。第一个与HAProxy的“tcp-smart-connect”选项完全相同 - 它将HTTP请求与连接的ACK融合以保存一个数据包。第二个用RST关闭以保存另一个数据包。在此测试期间,单个进程每秒150k连接没有出现单个错误。我认为它与“-c”有关,但没有。摆脱问题的是“-F”使用和不使用“-F”的测试之间的区别在于,通过删除初始ACK,当连接被接受时,请求立即可用。开始认为这是HAProxy中的调度问题,可能没有处理一些已接受的连接。我们认为我们可以通过在绑定行上添加“defer-accept”来复制相同的行为。但“延迟接受”仍然遇到了问题:在整个过程中运行strace告诉我们没有任何单一的区别,事实上,在最后一个accept()返回“-1 EAGAIN”之后,很明显有一些连接仍处于未决状态。这与上面观察到的CPU绑定相结合,看起来内核中的accept()代码中某处缺少SMP内存屏障。内存屏障是一种同步机制,用于确保修改后的数据对其他CPU可见:这些内容包括刷新挂起缓存写入。没有它,其他CPU只能看到它们在缓存中的内容,并且不一定知道在内存区域中执行的最近更改。在我们的当前情况下可能出现的是,当新连接被接受时,指针正在被提升,但是其他CPU只偶尔看到了这个指针的快照,如下图所示:因此,当数据到达时,很可能没有应用无数据ACK的内存屏障,导致其他CPU无法看到整个传入连接列表。它导致其中一些留在队列中,当侦听套接字关闭时,它被重置。似乎有可能没有办法比这更精确,同时保持高性能水平(我不确定)。但至少我确认阻止空的ACK摆脱了这个问题5.临时解决办法在轻负载下运行的那些可以简单地确保它们的HAProxy进程始终绑定到接收网络中断的同一CPU。如果所有中断都路由到同一个CPU,则仅对单队列NIC或多队列NIC可行。在每秒处理数万个连接或需要多队列保持启用的数千兆位负载时,请勿执行此操作。将NIC和haproxy绑定到CPU 0的示例:$ grep eth0- /proc/interrupts 28: 1259842789 181 PCI-MSI-edge eth0-rx-0 29: 1276436141 772 PCI-MSI-edge eth0-tx-0 $ for i in $(grep eth0- /proc/interrupts |cut -f1 -d:); do echo 1 > /proc/irq/$i/smp_affinity done那些在较高负载下运行的,或那些不能应用上述内容的人,或那些使用nbproc并且无法将haproxy的套接字绑定到带来传入流量的相同CPU的那些,但是在重载操作期间CAN可以阻止传入的空ACK。阻止空ACK是可行的,因为它们不会引起任何额外的延迟(与SYN相反)。ACK用于确认连接(并且紧接着是其他数据),它们用于确认接收到的段,以便窗口可以前进(但只要发送窗口未满,就会继续传输段) 。它们最后用于关闭LAST_ACK连接,也可以安全地延迟。上面展示的iptables规则不能在生产中原样使用,因为它依赖于TCP时间戳并且会在没有它们的情况下阻止其他数据包。下面介绍的以下内容适用于生产。它阻止所有纯ACK数据包以及携带少于3个字节有效负载而没有PUSH标志的数据包。这里不可能匹配单个字节,因为U32仅引用32位有效负载,但同时,没有PUSH标志的3字节数据包没有意义:$ sudo iptables -I INPUT -i lo -p tcp --dport 80 --tcp-flags SYN,PSH,ACK,FIN,RST ACK -m u32 \! --u32 '0>>22&0x3C@12>>26&0x3C@0&0x0=0:0' -j DROP $ sudo iptables -I INPUT -i lo -p tcp --dport 443 --tcp-flags SYN,PSH,ACK,FIN,RST ACK -m u32 \! --u32 '0>>22&0x3C@12>>26&0x3C@0&0x0=0:0' -j DROP6.适当的长期解决方案就提出适当的长期解决方案而言,第一个想法是看看是否可以调整内核以避免问题。但这可能会导致不良的副作用,而且看起来很棘手,因为问题可能会在以后重新出现。一个更安全,更恰当的长期解决方案被证明是我们在步骤#4中已经讨论过的 - 将监听文件描述符传递给新进程,以便永远不会关闭连接。运的是,Olivier已经得到了相当好的代码。实现仅限于最多传递253个侦听器,但这是SCM_RIGHTS API的限制以及我们此时不想轮询的事实,并且甚至足以支持多进程重新加载。这个补丁集合并到HAProxy 1.8开发分支中,计划于2017年11月稳定发布。与此同时,我们正在验证剩余的极端情况,并且已经在考虑将此补丁集集成到HAProxy Enterprise 1.7r1中,甚至可能是1.6r2。Olivier用他的代码尽可能不引人注意,以便轻松地向后移植。7.证明解决方案我们可以运行一个脚本来测试结果,从重新启动到重新加载,再到在HAProxy实例之间传输套接字的重新加载:重新启动HAProxywhile true do sleep 3 ./haproxy -f /etc/hapee-1.7/hapee-lb.cfg -p /run/hapee-1.7-lb.pid -st $(cat /run/hapee-1.7-lb.pid) donerestart results$ ab -r -c 10 -n2000 https://127.0.0.1/ Concurrency Level: 10 Time taken for tests: 3.244 seconds Complete requests: 2000 Failed requests: 11 (Connect: 0, Receive: 0, Length: 9, Exceptions: 2)reload haproxywhile true do sleep 3 ./haproxy -f /etc/hapee-1.7/hapee-lb.cfg -p /run/hapee-1.7-lb.pid -sf $(cat /run/hapee-1.7-lb.pid) doneReload results$ ab -r -c 10 -n2000 https://127.0.0.1/ Concurrency Level: 10 Time taken for tests: 3.510 seconds Complete requests: 2000 Failed requests: 1 (Connect: 0, Receive: 0, Length: 1, Exceptions: 0)通过在HAProxy实例之间传输套接字来重新加载HAProxy注意:HAProxy配置中的套接字定义需要在其上具有“expose-fd侦听器”,以便-x接受套接字传输while true do sleep 3 ./haproxy -f /etc/hapee-1.7/hapee-lb.cfg -p /run/hapee-1.7-lb.pid -x /var/run/hapee-lb.sock -sf $(cat /run/hapee-1.7-lb.pid) done重新加载+套接字传输结果$ ab -r -c 10 -n2000 https://127.0.0.1/ Concurrency Level: 10 Time taken for tests: 2.084 seconds Complete requests: 2000 Failed requests: 0延伸阅读linuxea:haproxy 1.9中的多线程linuxea:haproxy1.9 了解四个基础部分linuxea:haproxy1.9日志简介linuxea: 使用HAproxy 1.9 Runtime API进行动态配置
2019年06月09日
4,272 阅读
0 评论
1 点赞
2019-06-08
linuxea: 使用HAproxy 1.9 Runtime API进行动态配置
在这篇博文中,你将学习如何使用Runtime API动态配置HAProxy。要了解有关HAProxy配置的更多信息,请参阅我们的博客文章HAProxy配置的四个基本部分。在过去的15年中,HAProxy以其可靠性,卓越的性能,可扩展的功能和先进的安全性而闻名。这是相对较少众所周知,HAProxy的核心基石之一是运行时API,它提供了非常强大的动态配置功能,没有服务重载或重新启动。Runtime API的动态配置功能的早期改进是由高级HAProxy用户(如Airbnb和Yelp)通过开发SmartStack(一种开创性的自动服务发现和注册平台)的请求推动的。在这篇博文中,我们将带你了解HAProxy Runtime API及其一些关键功能,例如动态配置ACL,粘贴表和TLS密钥的功能。除此之外,它还允许改进与服务发现工具和编排系统的集成,增强geolocation定位功能,启用自适应安全策略,提高SSL / TLS集群的效率等等入门HAProxy Runtime API的起源可以追溯到我们希望为HAProxy创建完整的配置和统计API,其命令在运行时将立即生效。我们在此API中的早期功能之一当然是能够检索详细的实时统计信息。此外,与仅支持HTTP的典型新API不同,HAProxy Runtime API始终可通过TCP和Unix套接字访问。这就是为什么我们有时仍然将它称为HAProxy stats套接字或仅仅是套接字,以及为什么用于启用Runtime API的配置指令具有相同的名称。使用以下示例在HAProxy配置中启用运行时API:global stats socket ipv4@127.0.0.1:9999 level admin stats socket /var/run/haproxy.sock mode 666 level admin stats timeout 2m了以交互方式测试或执行命令,可以使用socat提供的交互式命令提示符方便地访问Runtime API :[root@node-www.linuxea.com]# socat readline /var/run/hapee-lb.sock [root@node-www.linuxea.com]# socat readline tcp4-connect:127.0.0.1:9999请注意,为了实现上述功能,你的socat版本需要使用GNU Readline支持进行编译。这可以通过运行来验证socat -V | grep READLINE。如果输出socat -V未提及READLINE,或者它提到undef READLINE,或者运行实际命令会产生错误未知设备/地址“readline”,则表示你的版本没有readline支持。要从脚本访问Runtime API,或者作为上面显示的交互式用法的替代,可以使用以下命令[root@node-www.linuxea.com]# echo "help" | socat stdio /var/run/haproxy.sock [root@node-www.linuxea.com]# echo "help" | socat stdio tcp4-connect:127.0.0.1:9999最后,作为socat的替代方案,可以使用来自netcat包的命令nc。在这种情况下,请使用的netcat,OpenBSD的版本的netcat ; 它还支持连接到Unix域套接字的选项。nc -U从Runtime API开始的最佳方法是执行一个简单的请求,返回所有可用命令的列表。这是通过向helpAPI 发送或任何未知命令来完成的。以下是“help”的实际输出,在HAProxy版本1.9上执行[root@node-www.linuxea.com /usr/local/haproxy-1.9.0/contrib/halog]# echo "@1;help" | socat stdio /var/run/haproxy.sock Unknown command. Please enter one of the following commands only : help : this message prompt : toggle interactive mode with prompt quit : disconnect show sess [id] : report the list of current sessions or dump this session shutdown session : kill a specific session shutdown sessions server : kill sessions on a server clear counters : clear max statistics counters (add 'all' for all counters) show info : report information about the running process show stat : report counters for each proxy and server show schema json : report schema used for stats disable agent : disable agent checks (use 'set server' instead) disable health : disable health checks (use 'set server' instead) disable server : disable a server for maintenance (use 'set server' instead) enable agent : enable agent checks (use 'set server' instead) enable health : enable health checks (use 'set server' instead) enable server : enable a disabled server (use 'set server' instead) set maxconn server : change a server's maxconn setting set server : change a server's state, weight or address get weight : report a server's current weight set weight : change a server's weight (deprecated) show resolvers [id]: dumps counters from all resolvers section and associated name servers clear table : remove an entry from a table set table [id] : update or create a table entry's data show table [id]: report table usage stats or dump this table's contents disable frontend : temporarily disable specific frontend enable frontend : re-enable specific frontend set maxconn frontend : change a frontend's maxconn setting show servers state [id]: dump volatile server information (for backend <id>) show backend : list backends in the current running config shutdown frontend : stop a specific frontend set dynamic-cookie-key backend : change a backend secret key for dynamic cookies enable dynamic-cookie backend : enable dynamic cookies on a specific backend disable dynamic-cookie backend : disable dynamic cookies on a specific backend show errors : report last request and response errors for each proxy set maxconn global : change the per-process maxconn setting set rate-limit : change a rate limiting value set severity-output [none|number|string] : set presence of severity level in feedback information set timeout : change a timeout setting show env [var] : dump environment variables known to the process show cli sockets : dump list of cli sockets show cli level : display the level of the current CLI session show fd [num] : dump list of file descriptors in use show activity : show per-thread activity stats (for support/developers) operator : lower the level of the current CLI session to operator user : lower the level of the current CLI session to user show startup-logs : report logs emitted during HAProxy startup show cache : show cache status add acl : add acl entry clear acl <id> : clear the content of this acl del acl : delete acl entry get acl : report the patterns matching a sample for an ACL show acl [id] : report available acls or dump an acl's contents add map : add map entry clear map <id> : clear the content of this map del map : delete map entry get map : report the keys and values matching a sample for a map set map : modify map entry show map [id] : report available maps or dump a map's contents show pools : report information about the memory pools usage show profiling : show CPU profiling options set profiling : enable/disable CPU profiling检索统计数据有关在进入Runtime API更强大的命令之前的简单介绍,让我演示从HAProxy获取实时统计信息的方法。用于检索实时统计数据的众所周知的方法之一是通过HAProxy的内置HTML网页。这些统计信息以简单直接的方式格式化,可以在HAProxy中配置统计信息uri并访问统计信息URL后获取。也可以通过HAProxy Runtime API获取相同的完整和原始信息。API命令命名为show stat:show stat命令的输出将以CSV格式提供。统计信息输出包含80多个不同的度量标准。为了快速将其转换为更短且人类可读的输出,我们可以使用标准命令行工具。下面是一个显示所选数据子集并每两秒刷新一次的示例:[root@node-www.linuxea.com ~]# watch 'echo "@1;show stat" | socat stdio /var/run/haproxy.sock | cut -d "," -f 1-2,5-10,34-36 | column -s, -t' Every 2.0s: echo "@1;show stat" | socat stdio /var/run/haproxy.sock | cut -d "," -f 1-2,5-10,34-36 | column -s, -t Wed Jun 5 16:39:10 2019 # pxname svname scur smax slim stot bin bout rate rate_lim rate_max stats FRONTEND 0 0 100000 0 0 0 0 0 0 stats BACKEND 0 0 10000 0 0 0 0 0 frontend-web.com FRONTEND 0 1 100000 31 21276 7385 0 0 6 backend-linuxea.com etcd1 0 1 11 7546 2585 0 2 backend-linuxea.com etcd2 0 1 10 6860 2430 0 2 backend-linuxea.com etcd3 0 1 10 6870 2370 0 2 backend-linuxea.com BACKEND 0 1 10000 31 21276 7385 0 6通过使用cut上面的命令,我们将选择范围缩小到对快速和汇总监视有用的字段:scur:当前会话数smax:自HAProxy重新加载/重启或重置统计信息以来所见的最高会话数slim:配置会话数上限stot:到目前为止已处理的累计会话数bin:中的字节数bout:字节输出rate:平均每秒会话数,基于1秒计算rate_lim:配置每秒新会话的上限rate_max:自HAProxy重新加载/重新启动或重置其统计信息以来,每秒看到的最大新会话数有关show stat输出中可用的所有字段的列表和说明,请参阅“ HAProxy管理指南”的9.1节。管理服务器和代理使用Runtime API,你可以禁用和启用服务器,或逐渐消除流量。你还可以启用和禁用运行状况检查,启用和禁用前端,以及更改分配给服务器的负载平衡权重。我们来看几个例子。禁用启用节点如果要逐渐从特定服务器中消耗流量,请使用set server带有state参数set 的命令来排除:drain 一个节点echo "@1;set server backend-linuxea.com/etcd1 state drain"|socat stdio /var/run/haproxy.sock而后通过状态页面查看再次接收echo "@1;set server backend-linuxea.com/etcd1 state ready"|socat stdio /var/run/haproxy.sock这个过程我简单使用while观察也可以[root@DS-VM-Node99 ~]# while true;do curl 172.25.10.245:2379 && sleep 1;done 172.25.50.250 172.25.10.245 172.25.6.37 172.25.50.250 172.25.10.245 172.25.6.37 172.25.50.250 172.25.10.245 172.25.6.37 172.25.50.250 172.25.10.245 172.25.6.37 172.25.50.250 172.25.10.245 172.25.50.250 172.25.10.245 172.25.50.250 172.25.10.245 172.25.50.250 172.25.10.245 172.25.50.250 172.25.10.245 172.25.50.250 172.25.10.245 172.25.50.250 172.25.10.245 172.25.6.37 172.25.50.250 172.25.10.245 172.25.6.37 172.25.50.250 172.25.10.245 172.25.6.37当服务器处于drain模式时,HAProxy仍会定期发送健康检查。你也可以通过将服务器的状态设置为maint而不是drain来阻止它们。耗尽服务器逐渐将其从负载平衡旋转中取出,而将其置于维护模式与立即禁用它相同。健康状态检查如果你只想停止运行状况检查,请使用disable health命令,如下所示:关闭健康检查 echo "@1; disable health backend-linuxea.com/etcd1 "|socat stdio /var/run/haproxy.sock启用健康检查echo "@1; enable health backend-linuxea.com/etcd1 "|socat stdio /var/run/haproxy.sock权重或者,如果你想向服务器发送更多或更少的流量,你可以更改其权重。使用set server带有weight参数的命令:按原始值的百分比更改重量echo "@1; set server backend-linuxea.com/etcd1 weight 50% "|socat stdio /var/run/haproxy.sock修改完成后就变成了蓝色,并且接收的请求也降低按其他服务器的比例改变重量echo "@1; set server backend-linuxea.com/etcd1 weight 100% "|socat stdio /var/run/haproxy.sock关闭打开frontend你可以做的其他事情是停止前端代理的所有流量。使用此disable frontend命令从前端释放端口绑定。如果原始端口导致问题,你可以使用此端口将该端口与不同的前端相关联。这是一个例子:禁用echo "@1; disable frontend frontend-web.com "|socat stdio /var/run/haproxy.sock图示:开启 echo "@1; enable frontend frontend-web.com "|socat stdio /var/run/haproxy.sock图示:更新Stick表Stick表是另一个非常强大,但在HAProxy中使用简单。Stick表允许跨请求跟踪任意客户端信息,因此它们用于创建“sticky”会话,实施安全保护,设置限制以及维护计数器和列表等目的。Stick table基于haproxy的高性能 弹性二叉树。Ebtrees允许这些表包含数百万条记录,同时保持极快的访问速度。Runtime API允许在运行时添加,删除,搜索和更新sticky表条目。在下面的示例中,我们将创建一个包含100万个条目的表格,以跟踪来自各个客户端IP的请求率。我们将限制每秒最多30个请求,并且在10秒的时间段内继续以高于该限制的速率发送请求的IP地址将被拒绝,时间为15分钟。frontend www.linuxea.com bind *:2379 mode http option httplog stick-table type ip size 1m expire 15m store gpt0,http_req_rate(10s) http-request allow if { src -f /etc/haproxy/whitelist.lst } http-request track-sc0 src acl abuse src_http_req_rate ge 30 http-request sc-set-gpt0(0) 1 if abuse http-request deny if { sc0_get_gpt0 ge 1 } touch /etc/haproxy/whitelist.lst echo "reload" | socat stdio /var/run/haproxy.sock测试下[root@DS-www.linuxea.com ~]# while true;do curl 172.25.10.245:2379 ; done 172.25.10.245 172.25.50.250 172.25.6.37 172.25.10.245 172.25.50.250 172.25.6.37 172.25.10.245 172.25.50.250 172.25.6.37 172.25.10.245 172.25.50.250 172.25.6.37 172.25.10.245 172.25.50.250 172.25.6.37 172.25.10.245 172.25.50.250 172.25.6.37 172.25.10.245 172.25.50.250 172.25.6.37 172.25.10.245 <html><body><h1>403 Forbidden</h1> Request forbidden by administrative rules. </body></html> <html><body><h1>403 Forbidden</h1> Request forbidden by administrative rules. </body></html> <html><body><h1>403 Forbidden</h1> Request forbidden by administrative rules. </body></html> <html><body><h1>403 Forbidden</h1> Request forbidden by administrative rules. </body></html> <html><body><h1>403 Forbidden</h1> Request forbidden by administrative rules. </body></html> <html><body><h1>403 Forbidden</h1> Request forbidden by administrative rules.在/etc/haproxy/whitelist.lst文件中可以存放被放行的IP,而后reload生效即可。那我们在Runtime API中看下[root@node-www.linuxea.com ~]# echo "@1; show table frontend-web.com "|socat stdio /var/run/haproxy.sock # table: frontend-web.com, type: ip, size:1048576, used:1 0x7fbe7401b670: key=172.25.50.250 use=0 exp=809045 gpt0=1 http_req_rate(10000)=0我们可以通过api设置GPT0来释放12065> set table frontend-web.com key 172.25.50.250 data.gpt0 0 12065> show table frontend-web.com data.gpt0 gt 0 # table: frontend-web.com, type: ip, size:1048576, used:2 12065> show table frontend-web.com # table: frontend-web.com, type: ip, size:1048576, used:1 0x1c0f390: key=127.0.0.1 use=0 exp=659815 gpt0=0 http_req_rate(10000)=0或者直接删除12065> clear table frontend-web.com key 172.25.50.250 12065> show table frontend-web.com data.gpt0 gt 0 # table: frontend-web.com, type: ip, size:1048576, used:1 12065> show table frontend-web.com # table: frontend-web.com, type: ip, size:1048576, used:1 0x1c0f390: key=127.0.0.1 use=0 exp=659815 gpt0=0 http_req_rate(10000)=0更新ACL为了扩展上述限制传入HTTP请求的示例,我们假设现在要将现有速率限制从每秒30个更改为60个请求。为此,HAProxy Runtime API肯定允许我们在运行时更改ACL。我们将执行命令“show acl”以查看配置的ACL,然后识别我们要修改的ACL,最后执行实际修改。修改将包括添加新值,然后删除旧值以完成转换。完整的会话可能如下所示:12065> show acl # id (file) description 0 (/etc/haproxy/whitelist.lst) pattern loaded from file '/etc/haproxy/whitelist.lst' used by acl at file '/etc/haproxy/haproxy.cfg' line 77 1 () acl 'src' file '/etc/haproxy/haproxy.cfg' line 77 2 () acl 'src_http_req_rate' file '/etc/haproxy/haproxy.cfg' line 79 3 () acl 'sc0_get_gpt0' file '/etc/haproxy/haproxy.cfg' line 81 -1 () acl 'http_auth' file 'internal-stats-auth-compat' line 0我们仅仅对src_http_req_rate感兴趣,查看下12065> show acl #2 0x1b87610 30:而后添加一个新的6012065> add acl #2 60此时你会看到有两个12065> show acl #2 0x1b87610 30: 0x1c17a20 60我们随即将位于30秒的删除,0x1b8761012065> del acl #2 #0x1b87610在查看已经只有60s一个配置12065> show acl #2 0x1c17a20 60更新白名单和黑名单再次扩展我们的原始速率限制示例,请注意我们已使用以下配置指令来配置列入白名单的IP地址: http-request allow if { src -f /etc/haproxy/whitelist.lst }此配置行告诉HAProxy获取源IP,根据从whitelist.lst加载的IP地址列表进行检查,并在不进一步检查列表中是否找到IP地址的情况下通过请求。在此示例中,我们将使用Runtime API修改白名单的内容 - 我们将IP地址172.25.50.250添加。像往常一样,为此我们将列出ACL,识别我们想要修改的条目,然后执行实际修改。修改将包括添加新值,然后删除旧值以完成转换。完整的会话可能如下所示:12065> show acl # id (file) description 0 (/etc/haproxy/whitelist.lst) pattern loaded from file '/etc/haproxy/whitelist.lst' used by acl at file '/etc/haproxy/haproxy.cfg' line 77 1 () acl 'src' file '/etc/haproxy/haproxy.cfg' line 77 2 () acl 'src_http_req_rate' file '/etc/haproxy/haproxy.cfg' line 79 3 () acl 'sc0_get_gpt0' file '/etc/haproxy/haproxy.cfg' line 81 -1 () acl 'http_auth' file 'internal-stats-auth-compat' line 0列出12065> show acl #0 0x1b87080 10.10.0.96 0x1b870c0 10.10.195.99添加172.25.50.25012065> add acl #0 172.25.50.250在查看即可12065> show acl #0 0x1b87080 10.10.0.96 0x1b870c0 10.10.195.99 0x1b87610 172.25.50.250更新TLS当现有客户端想要在关闭前一个会话后启动新会话时,HAProxy使用tls-ticket-keys来避免密钥重新协商。如果客户端支持tls会话,HAProxy将向其发送包含所有协商会话数据(密码套件,主密钥等)的新会话凭证记录。该记录将使用仅为HAProxy进程知道的密钥加密,确保客户端不会读取或修改数据。用于加密TLS凭证的是在HAProxy启动时生成的。如果设置了主动 - 主动HAProxy群集并且客户端在节点之间移动,则必须经常重新协商密钥,因为群集中的其他节点将无法理解使用特定于节点的密钥加密的故障单。为了避免这种情况,可以将秘密放入文件中并定期轮叫它们以保持完美的前向保密。这样,集群中的所有节点都将使用完全相同的密钥集,客户端将能够在HAProxy节点之间移动而没有任何副作用。这可以通过更新包含键的文件并手动重新加载HAProxy来完成,但也可以在运行时使用HAProxy Runtime API完成。完整的会话可能如下所示:# List keys files > show tls-keys # id (file) 0 (/dev/shm/hapee_ticket_keys.txt) # List keys in a particular file > show tls-keys #0 # id secret # 0 (/dev/shm/hapee_ticket_keys.txt) 0.0 vaL65b3ns0mAJbiQRGiQZ84H4C9N1dZAyDYrHXVqG6KRDuXCo8mpwfk6+xPtlM1m 0.1 fQxhSJT8sBKNb6JAFZT11UkzplfXEI1uUijPQUTBysZpNqzT26s2RVARxCoo5E52 0.2 QtxrjBbPrX6z/PljdHIFqmHMH2/Rc5zZzIKklcfBPJa01G6PU9Dp9ixcibeisZxU # Update key > set ssl tls-keys #0 CaF7HpWr0gUByzxDqlbvYXCFT2zqmhnKFAdbM4MyQHfty974QO31Pn1OLJIR92rk TLS ticket key updated! # Verify successful update > show tls-keys #0 # id secret # 0 (/dev/shm/hapee_ticket_keys.txt) 0.0 fQxhSJT8sBKNb6JAFZT11UkzplfXEI1uUijPQUTBysZpNqzT26s2RVARxCoo5E52 0.1 QtxrjBbPrX6z/PljdHIFqmHMH2/Rc5zZzIKklcfBPJa01G6PU9Dp9ixcibeisZxU 0.2 CaF7HpWr0gUByzxDqlbvYXCFT2zqmhnKFAdbM4MyQHfty974QO31Pn1OLJIR92rk显示错误如上所述,HAProxy将错误记录到日志文件中。例如,如果我们发送简单的无效流量,如下所示:[root@node-www.linuxea.com ~]# echo "This is invalid traffic\n\nMore invalid traffic" | nc -v 172.25.10.245 2379 Ncat: Version 7.50 ( https://nmap.org/ncat ) Ncat: Connected to 172.25.10.245:2379. HTTP/1.0 400 Bad request Cache-Control: no-cache Connection: close Content-Type: text/html <html><body><h1>400 Bad request</h1> Your browser sent an invalid request. </body></html> Ncat: 48 bytes sent, 187 bytes received in 0.01 seconds.然后日志将显示以下错误:Jun 6 17:47:11 host-172-25-10-245 haproxy[12065]: 172.25.10.245:35540 [06/Jun/2019:17:47:11.193] frontend-web.com frontend-web.com/<NOSRV> -1/-1/-1/-1/0 400 187 - - PR-- 1/1/0/0/0 0/0 "<BADREQ>"但是为了获得有关请求的更多信息,甚至查看请求的内容,我们可以使用Runtime API命令“show errors”:[root@node-www.linuxea.com ~]# echo "@1;show errors" | socat stdio /var/run/haproxy.sock Total events captured on [06/Jun/2019:17:48:25.444] : 3 [06/Jun/2019:17:47:49.265] frontend frontend-web.com (#3): invalid request backend <NONE> (#-1), server <NONE> (#-1), event #2, src 172.25.10.245:35664 buffer starts at 0 (including 0 out), 16372 free, len 12, wraps at 16384, error at position 11 stream #35060, stream flags 0x00000000, tx flags 0x00000000 HTTP msg state MSG_ERROR(26), msg flags 0x00000000 HTTP chunk len 0 bytes, HTTP body len 0 bytes, channel flags 0x00d08002 : 00000 show errors\nDumping 会话根据日志记录配置,可以将所有连接记录到HAProxy的日志文件中。但是,像往常一样,只有在HAProxy从后端服务器获得回复或其中一个定时器到期后才会记录它们。在涉及长时间超时或会话需要很长时间才能完成的情况下,这可能会导致日志似乎永远不会到达。在这种情况下,Runtime API命令“show sess”可用于转储所有当前会话及其相关信息:[root@node-www.linuxea.com ~]# echo "@1; show sess " | socat stdio /var/run/haproxy.sock 0x7fbe7c016760: proto=tcpv4 src=172.25.50.250:19548 fe=frontend-web.com be=backend-linuxea.com srv=etcd3 ts=00 age=0s calls=1 cpu=77210 lat=9950 rq[f=cc08000h,i=0,an=8000h,rx=,wx=,ax=] rp[f=80000000h,i=0,an=00h,rx=,wx=,ax=] s0=[7,40008h,fd=20,ex=] s1=[5,110h,fd=24,ex=5s] exp=5s 0x1c01240: proto=sockpair ts=00 age=0s calls=1 cpu=9303 lat=17664 rq[f=c0c220h,i=0,an=00h,rx=,wx=,ax=] rp[f=80008002h,i=0,an=00h,rx=,wx=,ax=] s0=[7,280008h,fd=25,ex=] s1=[7,204018h,fd=-1,ex=] exp=在上面的例子中,我们可以看到两个会话:第一个是IPv4会话; 第二个是与我们调用Runtime API相关的会话。从查看输出,我们可以,例如,识别IPv4会话fe=frontend-web.com be=backend-linuxea.com。此外,为了帮助我们进一步解决复杂问题,我们可以使用命令“show sess”将会话ID作为参数提供(“show sess ID”)以获取有关特定会话的更多详细信息。tcpv4的回话太快,我么查看第二个[root@node-www.linuxea.com ~]# echo "@1; show sess 0x1c01240 " | socat stdio /var/run/haproxy.sock 0x1c01240: [06/Jun/2019:17:51:44.877386] id=48347 proto=sockpair flags=0x8, conn_retries=0, srv_conn=(nil), pend_pos=(nil) frontend=GLOBAL (id=0 mode=tcp), listener=? (id=2) addr=172.25.50.250:81 backend=<NONE> (id=-1 mode=-) server=<NONE> (id=-1) task=0x1c0a3f0 (state=0x00 nice=-64 calls=1 exp=<NEVER> tmask=0x1 age=0s) si[0]=0x1c014d8 (state=EST flags=0x280008 endp0=CS:0x1c01730 exp=<NEVER>, et=0x000) si[1]=0x1c01518 (state=EST flags=0x204018 endp1=APPCTX:0x1c09eb0 exp=<NEVER>, et=0x000) co0=0x1c00ec0 ctrl=sockpair xprt=RAW mux=PASS data=STRM target=LISTENER:0x1b7edb0 flags=0x00241300 fd=25 fd.state=22 fd.cache=0 updt=0 fd.tmask=0x1 cs=0x1c01730 csf=0x00001000 ctx=0x1c01750 app1=0x1c09eb0 st0=7 st1=0 st2=3 applet=<CLI> tmask=0x1, nice=-64, calls=1, cpu=0, lat=9846 req=0x1c01250 (f=0xc0c220 an=0x0 pipe=0 tofwd=0 total=22) an_exp=<NEVER> rex=<NEVER> wex=<NEVER> buf=0x1c01258 data=0x1be28c0 o=0 p=0 req.next=0 i=0 size=16384 res=0x1c012b0 (f=0x80008000 an=0x0 pipe=0 tofwd=-1 total=0) an_exp=<NEVER> rex=<NEVER> wex=<NEVER> buf=0x1c012b8 data=0x1c05a90 o=0 p=0 rsp.next=0 i=0 size=16384结束会话除了使用“show sess”显示活动会话外,我们还可以使用Runtime API通过“shutdown session”随意关闭会话:> shutdown session 0x7fbe7c016760此类会话将显示在包含标记“K”的日志中,表示它们已关闭。更新GeoIP数据库GeoIP数据库将IP地址范围映射到地理位置。这些数据库可以在HAProxy中用于不同的目的。通常,它们用于在HAProxy中本地执行GeoIP查找并将数据提供给后端服务器。然后,后端服务器可以依赖于作为传入请求的一部分可用的信息,不需要特定的GeoIP代码,也不会导致应用程序代码本身的任何减速。有关将GeoIP与HAProxy配合使用的更多信息,请参阅我们之前的博客文章“ 将GeoIP数据库与HAProxy一起使用”。GeoIP的另一个常见用例是在HAProxy日志中包含客户端国家/地区代码。这可以通过使用以下log-format指令来实现:以上行将使用map_ip转换器从映射文件ip-country.lst获取国家/地区代码。基于此格式的日志将如下所示:Jun 6 17:56:32 host-172-25-10-245 haproxy[12065]: 10.10.0.96:5231 [06/Jun/2019:17:56:32.955] stats stats/<STATS> 0/0/0/0/0 200 23696 - - LR-- 1/1/0/0/0 0/0 "GET /stats HTTP/1.1" Jun 6 17:56:33 host-172-25-10-245 haproxy[12065]: 10.10.0.96:5232 [06/Jun/2019:17:56:33.010] stats stats/<NOSRV> 0/-1/-1/-1/0 503 212 - - SC-- 1/1/0/0/0 0/0 "GET /favicon.ico HTTP/1.1"现在,在更新GeoIP数据库方面,我们假设我们在地图文件中有以下新的GeoIP条目:2.0.0.0/12 FR 3.55.0.0/24 FR 4.16.2.0/23 FR 9.16.10.0/24 FR我们可以使用Runtime API命令轻松地将它们添加到运行配置中add map。此外,我们将使用一些bash shell脚本来自动执行数据导入,而不是逐个添加条目:IFS=$'\n' for ip_country in $(cat /tmp/linuxea-ip.list); do echo "@1; add map #1 /tmp/ip-country.lst $ip_country" done | socat stdio /var/run/haproxy.sock这里会提示,因为这些IP无效[root@node-www.linuxea.com /var/log]# IFS=$'\n' [root@node-www.linuxea.com /var/log]# for ip_country in $(cat /tmp/linuxea-ip.list); do > echo "@1; add map #1 /tmp/ip-country.lst $ip_country" > done | socat stdio /var/run/haproxy.sock '/tmp/ip-country.lst' is not a valid IPv4 or IPv6 address. '/tmp/ip-country.lst' is not a valid IPv4 or IPv6 address. '/tmp/ip-country.lst' is not a valid IPv4 or IPv6 address. '/tmp/ip-country.lst' is not a valid IPv4 or IPv6 address.延伸阅读linuxea:haproxy 1.9中的多线程linuxea:haproxy1.9 了解四个基础部分linuxea:haproxy1.9日志简介
2019年06月08日
5,758 阅读
0 评论
0 点赞
2019-06-07
linuxea:haproxy1.9日志简介
在操作日志数据时,HAProxy提供了丰富的信息。在这篇博文中,我们将演示如何设置HAProxy日志记录,定位Syslog服务器,了解日志字段以及建议一些用于解析日志文件的有用工具。HAProxy位于基础架构的关键拓扑中。无论是用作load balancer,sidecar还是作为Kubernetes ingress controller,从HAProxy中获取有意义的日志都是必须的。日志记录可以为你提供有关每个连接和请求的详情。它实现了故障排除所需的可观察性,甚至可以用于及早发现问题。这是从HAProxy获取信息的众多方法之一。其他方法包括使用统计信息页面或runtime API获取指标,设置邮件警报,以及利用各种开源集成来存储日志或统计数据。HAProxy提供非常详细的日志,精确到毫秒级,并生成有关流入基础架构的流量的大量信息。这包括:有关流量的指标:时间数据,连接计数器,流量大小等。有关HAProxy调用信息:内容切换,过滤,持久性等。有关请求和响应的信息:标头,状态代码,有效负载等。会话的终止状态以及跟踪故障发生位置的能力(客户端,服务器端?)在本文中,你将学习如何配置HAProxy日志记录以及如何读取它生成的日志消息。然后,我们将列出一些在操作日志数据时会发现有用的工具。Syslog服务器HAProxy可以发出日志消息以供syslog服务器处理。这与熟悉的系统日志工具(如Rsyslog)以及较新的systemd服务日志兼容。你还可以使用各种日志转发器(如Logstash和Fluentd)从HAProxy接收Syslog消息,并将它们发送到中央日志聚合器。如具代表意义的有ELK等。如果你在容器环境中工作,HAProxy支持Cloud Native Logging,它允许你将日志消息发送到stdout和stderr。在这种情况下,docker的配置日志)。在研究如何通过HAProxy配置文件启用日志记录之前,应首先确保已配置Syslog服务器(如rsyslog)以接收日志。在centos7上,你将使用yum包管理器安装rsyslog,如下所示:[root@www.linuxea.com ~]# yum install rsyslog -y安装rsyslog后,编辑其配置以处理摄取HAProxy日志消息。将以下内容添加到/etc/rsyslog.conf或rsyslog.d目录中的新文件,如/etc/rsyslog.d/haproxy.conf:cat > /etc/rsyslog.d/haproxy.conf << EOF # Collect log with UDP \$ModLoad imudp \$UDPServerAddress 127.0.0.1 \$UDPServerRun 514 # Creating separate log files based on the severity local0.* /var/log/haproxy-traffic-linuxea-com.log local0.notice /var/log/haproxy-admin-linuxea-com.log EOF然后,重新启动rsyslog服务。在上面的示例中,rsyslog侦听默认UDP端口514上的IP环回地址127.0.0.1。此特定配置写入两个日志文件。选择的文件基于记录消息的严重性级别。为了理解这一点,请仔细查看文件中的最后两行。他们这样开始:local0.* ... local0.notice ...Syslog标准规定应为每个记录的消息分配facility code和严重性 级别。鉴于上面的示例rsyslog配置,你可以假设我们将配置HAProxy以使用facility code local0发送其所有日志消息。严重性级别在facility code之后指定,以点分隔。这里,第一行捕获所有严重性级别的消息,并将它们写入名为haproxy-traffic-linuxea-com.log的文件。第二行仅捕获通知级消息及以上,将它们记录到名为haproxy-admin-linuxea-com.log的文件中。在发送某些消息时,HAProxy被硬编码为使用某些严重性级别。例如,它将与连接和HTTP请求相关的日志消息与信息严重性级别分类。其他事件使用其他一个较不详细的级别进行分类。从最重要到最不重要,严重性级别为:| 严重程度 | HAProxy日志 | EMERG: | 诸如用尽操作系统文件描述符之类的错误。 | alert: | 发生意外情况的一些罕见情况,例如无法缓存响应。 | crit: | 不曾用过。 | err: | 诸如无法解析映射文件,无法解析HAProxy配置文件以及粘贴表上的操作失败等错误。 | warning:| 某些重要但非关键的错误,例如未能设置请求标头或未能连接到DNS名称服务器。 | notice: | 更改服务器的状态,例如UP或DOWN或禁用服务器。启动时的其他事件,如启动代理和加载模块也包括在内。运行状况检查日志记录(如果已启用)也使用此级别。 | info: | TCP连接和HTTP请求详细信息和错误。 | debug: | 你可以编写记录调试消息的自定义Lua代码现Linux发行版随服务管理器systemd一起提供,它引入了用于收集和存储日志的日志。journald服务不是Syslog实现,但它兼容Syslog,因为它将侦听相同的/dev/log套接字。它将收集接收的日志,并允许用户使用等效的日记字段(SYSLOG_FACILITY,PRIORITY)按facility code和/或严重性级别对其进行过滤。HAProxy日志配置HAProxy 配置手册解释了可以通过两个步骤启用日志记录:第一步是global使用log指令在该部分中指定Syslog服务器:global log 127.0.0.1:514 local0 该log指令指示HAProxy将日志发送到侦听127.0.0.1:514的Syslog服务器。消息与local0一起发送,local0是标准的,用户定义的Syslog Facility之一。它也是我们的rsyslog配置所期望的功能。你可以添加多个log语句以将输出发送到多个Syslog服务器。你可以通过将Syslog级别添加到行尾来控制记录的信息量:log 127.0.0.1:514 local0 info配置日志记录的第二步是更新不同的代理(frontend,backend和listen部分)以将消息发送到该global部分中配置的Syslog服务器。这是通过添加log global指令来完成的。你可以将其添加到该defaults部分,如下所示:defaults log global option httplog该log global指令基本上说,使用log该global部分中设置的行。将log global指令放入该defaults部分等同于将其放入所有后续代理部分。因此,这将启用所有代理的日志记录。你可以在我们的博客文章“HAProxy配置的四个基本部分”中阅读有关HAProxy配置文件各部分的更多信息。默认情况下,HAProxy的输出很小。将行添加option httplog到你的defaults部分将启用更详细的HTTP日志记录,稍后我们将对此进行更详细的说明。典型的HAProxy配置如下所示:global log 127.0.0.1:514 local0 chroot /usr/local/haproxy stats socket /var/run/haproxy.sock mode 600 level admin stats timeout 2m maxconn 4096 ###每个进程的最大连接数,默认4000 user haproxy #用户组 group haproxy daemon ###创建1个进程进入deamon模式运行。此参数要求将运行模式设置为"daemon" nbproc 1 #设置启动进程数,默认是1 nbthread 4 #4个线程 cpu-map auto:1/1-4 0-3 # 绑定cpu profiling.tasks on defaults mode http log global ###采用全局定义的日志 option dontlognull ###不记录健康检查的日志信息,日志不会记录空连接 option httpclose ###每次请求完毕后主动关闭http通道 option httplog ###访问日志类别http日志格式 option forwardfor ###如果后端服务器需要获得客户端真实ip需要配置的参数,可以从Http Header中获得客户端ip option abortonclose #当服务器负载很高的时候,自动结束掉当前队列处理比较久的链接 option redispatch timeout connect 5000ms #default 10 second timeout if a backend is not found timeout client 500000 ###客户端连接超时 timeout server 500000 ###服务器返回的响应时间 maxconn 100000 ###最大连接数 retries 3 ###。重试时间。3次连接失败就认为服务不可用,也可以通过后面设置 使用全局日志记录规则是最常见的HAProxy设置,但你可以将它们直接放入某个frontend部分。将不同的日志记录配置作为一次性配置可能很有用。例如,你可能希望指向不同的目标Syslog服务器,使用不同的日志记录工具,或根据后端应用程序的用例捕获不同的严重性级别。请考虑以下示例,其中linuxea.com-fe_site1和linuxea.com-fe_site2的frontend部分设置不同的IP地址和严重性级别:frontend linuxea.com-fe_site1 log 127.0.0.1 local0 notice # other configuration frontend linuxea.com-fe_site2 log 127.0.0.2 local0 warning # other configurationrsyslog示例当syslog配置完成后重启即可,而后启动haproxy观察日志start haproxy[root@www.linuxea.com ~]# haproxy -W -S /var/run/haproxy.sock -f /etc/haproxy/haproxy.cfghaproxy-traffic-linuxea-com.log[root@www.linuxea.com ~]# tail -f /var/log/haproxy-traffic-linuxea-com.log Jun 5 13:40:23 localhost haproxy[31362]: Proxy stats started. Jun 5 13:40:23 localhost haproxy[31362]: Proxy frontend-web.com started. Jun 5 13:40:23 localhost haproxy[31362]: Proxy backend-linuxea.com started. Jun 5 13:40:44 localhost haproxy[31365]: 10.10.0.96:7925 [05/Jun/2019:13:40:44.813] frontend-web.com backend-linuxea.com/etcd1 0/0/0/1/1 200 235 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1" Jun 5 13:40:46 localhost haproxy[31365]: 10.10.0.96:7933 [05/Jun/2019:13:40:46.215] frontend-web.com backend-linuxea.com/etcd2 0/0/0/0/0 200 243 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1" Jun 5 13:40:46 localhost haproxy[31365]: 10.10.0.96:7934 [05/Jun/2019:13:40:46.589] frontend-web.com backend-linuxea.com/etcd3 0/0/1/1/2 200 237 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1" Jun 5 13:40:46 localhost haproxy[31365]: 10.10.0.96:7941 [05/Jun/2019:13:40:46.813] frontend-web.com backend-linuxea.com/etcd1 0/0/0/1/1 200 235 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1" Jun 5 13:40:47 localhost haproxy[31365]: 10.10.0.96:7942 [05/Jun/2019:13:40:47.078] frontend-web.com backend-linuxea.com/etcd2 0/0/0/0/0 200 243 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1" Jun 5 13:40:47 localhost haproxy[31365]: 10.10.0.96:7943 [05/Jun/2019:13:40:47.213] frontend-web.com backend-linuxea.com/etcd3 0/0/1/1/2 200 237 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1" Jun 5 13:40:47 localhost haproxy[31365]: 10.10.0.96:7944 [05/Jun/2019:13:40:47.420] frontend-web.com backend-linuxea.com/etcd1 0/0/0/1/1 200 235 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"haproxy-admin-linuxea-com.log[root@www.linuxea.com ~]# tail -f /var/log/haproxy-admin-linuxea-com.log Jun 5 13:40:23 localhost haproxy[31362]: Proxy stats started. Jun 5 13:40:23 localhost haproxy[31362]: Proxy frontend-web.com started. Jun 5 13:40:23 localhost haproxy[31362]: Proxy backend-linuxea.com started.UNIX套接字日志记录记录到本地Syslog服务时,写入UNIX套接字可能比定位TCP回送地址更快。通常,在Linux系统上,在/dev/ log中可以使用侦听Syslog消息的UNIX套接字,因为这是GNU C 库的syslog()*函数默认发送消息的位置。像这样定位UNIX套接字:log /dev/log local0 但是,你应该记住,如果你要使用UNIX套接字进行日志记录,同时在chrooted环境中运行HAProxy,或者让HAProxy chroot使用chroot配置指令为你创建目录 -然后必须在该chroot目录中提供UNIX套接字。这可以通过两种方式之一完成。首先,当rsyslog启动时,它可以在chroot文件系统中创建一个新的侦听套接字。将以下内容添加到HAProxy rsyslog配置文件中:# unix套接字 $ModLoad imuxsock $AddUnixListenSocket /usr/local/haproxy/dev/log第二种方法是使用mount带有该--bind选项的命令手动将套接字添加到chroot文件系统。 mkdir /usr/local/haproxy/dev/ -p touch /usr/local/haproxy/dev/log mount --bind /dev/log /usr/local/haproxy/dev/log如果使用第二种方法,请务必在/ etc / fstab文件或systemd单元文件中添加一个条目,以便在重新引导后保持挂载状态。配置完日志后,你将需要了解消息的结构。在下一节中,你将看到组成TCP和HTTP级日志的字段。套接字配置示例haproxy.cfg中修改为global log /dev/log local0 .....在/etc/rsyslog.d/haproxy.conf中下面这段是必须的,不管是套接字还是UDP# Creating separate log files based on the severity local0.* /var/log/haproxy-traffic-linuxea-com.log local0.notice /var/log/haproxy-admin-linuxea-com.log而后添加# unix套接字 $ModLoad imuxsock $AddUnixListenSocket /usr/local/haproxy/dev/log完成的文件格式如下:[root@www.linuxea.com /etc/haproxy]# cat /etc/rsyslog.d/haproxy.conf # Collect log with UDP #$ModLoad imudp #$UDPServerAddress 127.0.0.1 #$UDPServerRun 514 # Creating separate log files based on the severity local0.* /var/log/haproxy-traffic-linuxea-com.log local0.notice /var/log/haproxy-admin-linuxea-com.log # unix套接字 $ModLoad imuxsock $AddUnixListenSocket /usr/local/haproxy/dev/log重启[root@www.linuxea.com /etc/haproxy]# systemctl restart rsyslog.service在查看即可[root@host-www.linuxea.com ~]# tail -f /var/log/haproxy-traffic-linuxea-com.log Jun 5 14:41:20 host-www.linuxea.com haproxy[3872]: 10.10.195.99:42604 [05/Jun/2019:14:41:20.923] frontend-web.com backend-linuxea.com/etcd3 0/0/0/2/2 200 237 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1" Jun 5 14:41:20 host-www.linuxea.com haproxy[3872]: 10.10.195.99:42606 [05/Jun/2019:14:41:20.930] frontend-web.com backend-linuxea.com/etcd1 0/0/0/1/1 200 235 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1" Jun 5 14:41:20 host-www.linuxea.com haproxy[3872]: 10.10.195.99:42608 [05/Jun/2019:14:41:20.936] frontend-web.com backend-linuxea.com/etcd2 0/0/0/0/0 200 243 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1" Jun 5 14:41:20 host-www.linuxea.com haproxy[3872]: 10.10.195.99:42610 [05/Jun/2019:14:41:20.941] frontend-web.com backend-linuxea.com/etcd3 0/0/1/-1/1 400 187 - - CH-- 1/1/0/0/0 0/0 "GET / HTTP/1.1"日志限制如果你需要限制存储的数据量,一种方法是仅采样一部分日志消息。对于随机数量的请求,将日志级别设置为静默,如下所示:frontend website http-request set-log-level silent unless { rand(100) lt 5 }请注意,如果可能,最好尽可能多地捕获数据。这样,你最不需要时就不会丢失信息。你还可以修改ACL表达式,以便某些条件覆盖该规则。http-request set-log-level silent unless { rand(100) lt 5 } OR <SOME_CONDITION>限制记录消息数量的另一种方法是option dontlog-normal在你的defaults或中设置frontend。这样,只捕获超时,重试和错误。你可能不希望始终启用此功能,但仅限于某些时间,例如执行基准测试时。注意如果你使用了日志限制,你将无法正常统计,这些限制会做一些过滤。docker日志格式如果你在Docker容器内运行HAProxy并且你正在使用HAProxy版本1.9,那么你可以将其发送到stdout和/或stderr,而不是将日志输出发送到Syslog服务器。将地址分别设置为stdout或stderr。在这种情况下,最好将消息的格式设置为raw,如下所示:global log stdout format raw local0 infoHAProxy日志格式你将看到的日志记录类型由你在HAProxy中设置的代理模式决定。HAProxy可以作为第4层(TCP)代理或第7层(HTTP)代理运行。TCP模式是默认模式。在此模式下,将在客户端和服务器之间建立全双工连接,并且不会执行第7层检查。如果你根据我们在第一部分中的讨论设置了rsyslog配置,你将在/var/log/haproxy-traffic-linuxea-com.log.log中找到该日志文件。在TCP模式下(通过添加设置)mode tcp,你还应该添加选项tcplog。使用此选项,日志格式默认为提供有用信息的结构,如第4层连接详细信息,计时器,字节数等。如果要重新创建此格式log-format,用于设置自定义格式,它将看起来像这样:log-format "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq"这些字段的描述可以在TCP日志格式文档中找到,尽管我们将在下一节中介绍几个。当HAProxy作为第7层代理运行时mode http,你应该添加选项httplog指令。它确保深入分析HTTP请求和响应,并且不会破坏与RFC兼容的内容。这种模式真正突出了HAProxy的诊断价值。HTTP日志格式提供与TCP格式相同级别的信息,但具有特定于HTTP协议的其他数据。如果你要使用重新创建此格式log-format,它将如下所示:log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"可以在HTTP日志格式文档中找到不同字段的详细说明。你还可以定义自定义日志格式,仅捕获所需内容。在你的或中使用log-format(或log-format-sd结构化数据系统日志)指令。阅读我们的博客文章HAProxy Log Customization以了解更多信息并查看一些示例。defaults`frontend`在接下来的几节中,你将熟悉使用option tcplog或时包含的字段 option httplog。添加的字段示例frontend www.linuxea.com bind *:2379 mode http option httplog log global # http-request set-log-level silent unless { rand(100) lt 5 } default_backend backend-linuxea.com log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"代理在生成的日志文件中,每一行都以请求发送到的前端,后端和服务器开头。例如,如果你具有以下HAProxy配置,则会看到将请求描述为通过http-in前端路由到静态后端然后再路由到srv1服务器的行。frontend www.linuxea.com bind :80 default_backend static backend backend-linuxea.com server srv1 192.168.1.10:80 check server srv2 192.168.1.11:80 check当你需要知道发送请求的位置时(例如,当看到仅影响某些服务器的错误时),这将成为重要信息。计时器计时器以毫秒为单位提供,涵盖会话期间发生的事件。默认TCP日志格式捕获的定时器为Tw / Tc / Tt。默认HTTP日志格式提供的是TR / Tw / Tc / Tr / Ta。这些翻译为:计时器 含义 TR:获取客户端请求的总时间(仅限HTTP模式)。 TW:在等待连接槽的队列中花费的总时间。 TC:建立与服务器的TCP连接的总时间。 TR:服务器响应时间(仅限HTTP模式)。 Ta:HTTP请求的总活动时间(仅限HTTP模式)。 TT:代理接受它的时刻与两端结束时刻之间的总TCP会话持续时间。你可以在HAProxy文档中找到所有可用计时器的详细说明。下图还演示了在单个端到端事务中记录时间的位置。请注意,边缘上的紫色线条表示计时器。在单个端到端事务期间记录时间。下图断开连接时的会话状态TCP和HTTP日志都包含一个终止状态代码,用于告诉你TCP或HTTP会话的结束方式。这是一个双字符代码。第一个字符报告导致会话终止的第一个事件,而第二个字符报告TCP或HTTP会话状态何时关闭。以下是一些终止代码示例:双字符代码 含义 - : 双方正常终止。 cd :客户端没有发送或确认任何数据并最终timeout client到期。 sc :服务器明确拒绝TCP连接。 pc :代理拒绝建立与服务器的连接,因为尝试连接时达到了进程的套接字限制连接可能已被关闭的原因有很多种。有关所有可能的终止代码的详细信息,请参阅HAProxy文档。计数器计数器指示请求通过时系统的运行状况。HAProxy为每个连接或请求记录五个计数器。它们在确定系统上放置了多少负载,系统滞后的位置以及是否已达到限制时非常有用。查看日志中的一行时,你会看到列为由斜杠分隔的五个数字的计数器:0/0/0/0/0。在TCP或HTTP模式下,这些分解为:记录会话时HAProxy进程上的并发连接总数。frontend记录会话时通过此路由的并发连接总数。backend记录会话时路由到此的并发连接总数。server记录会话时,此时仍然处于活动状态的并发连接总数。尝试连接到后端服务器时尝试的重试次数日志字段HAProxy不会记录开箱即用的所有内容,但你可以调整它以捕获你需要的内容。可以通过添加http-request capture指令来记录HTTP请求标头:frontend website bind :80 http-request capture req.hdr(Host) len 10 http-request capture req.hdr(User-Agent) len 100 default_backend webservers日志将显示花括号之间的标题,并用管道符号分隔。在这里,你可以看到请求的主机和用户代理标头:Jun 5 14:52:36 host-www.linuxea.com haproxy[4756]: 10.10.0.96:4910 [05/Jun/2019:14:52:36.613] frontend-web.com backend-linuxea.com/etcd1 0/0/0/1/1 200 235 - - ---- 1/1/0/0/0 0/0 {172.25.10.|like Gecko) Chrome/74.0.3729.169 Safari/537.36} "GET / HTTP/1.1"相比此前,日志中多了头部信息可以通过添加http-response capture指令来记录响应头:frontend website bind :80 declare capture response len 20 http-response capture res.hdr(Server) id 0 declare capture response len 20 http-response capture res.hdr(Content-Type) id 1 default_backend webservers在这种情况下,你还必须添加一个declare capture response指令,该指令分配一个捕获槽,一旦响应头到达,它就可以存储。你添加的每个插槽都会自动分配一个从零开始的ID。在致电时引用此ID http-response capture。请求标头之后,在一组单独的花括号内记录响应标头。日志表现如下:Jun 5 14:54:19 host-www.linuxea.com haproxy[4914]: 10.10.0.96:5497 [05/Jun/2019:14:54:19.382] frontend-web.com backend-linuxea.com/etcd1 0/0/1/0/1 200 235 - - ---- 1/1/0/0/0 0/0 {172.25.10.|like Gecko) Chrome/74.0.3729.169 Safari/537.36} {nginx|text/html} "GET / HTTP/1.1"可以看出,上述的日志中相比此前,多了{nginx|text/html}可以使用与http-request capture指令类似的方式记录Cookie值。frontend website bind :80 http-request capture req.cook(MyCookie) len 20 default_backend webservers捕获的任何内容http-request capture(包括HTTP标头和cookie)都将出现在同一组花括号中。任何捕获的东西都是如此http-response capture。Jun 5 14:57:27 host-www.linuxea.com haproxy[4987]: 10.10.0.96:6550 [05/Jun/2019:14:57:27.287] frontend-web.com backend-linuxea.com/etcd1 0/0/0/1/1 304 166 - - ---- 1/1/0/0/0 0/0 {172.25.10.|like Gecko) Chrome/74.0.3729.169 Safari/537.36|} {nginx|} "GET / HTTP/1.1"你还可以使用http-request capture记录棒表中的采样数据。如果你使用a 跟踪用户请求率stick-table,则可以将其记录为:frontend website bind :80 stick-table type ip size 1m expire 10s store http_req_rate(10s) http-request track-sc0 src http-request capture sc_http_req_rate(0) len 4 default_backend webservers因此,向包含HTML文档和两个图像的网页发出请求会显示用户的并发请求率增加到三个:Jun 5 15:13:24 host-www.linuxea.com haproxy[5141]: 10.10.195.99:21260 [05/Jun/2019:15:13:24.290] frontend-web.com backend-linuxea.com/etcd2 0/0/0/0/0 200 243 - - ---- 1/1/0/0/0 0/0 {172.25.10.|curl/7.29.0||1} {nginx|text/html} "GET / HTTP/1.1" Jun 5 15:13:25 host-www.linuxea.com haproxy[5141]: 10.10.195.99:21584 [05/Jun/2019:15:13:25.298] frontend-web.com backend-linuxea.com/etcd3 0/0/1/1/2 200 237 - - ---- 1/1/0/0/0 0/0 {172.25.10.|curl/7.29.0||2} {nginx|text/html} "GET / HTTP/1.1" Jun 5 15:13:26 host-www.linuxea.com haproxy[5141]: 10.10.195.99:21738 [05/Jun/2019:15:13:26.308] frontend-web.com backend-linuxea.com/etcd1 0/0/0/1/1 200 235 - - ---- 1/1/0/0/0 0/0 {172.25.10.|curl/7.29.0||3} {nginx|text/html} "GET / HTTP/1.1"你还可以记录fetch方法的值,例如记录所使用的SSL / TLS的版本(请注意,有一个内置的日志变量用于获取这个名为%sslv):# logs 'TLSv1.2' http-request capture ssl_fc_protocol len 10设置的变量http-request set-var也可以记录。frontend website bind :80 http-request set-var(req.MyVariable) str("My Value") if SOME_CONDITION http-request capture var(req.MyVariable) len 10ACL表达式计算为true或false。你无法直接记录它们,但可以根据表达式是否为true来设置变量。例如,如果用户访问/ api,你可以将名为req.is_api的变量设置为Is API的值,然后在日志中捕获该值acl is_api path_beg /api http-request set-var(req.is_api) str("Not API") http-request set-var(req.is_api) str("Is API") if is_api http-request capture var(req.is_api) len 10启用HAProxy性能分析随着HAProxy 1.9的发布,你可以记录在HAProxy中处理请求所花费的CPU时间。将profiling.tasks指令添加到你的global部分:global profiling.tasks on有一些新的fetch方法可以公开分析指标:获取方法 : 描述 date_us : 日期的微秒部分。 cpu_calls : 自分配以来处理流或当前请求的任务的调用次数。它会在同一连接上为每个新请求重置。 cpu_ns_avg : 每次调用处理流或当前请求的任务所花费的平均纳秒数。 cpu_ns_tot : 每次调用处理流或当前请求的任务所花费的总纳秒数。 lat_ns_avg : 在处理流的任务被唤醒的那一刻和它被有效调用的那一刻之间花费的平均纳秒数。 lat_ns_tot : 唤醒流的任务被唤醒的时刻与有效调用流的时刻之间的总纳秒数。将这些添加到你的日志消息,如下所示:log-format "%{+Q}r cpu_calls:%[cpu_calls] cpu_ns_tot:%[cpu_ns_tot] cpu_ns_avg:%[cpu_ns_avg] lat_ns_tot:%[lat_ns_tot] lat_ns_avg:%[lat_ns_avg]" # Outputs: "GET / HTTP/1.1" cpu_calls:2 cpu_ns_tot:7928946 cpu_ns_avg:3964473 lat_ns_tot:49814 lat_ns_avg:24907这是衡量哪些请求成本最高的好方法。日志就是这样的:Jun 5 15:16:21 host-www.linuxea.com haproxy[5250]: "GET / HTTP/1.1" cpu_calls:3 cpu_ns_tot:313669 cpu_ns_avg:104556 lat_ns_tot:45154 lat_ns_avg:15051 Jun 5 15:16:23 host-www.linuxea.com haproxy[5250]: "GET / HTTP/1.1" cpu_calls:4 cpu_ns_tot:268475 cpu_ns_avg:67118 lat_ns_tot:52472 lat_ns_avg:13118 Jun 5 15:16:24 host-www.linuxea.com haproxy[5250]: "GET / HTTP/1.1" cpu_calls:3 cpu_ns_tot:236518 cpu_ns_avg:78839 lat_ns_tot:44106 lat_ns_avg:14702 Jun 5 15:16:24 host-www.linuxea.com haproxy[5250]: "GET / HTTP/1.1" cpu_calls:3 cpu_ns_tot:318006 cpu_ns_avg:106002 lat_ns_tot:36628 lat_ns_avg:12209 Jun 5 15:16:24 host-www.linuxea.com haproxy[5250]: "GET / HTTP/1.1" cpu_calls:3 cpu_ns_tot:138176 cpu_ns_avg:46058 lat_ns_tot:31253 lat_ns_avg:10417解析HAProxy日志正如你所了解的那样,HAProxy有很多字段可以提供关于连接和请求的大量见解。但是,直接读取它们会导致信息过载。通常,使用外部工具解析和聚合它们更容易。在本节中,你将看到其中一些工具以及它们如何利用HAProxy提供的日志记录信息。HALogHALog是一个小而强大的日志分析工具,随HAProxy一起提供。它旨在部署到生产服务器上,可以帮助进行手动故障排除,例如面对实时问题时。它非常快,能够以每秒1到2 GB的速度解析TCP和HTTP日志。通过传递标志组合,你可以从日志中提取统计信息,包括每个URL的请求和每个源IP的请求。然后,你可以按响应时间,错误率和终止代码进行排序。我们先开始讨论如何安装[root@host-www.linuxea.com ~]# cd /usr/local/haproxy-1.9.0/contrib/halog/ [root@host-www.linuxea.com /usr/local/haproxy-1.9.0/contrib/halog]# make make: `halog' is up to date. [root@host-www.linuxea.com /usr/local/haproxy-1.9.0/contrib/halog]# ll total 108 -rw-rw-r-- 1 root root 7701 Dec 20 02:13 fgets2.c -rwxr-xr-x 1 root root 45208 Jun 5 15:39 halog -rw-rw-r-- 1 root root 47299 Dec 20 02:13 halog.c -rw-rw-r-- 1 root root 753 Dec 20 02:13 Makefile [root@DT_Node-172_25_10_245 /usr/local/haproxy-1.9.0/contrib/halog]# cp halog /usr/local/bin/例如,如果要从日志中提取每服务器统计信息,可以使用以下命令:[root@host-www.linuxea.com /var/log]# halog -srv -H < haproxy.log | column -t 19 lines in, 3 lines out, 15 parsing errors #srv_name 1xx 2xx 3xx 4xx 5xx other tot_req req_ok pct_ok avg_ct avg_rt backend-linuxea.com/etcd1 0 1 0 0 0 0 1 1 100.0 0 1 backend-linuxea.com/etcd2 0 1 0 0 0 0 1 1 100.0 0 0 backend-linuxea.com/etcd3 0 2 0 0 0 0 2 2 100.0 1 0当你需要解析每个状态代码的日志行并快速发现给定服务器是否不健康时(例如,返回太多5xx响应),这非常有用。或者,服务器可能拒绝太多请求(4xx响应),这是暴力攻击的标志。你还可以使用该avg_rt列获取每台服务器的平均响应时间,这有助于进行故障排除。使用HALog,你可以使用以下命令获取每URL统计信息:[root@host-www.linuxea.com /var/log]# halog -ut -H < haproxy.log | column -t 19 lines in, 1 lines out, 15 parsing errors #req err ttot tavg oktot okavg bavg btot src 4 0 2 0 2 0 238 952 /输出显示请求数,错误数,总计算时间,平均计算时间,成功请求的总计算时间,成功请求的平均计算时间,发送的平均字节数以及总数发送的字节数。除了解析服务器和URL统计信息之外,你还可以应用多个过滤器来匹配具有给定响应时间,HTTP状态代码,会话终止代码等的日志。HAProxy Stats使用HALog解析日志并不是从HAProxy中获取指标的唯一方法。该HAProxy的统计页面可以通过添加启用stats enable指令到一个frontend或listen部分。它显示服务器的实时统计信息。以下listen部分启动Stats页面,侦听端口8404:listen stats bind *:8404 stats enable stats uri / stats refresh 5s 统计页面对于获取有关流经HAProxy的流量的即时信息非常有用。但是,它不存储此数据,仅显示单个负载均衡器的数据。延伸阅读linuxea:haproxy 1.9中的多线程linuxea:haproxy1.9 了解四个基础部分
2019年06月07日
4,898 阅读
0 评论
0 点赞
1
2