一次服务访问超时故障引发的分析

请点击上方 “民生运维人” 添加订阅!

随着IT系统架构不断向微服务方向发展,我行目前已有数百套业务应用系统在运行,应用系统间以及应用系统与基础中间件之间,存在着数量庞大的高频服务访问。近日,我们在生产环境遇到一次服务访问超时故障,由于某三方设备的底层故障,导致部分网络包在短时间内“丢失”无应答,进而导致部分应用系统之间、应用系统到数据库之间的服务访问超时,出现了所谓的HANG现象。尽管大多数应用系统具备熔断、限流等服务治理机制,但部分资源隔离不甚完善的系统还是受到了影响。

在复盘分析中,我们就以下几个问题进行了分析研究。

  • 如何在开发测试环境中模拟此类超时问题。

  • 当系统间访问的数据包持续“丢失”(包括TCP重传的包)时,应用程序经过多久才能得到超时错误。

  • 新建连接和已有连接读写的超时时间是否一样,能否通过参数控制。

环境和工具

为了模拟服务请求超时,使用两台CentOS的虚拟机模拟服务的请求方和提供方,其中一台安装了DB2服务器,另一台安装DB2客户端,具体参数如下:

其中一台安装了DB2服务器,另一台安装DB2客户端,具体参数如下:

在基本环境就绪后,下一个问题就是如何模拟超时故障,这存在一定的难度,原因如下。

  • 新建TCP连接超时。源于UNIX的socket套接字接口中封装了整个TCP三步握手,应用程序员无法介入这个过程。

  • 访问中间件超时。例如访问数据库或者某个对象存储服务,虽然可以通过特定的操作(例如制造死锁)让应用访问超时,但不同的中间件需要不同的方法,而且有些中间件自身有保活机制,与网络层的无响应还是有一定区别的。

经过调研,我们选择使用linux自带的iptables工具进行网络超时的模拟。iptables工具可用于设置、维护和检查Linux操作系统的IP包过滤规则,从而对出入访的网络数据包进行控制,使用iptables命令可以方便的复现网络超时的故障场景。

下面通过实验展示如何对新建连接和已有连接访问进行超时模拟验证。此外还整理了影响超时时间的操作系统、数据库参数,以方便读者参考。

场景1:已有连接访问超时

该场景在长连接通信时较为常见,这里模拟客户端与服务端已成功建立连接,在后续通信中,网络链路上出现不响应的情况。

首先在服务端清空iptables规则。

在客户端连接服务端的数据库成功后,执行一条查询语句。

在服务端使用iptables设置规则丢弃60000端口的PSH包和ACK包。

以下命令中,–dport 指定端口,–tcp-flags用来指定TCP包头标志位,ALL表示(SYN,ACK,FIN,RST,URG,PSH)的标志都检查,但只匹配PSH和ACK。-j DROP设置匹配后的目标为丢弃。

再次执行同样的查询语句, 即可观察到超时的现象。可以看到大概920秒后客户端才返回报错信息。 该时间受Linux操作系统参数tcp_retries2(默认15)控制。

以上错误码110在标准库头文件errno.h中定义。

在服务端观察,可以发现连接大概2个小时后才被清理,该时间受Linux操作系统参数tcp_keepalive_time/ tcp_keepalive_probes/tcp_keepalive_intvl控制。

下面修改客户端操作系统参数tcp_retries2 = 8后再重复上面案例(省略重复步骤)。

再次发起数据库查询,可以观察到客户端的超时时间从920秒缩短到约100秒。

场景2:新建连接超时

该场景在短连接通信时较为常见,这里模拟客户端对服务端发起新请求,在建立连接时,网络链路上出现不响应的情况。

和场景1类似,在服务端通过 iptables命令配置丢弃60000端口的 SYN 报文

在客户端发起telnet 命令,经过127秒后客户端报超时。该时间受Linux操作系统参数tcp_syn_retries(默认6)控制。

通过tcpdump命令抓包可以看到客户端分别在1/2/4/8/16/32秒重试了6次后,返回超时。

修改了tcp_syn_retries参数为4后,可以观察到超时时间直接从127秒变成了15秒,限于篇幅不再赘述。

验证结果

Linux环境下,新建连接的超时时间默认为127秒,对应操作系统参数为tcp_syn_retries。已有连接的访问超时时间默认为920秒,对应操作系统参数为tcp_retries2。

在应用程序、中间件(见下文)、操作系统几个层级,均有对应的超时时间控制参数,同时使用时优先级为应用程序设置大于中间件设置,中间件设置大于操作系统设置。下面以表格的形式将全部验证结果列举如下,供读者参考。

首先是已有连接访问超时的场景。

