Home | 简体中文 | 繁体中文 | 杂文 | Github | 知乎专栏 | 51CTO学院 | CSDN程序员研修院 | OSChina 博客 | 腾讯云社区 | 阿里云栖社区 | Facebook | Linkedin | Youtube | 打赏(Donations) | About
知乎专栏多维度架构

2.3. 多维度架构之超时时间

超时时间俗称 Timeout 它是引起应用程序无响应或者网络服务雪崩灾难的罪魁祸首。

超时时间设置非常讲究,太长不行,太短也不行。

超时时间有哪些?

  1. 网络超时
  2. 文件系统超时
  3. 内存分配时间超时
  4. 磁盘IO时间超时
  5. 执行时间超时

2.3.1. 无处不在的超时时间

早期架构相对简单,拓扑成线性,例如:

		
用户 —> WEB服务器 —> 应用服务器 —> 缓存 —> 数据库
		
		

这是最典型的应用了,我们就用这个来举例,所有例子都是我职业生涯中遇到过的,绝对真实。

很早的时候,那时还没有分布式文件系统,不过我们的系统IO压力不大,仅仅是为了高可用。我们使用 NFS 共享 WEB服务器上的HTML文件和图片。然后通过DNS轮询做负载均衡,这是 2005年之前常用的做法。

发生了什么呢,NFS 发神经,用一段时间后出现卡顿,读不出数据,Apache httpd 的超时时间设置为 60s 秒,此时WEB服务器进来一个用户启动一个进程(那时 httpd 还不支持多线程),读取NFS共享的HTML,httpd 一直读不出来文件内容,直到60秒后 httpd 才会返回 500 错误给用户,用户始终超时等待。就这样,来一个用户,启动一个进程,用不了多久 httpd 最大连接数将被尽。

如果我们将超时时间30秒,可以加速进程的释放时间,可能会缓解 NFS 问题。设置成10秒呢? 答案是不行,有些请求过程中会出现网络不稳定的情况,设置成10秒钟,httpd 就会终止用户连接。这种情况在大文件下载,上传的过程中较为明显。

从WEB服务器到应用服务器,可能是 cgi-bin, fastcgi, servlet 等等,连接方式有反向代理,也有特别的协议(好久不用忘记Tomcat 插件,好像叫 mod-jk)也有超时设置。设置不当会出现什么问题呢?

开发中我们要计算一个请求所花费的时间,尽量在5秒之内完成执行并返回结果,大于五秒就会产生用户流失,用于没有耐心等待页面完成加载,就会跳到其他网站。所以超时时间设置 60 秒基本上没有什么意义,只有下载和上传服务可能会用到。正常控制在 20-30秒可以应对大多数需求。同时 WEB 服务器 与 应用服务器的设置需要匹配,例如 WEB服务器设置为 30秒,应用服务器设置为 60秒的后果是,程序还没有执行完成,WEB服务器就切断了与后面应用服务器的联系,并返回500错误。所以说后面应用服务器的超时时间设置,不能大于前面WEB服务器的超时时间设置。WEB切断与应用服务器通信后,应用服务器仍会继续执行,如果是 fastcgi 就可能看到非常多的进程在运行,并处于等待状态。

从应用服务器到缓存服务器,我遇到过这样一个事故,一名初级开发人员首次使用 memcached (那时还没有 Redis)没有经验,正确应该将一个数据结构序列化后存储到 memcache 中,他将这组数据,一条一条的写入memcache ,使用的时候使用循环遍历所有的 key。导致执行时间超过一分钟。 这样程序始终无法在规定的超时时间执行完成。上线后立即崩溃,虽然也做了压力测试,但是有很多代码在测试环境是无法展现的。压力测不是万能的。

最后是数据库超时时间,数据库超时时间的设置,执行超时时间比网络超时时间更重要。所谓执行超时时间,就是控制执行SQL语句的时间,在规定时间没有完成查询就直接返回超时。这样做的目的是为了保护数据库,否则数据库很容易就崩溃了。跟前面的例子一样,如果将数据库执行超时时间设置为60秒,有一条SQL执行很慢,运行时间超过60秒,查询就会堆积,直到数据库连接数被占用完为止。所以我们要经常审计慢查询日志。

再说说网络设备造成的延迟,前面谈到的各种服务器应用出现问题都比较好排查,基本都是可见。网络设备造成的故障就比较难,理由水晶头氧化了,网络偶尔出现丢包卡顿。重新插拔一次水晶头故障就消失了。

2.3.2. 流量漏斗

流量是呈现漏斗状的,每经过一个节点,流量会被分流,例如 1000 个用户访问你的网站,60% 是 HTML,被WEB服务器分流了(当然还有CDN)。剩下流量进入了应用服务器, 可以不需要访问数据库,被分流了 10%,剩下访问需要查询缓存,被分流 20%,最后 10%的流量需要查询数据库。那么这样设置超时时间合理吗?

			
用户(30秒) —> WEB服务器(30秒) —> 应用服务器(30秒) —> 缓存(30秒) —> 数据库(30秒)
			
		

答案是不合理,你应该参考漏斗模型去设置,前大后小的原则。

2.3.3. 微服务的超时时间

前面我以2005年网络架构为例是因为简单好理解,2005-2015 年的这段时间架构发生了天翻地覆的变化,这里一笔带过。最近五年最流行的是「微服务」。 我看到很多谈及架构文章中,大量的使用网关,层层代理,才触动了我写该文章,少有文章会谈到网络延迟和超时时间。

由于微服务提出了熔断器的概念,可以防止服务雪崩,微服务中会使用这种熔断技术。这相当于被蛇咬了,不管蛇有没有毒,先断臂自救,以现在的医疗技术是可以治愈的,但是却选择了截肢。而我们要做的是不让这种事情出现。

2.3.4. 容器技术的超时时间

Kubernetes 有种 sidecar 技术,为每个 pod 设置一个代理,这种方案优势是让容器更好管理。但是增加了超时的设置的规划难度。

2.3.5. 最后总结

目前几乎所有公司的架构设计首先服务于交付,交付后线上出现很多问题,然后再救火,修补,总结。交付后再做优化的结果,就是你在网上看到那些《XXXXX 踩过的坑》