同事反馈有一组应用的定时任务不执行了,简单看了下,该应用未定义过基于 TaskScheduler
或 ScheduledExecutorService
实现的 Bean,此时 Spring 会在 ScheduledTaskRegistrar.scheduleTasks() 中创建一个单线程的任务调度器:
1 | /** |
同事反馈有一组应用的定时任务不执行了,简单看了下,该应用未定义过基于 TaskScheduler
或 ScheduledExecutorService
实现的 Bean,此时 Spring 会在 ScheduledTaskRegistrar.scheduleTasks() 中创建一个单线程的任务调度器:
1 | /** |
前段时间有线上实例被负载均衡判定不可用,随即被摘除,同时我们收到该实例的 JVM GC 耗时较长的告警及负载较高的告警。从操作系统级别的监控可以看到磁盘读取速度几乎达到该规格的上限,近 120MB/s,IOPS 为 2200 左右,使用 ssh 登录该实例需要等待很久,且进入实例后几乎无法输入命令,2 核的机器负载达到了 20 左右。持续了七八分钟会恢复正常,恢复正常后我首先查看了 GC 日志,确认是否存在大量 FullGC,但是从日志中并未发现长时间的 Full GC,普通的 GC 的 real 耗时都很久,部分 GC 日志如下:
业务方反馈一到晚上就有接口时好时坏,用浏览器访问的话表现就是一直处于 pending 状态,直到超时,多次尝试的话有时又会恢复正常。开始怀疑是接口内部实现问题,于是我在多个请求处于 pending 状态时拉取了栈帧进行检查,发现没有符合该接口实现的栈帧。于是怀疑连接建立问题,使用 telnet 443 对负载均衡服务器发起连接,表现也是卡住,于是去查了该负载均衡实例的监控,果然是活跃连接数已经达到该实例的上限导致,因为当时选用的最低配,根本不能支撑现有的业务量,于是直接升配解决。可以猜测该实例到达连接数上限时采取的策略是丢弃 SYN 包,导致客户端重传直到超时,而没有采取直接返回 RST 的方式。当然这只是我根据现象进行的推测,具体的原因可以用 Wireshark 抓包确认,只不过这次还没用到就解决了该问题。
之前遇到类似的问题,最后排查出来是因为风控系统将特定 IP 加入了负载均衡层的黑名单,表现也是一直处于 pending 状态,猜测负载均衡服务器的实现也是丢弃 SYN 包。
设置调度器的核心逻辑位于 ScheduledAnnotationBeanPostProcessor.java at v4.3.16.RELEASE:
1 | @Override |
Bits
类中通过申请 8 字节的内存,然后填入一个 Long
类型的数字再根据头部字节判断出大端序还是小端序,源码位于 jdk/Bits.java at jdk8-b120:
1 | static { |