Linux线程调度引起的业务问题

Posted supersmith

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux线程调度引起的业务问题相关的知识,希望对你有一定的参考价值。

 一、 问题现象

  1.业务组播出向报文偶尔有延迟;

  2.单播出向报文平滑

二、 分析及定位

  使用wireshark分析了组播出向报文的抓包,报文无丢包,但是IO 输出流量显示burst和掉坑现象。 

  波形和抓包文件分析如下图:

 

 

   后来在接收侧抓包,并分析日志,接收方没有出现丢包问题,但是有接收码流不足,导致收包不及时,业务不流畅。

 

  通过在系统内核发包udp_sendmsg函数打点,发现有时候有300ms+没有报文发出,说明发包线程被阻塞。

  下面是监控组播出向发包函数udp_sendmsg的打点记录日志:

__dev_xmit_skb:

78      send rate:  9 Mbps

79      send rate:  9 Mbps

80      send rate:  6 Mbps   ##有流量下降

diff_send_time_ms = 346      ##346毫秒无报文发送

81      send rate:  12 Mbps  ##有流量上升

82      send rate:  9 Mbps

83      send rate:  9 Mbps

84      send rate:  8 Mbps

diff_send_time_ms = 316

85      send rate:  7 Mbps   ##被发包线程削峰

86      send rate:  9 Mbps

87      send rate:  9 Mbps

 

  确认系统上有migration实时线程频繁调度,同时发现系统记账功能pacct在系统上写了近70G文件。

 

 

 

 

 

  其中一台设备上的 pacct文件:

 

 

   业务组播发包线程也是实时线程:

 

    关闭psacct服务后,内核migration线程没有再频繁调度,而且发包没有再出现300ms延迟(上图就是去掉psacct服务后的线程调度情况)。

 经过几次抓包分析,出向流量很平稳,没有burst情况,业务阻塞现象消失。

 

  关闭方法:  

  systemctl stop psacct.service

  systemctl disable psacct.service

 

  为什么psacct服务引起了migration,进而影响了业务组播发包线程的延迟?

   一个猜测是,psacct进程写日志时造成cpu占用太高(当时psacct日志已经达到70G),触发了migration调度,而migration调度又导致业务

ForwardThread实时线程阻塞,引起发包抖动。

 

 三、migration和被阻塞线程ForwardThread调度方式

migration线程简介

为什么存在migration线程?

在计算机系统中,资源使用需要均衡,因此在相同硬件上能够获得较好的星星。在Linux内核系统中,使用一些迁移内核线程来做这些事情。

内核怎么创建migration线程?

migration线程相关结构定义:

static struct smp_hotplug_thread cpu_stop_threads = {
    .store            = &cpu_stopper.thread,
    .thread_should_run    = cpu_stop_should_run,
    .thread_fn        = cpu_stopper_thread,
    .thread_comm        = "migration/%u",
    .create            = cpu_stop_create,
    .setup            = cpu_stop_unpark,
    .park            = cpu_stop_park,
    .pre_unpark        = cpu_stop_unpark,
    .selfparking        = true,
};

migration线程创建过程:

static int __init cpu_stop_init(void)
-->BUG_ON(smpboot_register_percpu_thread(&cpu_stop_threads));
    1)__smpboot_create_thread
        ## kthread_create_on_cpu 创建线程调度优先级为0,调度策略为SCHED_NORMAL
        tsk = kthread_create_on_cpu(smpboot_thread_fn, td, cpu, ht->thread_comm);  //register smpboot_thread_fn
            -->kthread_create_on_node
                -->sched_setscheduler_nocheck
    2)## cpu_stop_create 设置调度优先级为MAX_RT_PRIO - 1(99),调度策略为SCHED_FIFO
    ht->create(cpu); ## cpu_stop_create

 

系统中migration线程信息:

 

 

 

 

业务组播发包线程调度方式:

在我们的业务代码中,通过以下接口设置业务发包线程调度策略和优先级:

param.sched_priority = sched_get_priority_max(SCHED_FIFO)  ;   /* 这个优先级为99 */
ret = pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);

 批注: 使用pthread_setschedparam函数设置可能会出现EPERM错误,这个又是另外一个问题了,后面单独开篇:)

系统中业务发包线程信息:

 

 

参考资料:

【migration介绍】https://www.systutorials.com/239971/migration-thread-works-inside-linux-kernel/

【Linux调度优先级】https://superuser.com/questions/203657/difference-between-nice-value-and-priority-in-the-top-output

【psacct服务】https://thelinuxcode.com/monitor-user-activity-acct-psacct/

 

您的支持是对博主最大的鼓励

以上是关于Linux线程调度引起的业务问题的主要内容,如果未能解决你的问题,请参考以下文章

[架构之路-39]:目标系统 - 系统软件 - Linux OS内核进程/线程调度的基本原理

浅析Linux线程调度

linux内核调度问题分析

linux线程调度策略

java线程调度

Linux 线程调度与优先级