AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / server / 问题 / 966709
Accepted
Paulo Coghi
Paulo Coghi
Asked: 2019-05-11 04:56:19 +0800 CST2019-05-11 04:56:19 +0800 CST 2019-05-11 04:56:19 +0800 CST

如何识别系统容器上不断增长的阻塞进程的来源(LXC/OpenVZ)

  • 772

当阻塞进程的数量无限增长时,如何准确识别这些进程是什么。

在此处输入图像描述

由于我位于系统容器 (LXC/OpenVZ) 中,因此无法修改主机的内核模块以使用perf-tools或bcc-tools/bpfcc-tools 等工具


问题如何在 Linux 中跟踪新创建的进程?没有涵盖系统容器的场景,大部分答案依赖于perf-tools和bcc-tools.

monitoring
  • 1 1 个回答
  • 198 Views

1 个回答

  • Voted
  1. Best Answer
    Paulo Coghi
    2019-05-12T03:48:08+08:002019-05-12T03:48:08+08:00

    1.检查CONFIG_PROC_EVENTS

    首先检查是否CONFIG_PROC_EVENTS启用。根据您的发行版,您可以运行:

    grep CONFIG_PROC_EVENTS= /boot/config-`uname -r`
    

    如果启用,您将获得以下结果:

    CONFIG_PROC_EVENTS=y
    

    2.如果启用,创建监视器

    创建一个proc_events.c包含以下内容的文件:

    static volatile bool need_exit = false;
    
    static int nl_connect()
    {
        int rc;
        int nl_sock;
        struct sockaddr_nl sa_nl;
    
        nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
        if (nl_sock == -1) {
            perror("socket");
            return -1;
        }
        sa_nl.nl_family = AF_NETLINK;
        sa_nl.nl_groups = CN_IDX_PROC;
        sa_nl.nl_pid = getpid();
        rc = bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
        if (rc == -1) {
            perror("bind");
            close(nl_sock);
            return -1;
        }
        return nl_sock;
    }
    
    static int set_proc_ev_listen(int nl_sock, bool enable)
    {
        int rc;
        struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
            struct nlmsghdr nl_hdr;
            struct __attribute__ ((__packed__)) {
                struct cn_msg cn_msg;
                enum proc_cn_mcast_op cn_mcast;
            };
        } nlcn_msg;
    
        memset(&nlcn_msg, 0, sizeof(nlcn_msg));
        nlcn_msg.nl_hdr.nlmsg_len = sizeof(nlcn_msg);
        nlcn_msg.nl_hdr.nlmsg_pid = getpid();
        nlcn_msg.nl_hdr.nlmsg_type = NLMSG_DONE;
    
        nlcn_msg.cn_msg.id.idx = CN_IDX_PROC;
        nlcn_msg.cn_msg.id.val = CN_VAL_PROC;
        nlcn_msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);
    
        nlcn_msg.cn_mcast = enable ? PROC_CN_MCAST_LISTEN : PROC_CN_MCAST_IGNORE;
    
        rc = send(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0);
        if (rc == -1) {
            perror("netlink send");
            return -1;
        }
    
        return 0;
    }
    
    static int handle_proc_ev(int nl_sock)
    {
        int rc;
        struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
            struct nlmsghdr nl_hdr;
            struct __attribute__ ((__packed__)) {
                struct cn_msg cn_msg;
                struct proc_event proc_ev;
            };
        } nlcn_msg;
        while (!need_exit) {
            rc = recv(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0);
            if (rc == 0) {
                /* shutdown? */
                return 0;
            } else if (rc == -1) {
                if (errno == EINTR) continue;
                perror("netlink recv");
                return -1;
            }
            switch (nlcn_msg.proc_ev.what) {
                case PROC_EVENT_NONE:
                    printf("set mcast listen ok\n");
                    break;
                case PROC_EVENT_FORK:
                    printf("fork: parent tid=%d pid=%d -> child tid=%d pid=%d\n",
                            nlcn_msg.proc_ev.event_data.fork.parent_pid,
                            nlcn_msg.proc_ev.event_data.fork.parent_tgid,
                            nlcn_msg.proc_ev.event_data.fork.child_pid,
                            nlcn_msg.proc_ev.event_data.fork.child_tgid);
                    break;
                case PROC_EVENT_EXEC:
                    printf("exec: tid=%d pid=%d\n",
                            nlcn_msg.proc_ev.event_data.exec.process_pid,
                            nlcn_msg.proc_ev.event_data.exec.process_tgid);
                    break;
                case PROC_EVENT_UID:
                    printf("uid change: tid=%d pid=%d from %d to %d\n",
                            nlcn_msg.proc_ev.event_data.id.process_pid,
                            nlcn_msg.proc_ev.event_data.id.process_tgid,
                            nlcn_msg.proc_ev.event_data.id.r.ruid,
                            nlcn_msg.proc_ev.event_data.id.e.euid);
                    break;
                case PROC_EVENT_GID:
                    printf("gid change: tid=%d pid=%d from %d to %d\n",
                            nlcn_msg.proc_ev.event_data.id.process_pid,
                            nlcn_msg.proc_ev.event_data.id.process_tgid,
                            nlcn_msg.proc_ev.event_data.id.r.rgid,
                            nlcn_msg.proc_ev.event_data.id.e.egid);
                    break;
                case PROC_EVENT_EXIT:
                    printf("exit: tid=%d pid=%d exit_code=%d\n",
                            nlcn_msg.proc_ev.event_data.exit.process_pid,
                            nlcn_msg.proc_ev.event_data.exit.process_tgid,
                            nlcn_msg.proc_ev.event_data.exit.exit_code);
                    break;
                default:
                    printf("unhandled proc event\n");
                    break;
            }
        }
    
        return 0;
    }
    
    static void on_sigint(__attribute__ ((unused)) int unused)
    {
        need_exit = true;
    }
    
    int main()
    {
        int nl_sock;
        int rc = EXIT_SUCCESS;
    
        signal(SIGINT, &on_sigint);
        siginterrupt(SIGINT, true);
        nl_sock = nl_connect();
        if (nl_sock == -1)
            exit(EXIT_FAILURE);
        rc = set_proc_ev_listen(nl_sock, true);
        if (rc == -1) {
            rc = EXIT_FAILURE;
            goto out;
        }
        rc = handle_proc_ev(nl_sock);
        if (rc == -1) {
            rc = EXIT_FAILURE;
            goto out;
        }
        set_proc_ev_listen(nl_sock, false);
    out:
        close(nl_sock);
        exit(rc);
    }
    

    确保您可以编译 C 程序。在 Debian 或基于 Debian 的发行版上,例如 Ubuntu,运行:

    sudo apt-get install build-essential
    

    并编译它:

    gcc proc_events.c -o proc_events
    

    3.运行几秒钟

    以这种方式运行将直接在终端上输出:

    ./proc_events
    

    但是您也可以重定向它并运行几秒钟,以便将其输出保存在文件中:

    ./proc_events > results_file
    

    4. 分析结果

    输出将采用以下格式:

    fork: parent tid=48 pid=48 -> child tid=56 pid=56
    fork: parent tid=48 pid=48 -> child tid=57 pid=57
    exec: tid=57 pid=57
    exec: tid=56 pid=56
    exit: tid=57 pid=57 exit_code=0
    exit: tid=56 pid=56 exit_code=0
    

    归功于@cirosantilli

    • 0

相关问题

  • 如何监控系统在哪里写/读磁盘?[关闭]

  • 如何监控 SAN 服务器(通过 iSCSI)?

  • 共享点管理?

  • 安全地授予对 SQL 2005 复制监视器的访问权限以创建快照

  • SNMP HOSTMIB.MIB 未加载?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    新安装后 postgres 的默认超级用户用户名/密码是什么?

    • 5 个回答
  • Marko Smith

    SFTP 使用什么端口?

    • 6 个回答
  • Marko Smith

    命令行列出 Windows Active Directory 组中的用户?

    • 9 个回答
  • Marko Smith

    什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同?

    • 3 个回答
  • Marko Smith

    如何确定bash变量是否为空?

    • 15 个回答
  • Martin Hope
    Tom Feiner 如何按大小对 du -h 输出进行排序 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich 什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent 如何确定bash变量是否为空? 2009-05-13 09:54:48 +0800 CST
  • Martin Hope
    cletus 您如何找到在 Windows 中打开文件的进程? 2009-05-01 16:47:16 +0800 CST

热门标签

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve