zabbix_server代码分析--多进程创建

来源:互联网 发布:eai 数据黑盒 编辑:程序博客网 时间:2024/06/07 05:26

一、如果单纯的启动多个进程,那么代码如下:

//总体思路:父进程创建多个子进程,并且使用一个特殊标记值,使每个子进程这个数值都不同//父进程创建子进程之后,根据这个特殊数值依次给进程分配要执行的代码for(i = 0;i < thread_num;i++){if(0 == (thread_pid[i] = topo_fork())){        //每个子进程thread_mark都有一个唯一的数值,该值依次递增,从1开始。thread_mark = i + 1;break;}else{printf("thread(%d): %d\n",i,thread_pid[i]); }}    //根据thread_mark数值不同,设置条件,使不同的进程执行不同的代码。    //父进程的thread_mark为0if(0 == thread_mark){printf("This is parent process start\n");        //父进程执行的代码parent_main_loop();}    //第一个子进程的thread_mark为1else(thread_mark == 1){printf("This is snmp child process start\n");        //第一个进程执行的代码topo_main_loop();}    //第二个子进程的thread_mark为2else(thread_mark == 2){printf("This is watchdog child process start\n");        //第二个进程执行的代码watchdog_main_loop();}
这样做的缺点是要启动的进程个数是确定的,哪个功能要启动几个进程也是确定的,而zabbix里面启动多少个进程是不确定的,哪个功能要启动多少个进程也是不确定的,比如poller进程的个数,是可以配置文件配置个数的。


二、zabbix多进程实现

