2019.2.22 号凌晨 3 点半,是一个让人难以忘怀的、和瑞哥最后一次一起奋战的夜晚。
背景
我们有这样一个业务场景:用户提供各种数据源配置信息,然后基于数据源配置的模板,再者在模板基础上构建报表,而大数据计算平台则会根据这些信息生成数据计算任务,以实时、离线、混合的方式跑数,并将计算结果落到存储设备中。
线上事故
应用每天凌晨 1 点 10 分进行自清理重启后,会进行数据源连接池的初始化操作。而报表跑数也只能在数据源是连通的状态下正常进行,所以,这里我们就借助于 CountDownLatch 进行了数据源连接池初始化等待操作。正常情况下,不论是 Hive 集群、DRUID 集群还是 MySQL 等数据源都没出现问题。然后,事不绝对,海外的 Hive 集群的 HS2 却莫名其妙的不健康了(端口和服务监听仍在,但是就是不做任何 feedback),然而 Hive 连接是没有超时配置,和 MySQL 等不同,所以导致 CountDownLatch 计数器一直 Waiting 在最后一个数据源连接池初始化上,进而无法继续后续作业(因为数据源不完整,跑数便无意义),导致任务管理器、任务解析器以及后续的各个组件无法启动工作,最终还是我们的监控人员发现了该状况(任务量不正常、集群负载不正常、任务并发数不正常),紧急通知我们,经过排查发现是因为海外的 Hive 数据源连接池初始化无响应造成阻塞,影响任务运行,此时如果再大费周章联系对方集群负责人,估计受影响任务量会更大,白天根本追加不回来,会严重影响数据 KPI,苦逼些可能忙碌一年,到年底没了年终奖,岂不扯皮。所以,当机立断,禁用了海外 Hive 数据源,应用正常启动运行,然后就是追补数据的工作,还好抢救及时,今天白天任务正常完成。
事后反思
CountDownLatch 就是这么强大,你只要不调用 CountDownLatch#countDown(), 那我就敢等到地老天荒。但是,使用 CountDownLatch 的人也有责任,太过于相信集群的健康程度以及监控,即使知道 Hive 连接没有超时限制,却没有通过代码把控最大连接超时时间,如果指定时间内没有返回,就直接调用一次 countDown() 即可。可能你会说,那如果刚好那个时间点出现了网络延迟,导致连接请求一直没返回呢?你这样岂不是就无法初始化该数据源连接池了?这也简单,我们可以通过重试机制来处理,比如重试 3 次连接请求,如果均不可行,就直接调用 countDown 方法返回即可,这样就不会影响其他业务了。当然,后续也可以针对不同数据源进行相应隔离初始化,这样也只有使用该数据源的报表会受影响。
总结
不要过分相信监控指标等信息
针对长耗时的业务,一定要做超时限制,不可无所谓的放任
CountDownLatch 的确在高并发场景很实用,但是使用不当也会带来一定隐患
居然感觉和瑞哥一起奋战的夜晚时间很幸福的事情!