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

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》

《PostgreSQL 的小玩具, async Notification as a chat group》

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

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

Count

时间: 2024-08-03 23:18:55

PostgreSQL reload配置的动作反馈与源码分析的相关文章

PostgreSQL 最佳实践 - 任意时间点恢复源码分析

背景 我们知道PostgreSQL是支持任意时间点恢复的,那么背后的原理是什么? 本文将对PG的时间点恢复进行详细的讲解,帮助用户理解. 本文涉及源码参考PostgreSQL 9.2.2版本. 时间点恢复涉及的参数 我们知道PostgreSQL 支持PITR, 基于时间点的恢复. 通过配置recovery.conf可以指定3种恢复目标, 如下 : recovery_target_name (string) This parameter specifies the named restore po

Spark源码分析之二:Job的调度模型与运行反馈

        在<Spark源码分析之Job提交运行总流程概述>一文中,我们提到了,Job提交与运行的第一阶段Stage划分与提交,可以分为三个阶段:         1.Job的调度模型与运行反馈:         2.Stage划分:         3.Stage提交:对应TaskSet的生成.         今天,我们就结合源码来分析下第一个小阶段:Job的调度模型与运行反馈.         首先由DAGScheduler负责将Job提交到事件队列eventProcessLoop

Jquery1.9.1源码分析系列(十五)动画处理之外篇_jquery

a.动画兼容Tween.propHooks Tween.propHooks提供特殊情况下设置.获取css特征值的方法,结构如下 Tween.propHooks = { _default: { get: function(){...}, set: function(){...} }, scrollTop: { set: function(){...} } scrollLeft: { set: function(){...} } } Tween.propHooks.scrollTop 和Tween.

深入理解Spark:核心思想与源码分析

大数据技术丛书 深入理解Spark:核心思想与源码分析 耿嘉安 著 图书在版编目(CIP)数据 深入理解Spark:核心思想与源码分析/耿嘉安著. -北京:机械工业出版社,2015.12 (大数据技术丛书) ISBN 978-7-111-52234-8 I. 深- II.耿- III.数据处理软件 IV. TP274 中国版本图书馆CIP数据核字(2015)第280808号 深入理解Spark:核心思想与源码分析 出版发行:机械工业出版社(北京市西城区百万庄大街22号 邮政编码:100037)

Backbone.js 0.9.2 源码分析收藏

Backbone 为复杂Javascript应用程序提供模型(models).集合(collections).视图(views)的结构.其中模型用于绑定键值数据和自定义事件:集合附有可枚举函数的丰富API: 视图可以声明事件处理函数,并通过RESRful JSON接口连接到应用程序. 源码分析转之网上它人的备注,特收藏一下,以免方便阅读. // Backbone.js 0.9.2 // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. // Ba

jQuery插件-jRating评分插件源码分析及使用方法_jquery

该插件被广泛应用于各种需要评分的页面当中,今天作为学习,把源码拿出来分析一下,顺便学习其使用方法. 一.插件使用一览. 复制代码 代码如下: <div> <div>第一个例子</div> <div id="16_1" class="myRating"></div> </div> 复制代码 代码如下: <link href="Script/jRating/jRating.jquer

Spark源码分析之七:Task运行(一)

        在Task调度相关的两篇文章<Spark源码分析之五:Task调度(一)>与<Spark源码分析之六:Task调度(二)>中,我们大致了解了Task调度相关的主要逻辑,并且在Task调度逻辑的最后,CoarseGrainedSchedulerBackend的内部类DriverEndpoint中的makeOffers()方法的最后,我们通过调用TaskSchedulerImpl的resourceOffers()方法,得到了TaskDescription序列的序列Seq

Spark源码分析之五:Task调度(一)

        在前四篇博文中,我们分析了Job提交运行总流程的第一阶段Stage划分与提交,它又被细化为三个分阶段:         1.Job的调度模型与运行反馈:         2.Stage划分:         3.Stage提交:对应TaskSet的生成.         Stage划分与提交阶段主要是由DAGScheduler完成的,而DAGScheduler负责Job的逻辑调度,主要职责也即DAG图的分解,按照RDD间是否为shuffle dependency,将整个Job划分

Spark源码分析 – Deploy

参考, Spark源码分析之-deploy模块   Client Client在SparkDeploySchedulerBackend被start的时候, 被创建, 代表一个application和spark cluster进行通信  Client的逻辑很简单, 封装ClientActor, 并负责该Actor的start和stop  而ClientActor的关键在于preStart的时候, 向master注册该application, 并且在执行过程中接收master发来的event /**