一、 问题现象
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, ¶m);
批注: 使用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
原文地址:https://www.cnblogs.com/smith9527/p/12168508.html