PHP-FPM 记分牌(scoreboard) 机制
前文中提到 fpm 的初始化分很多步骤,其中一个重要的步骤就是调用 fpm_scoreboard_init_main() 初始化进程记分牌。为什么需要这个记分牌?因为 FPM 的父进程需要管理非常多的子进程,这就需要一个打分的机制,不能让一个进程老是干活,而另一部分进程老是闲置,因为每个进程维护的内存空间是有限的,如果一个进程处理了较多的任务可能会产生更多的内存碎片。
先看看其核心代码结构:
- fpm_scoreboard_acquire
- fpm_scoreboard_child_use
- fpm_scoreboard_free
- fpm_scoreboard_get
- fpm_scoreboard_get_tick
- fpm_scoreboard_init_main
- fpm_scoreboard_proc_acquire
- fpm_scoreboard_proc_alloc
- fpm_scoreboard_proc_free
- fpm_scoreboard_proc_get
- fpm_scoreboard_proc_release
- fpm_scoreboard_release
- fpm_scoreboard_update
结合上一节中 fpm 初始化的步骤可知,初始化首先被调用的是 fpm_scoreboard_init_main 函数。
for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
size_t scoreboard_size, scoreboard_nprocs_size;
void *shm_mem;
if (wp->config->pm_max_children < 1) {
zlog(ZLOG_ERROR, "[pool %s] Unable to create scoreboard SHM because max_client is not set", wp->config->name);
return -1;
}
if (wp->scoreboard) {
zlog(ZLOG_ERROR, "[pool %s] Unable to create scoreboard SHM because it already exists", wp->config->name);
return -1;
}
scoreboard_size = sizeof(struct fpm_scoreboard_s) + (wp->config->pm_max_children) * sizeof(struct fpm_scoreboard_proc_s *);
scoreboard_nprocs_size = sizeof(struct fpm_scoreboard_proc_s) * wp->config->pm_max_children;
shm_mem = fpm_shm_alloc(scoreboard_size + scoreboard_nprocs_size);
if (!shm_mem) {
return -1;
}
wp->scoreboard = shm_mem;
wp->scoreboard->nprocs = wp->config->pm_max_children;
shm_mem += scoreboard_size;
for (i = 0; i < wp->scoreboard->nprocs; i++, shm_mem += sizeof(struct fpm_scoreboard_proc_s)) {
wp->scoreboard->procs[i] = shm_mem;
}
wp->scoreboard->pm = wp->config->pm;
wp->scoreboard->start_epoch = time(NULL);
strlcpy(wp->scoreboard->pool, wp->config->name, sizeof(wp->scoreboard->pool));
}
这段代码是一个大循环,它会遍历所有的 fpm