记一次 Java Testcontainers CPU 100% 问题排查过程

news2025/1/10 14:01:45

以为代码进入了死循环,结果并没有!

文章目录

    • 背景与问题
    • 排查过程
      • 代码路经确认
      • 内存分析
      • 咨询 okio 社区
      • 等等,好像并没有死循环
      • 能否从内存快照发现其他问题?

背景与问题

本问题来源于 ShardingSphere issue:
Integration tests occasionally stuck in waiting for container ready #19648

为保证代码质量,Apache ShardingSphere 有自动化运行的单元测试、集成测试,测试会在每次提交 Pull Request 时通过 GitHub Actions 自动运行。

其中有一个专门做集成测试的模块,以前叫 integration-test,现在叫 e2e。集成测试会通过 Docker 启动 ZooKeeper、ShardingSphere-Proxy 等测试所需进程,通过客户端连接 Proxy 运行测试用例并断言。

前段时间,有几次在 GitHub Actions 上运行的集成测试发生超时退出,但是从日志上看,发生超时情况时都还没有开始运行测试用例,很可能是卡在环境准备阶段。

在开发 ShardingSphere 的过程中,也有本地运行集成测试的需求。有一次,在本地运行集成测试时,发现测试运行了十几分钟还是没有动静。

排查过程

代码路经确认

通过 top 命令观察,发现 Java 进程 CPU 100%,只有其中一条线程 100%。
jstack 观察到,消耗 CPU 的应该只有主线程 main,CPU 100% 的情况已经跑了接近 20 分钟了。以下为 jstack 输出结果节选:

"main" #1 prio=5 os_prio=0 cpu=1161262.57ms elapsed=1164.15s tid=0x00007feca80259b0 nid=0x22f2ae runnable  [0x00007fecadfb5000]
   java.lang.Thread.State: RUNNABLE
	at org.testcontainers.shaded.okio.Buffer.getByte(Buffer.java:312)
	at org.testcontainers.shaded.okio.RealBufferedSource.readHexadecimalUnsignedLong(RealBufferedSource.java:310)
	at org.testcontainers.shaded.okhttp3.internal.http1.Http1ExchangeCodec$ChunkedSource.readChunkSize(Http1ExchangeCodec.java:492)
	at org.testcontainers.shaded.okhttp3.internal.http1.Http1ExchangeCodec$ChunkedSource.read(Http1ExchangeCodec.java:471)
	at org.testcontainers.shaded.okhttp3.internal.Util.skipAll(Util.java:204)
	at org.testcontainers.shaded.okhttp3.internal.Util.discard(Util.java:186)
	a分析t org.testcontainers.shaded.okhttp3.internal.http1.Http1ExchangeCodec$ChunkedSource.close(Http1ExchangeCodec.java:511)
	at org.testcontainers.shaded.okio.ForwardingSource.close(ForwardingSource.java:43)
	at org.testcontainers.shaded.okhttp3.internal.connection.Exchange$ResponseBodySource.close(Exchange.java:313)
	at org.testcontainers.shaded.okio.RealBufferedSource.close(RealBufferedSource.java:476)
	at org.testcontainers.shaded.okhttp3.internal.Util.closeQuietly(Util.java:139)
	at org.testcontainers.shaded.okhttp3.ResponseBody.close(ResponseBody.java:192)
	at org.testcontainers.shaded.okhttp3.Response.close(Response.java:290)
	at org.testcontainers.shaded.com.github.dockerjava.okhttp.OkDockerHttpClient$OkResponse.close(OkDockerHttpClient.java:285)
	at org.testcontainers.shaded.com.github.dockerjava.core.DefaultInvocationBuilder.lambda$null$0(DefaultInvocationBuilder.java:272)
	at org.testcontainers.shaded.com.github.dockerjava.core.DefaultInvocationBuilder$$Lambda$178/0x0000000800ec12b0.close(Unknown Source)
	at com.github.dockerjava.api.async.ResultCallbackTemplate.close(ResultCallbackTemplate.java:77)
	at org.testcontainers.containers.output.FrameConsumerResultCallback.close(FrameConsumerResultCallback.java:100)
	at org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy.waitUntilReady(LogMessageWaitStrategy.java:51)
	at org.testcontainers.containers.wait.strategy.AbstractWaitStrategy.waitUntilReady(AbstractWaitStrategy.java:35)
	at org.testcontainers.containers.GenericContainer.waitUntilContainerStarted(GenericContainer.java:892)
	at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:440)
	at org.testcontainers.containers.GenericContainer.lambda$doStart$0(GenericContainer.java:325)
	at org.testcontainers.containers.GenericContainer$$Lambda$194/0x0000000800ece220.call(Unknown Source)
	at org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:81)
	at org.testcontainers.containers.GenericContainer.doStart(GenericContainer.java:323)
	at org.testcontainers.containers.GenericContainer.start(GenericContainer.java:311)
	at org.apache.shardingsphere.test.integration.env.container.atomic.DockerITContainer.start(DockerITContainer.java:49)
	at org.apache.shardingsphere.test.integration.env.container.atomic.ITContainers$$Lambda$95/0x0000000800d9ac08.accept(Unknown Source)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(java.base@17.0.1/ForEachOps.java:183)
	at java.util.stream.ReferencePipeline$2$1.accept(java.base@17.0.1/ReferencePipeline.java:179)
	at java.util.LinkedList$LLSpliterator.forEachRemaining(java.base@17.0.1/LinkedList.java:1242)
	at java.util.stream.AbstractPipeline.copyInto(java.base@17.0.1/AbstractPipeline.java:509)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(java.base@17.0.1/AbstractPipeline.java:499)
	at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(java.base@17.0.1/ForEachOps.java:150)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(java.base@17.0.1/ForEachOps.java:173)
	at java.util.stream.AbstractPipeline.evaluate(java.base@17.0.1/AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.forEach(java.base@17.0.1/ReferencePipeline.java:596)
	at org.apache.shardingsphere.test.integration.env.container.atomic.ITContainers.start(ITContainers.java:82)
	- locked <0x000000061cefdc20> (a org.apache.shardingsphere.test.integration.env.container.atomic.ITContainers)
	at org.apache.shardingsphere.test.integration.container.compose.mode.ClusterComposedContainer.start(ClusterComposedContainer.java:64)
	at org.apache.shardingsphere.test.integration.engine.BaseITCase.setUp(BaseITCase.java:78)
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@17.0.1/Native Method)
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@17.0.1/NativeMethodAccessorImpl.java:77)
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@17.0.1/DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(java.base@17.0.1/Method.java:568)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)

