最近在上线项目的过程中遇到由于一个请求大量查询数据库,导致生产系统宕机。后期在把开发、dba、运维都拉在一起开会讨论时,按dba提供的数据库配置 性能后都无法相信这个请求会导致数据库宕机。后面重新复盘,在执行一次这个请求后仔细排查执行过程,才发现是由于nginx自带的请求故障转移导致了这次的宕机。
我们系统是采用nginx作为负载均衡工具,负责转发请求到后端的应用节点。nginx有一个故障请求重试的机制。在后端节点请求超时时会把该请求自动转发到下一个节点,如果下一个节点返回结果则将该结果返回给用户,相关参数是proxy_next_upstream。但这次出现问题的请求需要大量查询数据库,性能无法优化,超过了nginx设定的超时时间。这种情况下雪崩开始了,nginx发现这个请求超时没有返回后将该请求转发到了其他的节点,相当于这个大请求执行了多次,这样更加加剧了数据库的压力,数据库宕机了,系统也无法响应了。
优化措施:优化该请求,另起线程执行耗时任务,缩短该请求的响应时间。
后面在网上看到这篇文章,Nginx upstream 失效转移机制研究,了解到nginx在get类型请求才会触发故障转移机制,在post类型则不会转发。而出问题的那个请求是get请求,如果是post发送该请求则不会导致上述问题。
结论:在nginx做负载均衡下,get类型的耗时的请求容易导致系统雪崩。需要优化请求,减少请求的响应时间或者改成post类型提交该请求。