性能指标之资源指标-网络IO--初步诊断-trace查看

本文介绍如何利用iptrace抓取网络数据并结合Wireshark进行分析,以定位网络中的延时、丢包等问题。通过实际案例展示了常见问题如TCP Keep-Alive频繁触发及重传现象的原因分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如果从应用层面或者ping等手段定位到网络有延时、抖动、丢包、中断等异常情况时,需要进行深入的诊断分析。

此时最好的方法是采用专业的网络抓包设备进行网络包捕获,并采用该厂商相应的工具进行分析诊断。不但不影响服务器本身的性能,并且可以比较快速地得出一些诊断结论。目前市场上这方面的厂商和工具也比较多。

然而本节将介绍另一种初步分析问题的手段-iptrace。通过在业务系统上监控iptrace日志,之后通过wireshark工具进行分析,即可对问题有个大致的判断。

1、iptrace抓取

举例说明
开启监控:startsrc -s iptrace "-a -s 目标机IP -b -S 1500 -L 1073741824 /var/trace/iptrace.out"

该命令的含义是:iptrace记录本机与目标机双向传输的信息,抓取的数据包最大限制为1500字节,日志记录最大为1073741824字节(1G大小)。

关闭监控:stopsrc -s iptrace

2、Wireshark简介

Wireshark是windows平台用于查看网口数据包的工具。核心功能是快速筛选自己需要的信息然后快速定位问题。使用Wireshark打开iptrace.out文件如下图:

1.png

No --- 截获的网络包序号
Time --- 时间
Source --- 数据源IP
Destination --- 目标IP
Length --- 消息包总字节长度
Protocol --- 消息包协议类型
Info --- 消息包相关基本信息

以下是对应的OSI七层模型
2.png

Frame:物理层的数据帧概况
Ethernet II:数据链路层以太网帧头部信息
Internet Protocol Version 4:互联网层IP包头部信息
Transmission Control Protocol:传输层TCP的数据段头部信息
WebSphere MQ:应用层的信息,此处是MQ

常用筛选命令
可以按照需求筛选显示网络包列表,常用筛选条件如下:
1 按消息包长度筛选frame.len== (Length的值)
2 按数据源ip 筛选 ip.src eq 10.x.x.x
3 同时筛选源IP 以及协议类型ip.src eq 10.x.x.x && mq
4 按需求的协议类型筛选 mq && tcp

3、分析实例

打开iptrace文件后,首先查看右侧标黑色的部分,这是wireshark认为有问题的网络传输。
3.png

以作者实践当中的一个例子,系统环境当中网络延时非常不稳定,抓取iptrace用wireshark打开之后,发现大量的黑色条带,几乎找不到不出错的时间段。
这其中的问题五花八门,例如有:
1. 大量的tcp keep-alive ack/ tcp keep-alive
2. 大量下一个回复包的SEQ值不等于ACK
3. RST ACK
4. 大量Retransmission
5. Previous segment uncaptured
6. ACKed Unseen segment
7. 大量Dup ack
8. Destination unreachable

在几分钟的trace当中竟然有这么多问题,也是醉了。

3.1 大量的tcp keep-alive / tcp keep-alive ack

几乎10个数据包里面就有2个tcp keep-alive / tcp keep-alive ack的数据包,大量占用网络带宽
4.png

首先,服务器的keep alive相关参数设置略有问题
no -a| grep tcp
tcp_keepcnt = 8
tcp_keepidle = 20
tcp_keepinit = 50
tcp_keepintvl = 2

这些参数的含义是:如果tcp连接有10秒钟空闲,没有报文传输(tcp_keepidle = 20,单位是0.5秒),那么开始发送探测(tcp alive),如果探测不成功,则后续每1秒发送一次 (tcp_keepintvl = 2),如果连续发送8次,对方没反应,把这个tcp连接关了。

这个探测比默认值来讲的确有些频繁,但试想,如果探测一次成功了的话,后续就不需要探测了。为什么有这么多的探测呢?

3.2 大量下一个回复包的SEQ值不等于ACK

正常情况下回复的seq数值=等于上一条请求的ACK数值,而trace中看到几乎所有keep alive的确认包(ACK)中的SEQ值=keep alive发起方的ACK+1。即每次探测后,对方的回复都不是期望的结果,因此后续不停的继续探测,导致了大量的keep alive包。