从代码路径上看,和等待容器就绪逻辑相关,看到有个 close 操作,结合容器所使用的等待策略为 LogMessageWaitStrategy,可能是正在关闭对 docker log 命令对应的接口的调用。

	at org.testcontainers.containers.output.FrameConsumerResultCallback.close(FrameConsumerResultCallback.java:100)
	at org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy.waitUntilReady(LogMessageWaitStrategy.java:51)

定位到相关代码,close 方法在 LogMessageWaitStrategy.java:51,代码中没有直接 close 方法,而是通过 try-with-resources 代码块隐式调用。
在这里插入图片描述
能够走到 close 方法,说明 51 行上面的等待逻辑已经执行结束或者抛出了异常。但如果是 callback.close() 方法内部产生了死循环,从日志和代码路径可能无法确定逻辑是正常结束还是抛了异常。

从内存快照上来看,好像既没有 TimeoutException,也没有 ContainerLaunchException,所以代码可能没有发生异常。
在这里插入图片描述

由于 jstack 是瞬时输出,在不确定代码是否陷入 getByte 方法死循环的情况下,可以用 async-profiler 做个 on-cpu 采样。
做了大约 78 秒 100 Hz 采样,样本数恰好 7800 左右,基本确定代码陷入了 Buffer.getByte 死循环导致 CPU 100%。
在这里插入图片描述

内存分析

确定代码陷入死循环,但原因还不明确。为尽可能收集信息,做了一次 Heap Dump 分析。
检查 Buffer 实例的信息,发现了问题:

在这里插入图片描述

咨询 okio 社区

我在 okio 社区提问了以上现象 Is it normal that the pos greater than limit in Buffer? #1133

得到的回复是:可能是多线程操作了线程不安全的 Buffer 导致的问题。
在这里插入图片描述

等等,好像并没有死循环

根据代码路径,查看循环代码。根据前面分析所得,代码应该是在 else 内的 while 循环:
在这里插入图片描述
循环的退出条件是 pos >= 0L,pos 在循环中不断 -2 的,如果 pos 是负数,持续 -2 是不是就能溢出为正数了?

