PostgreSQL 各个后台进程关系的理解

本文涉及的产品
云原生数据库 PolarDB MySQL 版,通用型 2核8GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介:

启动PostgreSQL 进程后,可以看到:

[root@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
[root@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. 









本文转自健哥的数据花园博客园博客,原文链接:http://www.cnblogs.com/gaojian/archive/2012/10/24/2736805.html,如需转载请自行联系原作者

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍如何基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
18天前
|
缓存 关系型数据库 BI
使用MYSQL Report分析数据库性能(下)
使用MYSQL Report分析数据库性能
56 3
|
24天前
|
关系型数据库 MySQL 数据库
自建数据库如何迁移至RDS MySQL实例
数据库迁移是一项复杂且耗时的工程,需考虑数据安全、完整性及业务中断影响。使用阿里云数据传输服务DTS,可快速、平滑完成迁移任务,将应用停机时间降至分钟级。您还可通过全量备份自建数据库并恢复至RDS MySQL实例,实现间接迁移上云。
|
2月前
|
存储 运维 关系型数据库
从MySQL到云数据库,数据库迁移真的有必要吗?
本文探讨了企业在业务增长背景下,是否应从 MySQL 迁移至云数据库的决策问题。分析了 MySQL 的优势与瓶颈,对比了云数据库在存储计算分离、自动化运维、多负载支持等方面的优势,并提出判断迁移必要性的五个关键问题及实施路径,帮助企业理性决策并落地迁移方案。
|
11天前
|
关系型数据库 MySQL 分布式数据库
阿里云PolarDB云原生数据库收费价格:MySQL和PostgreSQL详细介绍
阿里云PolarDB兼容MySQL、PostgreSQL及Oracle语法,支持集中式与分布式架构。标准版2核4G年费1116元起,企业版最高性能达4核16G,支持HTAP与多级高可用,广泛应用于金融、政务、互联网等领域,TCO成本降低50%。
|
12天前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS费用价格:MySQL、SQL Server、PostgreSQL和MariaDB引擎收费标准
阿里云RDS数据库支持MySQL、SQL Server、PostgreSQL、MariaDB,多种引擎优惠上线!MySQL倚天版88元/年,SQL Server 2核4G仅299元/年,PostgreSQL 227元/年起。高可用、可弹性伸缩,安全稳定。详情见官网活动页。
|
13天前
|
关系型数据库 分布式数据库 数据库
阿里云数据库收费价格:MySQL、PostgreSQL、SQL Server和MariaDB引擎费用整理
阿里云数据库提供多种类型,包括关系型与NoSQL,主流如PolarDB、RDS MySQL/PostgreSQL、Redis等。价格低至21元/月起,支持按需付费与优惠套餐,适用于各类应用场景。
|
12天前
|
SQL 关系型数据库 MySQL
Mysql数据恢复—Mysql数据库delete删除后数据恢复案例
本地服务器,操作系统为windows server。服务器上部署mysql单实例,innodb引擎,独立表空间。未进行数据库备份,未开启binlog。 人为误操作使用Delete命令删除数据时未添加where子句,导致全表数据被删除。删除后未对该表进行任何操作。需要恢复误删除的数据。 在本案例中的mysql数据库未进行备份,也未开启binlog日志,无法直接还原数据库。

推荐镜像

更多