intCONFIG_ALERTER_FORKS= 1;intCONFIG_DISCOVERER_FORKS= 1;intCONFIG_HOUSEKEEPER_FORKS= 1;intCONFIG_NODEWATCHER_FORKS= 1;intCONFIG_PINGER_FORKS= 1;intCONFIG_POLLER_FORKS= 5;intCONFIG_UNREACHABLE_POLLER_FORKS= 1;intCONFIG_HTTPPOLLER_FORKS= 1;intCONFIG_IPMIPOLLER_FORKS= 0;intCONFIG_TIMER_FORKS= 1;intCONFIG_TRAPPER_FORKS= 5;intCONFIG_SNMPTRAPPER_FORKS= 0;intCONFIG_JAVAPOLLER_FORKS= 0;intCONFIG_ESCALATOR_FORKS= 1;intCONFIG_SELFMON_FORKS= 1;intCONFIG_WATCHDOG_FORKS= 1;intCONFIG_DATASENDER_FORKS= 0;intCONFIG_HEARTBEAT_FORKS= 0;intCONFIG_CONFSYNCER_FORKS= 1;intMAIN_ZABBIX_ENTRY(){pid_tpid;inti, server_num = 0, server_count = 0;//要启动的进程数量由这些变量的值决定,配置值为1就启动该进程,为0就不启动该进程。//这些值有的有默认值,有的根据配置文件决定。threads_num = CONFIG_CONFSYNCER_FORKS + CONFIG_WATCHDOG_FORKS + CONFIG_POLLER_FORKS+ CONFIG_UNREACHABLE_POLLER_FORKS + CONFIG_TRAPPER_FORKS + CONFIG_PINGER_FORKS+ CONFIG_ALERTER_FORKS + CONFIG_HOUSEKEEPER_FORKS + CONFIG_TIMER_FORKS+ CONFIG_NODEWATCHER_FORKS + CONFIG_HTTPPOLLER_FORKS + CONFIG_DISCOVERER_FORKS+ CONFIG_HISTSYNCER_FORKS + CONFIG_ESCALATOR_FORKS + CONFIG_IPMIPOLLER_FORKS+ CONFIG_JAVAPOLLER_FORKS + CONFIG_SNMPTRAPPER_FORKS + CONFIG_PROXYPOLLER_FORKS+ CONFIG_SELFMON_FORKS;threads = zbx_calloc(threads, threads_num, sizeof(pid_t));//使用fork()产生新的进程,thread_num是多少,就产生多少个进程。//fork()产生新进程的过程中,对于父进程,fork函数返回了子程序的进程号,而对于子程序,fork函数则返回零//所以此处使用if,else结构,会使父进程和子进程执行不同的代码for (i = 0; i < threads_num; i++){if (0 == (pid = zbx_child_fork())){//每个子进程都中的server_num都会有一个唯一的依次递增的值//根据server_num这个在每个进程中数值都不一样的特点,可以在下面实现每个子进程去执行不同的代码//子进程执行break,直接跳出循环,去执行进程之后的代码server_num = i + 1;/* child processes are numbered starting from 1 */break;}else//父进程返回的是子进程的进程号,父进程将每个子进程的进程号记录在thread[]结构中threads[i] = pid;}//父进程的server_num为0,每个子进程都有不同的server_num,根据server_num的不同,使不同的进程执行不同的代码。if (0 == server_num){zabbix_log(LOG_LEVEL_INFORMATION, "server #0 started [main process]");while (-1 == wait(&i))/* wait for any child to exit */{if (EINTR != errno){zabbix_log(LOG_LEVEL_ERR, "failed to wait on child processes: %s", zbx_strerror(errno));break;}}/* all exiting child processes should be caught by signal handlers */THIS_SHOULD_NEVER_HAPPEN;zbx_on_exit();}    //server_count是已启动的子进程的个数,CONFIG_CONFSYNCER_FORKS为本次要启动的子进程的个数,server_num为每个子进程的标记值,    //以server_num <= (server_count += CONFIG_CONFSYNCER_FORKS)为条件,可实现让子进程依次去执行相关的代码功能    //server_count初始值为0,第一个子进程的server_num数值为1,    //如果CONFIG_CONFSYNCER_FORKS为0,则server_count += CONFIG_CONFSYNCER_FORKS 数值为0,不满足1<=0,不执行main_dbconfig_loop()    //如果CONFIG_CONFSYNCER_FORKS为1,则server_count += CONFIG_CONFSYNCER_FORKS 数值为1,满足1 <= 1,把main_dbconfig_loop()作为子进程要执行的代码。    //如果CONFIG_CONFSYNCER_FORKS为2,则server_count += CONFIG_CONFSYNCER_FORKS 数值为2,第一个子进程执行时满足1<=2,执行main_dbconfig_loop()    //第二个子进程执行时,满足2<=2,执行main_dbconfig_loop();由此可以实现同样的功能启动多个进程。CONFIG_CONFSYNCER_FORKS就是该功能启动进程的个数。else if (server_num <= (server_count += CONFIG_CONFSYNCER_FORKS)){INIT_SERVER(ZBX_PROCESS_TYPE_CONFSYNCER, CONFIG_CONFSYNCER_FORKS);main_dbconfig_loop();}else if (server_num <= (server_count += CONFIG_WATCHDOG_FORKS)){INIT_SERVER(ZBX_PROCESS_TYPE_WATCHDOG, CONFIG_WATCHDOG_FORKS);main_watchdog_loop();}return SUCCEED;}

    进程要有描述,这样才知道是哪个进程在执行哪个功能。有利于程序调试。

//对进程的描述,记录哪个进程执行的是什么功能//get_process_type_string根据传入的参数,执行switch case结构,返回对进程的描述。传入的参数为程序中宏定义的变量//server_num为第几个进程,et_process_type_string(process_type)为对进程执行功能的描述,process_num为该功能启动进程的计数(因为有的功能要启动多个进程)#define INIT_SERVER(type, count)\process_type = type;\process_num = server_num - server_count + count;\zabbix_log(LOG_LEVEL_INFORMATION, "server #%d started [%s #%d]",\server_num, get_process_type_string(process_type), process_num)#define ZBX_PROCESS_TYPE_POLLER0#define ZBX_PROCESS_TYPE_UNREACHABLE1#define ZBX_PROCESS_TYPE_IPMIPOLLER2#define ZBX_PROCESS_TYPE_PINGER3#define ZBX_PROCESS_TYPE_JAVAPOLLER4#define ZBX_PROCESS_TYPE_HTTPPOLLER5#define ZBX_PROCESS_TYPE_TRAPPER6#define ZBX_PROCESS_TYPE_SNMPTRAPPER7#define ZBX_PROCESS_TYPE_PROXYPOLLER8#define ZBX_PROCESS_TYPE_ESCALATOR9#define ZBX_PROCESS_TYPE_HISTSYNCER10#define ZBX_PROCESS_TYPE_DISCOVERER11#define ZBX_PROCESS_TYPE_ALERTER12#define ZBX_PROCESS_TYPE_TIMER13#define ZBX_PROCESS_TYPE_NODEWATCHER14#define ZBX_PROCESS_TYPE_HOUSEKEEPER15#define ZBX_PROCESS_TYPE_WATCHDOG16#define ZBX_PROCESS_TYPE_DATASENDER17#define ZBX_PROCESS_TYPE_CONFSYNCER18#define ZBX_PROCESS_TYPE_HEARTBEAT19#define ZBX_PROCESS_TYPE_SELFMON20#define ZBX_PROCESS_TYPE_COUNT21/* number of process types */#define ZBX_PROCESS_TYPE_UNKNOWN255            const char*get_process_type_string(unsigned char process_type){switch (process_type){case ZBX_PROCESS_TYPE_POLLER:return "poller";case ZBX_PROCESS_TYPE_UNREACHABLE:return "unreachable poller";case ZBX_PROCESS_TYPE_IPMIPOLLER:return "ipmi poller";case ZBX_PROCESS_TYPE_PINGER:return "icmp pinger";case ZBX_PROCESS_TYPE_JAVAPOLLER:return "java poller";case ZBX_PROCESS_TYPE_HTTPPOLLER:return "http poller";case ZBX_PROCESS_TYPE_TRAPPER:return "trapper";case ZBX_PROCESS_TYPE_SNMPTRAPPER:return "snmp trapper";case ZBX_PROCESS_TYPE_PROXYPOLLER:return "proxy poller";case ZBX_PROCESS_TYPE_ESCALATOR:return "escalator";case ZBX_PROCESS_TYPE_HISTSYNCER:return "history syncer";case ZBX_PROCESS_TYPE_DISCOVERER:return "discoverer";case ZBX_PROCESS_TYPE_ALERTER:return "alerter";case ZBX_PROCESS_TYPE_TIMER:return "timer";case ZBX_PROCESS_TYPE_NODEWATCHER:return "node watcher";case ZBX_PROCESS_TYPE_HOUSEKEEPER:return "housekeeper";case ZBX_PROCESS_TYPE_WATCHDOG:return "db watchdog";case ZBX_PROCESS_TYPE_DATASENDER:return "data sender";case ZBX_PROCESS_TYPE_CONFSYNCER:return "configuration syncer";case ZBX_PROCESS_TYPE_HEARTBEAT:return "heartbeat sender";case ZBX_PROCESS_TYPE_SELFMON:return "self-monitoring";}assert(0);}