这么看也许代码并没有进入死循环,可能只是执行的时间不够久?

打算用 jshell 执行循环累加 -2 模拟死循环情况,不过考虑到 long 类型的长度,先把步进调大一点。
在这里插入图片描述
执行发现,long 类型初始值 -1:

  • 每次加 -200,000,000 的话,需要 11 秒才能变为正数;
  • 每次加 -20,000,000 的话,需要 107 秒才能变为正数。

以此推算,如果每次加 -2,大约就需要 1,000,000,000 秒才能把 long 溢出为正数?

1000000000 / 3600 / 24 / 365 约等于 31.71 年

所以,代码实际上并没有进入死循环,只是还没有运行完! 🌚️🌚️

能否从内存快照发现其他问题?

粗略看了一下暂时没能发现新的点。从内存快照中只能看到目前只有 main 线程的栈中引用了这个存在问题的 Buffer。

如果大家有兴趣也可以下载内存快照和 JFR 文件分析看看。

testcontainers 100% CPU 采样与内存快照 https://download.csdn.net/download/wu_weijie/87522297

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1030754.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用applescript自动化trilium的数学公式环境

众所周知&#xff0c;trilium什么都好&#xff0c;就是对数学公式的支持以及markdown格式的导入导出功能太拉了&#xff0c;而最拉的时刻当属把这两个功能结合起来的时候&#xff1a;导入markdown文件之后&#xff0c;原来的数学公式全没了&#xff0c;需要一个一个手动用ctrlm…

解密list的底层奥秘

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;…

AS中部署NCNN

参考链接 http://681314.com/A/Clzr6Q2OBO https://blog.csdn.net/xs1997/article/details/131747372 一、文章背景&#xff1a;公司再进行一个项目时&#xff0c;使用PyTorch框架&#xff0c;python语言及opencv工具进行神经网络深度学习算法进行训练。生成ONNX模型&#xff…

RocketMQ 消费者分类与分组

文章目录 消费者分类PushConsumerPushConsumer 内部原理使用注意事项 SimpleConsumerinvisibleDuration 消息不可见时间 消费者分组&#xff08;消费者负载均衡&#xff09;广播消费和共享消费负载均衡策略多个消费者消费顺序消息多消费者消费顺序消息示例 消费者分组管理关闭自…

八股文死记硬背打脸记

背景 我们都知道&#xff0c;再编程领域数据结构的重要性&#xff0c;常见的数据结构包括 List、Set、Map、Queue、Tree、Graph、Stack 等&#xff0c;其中 List、Set、Map、Queue 可以从广义上统称为集合类数据结构。而Java也提供了很多的集合数据结构以供开发者开箱即用&…

左神高级提升班2 约瑟夫环结构

目录 【案例1】 【题目描述】 【输入描述&#xff1a;】 【输出描述&#xff1a;】 【输入】 【输出】 【思路解析】 【代码实现】 【案例1】 【题目描述】 某公司招聘&#xff0c;有n个人入围&#xff0c;HR在黑板上依次写下m个正整数A1、A2、……、Am&#xff0c;然后…

alist windows桌面版下载安装

官网 Desktop | AList Docs 点击下载windows版本 安装 双击exe 修改安装路径 太可惜了&#xff0c;需要收费

LeetCode刷题---Add Two Numbers(一)

文章目录 &#x1f352;题目&#x1f352;解法一 迭代&#x1f352;解法二 递归&#x1f352;递归小案例&#x1f352;迭代 VS 递归 &#x1f352;题目 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只…

聚观早报 | 飞书签约韵达速递;蔚来首颗自研芯片“杨戬”量产

【聚观365】9月22日消息 飞书签约韵达速递 蔚来首颗自研芯片“杨戬”10月量产 靳玉志接任华为车 BU CEO 亚马逊发布全新Alexa语音助手 OpenAI推出图像生成器DALL-E 3 飞书签约韵达速递 近日&#xff0c;国内物流服务公司韵达快递宣布全员上飞书。飞书解决方案副总裁何斌表…

【大数据】Doris 构建实时数仓落地方案详解(一):实时数据仓库概述

本系列包含&#xff1a; Doris 构建实时数仓落地方案详解&#xff08;一&#xff09;&#xff1a;实时数据仓库概述Doris 构建实时数仓落地方案详解&#xff08;二&#xff09;&#xff1a;Doris 核心功能解读Doris 构建实时数仓落地方案详解&#xff08;三&#xff09;&#…

