Nginx后端节点可用性探测和配置实操
前面的时候,我们讲解了Nginx的负载均衡的配置,还有常见的一些策略
那他有没有一些更深入的东西我们可以掌握,且在实际工作中是非常有用的?
肯定是有的,那我们现在就通过一些案例背景,来进一步学习Nginx更多核心知识。
Nginx探测后端节点可用性
下面这一个是我们很常见的负载均衡的配置,但里面有两个参数,我们需要重点去掌握先。
upstream lbs {
server 192.168.0.106:8080 max_fails=2 fail_timeout=60s ;
server 192.168.0.106:8081 max_fails=2 fail_timeout=60s;
}
max_fails和fail_timeout这两个参数有什么意思呢?我们来详细的给他讲解这两个参数的作用以及强大之处。
假如请求分发到IP1这个节点,但是IP1这个节点已经挂了,那后续有其他请求,是不是还会继续分配给IP1这个节点呢?这个max_fails的配置就是表示允许某一个节点失败的次数,默认为1,当超过最大次数时就不会请求
那这个ip1节点没有分配流量,它是长时间都不会分配流量了吗?假如我这个节点又恢复正常之后,那是应该合理的给他分配一些流量。所以fail_timeout 这个配置,就表示在max_fails 次失败之后暂停分配流量的时间,默认是10秒。
综合起来解释:max_fails=N 设定Nginx与后端节点通信的尝试失败的次数,在fail_timeout参数定义的时间内,如果失败的次数达到此值,Nginx就认为这个节点不可用,在下一个fail_timeout时间段到来前,服务器不会再被尝试分配流量。如果设为0就会停止统计尝试次数,认为服务器是一直可用的。
那具体什么是nginx认为的失败呢,可以通过指令proxy_next_upstream来配置什么是失败的尝试。
这又是我们另外一个很常见的一个坑以及技能,下面再进一步去讲一下我们这个配置的使用。
但有个点先注意下:默认配置时,http_404状态不被认为是失败的尝试。
互联网公司基本架构都是如下图所示 (排除其他硬件负载均衡、流量清洗等组件)
整个链路基本都要考虑高可用,避免单点故障,先不说如何架构整个系统,
流量入口是Nginx, 再到业务网关或者公共网关,再到业务服务器,最后到数据库。
这边剖析几个实际工作中遇到的问题 和 团队小伙伴在生产环境犯的错误(其他公司里面的P0和P1事故)
先说几个场景:
场景一:由于你的重启部署,测试人员正在测试一个复杂项目,突然服务不可用;
再或者应用上线,生产环境启动不成功或者启动耗时久,导致线上接口成功率下降严重。
场景二: 为了解决上述的问题,前端或者后端进行了应用接口探测和请求重试,由于部分接口是新人开发没做好接口幂等性处理,导致业务数据故障。
在敏捷开发和持续交付盛行的时代,作为开发人员,在项目开发尾声或者进入提测阶段的时候,会把项目部署到测试环境,然后由测试人员进行测试。
稍微有点规模的公司都是有多套环境,用于应对不同场景,比如阿里、腾讯等这些大厂,应用开发上线的流程基本都 开发人员在开发环境验证好后,项目部署到测试环境发提测邮件,测试人员在测试环境测试,没问题后进入预发布环境,最后到上线到灰度或者生产环境。
看起来是不是很nice没问题?如果项目周期短,那开发和测试人员肯定会接触特别频繁,谁写的代码敢保证一定没有bug呢?
所以在提测阶段,测试人员发现了bug,反馈给开发人员进行修复,修复后又部署到测试环境;
由于开发人员的重新部署项目到测试环境,测试人员在测试一个重大功能或者复杂流程的时候,突然接口出现不可访问或者5XX错误,出现一两次可以忍受,但是频繁出现,测试人员就会提着40米的大刀来找开发人员,这个肯定是影响项目进度的。
且多数公司包括大厂,在测试环境的服务器配置比较差,且一个项目也不会分配太多服务器资源,所以部署启动又很耗时,复杂项目启动花个几分钟到十多分钟都是存在的,特别是项目周期短且急的情况下。
那怎么解决这个问题呢?
测试环境由测试人员进行部署,但往往应用部署需要有依赖上下文,比如数据库更新,配置文件更新,RPC接口更新,这些交给测试人员进行的话多少会有点难度,所以一般还是开发人员部署。
采用无感知部署和业务重试,这个思想也类似应用优雅上下线,总体流程是这样的:
一个请求到后端服务器,如果接口不可用或者出现特定的错误,比如5XX等,就把请求转发到另外一个应用节点,直到请求成功(也可以设置一定的转发次数)
那上述这个就可以解决由于重启应用导致接口不可用的问题,做到了无感知部署,但是也并非全部都是无感知的,先继续往下看。
那应该怎么做呢,有没啥开源的中间件可以解决我这个问题呢?
Nginx就可以解决你的这个问题,里面有个负载均衡模块upstream,里面最少配置两个后端应用节点
光这样就可以了吗?其实不是的,Nginx怎么知道你说的请求不可用是什么意思呢,认定标准是什么吗,
比如接口超时、服务不可用、Http状态码404、5XX错误等等,这些都是有问题的请求,肯定是可以指定的,所以你还需要配置下面这个指令 proxy_next_upstream
upstream lbs {
server 192.168.0.106:8080 max_fails=2 fail_timeout=60s ;
server 192.168.0.106:8081 max_fails=2 fail_timeout=60s;
}
location /api/ {
proxy_pass http://lbs;
proxy_next_upstream error timeout http_500 http_503 http_404;
}
可定制化才是最厉害的,如果业务认为http状态码404不需要转发,那把这个http_404去除即可。
所以使用了上述配置,如果你重启了某个节点,那测试人员是不是可以依旧正常进行测试了,假如请求分发到你重启的那个应用,请求失败后依旧会被转发到其他节点。
对应生成环境也是,如果某个服务器接口挂了,配置了重试策略,这个就可以做到自动转发请求, 接口容灾 ,除非全部节点都不可用。
一切都是那么如意,采用了上述的配置后,接口成功率也提高了,加入原先的时候是95%, 现在变成98%了。
但是,看问题别想的那么简单,业务故障的坑就来了。
接口重试一定要和业务互相配合,包括远程RPC调用,只要是涉及到数据的新增、修改、删除操作,你是否有考虑幂等性呢?尽管你有考虑,但是你能保证团队里面每个人都一直有重视这个问题不?
虽然有些同学会说 公司会做CodeReview代码审查,但谁能保证每次都可以全部审查完,包括很大厂也是没把这个工作落实好。
故障例子: 好比你做了一个话费充值项目或者发送验证码的接口,一般会涉及到第三方接口调用,是很容易报错或者超时的。
由于没做接口幂等性处理,接口重试会造成业务数据重复增加,比如老王充值了50元,由于接口没做幂等性处理,被转发了好几遍,那最终这个就是公司的资损了,如果再经过“羊毛党”规模化,造成的损失就大了。
尽管前端、后端代码 是没做请求重试,但是Nginx那么做了转发重试,最终酿成了业务故障。
所以Nginx这边的重试配置,上述默认只会对GET请求进行重试,其他的POST、PATCH等对数据有修改的请求是不进行重试的。
有兴趣的可以看下官方文档:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream
如果你想提高接口成功率,一定需要Nginx帮你做重试,那你需要做好接口幂等性处理, 然后在Nginx那边增加这个指令参数 non_idempotent
所以凡事有利也有弊,一定要细心,好比算法里面强调的,“时间和空间”,应该用时间换空间,还是空间换时间,还是两个取中间,没有绝对的事情,一定要和业务实际情况进行选择。
上面讲解了很多个例子,如果大家想实际操作那就可以按照下面这两个步骤进行验证。
-
暂停一个后节点,然后访问接口大于10次,Nginx会把这个节点剔除 -
重启这个节点,在fail_timeout周期里面不会再获取流量
upstream lbs {
server 192.168.0.106:8080 max_fails=10 fail_timeout=20s ;
server 192.168.0.106:8081 max_fails=10 fail_timeout=20s;
}
location /api/ {
proxy_pass http://lbs;
proxy_next_upstream error timeout http_500 http_503 http_404;
}
本章小结
掌握Nginx的fail_timeout 和 max_fails的使用
掌握Nginx的 proxy_next_upstream 的使用
- 点赞
- 收藏
- 关注作者
评论(0)