注意,长查询不返回结果集时,客户端与数据库之间持续有网络包(ACK载荷为零),不会触发OS层超时,但如果配置了DB层读超时参数(详情见下文),则会触发DB层的超时。因此DB层的超时判断机制无法区分网络层无响应和长查询不返回这两种情况,一旦设置了DB层的超时参数,长查询可能也会报错中断,这对一些数据分析系统可能影响正常业务运行,需要注意。

下面是新建连接超时的场景。

*相关命令:

关闭防火墙*,Linux命令:firewall-cmd –permanent –remove-port=60000/tcp

关闭网卡*,Linux命令:ifconfig enp0s3 down,AIX命令:ifconfig 网卡名 down

数据库访问超时参数调研

针对数据库访问涉及的超时参数,同样利用iptables命令进行了模拟验证,这里以DB2为例,将验证结果列举如下,供读者参考。

已有数据库连接访问超时

新建数据库连接超时

对数据库应用来说,超时参数的优先级为应用程序中设置(CLI/JDBC) > 配置文件(db2dsdriver.cfg > db2cli.ini) > 中间件设置(DB2注册变量)。

其他工具和混沌工程

除了本文中提到的iptables工具,还有其他工具可以用于实现类似的超时模拟验证。Linux上的网络流量控制工具tc(traffic control)可以轻松设置延时(delay)、丢包率(loss)等参数,将丢包率设置为100%也可以完成上述验证。nftables作为iptables工具的下一代增强工具,在较新内核版本的Linux(3.13以上)上已经被支持,并可以直接兼容iptables命令。当然也有一些对用户更友好的高阶工具如ufw和firewalld可以用于部分场景的模拟验证。

不得不说,自从NetFlix提出了Chaos Monkey工具,混沌工程技术近年越来越被人们所接受,用来在测试乃至生产环境中进行主动的故障注入,验证系统的健壮性和可靠性。随着时间的推移,越来越多的方法论、原则和试验设计方法被提出和不断丰富,甚至提出了混沌工程成熟度这样的体系化模型,恰逢IT系统云化及分布式演进中遇到了对系统架构的弹性挑战,可以说混沌工程有潜力发展成为一个新的独立的IT工程分支领域。

在笔者看来,混沌工程最大的特点是对故障场景的全面覆盖、经验沉淀和工具化。以下是混沌工程国产开源项目ChaosBlade的命令行工具选项,从中可以看出其覆盖了非常多的故障场景。

在GitHub上搜索关键词chaos可以找到很多的混沌工程开源项目,star数最多的包括Netflix的chaosmonkey/SimiaArmy,Shopify的toxiproxy,阿里的chaosblade。同时还有一些专门技术领域内的工具,例如针对k8集群的kube-monkey,这里不再赘述。

目前,民生银行信息科技部已经启动了自主的混沌工程工具研发工作,除了通用的故障场景覆盖以外,将提供更好匹配我行技术框架和体系架构的故障模拟和验证能力。

近年来IT架构的快速演进,大大提高了其复杂性,微服务架构导致了应用系统数量快速增加,系统间的服务调用呈指数级增长,带来了异步、负载均衡和服务治理等需求;分布式架构则带来了数据一致性、分布式事务、分布式协同等问题;而系统云化则引入了容器层的各种组件,带来了相应的调度、编排和管理要求。

所有这些变化都导致应用系统故障的影响分析和处理愈发困难,抛开故障的来源和种类来看故障影响的形式,一般导致立即失败的故障处理是相对容易的,但对访问超时的情况,异常处理会相对复杂很多,对服务间访问需要完善的服务治理机制,对应用与基础中间件之间的访问超时异常,则需要建立资源隔离机制并设置合理的超时时间,避免少数高频访问超时耗尽应用系统资源,导致无法提供其他正常的服务,进而导致全局性的故障。

作为应用运维团队,在实际工作中不时会遇到服务访问超时的情况,持续时间短一般称之为抖动,持续时间长则很危险,相较于逻辑错误、数据问题影响更大。本文中介绍的工具和方法,曾几次帮助我们复现、模拟、定位一些在生产环境中遇到的疑难问题。

通过本文的分析和整理,相信读者可以对服务访问超时的现象、影响因素、分析方法能有一个更全面的认识,在设计应用系统的异常处理机制时更有把握。

作者介绍:

刘畅:民生银行信息科技部应用运维工程师,目前主要负责支付领域的运维工作。

苗庆松:IBM认证高级数据库管理员,MySQL OCP。曾任职于IBM全球技术服务部技术支持中心,2018年加入中国民生银行信息科技部系统管理中心,负责数据库运维相关工作。

陈昊:民生银行信息科技部应用运维工程师,2018年加入民生银行,目前主要负责支付领域支付产品系统的运维工作。

作者:刘畅、苗庆松、陈昊

编辑:民生运维文化建设组