【银河麒麟】unzip程序卡住,处理机制详解,附代码

1.服务器环境以及配置

【机型】

处理器:

HUAWEI,Kunpeng 920

内存:

400G+

【内核版本】

4.19.90-23.18.v2101.ky10.aarch64

【OS镜像版本】

银河麒麟高级服务器操作系统V10-SP1-0711-arm

【第三方软件】

docker

2.问题现象描述

一台k8s服务器里面的容器java程序启动shell脚本执行解压unzip命令,进程一直处于sleep状态,没有执行解压,一直卡着。

3.问题分析

通过gdb查看,可看到unzip进程栈为:

可看到阻塞在fgets调用read上,此时read通过系统调用到了内核,所以推测为阻塞在内核阶段。

此时查看进程内核栈为:

根据内核栈,可知unzip进程卡在了读取管道数据上,此状态可以用以下方式进行模拟:

即直接cat 标准输入,则可直接模拟问题,至此,直接原因可明确:unzip进程卡在了读取管道数据上。

但问题根本原因,以及正常是怎样的流程,需要继续分析:

查看现场文件描述符信息如下:

查看确认0,1,2描述符继承自父进程。

通过cat测试相关描述符,发现描述符内容很多。

本地java启动shell脚本启动unzip可看到同样的描述符继承关系:

java程序如下:

public static void main(String[] args) throws Exception {

String command = "sh a.sh logfile.zip .";

Process process = Runtime.getRuntime().exec(command);

process.waitFor();

process.destroy();

int i = process.exitValue();

System.out.println("子进程退出值:"+i);

}

a.sh脚本为:unzip -o $1 -d $2

但本地无法模拟出现场情况,本地测试,cat 0,2管道都无内容,1有解压时的标准输出内容,与现场管道中有大量内容不同。同时,本地对unzip进程fgets函数做跟踪,无法捕捉到fgets调用,也没有捕捉到pipe_read操作。本地的所有read操作都是对文件描述符3的操作:

即从压缩文件中读数据。

推测无法复现原因与现场的环境相关,本地可能无法完全模拟现场状态,导致无法追踪到对应调用。

尝试从其它方向获得更多有用信息。

根据fgets说明:

fgets() 的原型为: char *fgets(char *s, int size, FILE *stream);

它的功能是从 stream 流中读取 size 个字 符指针变量 s 所指向的内存空间。它的返回值是个指针,指向字符串中第个字符的地址。

从函数介绍,结合前面信息可知unzip阻塞在尝试从管道读取若干数据。

本地使用head模拟读取若干数据后返回操作,如下:

可看到在未获取到对应数据之前,进程将一直阻塞在pipe_wait处。直到获取到对应数据,则返回。

由于本地无法模拟,所以无法弄清楚,unzip进程在读管道里的什么数据,以及这些数据从哪里来。

现场可尝试搭建一个测试环境,安装glibc的debuginfo包,对fgets进行调试,即可对进程核外调用有更准确的掌握,如从哪个描述符取多少数据,以及谁在往里写数据。

同时我们对java的管道规范进行了梳理,发现:

JDK中有相关说明:

By default, the created subprocess does not have its own terminal or console. All its standard I/O (i.e. stdin, stdout, stderr) operations will be redirected to the parent process, where they can be accessed via the streams obtained using the methods getOutputStream(), getInputStream(), and getErrorStream (). The parent process uses these streams to feed input to and get output from the subprocess. Becau se some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, or even deadlock. 

从JDK的说明中可以看出两点:

1.子进程的标准I/O已经被重定向到了父进程。父进程可以通过对应的接口获取到子进程的I/O

2.如果系统中标准输入输出流使用的bufffer大小有限,所有读写时可能会出现阻塞或死锁。

结合现场cat描述符异常,基本可确认现场标准输入输出流异常。

基于此,在相关编程中,java编程中推荐了多种处理方法:

1.不断的读取消耗缓冲区的数据,以至子进程不会挂起,如:

