设为首页 收藏本站
查看: 1224|回复: 0

[经验分享] PostgreSQL 各个后台进程关系的理解

[复制链接]

尚未签到

发表于 2016-11-21 10:10:33 | 显示全部楼层 |阅读模式
  启动PostgreSQL 进程后,可以看到:
  [iyunv@localhost ~]# ps -ef | grep post
root      2991  2925  0 10:42 pts/1    00:00:00 su - postgres
postgres  2992  2991  0 10:42 pts/1    00:00:00 -bash
postgres  3029  2992  0 10:42 pts/1    00:00:00 /usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data
postgres  3031  3029  0 10:42 ?        00:00:00 postgres: checkpointer process                        
postgres  3032  3029  0 10:42 ?        00:00:00 postgres: writer process                              
postgres  3033  3029  0 10:42 ?        00:00:00 postgres: wal writer process                          
postgres  3034  3029  0 10:42 ?        00:00:00 postgres: autovacuum launcher process                 
postgres  3035  3029  0 10:42 ?        00:00:00 postgres: stats collector process                     
root      3061  3039  0 10:43 pts/2    00:00:00 grep post
[iyunv@localhost ~]#
  不难发现,
  checkpointer process,
  writer process,
  wal writer process
  autovacuum launcher process
  stats collector process
  都是 postgres 进程的子进程。
  那么是如何做到的呢?各个子进程名称不同,而且还被同一个父进程来生成,用来完成不同的工作。
  有点 龙生九子各不同的感觉。
  看代码(Postmaster.c):



#define StartupDataBase()        StartChildProcess(StartupProcess)                    
#define StartBackgroundWriter()         StartChildProcess(BgWriterProcess)                    
#define StartCheckpointer()        StartChildProcess(CheckpointerProcess)                    
#define StartWalWriter()        StartChildProcess(WalWriterProcess)                    
#define StartWalReceiver()        StartChildProcess(WalReceiverProcess)                    


"/*
* Main idle loop of postmaster
*/
"                           
static int                           
ServerLoop(void)                           
{                           
…                           
for (;;)                        
{                        
……                    
/*                    
* If no background writer process is running, and we are not in a                    
* state that prevents it, start one.  It doesn't matter if this                    
* fails, we'll just try again later.  Likewise for the checkpointer.                    
*/                    
if (pmState == PM_RUN || pmState == PM_RECOVERY ||                    
pmState == PM_HOT_STANDBY)               
{                    
if (CheckpointerPID == 0)               
CheckpointerPID = StartCheckpointer();            
if (BgWriterPID == 0)               
BgWriterPID = StartBackgroundWriter();            
}                    
…                    
}                        
…                           
}                           

* StartChildProcess -- start an auxiliary process for the postmaster                           
*                           
* xlop determines what kind of child will be started.    All child types                        
* initially go to AuxiliaryProcessMain, which will handle common setup.                           
*                           
* Return value of StartChildProcess is subprocess' PID, or 0 if failed                           
* to start subprocess.                           
*/                           
static pid_t                           
StartChildProcess(AuxProcType type)                           
{                           
pid_t    pid;                    
char    *av[10];                    
int    ac = 0;                    
char    typebuf[32];                    
/*                        
* Set up command-line arguments for subprocess                        
*/                        
av[ac++] = "postgres";                        
#ifdef EXEC_BACKEND                        
av[ac++] = "--forkboot";                    
av[ac++] = NULL;            /* filled in by postmaster_forkexec */        
#endif                        
snprintf(typebuf, sizeof(typebuf), "-x%d", type);                        
av[ac++] = typebuf;                        
av[ac] = NULL;                        
Assert(ac < lengthof(av));                        
#ifdef EXEC_BACKEND                        
pid = postmaster_forkexec(ac, av);                    
#else    /* !EXEC_BACKEND */                    
pid = fork_process();                    
if (pid == 0)        /* child */            
{                    
IsUnderPostmaster = true;                /* we are a postmaster subprocess now */
/* Close the postmaster's sockets */               
ClosePostmasterPorts(false);               
/* Lose the postmaster's on-exit routines and port connections */               
on_exit_reset();               
/* Release postmaster's working memory context */               
MemoryContextSwitchTo(TopMemoryContext);               
MemoryContextDelete(PostmasterContext);               
PostmasterContext = NULL;               
AuxiliaryProcessMain(ac, av);               
ExitPostmaster(0);               
}                    
#endif   /* EXEC_BACKEND */                        
if (pid < 0)                        
{                        
/* in parent, fork failed */                    
int            save_errno = errno;        
errno = save_errno;                    
switch (type)                    
{                    
case StartupProcess:               
ereport(LOG,            
(errmsg("could not fork startup process: %m")));   
break;            
case BgWriterProcess:               
ereport(LOG,            
(errmsg("could not fork background writer process: %m")));            
break;            
case CheckpointerProcess:               
ereport(LOG,            
(errmsg("could not fork checkpointer process: %m")));   
break;            
case WalWriterProcess:               
ereport(LOG,            
(errmsg("could not fork WAL writer process: %m")));   
break;            
case WalReceiverProcess:               
ereport(LOG,            
(errmsg("could not fork WAL receiver process: %m")));   
break;            
default:               
ereport(LOG,            
(errmsg("could not fork process: %m")));   
break;            
}                    
/*                    
* fork failure is fatal during startup, but there's no need to choke                    
* immediately if starting other child types fails.                    
*/                    
if (type == StartupProcess)                    
ExitPostmaster(1);               
return 0;                    
}                        
/*                        
* in parent, successful fork                        
*/                        
return pid;                        
}                           
  可以看到 ,Postmaster.c 的 主循环中,安排了如下部分:

if (BgWriterPID == 0)               
BgWriterPID = StartBackgroundWriter();   
而根据宏定义, StartBackgroundWriter() 就是  StartChildProcess(BgWriterProcess)
在 通用程序   StartChildProcess 中,根据参数的不同,来完成对不同的程序的 fork动作:

av[ac++] = "postgres";
snprintf(typebuf, sizeof(typebuf), "-x%d", type);
两句,就是我们ps 的时候能够看到  postgres: writer process 信息的原因。

AuxiliaryProcessMain(ac, av); 是各个子进程真正各自为战的入口点。
而关于 EXEC_BACKEND ,可以看如下这段(I put the following just for memo):

  http://postgresql.1045698.n5.nabble.com/where-EXEC-BACKEND-td2008305.html
> hi,
>
> actually i try to execute postgres step by step (on paper)
> i don't retreive where EXEC_BACKEND is initialized
> can any one help me?
> it is very important for me
Nowhere.  If you want it, you have to define it manually in
pg_config_manual.h.
EXEC_BACKEND is a source code hack that allows the Unix build (which
normally uses only fork() without exec()) to follow the same startup
code as the Windows version (which uses CreateProcess(), equivalent to
both fork() and exec()), allowing for better debuggability for those of
us that do not use Windows.
If you want to follow postmaster initialization on a POSIX platform,
it's easier if you just assume that EXEC_BACKEND is not defined.

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-303314-1-1.html 上篇帖子: [Postgres]postgresql.conf : Permission denied处理一法 下篇帖子: ASP.Net2.0连接PostgreSQL数据库
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表