我们的 Scala 应用程序(Kubernetes 部署)不断遇到约 3 秒的 Akka 集群心跳延迟。
有一次我们甚至出现了 200 秒的延迟,如下图所示:
有人可以提出进一步调查的建议吗?
规范
- Kubernetes 1.12.5
requests.cpu = 16
# limits.cpu not set
- 斯卡拉2.12.7
- Java 11.0.4+11
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:+AlwaysPreTouch
-Xlog:gc*,safepoint,gc+ergo*=trace,gc+age=trace:file=/data/gc.log:time,level,tags:filecount=4,filesize=256M
-XX:+PerfDisableSharedMem
- Akka 集群 2.5.25
Java 飞行记录
一些例子:
timestamp delay_ms
06:24:55.743 2693
06:30:01.424 3390
07:31:07.495 2487
07:36:12.775 3758
有 4 个可疑时间点,其中发生了大量 Java Thread Park 事件 同时注册 Akka 线程(参与者和远程处理) 所有这些都与心跳问题相关:
07:05:39
左右没有“心跳延迟”日志,但有以下日志:
07:05:39,673 WARN PhiAccrualFailureDetector heartbeat interval is growing too large for address SOME_IP: 3664 millis
期间未发现与暂停事件或阻塞线程的相关性 Java 飞行记录 session ,只有两个 Safepoint Begin 事件 接近延误:
CFS 节流
应用程序 CPU 使用率较低,因此我们认为这可能与
how K8s schedule our application node for CPU 。
但关闭 CPU 限制并没有多大改善,
尽管kubernetes.cpu.cfs.throttled.second
指标消失了。
单独的调度程序
使用单独的调度程序似乎没有必要,因为即使在以下情况下也会发生延迟 没有负载,我们还构建了一个与我们自己的类似的显式应用程序 除了心跳之外什么也不做,但它仍然会遇到这些延迟。
K8s集群
根据我们的观察,这种情况在以下几个 K8s 节点上发生的频率更高: 当我们的应用程序加载不多时,与许多其他应用程序共享一个大型 K8s 集群。
单独的 我们的应用程序经过负载测试的专用 K8s 集群几乎没有任何问题 心跳延迟。
最佳答案
您是否能够排除垃圾收集的可能性?根据我的经验,这是 JVM 分布式系统中心跳延迟的最常见原因(并且 Kubernetes/Mesos 环境中的 CFS 配额可以使非 Stop-The-World GC 有效地 STW,特别是如果您没有使用最近的(高于 JDK8 版本 212)的 openjdk 版本)。
“安全点开始”之前的每个线程停放确实让我相信 GC 实际上是罪魁祸首。某些 GC 操作(例如重新排列堆)要求每个线程都处于安全点,因此在未阻塞时,线程会经常检查 JVM 是否希望它们处于安全点;如果是这样,线程会自行停顿以到达安全点。
如果您排除了 GC,您是否在云环境中运行(或者在无法确定 CPU 或网络是否超额订阅的虚拟机上)? akka-cluster 文档建议增加 akka.cluster.failure- detector.threshold 值,该值默认为适合更受控制的 LAN/裸机环境的值:建议云环境使用 12.0。这不会防止延迟的心跳,但会减少由于单个长心跳而导致虚假关闭事件的可能性(并且还会延迟对真正的节点丢失事件的响应)。不过,如果您想容忍心跳间隔时间从 1 秒到 200 秒的峰值,则需要一个非常高的阈值。
关于java - Kubernetes 上的 Akka 集群心跳延迟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58015699/