事情是这样的,服务端使用 tornado 提供 api 接口给客户端使用,存储使用 mysql ,使用 tormysql 连接 MySQL 数据库查询,前天下午时服务器网络突然断了, 15 分钟后回复,可是 api 接口还是无法使用,查看服务器状态,网络正常,负载正常,服务正常,于是去查看 nginx 日志,发现 99%的请求都 504 超时了,查看 mysql 服务器, cpu 负载接近 100%,命令行进 mysql show processlist 查看,将近 400 个查询正在运行,大量处于 statistics 状态,每个查询时间明显高了不少,但也还是有查询正常返回了,并未超过请求超时时间,为什么 nginx 显示几乎所有请求都超时了呢? 想不明白于是果断重启试试,重启不一会 504 超时又慢慢上升,不一会几乎所有的请求均超时无返回,如此数次还是无法正常启动,最后不得不关掉大部分借口再慢慢放开服务才起来,为此导致借口听着服务达数小时。 事后对 mysql 负载虽然满了,查询很慢却还是有返回,但请求几乎都超时甚是不接,于是仔细查看日志,终于发现原来网络异常后,客户端一直在重试,网络正常后,瞬间过来的并发高了十几倍,由于 tornado 异步 IO 高并发的特性,并未出现访问拒绝,而是接受了所有的请求,并都产生了 mysql 查询发往数据库,所有 mysql 瞬间并发查询十分高导致负载上升,每个查询耗时高达数秒,同时 tornado 在使用 tormysql 查询超过最大连接数后并进入队列等待,慢慢的,队列等待时间超过请求超时时间, nginx 返回 504 超时,但在队列中的查询还是继续发往 mysql ,因为客户端为收到正常返回,所以再次发起重试,又再次增加了查询队列的长度,最终所有请求在队列中等待 mysql 查询的时间都超过了请求超时时间,所以也就出现了 mysql 负载很高但几乎所有请求都超时的情况。 tornado 使用异步 io 确实实现了超高并发的支持,但也正是因为如此,但其依赖的后端服务超过负载后缺少快速失败的特性,其能同时接受大量请求的特性会使得在等待后端服务过程中出现循环超时,最终出现服务不可用情况,