Seq和Ack两个字段是TCP可靠传输服务的关键部分,Seq是网络包序列号(TCP把数据看成是有序的字节流,TCP隐式地对数据流的每个字节进行编号)。Ack是期望得到的下一个回复包的序列号(即Seq值)。

3.3 RST ACK

5.png

RST可能是B发的太多,A告诉B 不要发包,直到A再次通知B可以发包。 或者是A关闭异常连接,清空缓存。

由于只发现一条RST ACK,因此并未深入分析。

3.4 大量Retransmission重传

6.png

重传意味着网络质量不佳,可能的原因有拥堵、目标机回复延迟、网络设备丢包、网线质量不佳、接口松动、电磁干扰等。

3.5 Previous segment uncaptured

7.png

先前片段未能捕获,当前收到报文的序列号值高于该连接的下一个期望序列号值时,表明之前的一个或多个网络包未捕获到。Previous segment uncaptured在正常通讯过程中也经常出现,且出现次数不多,因此并未深入分析。

3.6 ACKed Unseen segment

8.png

Tcp ACKed unseen segment 网络包回复的先前片段未截获到,与Tcp Previoud segment not captured先前片段未能捕获,问题相似。由于Previous segment uncaptured在正常通讯过程中也经常出现,且出现次数不多,因此并未深入分析。

3.7 大量Dup ack

9.png

Dup ACK是没有收到对方的应答(ACK),需要对方重复应答,3次以上的Dup ACK会造成重传和传输降速。后分析发现,系统环境中对方服务器发送出来的数据包在核心交换大机侧的接口处就有大量乱序。

3.8 Destination unreachable

10.png

目标不可达。由于只出现一次这个报错,因此并未深入分析

综上,从iptrace的结果中可以看到表现出来的问题很多,但经过初步分析,主要问题归结起来是1)对端回复的TCP包的SEQ值不是预期值,2)网络质量不佳。下一步就需要研究出问题的对端节点以及采用网络抓包设备判断哪一段网络质量不佳。

