• Linux 线程绑核


    假设业务模型中耗费cpu的分四种类型,(1)网卡中断(2)1个处理网络收发包进程(3)耗费cpu的n个worker进程(4)其他不太耗费cpu的进程

    基于1中的 负载均衡是针对进程数,那么(1)(2)大部分时间会出现在cpu0上,(3)的n个进程会随着调度,平均到其他多个cpu上,(4)里的进程也是随着调度分配到各个cpu上;

    当发生网卡中断的时候,cpu被打断了,处理网卡中断,那么分配到cpu0上的worker进程肯定是运行不了的

    其他cpu上不是太耗费cpu的进程获得cpu时,就算它的时间片很短,它也是要执行的,那么这个时候,你的worker进程还是被影响到了;按照调度逻辑,一种非常恶劣的情况是:(1)(2)(3)的进程全部分配到cpu0上,其他不太耗费cpu的进程数很多,全部分配到cpu1,cpu2,cpu3上。。那么网卡中断发生的时候,你的业务进程就得不到cpu了

    如果从业务的角度来说,worker进程运行越多,肯定业务处理越快,人为的将它捆绑到其他负载低的cpu上,肯定能提高worker进程使用cpu的时间

    每个cpu都利用起来了,负载会比不绑定的情况下好很多

    有效果的原因:

    依据《linux内核设计与实现》的42节,人为控制一下cpu的绑定还是有用处地
        linux的SMP负载均衡是基于进程数的,每个cpu都有一个可执行进程队列(为什么不是线程队列呢??),只有当其中一个cpu的可执行队列里进程数比其他cpu队列进程数多25%时,才会将进程移动到另外空闲cpu上,也就是说cpu0上的进程数应该是比其他cpu上多,但是会在25%以内。


    示例程序

    cpu.c


    #include<stdlib.h>
    #include<stdio.h>
    #include<sys/types.h>
    #include<sys/sysinfo.h>
    #include<unistd.h>

    #define __USE_GNU
    #include<sched.h>
    #include<ctype.h>
    #include<string.h>

    int main(int argc, char* argv[])
    {
    int num = sysconf(_SC_NPROCESSORS_CONF);
    int created_thread = 0;
    int myid;
    int i;
    int j = 0;

    cpu_set_t mask;
    cpu_set_t get;

    if (argc != 2)
    {
    printf("usage : ./cpu num\n");
    exit(1);
    }

    myid = atoi(argv[1]);

    printf("system has %i processor(s). \n", num);

    CPU_ZERO(&mask);
    CPU_SET(myid, &mask);

    if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
    {
    printf("warning: could not set CPU affinity, continuing...\n");
    }
    while (1)
    {

    CPU_ZERO(&get);
    if (sched_getaffinity(0, sizeof(get), &get) == -1)
    {
    printf("warning: cound not get cpu affinity, continuing...\n");
    }
    for (i = 0; i < num; i++)
    {
    if (CPU_ISSET(i, &get))
    {
    printf("this process %d is running processor : %d\n",getpid(), i);
    }
    }
    }
    return 0;
    }


    下面是在两个终端分别执行了./cpu 0 ./cpu 2 后得到的结果. 效果比较明显.

    QUOTE:

    Cpu0 : 5.3%us, 5.3%sy, 0.0%ni, 87.4%id, 0.0%wa, 0.0%hi, 2.0%si, 0.0%st
    Cpu1 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
    Cpu2 : 5.0%us, 12.2%sy, 0.0%ni, 82.8%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
    Cpu3 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
    Cpu4 : 0.0%us, 0.0%sy, 0.0%ni, 99.7%id, 0.3%wa, 0.0%hi, 0.0%si, 0.0%st
    Cpu5 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
    Cpu6 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
    Cpu7 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

    CPU亲和力
        
    linux下的进程可以通过sched_setaffinity系统调用设置进程亲和力,限定进程只能在某些特定的CPU上运行。负载均衡必须考虑遵守这个限制(前面也多次提到)。

    迁移线程
        
    前面说到,在普通进程的load_balance过程中,如果负载不均衡,当前CPU会试图从最繁忙的run_queue中pull几个进程到自己的run_queue来。
        但是如果进程迁移失败呢?当失败达到一定次数的时候,内核会试图让目标CPU主动push几个进程过来,这个过程叫做active_load_balance。这里的“一定次数”也是跟调度域的层次有关的,越低层次,则“一定次数”的值越小,越容易触发active_load_balance。
        这里需要先解释一下,为什么load_balance的过程中迁移进程会失败呢?最繁忙run_queue中的进程,如果符合以下限制,则不能迁移:
        1、进程的CPU亲和力限制了它不能在当前CPU上运行;
        2、进程正在目标CPU上运行(正在运行的进程显然是不能直接迁移的);
        (此外,如果进程在目标CPU上前一次运行的时间距离当前时间很小,那么该进程被cache的数据可能还有很多未被淘汰,则称该进程的cache还是热的。对于cache热的进程,也尽量不要迁移它们。但是在满足触发active_load_balance的条件之前,还是会先试图迁移它们。)
        对于CPU亲和力有限制的进程(限制1),即使active_load_balance被触发,目标CPU也不能把它push过来。所以,实际上,触发active_load_balance的目的是要尝试把当时正在目标CPU上运行的那个进程弄过来(针对限制2)。

        在每个CPU上都会运行一个迁移线程,active_load_balance要做的事情就是唤醒目标CPU上的迁移线程,让它执行active_load_balance的回调函数。在这个回调函数中尝试把原先因为正在运行而未能迁移的那个进程push过来。为什么load_balance的时候不能迁移,active_load_balance的回调函数中就可以了呢?因为这个回调函数是运行在目标CPU的迁移线程上的。一个CPU在同一时刻只能运行一个进程,既然这个迁移线程正在运行,那么期望被迁移的那个进程肯定不是正在被执行的,限制2被打破。

        当然,在active_load_balance被触发,到回调函数在目标CPU上被执行之间,目标CPU上的TASK_RUNNING状态的进程可能发生一些变化,所以回调函数发起迁移的进程未必就只有之前因为限制2而未能被迁移的那一个,可能更多,也可能一个没有。

  • 相关阅读:
    高性能Javascript DOM编程学习笔记
    高性能Javascrip 改变作用域链
    高性能Javascript 加载和执行 读书笔记
    javascript 在function 里return 重写function 而得到更多的作用域 闭包
    HTML、css和javascript开发Android程序第五章节 客户端存储 学习笔记
    高性能Javascript HTML集合访问的学习笔记
    高性能Javascript 数据访问读书笔记
    博客
    高性能Javascript 缓存对象成员
    高性能Javascript 克隆节点学习笔记
  • 原文地址:https://www.cnblogs.com/dongzhiquan/p/2353215.html
Copyright © 2020-2023  润新知