1.线程的负载均衡
对task_struct做负载均衡;
分布式系统中,linux的每个核都自动以劳动为乐,(共产主义社会)。
分别对RT任务和普通线程做负载均衡:
RT任务:将n个优先级最高的线程自动分配到n个核;
pull_rt_task()
push_rt_task()
普通任务:
周期性负载均衡,在时钟tick会检查哪个核空闲,优先使空闲核工作(从负载重的核pull任务,或push任务给空闲核,每个CPU以劳动为乐);
idle时负载均衡;某个核进入idle状态,会主动pull任务执行;
fork和exec时负载均衡;创建的新进程,会放到最闲的核去跑;
软亲和性(affinity) Linux 内核进程调度器天生就具有被称为软 CPU
亲和性(affinity)的特性,这意味着进程通常不会在处理器之间频繁迁移。这种状态正是我们希望的,因为进程迁移的频率小就意味着产生的负载小。
硬亲和性(affinity): 就是利用linux内核提供给用户的API,强行将进程或者线程绑定到某一个指定的cpu核运行。
需要绑定CPU的原因:
1.提高cache命中率;
2.在一些非对称CPU,比如NUMA中,防止一个CPU去另外一个插槽的内存读写数据;
也可以用taskset工具设置:-a 所有线程
pidof ./a.out
进程a.out占用CPU800%(八核)
设置只在2号核跑
taskset -a -p 02 554
CPU占有率降至100%,所有线程只在2号核上跑;
2.中断负载均衡
负载除了进程还有中断,执行完中断,才会去执行task_struct任务;
硬件中断一般比较短(linux2.6.34后内核不支持中断嵌套),比如网卡收包,在硬中断接收完包,会调用软中断(处理tcp/ip包,软中断可以嵌套),软中断结束后,会调用vtime最小的线程;
top命令的hi表示硬中断时间(isr,屏蔽中断),si表示软中断,
当网络流量大的时候,CPU花在硬中断和软中断时间比较多,这时候需要做中断的负载均衡;
现在新网卡一般有多个队列,假如在一个4核的系统,网卡有4个队列,每个队列可以单独产生中断,硬件支持负载均衡;那么可以将一个队列绑定到一个核,这样,所有CPU都会参与网卡发送包服务;
设定方法:将每个中断号,分别设置affinity,绑定到指定CPU
cat /proc/interrupts |grep ‘enp’
124: 0 0 0 0 0 0 0 34 415207449 PCI-MSI 1572864-edge enp3s0
sudo sh -c “echo 3 > /proc/irq/124/smp_affinity”
有的网卡只有一个队列:单个核抛出的软中断只能在这个核跑,那么一个队列抛出的软中断(tcp/ip层处理)只能在这一个核执行,其他核会空闲;
测试:
客户端:$ echo “不要回答!不要回答!不要回答!” | nc 10.10.100.16 1235
服务端:$ nc -l -p 1235
3 RPS补丁
Google推出了rps补丁,可以把TCP/IP协议栈的处理,均衡到多个核上去,这个技术叫RPS;
比如我手头板子是单个网卡队列收包,默认是单核上执行
#cat /sys/class/net/eth0/queues/rx-0/rps_cpus
0
收包只在CPU0上执行
nc -l -p 1235
监听1235端口收到数据时,只有CPU0继续增加;
多核间的softIRQ scaling
设置rps在CPU0/1上均衡
echo 3 > /sys/class/net/eth0/queues/rx-0/rps_cpus
watch –d “cat /proc/softirqs | grep NET_RX”
/proc/interrupt
/proc/softirq
分别查看硬中断和软中断次数
top +1显示多核的负载
由上可以看到CPU0/1都开始处理网络接收包
经实验得出结论:
- 硬中断绑定的CPU核,一定会响应softirqs,不管对应rps_cpus位设置与否;
2.当rps_cpus位设置时,对应CPU核会响应softirqs;
RPS原理:由单一CPU核响应硬件中断,将大量网络接收包,通过多核间中断方式分发给其他空闲核,如下网络图清晰说明情况
上图引用自https://blog.csdn.net/dog250/article/details/46705657
4.linux不是硬实时系统:
硬实时:满足可预期,非一定越快越好,强调的是截止期限的可预期性;
Linux的设计决定了她不是硬实时系统,有些情况(比如spin_lock)不可抢占,其不可预期,是软实时系统;
用什么系统由场景决定,并非硬实时一定优于软实时。
Linux的抢占算法演变,越新的内核支持抢占越多;
Linux的CPU消耗主要分以下几种:
内核态的spin_lock,是自旋锁,用户态不是;
1,2,3都不可抢占,所以linux不是一个硬实时系统,硬实时系统要求任何时刻都可以抢占。
T3时刻唤醒一个更高优先级RT线程,
RT线程只能到T5时刻(硬中断,软中断都执行完,并且释放spin_lock之后)才能抢占,等待时间是未知的。
要解决linux硬实时性,需要打rt补丁,
补丁不在mainline中,维护网站;
https://wiki.linuxfoundation.org/realtime/start
https://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-stable-rt.git/
rt补丁
将所有中断线程化,
去掉软中断,
spin_lock改成mutex实现,即系统中只有上图第4类进程,任何线程都可以被抢占;
使延迟变为可预期,即成为硬实时系统。
不是每一个内核版本都有相应rt补丁。
rt可以将linux延迟做到100us量级(1G CPU),同时吞吐会下降。
打上补丁后如下图
Server:不抢占
Desktop: kernel不抢占
Low-Latency Destktop:手机用,kernel也抢占
Real-Time:完全抢占;
调度器实时后,linux还不一定实时,有无数内存坑,比如内存管理部分,ROW,写内存时发现内存尚未分配,此时无法保持实时性。
其他方法:
同时运行两个系统,实时任务放在RTOS跑,非实时任务放在Linux跑。
比如单反,一般用两个系统,传统拍照用实时系统,涉及网络相关任务放在linux,利用linux强大的网络协议栈。
5.Deadline调度算法
https://elinux.org/images/f/fe/Using_SCHED_DEADLINE.pdf
如下场景需求,系统有两个任务,核电站任务要求运行1/2s, 洗衣机要求运行20ms/200ms;
用传统RT或CFS调度算法,必须设置洗衣机优先级更高才能满足需求。(核电站优先级更高将独占CPU超过0.5s,
下一个周期无法满足CPU需求)
但当系统有多个任务,比如核电站要求800ms周期内必须跑500ms,洗碗机要求300/900ms,
洗衣机要求100/800ms:
总的CPU消耗是小于100%的。但是按照传统RR算法,无法满足调度需求;
Linux提供了一个Rate Monotonic Scheduling:
Deadline调度算法思想:当产生一个调度点的时候,DL调度器总是选择其Deadline距离当前时间点最近的那个任务并调度它执行,谁更紧急,谁先跑;
Deadline需要设置三个参数,周期Period,Deadline, Runtime
deadline调度器虽然可以保证每个RT任务在deadline之前完成,但是并不能保证每一个任务的最小响应时间。
内核实例,sched-deadline.c
设置允许普通用户修改app调度策略
sudo setcap 'cap_sys_nice=eip' ./a.out
pidof ./a.out
sudo chrt -d -T 1000000 -P 3000000 -D 2000000 0 pid
sudo chrt -p pid
$ sudo chrt -p 6276
chrt: unknown scheduling policy
pid 6276's current scheduling policy: pid 6276's current scheduling priority: 0
chrt 版本太低,未支持显示deadline参数;
Deadline在top显示rt进程,