PostgreSQL reload配置的动作反馈与源码分析

本文涉及的产品
云数据库 RDS SQL Server,基础系列 2核4GB
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
简介:

PostgreSQL reload配置的动作反馈与源码分析

作者

digoal

日期

2016-09-01

标签

PostgreSQL , reload , 配置


背景

PostgreSQL数据库的配置文件中,有一些配置项是支持reload的,但是如果配置写错了,reload时怎么知道呢?

源码分析

reload其实是通过给postmaster进程发SIGHUP信号来实现的。

通过pg_ctl或者kill或者pg_reload_conf()函数都可以发信号。

postmaster收到这个信号之后,会调用SIGHUP_handler,处理一堆事务,包括重载配置文件(包括postgresql.conf, pg_hba.conf, pg_ident.conf),以及调用一些处理函数。

从代码来看,发起reload的进程,并不知道reload的结果,因为信号发完就了事了。
src/backend/utils/adt/misc.c

/*
 * Signal to reload the database configuration
 */
Datum
pg_reload_conf(PG_FUNCTION_ARGS)
{
        if (!superuser())
                ereport(ERROR,
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                 (errmsg("must be superuser to signal the postmaster"))));

        if (kill(PostmasterPid, SIGHUP))
        {
                ereport(WARNING,
                                (errmsg("failed to send signal to postmaster: %m")));
                PG_RETURN_BOOL(false);
        }

        PG_RETURN_BOOL(true);
}

postmaster进程收到SIGHUP信号后的处理,如下
src/backend/postmaster/postmaster.c

/*  
 * SIGHUP -- reread config files, and tell children to do same  
 */  
static void  
SIGHUP_handler(SIGNAL_ARGS)  
{  
        int                     save_errno = errno;  

        PG_SETMASK(&BlockSig);  

        if (Shutdown <= SmartShutdown)  
        {  
                ereport(LOG,  
                                (errmsg("received SIGHUP, reloading configuration files")));  
                ProcessConfigFile(PGC_SIGHUP);  
                SignalChildren(SIGHUP);  
                if (StartupPID != 0)  
                        signal_child(StartupPID, SIGHUP);  
                if (BgWriterPID != 0)  
                        signal_child(BgWriterPID, SIGHUP);  
                if (CheckpointerPID != 0)  
                        signal_child(CheckpointerPID, SIGHUP);  
                if (WalWriterPID != 0)  
                        signal_child(WalWriterPID, SIGHUP);  
                if (WalReceiverPID != 0)  
                        signal_child(WalReceiverPID, SIGHUP);  
                if (AutoVacPID != 0)  
                        signal_child(AutoVacPID, SIGHUP);  
                if (PgArchPID != 0)  
                        signal_child(PgArchPID, SIGHUP);  
                if (SysLoggerPID != 0)  
                        signal_child(SysLoggerPID, SIGHUP);  
                if (PgStatPID != 0)  
                        signal_child(PgStatPID, SIGHUP);  

                /* Reload authentication config files too */  
                if (!load_hba())  
                        ereport(WARNING,  
                                        (errmsg("pg_hba.conf not reloaded")));  

                if (!load_ident())  
                        ereport(WARNING,  
                                        (errmsg("pg_ident.conf not reloaded")));  

#ifdef EXEC_BACKEND  
                /* Update the starting-point file for future children */  
                write_nondefault_variables(PGC_SIGHUP);  
#endif  
        }  

        PG_SETMASK(&UnBlockSig);  

        errno = save_errno;  
}  

我们关心的是重载配置文件的几个调用

ProcessConfigFile(PGC_SIGHUP);  
load_hba()  
load_ident()  

postgresql.conf 配置文件重载的代码如下,如果有错误,会调用ereport,输出到日志。

void  
ProcessConfigFile(GucContext context)  
{  

        /*  
         * Read and apply the config file.  We don't need to examine the result.  
         */  
        (void) ProcessConfigFileInternal(context, true, elevel);  
...  
ProcessConfigFileInternal(context, true, elevel)  
...  

                else if (strchr(item->name, GUC_QUALIFIER_SEPARATOR) == NULL)  
                {  
                        /* Invalid non-custom variable, so complain */  
                        ereport(elevel,  
                                        (errcode(ERRCODE_UNDEFINED_OBJECT),  
                                         errmsg("unrecognized configuration parameter \"%s\" in file \"%s\" line %u",  
                                                        item->name,  
                                                        item->filename, item->sourceline)));  
                        item->errmsg = pstrdup("unrecognized configuration parameter");  
                        error = true;  
                        ConfFileWithError = item->filename;  
                }  
...  
                if (gconf->context < PGC_SIGHUP)  
                {  
                        ereport(elevel,  
                                        (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),  
                                         errmsg("parameter \"%s\" cannot be changed without restarting the server",  
                                                        gconf->name)));  
                        record_config_file_error(psprintf("parameter \"%s\" cannot be changed without restarting the server",  
                                                                                          gconf->name),  
                                                                         NULL, 0,  
                                                                         &head, &tail);  
                        error = true;  
                        continue;  
                }  
...  
                        /* Log the change if appropriate */  
                        if (context == PGC_SIGHUP)  
                                ereport(elevel,  
                                                (errmsg("parameter \"%s\" removed from configuration file, reset to default",  
                                                                gconf->name)));  

重载pg_hba.conf的代码,如果有错误也会输出,但是同样是postmaster进程的输出,而不是用户进程。

