分类: LINUX
2011-12-08 14:43:01
转自:
Nginx允许设置worker进程的CPU亲和性,这样有利于充分利用服务器资源,减少进程在CPU之间移动的可能性。
在ChinaUnix上看到一个非常好的例子程序——,该示例的源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | #include #include #include #include #include #define __USE_GNU #include #include #include int main(int argc, char* argv[]) { //获得CPU的数量,本服务器有8个CPU 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; } |
运行程序如下:
使用top看各CPU的使用率(运行top之后,按1就会显示CPU使用率列表),结果如下:
上面的结果清晰地显示出第0个和第1个CPU较别的CPU更为繁忙。
nginx.c中有两个函数分别为ngx_set_cpu_affinity和ngx_get_cpu_affinity,ngx_set_cpu_affinity根据nginx.conf的配置来设置每个进程的亲和性掩码。典型的设置如下:
根据上面这个配置,Nginx master进程将开启四个worker进程,它们分别运行在第1,2,3,4个CPU上。阅读ngx_get_cpu_affinity可以发现其设置 mask同最上面那个示例程序并不一样,它没有什么CPU_SET这些宏,而是自己来做。
nginx_precess_cycle.c的ngx_start_worker_processes函数负责创建worker process。在spawn进程之前,它会获取该进程的CPU亲和性掩码,并将其赋给cpu_affinity这个全局变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type) { ngx_int_t i; ngx_channel_t ch; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes"); ch.command = NGX_CMD_OPEN_CHANNEL; for (i = 0; i < n; i++) { cpu_affinity = ngx_get_cpu_affinity(i); ngx_spawn_process(cycle, ngx_worker_process_cycle, NULL, "worker process", type); ch.pid = ngx_processes[ngx_process_slot].pid; ch.slot = ngx_process_slot; ch.fd = ngx_processes[ngx_process_slot].channel[0]; ngx_pass_open_channel(cycle, &ch); } } |
worker进程的回调函数是ngx_worker_process_cycle,该函数会先调用”ngx_worker_process_init(cycle, 1);”初始化本进程,在ngx_worker_process_init中有这样一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 | #if (NGX_HAVE_SCHED_SETAFFINITY) if (cpu_affinity) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "sched_setaffinity(0x%08Xl)", cpu_affinity); //设置cpu亲和性 if (sched_setaffinity(0, 32, (cpu_set_t *) &cpu_affinity) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sched_setaffinity(0x%08Xl) failed", cpu_affinity); } } #endif |
我使用”./configure –with-debug”打开了Nginx的调试选项,启动Nginx之后,可以看到有四个进程启动,但是发现error.log四个这样的错误:
在网上一查,发现很多人都反应这个问题,据说是不支持RHEL 4.0,支持RHEL 5.0。晕死,服务器安装的都是RHEL 4.0,所以就没有可测试的环境了。如果能进行测试的话,就可以分别对设置了亲和性和没有设置亲和性的情况,使用ab进行压力测试,看看效率有没有差别。