"shortcutservice" prio=5 tid=200 Native | group="main" sCount=1 ucsCount=0 flags=1 obj=0x17560118 self=0xb400006fda2d2400 | sysTid=8169 nice=0 cgrp=ssfg sched=0/0 handle=0x6ff38f1730 | state=S schedstat=( 157157722 3434221361 1501 ) utm=3 stm=11 core=5 HZ=100 | stack=0x6ff37ee000-0x6ff37f0000 stackSize=1037KB | held mutexes= native: #00 pc 000b9cd0 /apex/com.android.runtime/lib64/bionic/libc.so (syscall+32) (BuildId: a3cde331295ff116d9c0d5e2198af1eb) native: #01 pc 0048f7a8 /apex/com.android.art/lib64/libart.so (art::ConditionVariable::WaitHoldingLocksWithInfo+160) (BuildId: 933ac9f8face98d6497ff39053c286bc) native: #02 pc 00c18448 /apex/com.android.art/lib64/libart.so (artJniMethodEnd+408) (BuildId: 933ac9f8face98d6497ff39053c286bc) native: #03 pc 007232bc /apex/com.android.art/lib64/libart.so (art_jni_method_end+12) (BuildId: 933ac9f8face98d6497ff39053c286bc) at java.io.FileDescriptor.sync(Native method) at android.os.FileUtils.sync(FileUtils.java:279) at com.android.server.pm.ResilientAtomicFile.finalizeOutStream(ResilientAtomicFile.java:64) at com.android.server.pm.ResilientAtomicFile.finishWrite(ResilientAtomicFile.java:145) at com.android.server.pm.ShortcutPackageItem.saveToFileLocked(ShortcutPackageItem.java:182) at com.android.server.pm.ShortcutPackageItem.saveShortcutPackageItem(ShortcutPackageItem.java:226) - locked <0x08628dd1> (a java.lang.Object) at com.android.server.pm.ShortcutPackageItem$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0) at android.os.Handler.handleCallback(Handler.java:973) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loopOnce(Looper.java:282) at android.os.Looper.loop(Looper.java:387) at android.os.HandlerThread.run(HandlerThread.java:85) DumpLatencyMs: 1290.67安卓稳定性watchdog的tracelog信息如上,怎么分析问题处在哪里呢
最新发布
07-11
<think>我们有一个watchdog的trace日志,需要分析问题所在。日志显示了一个线程的状态,包括native和Java堆栈。 分析步骤: 1. 首先看线程状态:state=S,表示休眠状态(Sleeping)。这通常不是死锁的直接表现(死锁通常是BLOCKED或WAITING),但需要结合上下文。 2. 查看堆栈信息: - Native部分:我们看到在ConditionVariable::WaitHoldingLocksWithInfo中等待,这是ART虚拟机内部的一个条件变量等待。然后看到在artJniMethodEnd和art_jni_method_end,说明这是JNI方法结束时的处理。 - Java部分:从堆栈顶部开始,我们看到在FileDescriptor.sync的Native方法中,然后调用FileUtils.sync,接着是ResilientAtomicFile.finalizeOutStream和finishWrite,最后是ShortcutPackageItem.saveToFileLocked方法。在saveToFileLocked方法中,它持有一个锁(locked <0x08628dd1>)。 3. 关键点:在ShortcutPackageItem.saveToFileLocked方法中,它持有锁(0x08628dd1)然后调用了文件同步操作(FileUtils.sync),而sync方法会调用native的FileDescriptor.sync。在native的sync方法中,它最终等待一个条件变量(ConditionVariable::WaitHoldingLocksWithInfo)。这可能是正常的等待I/O操作,但如果这个等待时间过长,可能会导致watchdog超时。 4. 注意:这个线程是运行在HandlerThread(名为"shortcutservice")中的,它是由HandlerThread运行的,通常用于后台任务。如果这个文件同步操作(sync)被阻塞(例如,由于文件系统缓慢或阻塞),它可能会导致这个线程长时间不响应,进而可能触发watchdog(如果主线程或其他关键线程被阻塞等待这个锁?)。 5. 但是,我们注意到这个线程状态是S(休眠),而且它并没有持有其他锁,也没有其他线程在等待它持有的锁(至少在这个堆栈中没有显示)。因此,这个线程本身可能不是导致watchdog的直接原因。然而,watchdog可能是在监控其他线程(比如主线程)时超时,而这个线程只是当时的一个状态。 6. 由于watchdog触发,说明系统中有某个关键线程(如主线程)没有在规定时间内响应。因此,我们需要检查其他线程的状态(特别是主线程)是否被阻塞。这个日志片段只给出了一个线程,所以我们需要更完整的trace(所有线程的堆栈)才能确定问题。 7. 但是,根据现有信息,我们可以注意到一个潜在问题:文件同步操作(FileDescriptor.sync)可能会阻塞很长时间,尤其是在文件系统繁忙或存储介质速度慢的情况下。如果这个操作阻塞了主线程(或者阻塞了其他关键线程),就会导致ANR。但在这个堆栈中,我们看到它是在后台线程(HandlerThread)中执行的,所以主线程应该不会被它阻塞,除非主线程在等待这个后台线程完成某个任务(比如锁)。 8. 然而,在堆栈中我们看到有一个锁(0x08628dd1),但只有这个线程持有。所以其他线程不会因为等待这个锁而阻塞。因此,这个线程的阻塞可能不会直接影响主线程。那么为什么watchdog会被触发呢?可能的原因包括: - 主线程因为其他原因被阻塞(例如等待另一个锁,或者执行耗时操作)。 - 这个后台线程的长时间阻塞导致了系统资源紧张,进而影响了主线程。 - Watchdog监控的不仅仅是主线程,还有系统关键服务线程,如果某个关键服务线程被阻塞,也会触发watchdog。 9. 结论:仅凭这个线程的堆栈,我们无法直接确定watchdog触发的根本原因。我们需要查看触发watchdog时所有线程的堆栈,特别是主线程和系统关键线程(如system_server主线程)的状态。 但是,这个堆栈也告诉我们:文件同步操作(FileUtils.sync)可能会长时间阻塞,这可能是系统中的一个性能瓶颈。建议检查文件系统性能,或者考虑将文件同步操作移到更轻量级的线程中,避免在关键路径中执行。 因此,分析建议: - 获取完整的trace文件(所有线程的堆栈)。 - 检查主线程(通常名为"main")的状态,看它是否被阻塞,以及阻塞在什么地方。 - 检查是否有死锁情况(多个线程互相等待锁)。 - 检查这个文件同步操作是否频繁发生,以及是否可能优化(比如减少同步次数,或使用异步写入)。 根据这个日志片段,我们只能推测:在保存ShortcutPackageItem数据到文件时,执行文件同步操作(sync)导致线程长时间阻塞。如果这个操作耗时过长(超过1秒以上),而系统此时有其他关键线程需要运行,可能会触发watchdog。但具体原因需要更多上下文。 注意:日志中显示DumpLatencyMs为1290.67毫秒,说明dump这个日志花费了1.29秒,但这通常是在watchdog触发后记录日志的时间,不是问题发生的时间。 所以,问题可能出现在文件同步操作上,但需要更多证据。 因此,分析步骤总结: 1. 获取完整的trace文件,检查所有线程状态。 2. 重点关注主线程(main)和系统关键线程(如system_server的主线程)是否被阻塞。 3. 检查是否有死锁。 4. 优化文件同步操作,避免在主线程或关键路径中执行,或者确保其执行时间不会过长。 如果完整trace中显示主线程在等待锁,而这个锁被当前这个线程(shortcutservice)持有,那么问题就清楚了:当前线程在文件同步操作中阻塞,导致无法释放锁,而主线程在等待这个锁,从而触发watchdog。但在这个堆栈中,我们没有看到其他线程在等待这个锁(0x08628dd1),所以可能不是这个锁。 因此,我们需要更多的信息。 但是,根据这个片段,我们只能给出初步分析:文件同步操作可能导致阻塞,需要优化。 现在,根据要求,提出相关问题:</think>### 分析 Android Watchdog TraceLog 的步骤与方法 #### 关键问题定位分析: 1. **线程状态分析** - `state=S`:线程处于休眠状态(Sleeping),通常表示等待资源或锁 - `locked <0x08628dd1>`:显示线程持有对象锁(地址0x08628dd1),可能存在锁竞争 2. **Native 层崩溃点** ```plaintext native: #00 pc 000b9cd0 /apex/com.android.runtime/lib64/bionic/libc.so (syscall+32) native: #01 pc 0048f7a8 /apex/com.android.art/lib64/libart.so (art::ConditionVariable::WaitHoldingLocksWithInfo+160) ``` - 崩溃发生在 `libc.so` 的 `syscall` 系统调用处 - ART 虚拟机内部 `ConditionVariable::WaitHoldingLocksWithInfo` 显示线程在持有锁的情况下等待条件变量 3. **Java 层调用链** ```plaintext at java.io.FileDescriptor.sync(Native method) at android.os.FileUtils.sync(FileUtils.java:279) at com.android.server.pm.ResilientAtomicFile.finalizeOutStream(...) at com.android.server.pm.ShortcutPackageItem.saveToFileLocked(...) ``` - 问题源头:`ShortcutPackageItem.saveToFileLocked()` 方法执行文件写入操作 - 阻塞点:`FileUtils.sync()` 调用 Native 文件同步操作时发生阻塞 4. **性能指标** - `DumpLatencyMs: 1290.67`:日志转储延迟达1.29秒,表明系统响应严重超时 - `schedstat=(157157722 3434221361 1501)`:CPU时间片使用异常(用户态3ms/内核态11ms) #### 根本原因诊断: 1. **文件I/O阻塞** `FileUtils.sync()` 调用底层 `fsync()` 系统调用时被阻塞,可能原因: - 存储设备I/O性能瓶颈(eMMC/UFS 读写过载) - 文件系统损坏(ext4/f2fs 元数据异常) - 文件锁竞争(其他进程持有文件锁未释放) 2. **锁竞争问题** `ShortcutPackageItem.saveToFileLocked()` 方法持有对象锁(0x08628dd1)时: - 同步操作耗时过长(超过Watchdog阈值) - 可能与其他线程形成死锁(检查其他线程是否等待此锁) 3. **系统资源压力** - 高I/O负载导致 `syscall` 阻塞 - CPU调度延迟(`core=5` 显示绑定大核仍响应缓慢) #### 解决方案建议: ```java // 优化方案:异步写入 + 锁超时机制 public void saveShortcutPackageItem() { ExecutorService ioExecutor = Executors.newSingleThreadExecutor(); ioExecutor.execute(() -> { synchronized (mLock) { // 添加超时保护 mLock.tryLock(500, TimeUnit.MILLISECONDS); saveToFileLocked(); } }); } ``` ### 分析结论 **核心问题**:`ShortcutService` 在持久化快捷方式数据时,因文件同步操作(`fsync`)阻塞导致持有锁时间过长,触发 Watchdog 超时机制(1.29秒 > 默认60秒阈值)。 **关键证据**: - Native 堆栈阻塞在 `syscall+32`(文件同步系统调用) - Java 调用链定位到 `ShortcutPackageItem.saveToFileLocked()` - 线程持有锁 `0x08628dd1` 时进入休眠等待
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值