load_hba(void)  
{  
...  
                if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num), lfirst(raw_line))) == NULL)  
                {  
...  
parse_hba_line(List *line, int line_num, char *raw_line)  
{  
...  
                                ereport(LOG,  
                                                (errcode(ERRCODE_CONFIG_FILE_ERROR),  
                                                 errmsg("hostssl requires SSL to be turned on"),  
                                                 errhint("Set ssl = on in postgresql.conf."),  
                                                 errcontext("line %d of configuration file \"%s\"",  
                                                                        line_num, HbaFileName)));  
...  

我们可以看到,如果重载异常,ereport调用是postmaster发出的,发送SIGHUP信号的进程(即与用户交互的backend process)收不到这个告警。

所以,用户可以查看数据库日志的方式,了解重载配置文件是否异常。

2016-09-01 18:49:50.617 CST,,,64793,,57c52489.fd19,14,,2016-08-30 14:15:37 CST,,0,LOG,F0000,"end-of-line before role specification",,,,,"line 94 of configuration file ""/u01/digoal/pg_root_1921/pg_hba.conf""",,,"parse_hba_line, hba.c:946",""  
2016-09-01 18:49:50.617 CST,,,64793,,57c52489.fd19,15,,2016-08-30 14:15:37 CST,,0,WARNING,01000,"pg_hba.conf not reloaded",,,,,,,,"SIGHUP_handler, postmaster.c:2494",""  

目前,不管reload有没有成功,都会更新reload时间,所以通过pg_conf_load_time获取到的是接收到SIGHUP信号的时间,并不能代表最后的成功reload时间

 pg_catalog | pg_conf_load_time                        | timestamp with time zone |                     | normal

backend process如何获取reload状态

但是backend process怎么样才能知道reload异常了呢?

因为backend process发完信号就返回了,所以只要信号发成功就可以,至于reload它才不管呢,那么postmaster怎么把问题反馈给backend process呢?

我想到一个思路是异步消息,我们知道PostgreSQL是支持异步消息的,我以前写过一些文档介绍异步消息, 例如
《PostgreSQL Notify/Listen Like ESB》
https://yq.aliyun.com/articles/14606

《PostgreSQL 的小玩具, async Notification as a chat group》
https://yq.aliyun.com/articles/81

其实Greenplum在一些管理手段中也使用了异步消息,用于传递一些状态信息。

PostgreSQL其实也可以这样做:
1. 后台进程调用pg_reload_conf(),并且监听一个channel(例如我们固定命名为reload channel)。
2. 信号发完,postmaster开始处理信号。
3. postmaster在解析配置文件,或者reload配置文件时,如果遇到错误,除了触发ereport之外,同时将异步消息通知到对应的channel。
4. 这样的话,只要backend process不退出,就能收到来自postmaster的通知,知道reload是否异常。

Count

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
存储 关系型数据库 数据库
用Patroni配置PostgreSQL高可用集群
Patroni是Zalando开发的数据库高可用管理软件,用于编排和自动化PostgreSQL集群的管理过程。Patroni 需要一系列其他组件的支持,通过利用第三方分布式一致性软件,组建并实现数据库高可用方案。
用Patroni配置PostgreSQL高可用集群
|
关系型数据库 MySQL Nacos
nacos数据库使用PostgreSQL及集群配置
从Nacos2.2版本开始,Nacos提供了数据源扩展插件,以便让需要进行其他数据库适配的用户自己编写插件来保存数据。
|
4月前
|
关系型数据库 MySQL Linux
在Linux中,如何配置数据库服务器(如MySQL或PostgreSQL)?
在Linux中,如何配置数据库服务器(如MySQL或PostgreSQL)?
|
5月前
|
SQL 分布式计算 关系型数据库
实时计算 Flink版产品使用问题之在使用FlinkCDC与PostgreSQL进行集成时,该如何配置参数
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
实时计算 Flink版产品使用问题之在使用FlinkCDC与PostgreSQL进行集成时,该如何配置参数
|
5月前
|
安全 关系型数据库 Linux
|
6月前
|
缓存 关系型数据库 数据库
postgresql.conf配置详解
postgresql.conf配置详解
|
安全 关系型数据库 Go
远程连接PostgreSQL:配置指南与安全建议
远程连接PostgreSQL:配置指南与安全建议
707 0
|
7月前
|
关系型数据库 网络安全 数据安全/隐私保护
你会开启Postgresql 的SSL单向认证 配置?
你会开启Postgresql 的SSL单向认证 配置?
351 0
你会开启Postgresql 的SSL单向认证 配置?
|
7月前
|
关系型数据库 Linux 数据安全/隐私保护
PostgreSQL【部署 02】在线安装PostgreSQL(Some psql features might not work 问题处理+角色密码设置+配置远程访问)
PostgreSQL【部署 02】在线安装PostgreSQL(Some psql features might not work 问题处理+角色密码设置+配置远程访问)
81 0
PostgreSQL【部署 02】在线安装PostgreSQL(Some psql features might not work 问题处理+角色密码设置+配置远程访问)
|
7月前
|
监控 关系型数据库 Java
SpringBoot【集成 01】Druid+Dynamic+Greenplum(实际上用的是PostgreSQL的驱动)及 dbType not support 问题处理(附hikari相关配置)
SpringBoot【集成 01】Druid+Dynamic+Greenplum(实际上用的是PostgreSQL的驱动)及 dbType not support 问题处理(附hikari相关配置)
330 0

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版