云原生Kubernetes:K8S集群list-watch机制与 pod调度约束

目录 一、理论 1.K8S的list-watch 机制 2.亲和性 二、实验 1. 指定调度节点 2.节点亲和性 3.亲和性和反亲和 三、问题 1.新生成pod一直为pending 2.如何一次性删除pod和deployment 3.pod亲和性资源报错 4.pod反亲和性资源报错 四、总结 一、理论 1.K8S的list-wat…

zookeeper + kafka

Zookeeper 概述 Zookeeper是一个开源的分布式服务管理框架。存储业务服务节点元数据及状态信息&#xff0c;并负责通知再 ZooKeeper 上注册的服务几点状态给客户端 Zookeeper 工作机制 Zookeeper从设计模式角度来理解: 是一个基于观察者模式设计的分布式服务管理框架&…

vector的扩容机制—为何是1.5倍或者是2倍

文章目录 前言一、Vector 扩容过程二、为什么是1.5倍或者2倍&#xff1f; 前言 在 C 编程中&#xff0c;Vector 是一种常用的动态数组容器。其大小是可以动态调整的&#xff0c;而在扩容操作中&#xff0c;Vector 通常会将容量增加为原来的两倍。本篇博客将详细介绍 Vector 扩…

Kindle电子书下载功能关闭怎么办,借助calibre和cpolar搭建私有的网络书库公网访问

Kindle中国电子书店停运不要慌&#xff0c;十分钟搭建自己的在线书库随时随地看小说&#xff01; 文章目录 Kindle中国电子书店停运不要慌&#xff0c;十分钟搭建自己的在线书库随时随地看小说&#xff01;1.网络书库软件下载安装2.网络书库服务器设置3.内网穿透工具设置4.公网…

RT-Thread(学习)

RT-Thread是一款完全由国内团队开发维护的嵌入式实时操作系统&#xff08;RTOS&#xff09;&#xff0c;具有完全的自主知识产权。经过16个年头的沉淀&#xff0c;伴随着物联网的兴起&#xff0c;它正演变成一个功能强大、组件丰富的物联网操作系统。 RT-Thread概述 RT-Threa…

openssl创建CA证书教程

配置生成CA证书 总示意图&#xff1a; (1)&#xff0c;通过openssl创建CA证书 第一步&#xff1a;创建一个秘钥&#xff0c;这个便是CA证书的根本&#xff0c;之后所有的东西都来自这个秘钥 # 通过rsa算法生成2048位长度的秘钥 openssl genrsa -out myCA.key 2048 第二步&#…

Wireshark TS | MQ 传输缓慢问题

问题背景 应用传输慢是一种比较常见的问题&#xff0c;慢在哪&#xff0c;为什么慢&#xff0c;有时候光从网络数据包分析方面很难回答的一清二楚&#xff0c;毕竟不同的技术方向专业性太强&#xff0c;全栈大佬只能仰望&#xff0c;而我们能做到的是在专注于自身的专业方向之…

什么是Selenium?使用Selenium进行自动化测试!

你知道什么是 Selenium 吗&#xff1f;你知道为什么要使用它吗&#xff1f;答案就在本文中&#xff0c;很高兴能够与你共飧。 自动化测试正席卷全球&#xff0c;Selenium 认证是业界最抢手的技能之一。 什么是 Selenium&#xff1f; Selenium 是一种开源工具&#xff0c;用于…

Spring Cloud Alibaba Nacos 2.2.3 (2) - 单机版启动 (winodows 和 linux )

Nacos 2.2.3 (1) - 下载与数据库配置 参考下载与数据库配置 启动服务器 执行 nacos-server-2.2.3\bin 下的startup.sh或者startup.cmd &#xff08;根据不同系统&#xff09; windows 下nacos 单机启动 方式一&#xff1a; 1&#xff0c;打开cmd 2&#xff0c;cd 到nacos-s…

数据库数据恢复-SQL SERVER数据库分区被格式化的数据恢复方案

SQL SERVER数据库故障类型&#xff1a; 1、SQL SERVER数据库文件被删除。 2、SQL SERVER数据库所在分区格式化。 3、SQL SERVER数据库文件大小变为“0”。 4、使用备份还原数据库时覆盖原数据库。 SQL SERVER数据库故障原因&#xff1a; 1、人为误操作。 2、文件系统损坏&#…