public class ProcessUtils {

public static void main(String[] args) throws IOException, InterruptedExcption{

String command = "unzip xxxx";

Process process = Runtime.getRuntime().exec(command);

readStreamInfo(process.getInputStream(), process.getErrorStream());

int exit = process.waitFor();

process.destroy();

if (exit == 0) {

log.debug("子进程正常完成");

} else {

log.debug("子进程异常结束");

}

}

/**

* 读取RunTime.exec运行子进程的输入流 和 异常流

* @param inputStreams 输入流

*/

public static void readStreamInfo(InputStream... inputStreams){

ExecutorService executorService = Executors.newFixedThreadPool(inputS

for (InputStream in : inputStreams) {

executorService.execute(new MyThread (in));

}

executorService.shutdown();

}

}

public class MyThread implements Runnable {

private InputStream in;

public MyThread(InputStream in){

this.in = in;

}

public void run() {

try{

BufferedReader br = new BufferedReader(new InputStreamReader(in,

String line = null;

while((line = br.readLine())!=null){

log.debug(" inputStream: " + line);

}

}catch (IOException e){

e.printStackTrace();

}finally {

try {

in.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

  1. 添加timeout超时:

public static int executeProcess(int timeout)throws IOException, InterruptedException, TimeoutException {

Process process = Runtime.getRuntime().exec(command);

Worker worker = new Worker(process);

worker.start();

try {

worker.join(timeout);

if (worker.exit != null){

return worker.exit;

} else{

throw new TimeoutException();

}

} catch (InterruptedException ex) {

worker.interrupt();

Thread.currentThread().interrupt();

throw ex;

}

finally {

process.destroy();

}

}

现场同时也发现java程序所在docker容器内存已被占满,本地模拟内存占满测试,并未复现,同时本地测试中,始终没有捕捉到unzip的fgets及pipe_read动作。所以内存占满可能并非为唯一关键因素。

4.问题总结

通过测试分析,可知问题的直接原因为java调用unzip进程阻塞在了读取管道数据调用上。但由于没有现场代码及环境,使用简单的本地java模拟无法复现对应调用流程,所以无法对其可能的触发流程做详细梳理,如果现场有条件,可安装unzip及glibc的debuginfo包,通过gdb对相关进程的fgets操作管道的流程进行捕捉,及梳理。基于此,可确认正常的调用流程。

同时现场可进一步检查unzip的0,1,2管道的情况,通过cat管道内容到文件的方式保存管道内容进行分析,如果仅仅只作为unzip的标准输入输出及错误输出,不应该有很多内容才对,是否在java编程中做了更多的操作需梳理下java的相关调用。结合unzip操作管道的正常流程,来最终确认管道异常原因。

针对java编程中父子进程管道通信可能存在的潜在问题,提供了两个可能的优化方法:

  1. 不断的读取消耗缓冲区的数据,以至子进程不会挂起
  2. 添加timeout超时,防止子进程异常阻塞导致父进程异常无法恢复。

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

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

相关文章

水上实用救生工具_救生拉杆_鼎跃安全

每年,由于水上事故而失去生命的人数不胜数,水上安全问题也成为公众关注的焦点。如何在关键时刻实施有效的救援,成为保障生命的重要课题。作为水上救援的重要工具,救生拉杆在紧急情况下发挥了无可替代的作用。 救生拉杆&#xff0c…

springboot 缓存框架Cache整合redis组成二级缓存

springboot 缓存框架Cache整合redis组成二级缓存 项目性能优化的解决方案除开硬件外的方案无非就是优化sql,减少sql 的执行时间,合理运用缓存让同样的请求和数据库之间的连接尽量减少,内存的处理速度肯定比直接查询数据库来的要快一些。今天就…

CDP问卷的常见问题

CDP问卷的常见问题可以归纳如下: 哪些企业会收到CDP邀请? 企业会收到来自投资和/或采购机构的邀请,以填写CDP问卷并披露相应的环境管理信息。 未收到邀请的企业可否填报? 未收到邀请的企业可以选择自行填报。他们需发送申请自愿…

多线程(基础)

前言👀~ 上一章我们介绍了什么是进程,对于进程就了解那么多即可,我们作为java程序员更关注线程,线程内容比较多,所以我们要分好几部分才能讲完 目录 进程的缺点 多线程(重要) 进程和线程的区…

鸿蒙开发Ability Kit(程序框架服务):【FA模型切换Stage模型指导】 module的切换

module的切换 从FA模型切换到Stage模型时,开发者需要将config.json文件module标签下的配置迁移到module.json5配置文件module标签下,具体差异见下列表格。 表1 FA模型module标签与Stage模型module标签差异对比 FA标签标签说明对应的Stage标签差异说明…

LeetCode刷题之HOT100之课程表

吃完普通的食堂饭菜,回到实验室,继续做一道题! 1、题目描述 2、逻辑分析 这道题涉及到图相关知识,应用到了拓扑排序。 题意解释 一共有 n 门课要上,编号为 0 ~ n-1。先决条件 [1, 0],意思是必须先上课 0…

触动心弦的成语之旅:《米小圈动画成语》带你走进中华智慧

成语,这些古老而典雅的语言精华,如同中华文化的晶莹明珠,闪耀着历史的光辉和智慧的火花。从古至今,它们在中国人的日常交流中扮演着重要角色,不仅传递着深刻的哲理和文化内涵,更是凝聚了世代智者的思想和智…

【Linux】线程id与互斥(线程三)

上一期我们进行了线程控制的了解与相关操作,但是扔就有一些问题没有解决 本章第一阶段就是解决tid的问题,第二阶段是进行模拟一个简易线程库(为了加深对于C库封装linux原生线程的理解),第三阶段就是互斥。 目录 线程id…

链在一起怎么联机 链在一起远程同玩联机教程

steam中最近特别热门的多人跑酷冒险的游戏:《链在一起》,英文名称叫做Chained Together,在游戏中我们需要开始自己的旅程,在地狱的深处,与我们的同伴被链在一起。我们的任务是通过尽可能高的攀登逃离地狱。每一次跳跃都…

Python第三方库GDAL 安装

安装GDAL的方式多种,包括pip、Anaconda、OSGeo4W等。笔者在安装过程中,唯独使用pip安装遇到问题。最终通过轮子文件(.whl)成功安装。 本文主要介绍如何下载和安装较新版本的GDAL轮子文件。 一、GDAL轮子文件下载 打开Github网站…

Python学习打卡:day16

day16 笔记来源于:黑马程序员python教程,8天python从入门到精通,学python看这套就够了 目录 day16116、SQL 基础和 DDLSQL的概述SQL语言的分类SQL的语法特征DDL — 库管理DDL — 表管理 117、SQL — DMLDML概述数据插入 INSERT数据删除 DEL…

深入理解 Dubbo:分布式服务框架的核心原理与实践

目录 Dubbo 概述Dubbo 的架构Dubbo 的关键组件 服务提供者(Provider)服务消费者(Consumer)注册中心(Registry)监控中心(Monitor)调用链追踪(Trace) Dubbo 的…

专题页面设计指南:从构思到实现

如何设计专题页?你有什么想法?专题页的设计主要以发扬产品优势为核心。一个好的专题页可以从不同的角度向用户介绍产品,扩大产品的相关优势,表达产品的优势,让用户在短时间内了解产品。因此,在设计详细信息…

纯血鸿蒙Beta版本发布,中国华为,站起来了!

2024年6月21日至23日,华为开发者大会2024(HDC 2024)于东莞盛大举行。 此次大会不仅在会场设置了包括鸿蒙原生应用、统一生态统一互联等在内的11个展区,以供展示HarmonyOS NEXT的强大实力,还对外宣布了HarmonyOS的最新进…

240627_关于CNN中图像维度变化问题

240627_关于CNN中图像维度变化问题 在学习一些经典模型时,其中得维度变化关系总搞不太明白,集中学习了以下,在此作以梳理总结: 一般来说涉及到的维度变换都是四个维度,当batch size4,图像尺寸为640*640&a…

kylin v10 离线安装chrome centos离线安装chrome linux离线安装谷歌浏览器

1. 先用自己联网的计算机,下载离线安装包,浏览器输入链接下载安装包: https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm 1.2. 信创环境不用执行下面,因为没网 1.3. 若为阿里云服务器,或服…

AR导航技术加持,图书馆阅读体验智慧升级

在信息爆炸的今天,图书馆作为知识的宝库,其藏书量和种类日益增多。然而,传统的图书馆导航方式已逐渐无法满足用户对快速、准确定位图书的需求。本文将探讨图书馆AR地图导航的实现原理、技术优势、功能特点以及市场前景,揭示为何AR…

VS studio2019配置远程连接Ubuntu

VS studio2019配置远程连接Ubuntu 1、网络配置 (1)获取主机IP (2)获取Ubuntu的IP (3)在 windows 的控制台中 ping 虚拟机的 ipv4 地址,在 Ubuntu 中 ping 主机的 ipv4 地址。 ubuntu: ping…

【Linux】对共享库加载问题的深入理解——基本原理概述

原理概述 【linux】详解——库-CSDN博客 共享库被加载后,系统会为该共享库创建一个结构,这个结构体中的字段描述了库的各种属性。在内存中可能会加载很多库,每一个库都用一个结构体描述。把这些结构体用一些数据结构管理起来,系…

WordPress Dokan Pro插件 SQL注入漏洞复现(CVE-2024-3922)

0x01 产品简介 WordPress Dokan Pro插件是一款功能强大的多供应商电子商务市场解决方案,功能全面、易于使用的多供应商电子商务平台解决方案,适合各种规模的电商项目。允许管理员创建一个多卖家平台,卖家可以注册账户并在平台上创建自己的店铺,展示和销售自己的产品。提供…