postgresql源码学习(54)—— HotStandby从库必须设置大于等于主库的参数

news2024/9/22 21:24:42

       新的一篇本来计划研究lazy_scan_heap函数,但过于复杂还没研究出来下午做题遇到一个这样的问题,之前没太关注过,打算学习学习,避免主从配置踩坑。

       题干搜一搜,没搜出啥有用的玩意…渣翻成英文搜一搜,搜出来了官方文档:PostgreSQL: Documentation: 14: 27.4. Hot Standby

一、 从库必须>=主库的几个参数

    这里把几个版本的文档都看了看,发现一点有意思的区别。

1. pg 11版本

https://www.postgresql.org/docs/11/hot-standby.html

         11的文档写的很简单,只是说有4个参数从库设置不能小于主库,就是题目那4个:max_connections,max_prepared_transactions,max_locks_per_transaction,max_worker_processes

  • 加大参数时:先加从库,再加主库
  • 减小参数时:先减主库,再减从库

       如果设错了会怎么样?还蛮严重的,从库会启动不了。

      If these parameters are not set high enough then the standby will refuse to start. Higher values can then be supplied and the server restarted to begin recovery again. 

2. pg 12版本

PostgreSQL: Documentation: 12: 26.5. Hot Standby

       内容跟11基本没什么区别,但是新增了一个参数:max_wal_senders,变成了5个,13版本的文档跟12一样。

3. pg 14版本

       有了简单的原因介绍:说这些参数跟tracking transaction IDs, locks, and prepared transactions的共享内存大小相关。为了避免从库在recovery过程在耗尽相关共享内存,从库这些共享内存的结构必须>=主库。

     例如,如果主库使用了一个prepared transaction,但从库没有为它分配共享内存,那么recovery操作会无法继续,直到参数设置正确。

       文档还给了个设置错误时的例子

WARNING:  hot standby is not possible because of insufficient parameter settings

DETAIL:  max_connections = 80 is a lower setting than on the primary server, where its value was 100.

LOG:  recovery has paused

DETAIL:  If recovery is unpaused, the server will shut down.

HINT:  You can then restart the server after making the necessary configuration changes.

       注意这个DETAIL,当参数设错时,从库由直接不能启动变成了暂停recovery操作(刚好前两天看了新特性文档,又找了遍没找到这项,可能只算是个小优化?)。

二、 源码学习

1. 找到对应函数

最简单的就是直接搜索告警内容

2. RecoveryRequiresIntParameter函数

      这里还发现它其实对HotStandby从库才有这些参数要求,SetRecoveryPause很明显就是暂停recovery的函数。

static void
RecoveryRequiresIntParameter(const char *param_name, int currValue, int minValue)
{
    if (currValue < minValue)
    {
        if (LocalHotStandbyActive)
        {
            bool        warned_for_promote = false;

            ereport(WARNING,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("hot standby is not possible because of insufficient parameter settings"),
                     errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.",
                               param_name,
                               currValue,
                               minValue)));

            SetRecoveryPause(true);

            ereport(LOG,
                    (errmsg("recovery has paused"),
                     errdetail("If recovery is unpaused, the server will shut down."),
                     errhint("You can then restart the server after making the necessary configuration changes.")));

            while (GetRecoveryPauseState() != RECOVERY_NOT_PAUSED)
            {
                HandleStartupProcInterrupts();

                if (CheckForStandbyTrigger())
                {
                    if (!warned_for_promote)
                        ereport(WARNING,
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                 errmsg("promotion is not possible because of insufficient parameter settings"),

                        /*
                         * Repeat the detail from above so it's easy to find
                         * in the log.
                         */
                                 errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.",
                                           param_name,
                                           currValue,
                                           minValue),
                                 errhint("Restart the server after making the necessary configuration changes.")));
                    warned_for_promote = true;
                }

                /*
                 * If recovery pause is requested then set it paused.  While
                 * we are in the loop, user might resume and pause again so
                 * set this every time.
                 */
                ConfirmRecoveryPaused();

                /*
                 * We wait on a condition variable that will wake us as soon
                 * as the pause ends, but we use a timeout so we can check the
                 * above conditions periodically too.
                 */
                ConditionVariableTimedSleep(&XLogCtl->recoveryNotPausedCV, 1000,
                                            WAIT_EVENT_RECOVERY_PAUSE);
            }
            ConditionVariableCancelSleep();
        }

        ereport(FATAL,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("recovery aborted because of insufficient parameter settings"),
        /* Repeat the detail from above so it's easy to find in the log. */
                 errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.",
                           param_name,
                           currValue,
                           minValue),
                 errhint("You can restart the server after making the necessary configuration changes.")));
    }
}

3. SetRecoveryPause函数

       来看看它是怎么暂停的,其实就是获取锁,改了控制文件的recoveryPauseState状态。并且这里只是把状态改为RECOVERY_PAUSE_REQUESTED,实际暂停状态由ConfirmRecoveryPaused函数修改。

/*
 * Set the recovery pause state.
 *
 * If recovery pause is requested then sets the recovery pause state to
 * 'pause requested' if it is not already 'paused'.  Otherwise, sets it
 * to 'not paused' to resume the recovery.  The recovery pause will be
 * confirmed by the ConfirmRecoveryPaused.
 */
void
SetRecoveryPause(bool recoveryPause)
{
    SpinLockAcquire(&XLogCtl->info_lck);

    if (!recoveryPause)
        XLogCtl->recoveryPauseState = RECOVERY_NOT_PAUSED;
    else if (XLogCtl->recoveryPauseState == RECOVERY_NOT_PAUSED)
        XLogCtl->recoveryPauseState = RECOVERY_PAUSE_REQUESTED;

    SpinLockRelease(&XLogCtl->info_lck);

    if (!recoveryPause)
        ConditionVariableBroadcast(&XLogCtl->recoveryNotPausedCV);
}

4. ConfirmRecoveryPaused函数

       把状态由RECOVERY_PAUSE_REQUESTED改为RECOVERY_PAUSED

/*
 * Confirm the recovery pause by setting the recovery pause state to
 * RECOVERY_PAUSED.
 */
static void
ConfirmRecoveryPaused(void)
{
    /* If recovery pause is requested then set it paused */
    SpinLockAcquire(&XLogCtl->info_lck);
    if (XLogCtl->recoveryPauseState == RECOVERY_PAUSE_REQUESTED)
        XLogCtl->recoveryPauseState = RECOVERY_PAUSED;
    SpinLockRelease(&XLogCtl->info_lck);
}

5. CheckRequiredParameterValues函数

        搜一下我们的5个参数,会发现它们的检查都在本函数中。

/*
 * Check to see if required parameters are set high enough on this server
 * for various aspects of recovery operation.
 */
static void
CheckRequiredParameterValues(void)
{
    /*
     * For archive recovery, the WAL must be generated with at least 'replica'
     * wal_level.
     */
    if (ArchiveRecoveryRequested && ControlFile->wal_level == WAL_LEVEL_MINIMAL)
    {
        ereport(FATAL,
                (errmsg("WAL was generated with wal_level=minimal, cannot continue recovering"),
                 errdetail("This happens if you temporarily set wal_level=minimal on the server."),
                 errhint("Use a backup taken after setting wal_level to higher than minimal.")));
    }

    /*
     * For Hot Standby, the WAL must be generated with 'replica' mode, and we
     * must have at least as many backend slots as the primary.
     */
    if (ArchiveRecoveryRequested && EnableHotStandby)
    {
        /* We ignore autovacuum_max_workers when we make this test. */
        RecoveryRequiresIntParameter("max_connections",
                                     MaxConnections,
                                     ControlFile->MaxConnections);
        RecoveryRequiresIntParameter("max_worker_processes",
                                     max_worker_processes,
                                     ControlFile->max_worker_processes);
        RecoveryRequiresIntParameter("max_wal_senders",
                                     max_wal_senders,
                                     ControlFile->max_wal_senders);
        RecoveryRequiresIntParameter("max_prepared_transactions",
                                     max_prepared_xacts,
                                     ControlFile->max_prepared_xacts);
        RecoveryRequiresIntParameter("max_locks_per_transaction",
                                     max_locks_per_xact,
                                     ControlFile->max_locks_per_xact);
    }
}

三、 这5个参数到底是干啥的?

1. max_connections

       实例的最大并发连接数(Sets the maximum number of concurrent connections.)。

2. max_wal_senders

       同时运行的wal sender process的最大数量Sets the maximum number of simultaneously running WAL sender processes.)。

       pg 12开始,该进程数量不计入max_connections,这样即使db连接数爆,也不影响主从同步。Make max_wal_senders not count as part of max_connections.

https://www.postgresql.org/docs/12/release-12.html

3. max_worker_processes

        同时运行的工作进程的最大数量(Maximum number of concurrent worker processes.)

4. max_locks_per_transaction

       控制每个事务能够得到的平均的对象锁的个数,默认值是64。

       共享锁表最大可以保存max_locks_per_transaction * (max_connections + max_prepared_transactions)个对象锁。每个锁需要预留270字节的共享内存,单个事务可以同时获得的对象锁的数目可以超过max_locks_per_transaction的值,只要共享锁表中还有剩余空间

5. max_prepared_transactions

       此参数用于指定分布式事务两步提交中,准备事务的最大数量。默认值为0,即不支持分布式事务。如果要设置,max_prepared_transactions建议不小于max_connections,这样每个session都可以至少有一个可用的准备事务。

参考

PostgreSQL: Documentation: 14: 27.4. Hot Standby

pg12新特性-max_wal_senders从max_connections分离_瀚高PG实验室的博客-CSDN博客_max_wal_senders

http://t.zoukankan.com/f2flow-p-6050469.html

max_locks_per_transaction 设置过大引发数据库启动问题 - 墨天轮问答

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/181932.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

windows搭建go语言开发环境,IDEA安装go插件并运行Hello world代码

2023年1月27日1.Windows上安装Go语言开发包参考链接&#xff1a;http://c.biancheng.net/view/3992.html1.1.下载Go语言开发包可以在Go语言官网 &#xff08;https://golang.google.cn/dl/&#xff09; 下载Windows 系统下的Go语言开发包&#xff0c;如下图所示。这里我们下载的…

学习Docker就应该掌握的dockerfile语法与指令

在日常的工作中&#xff0c;常常需要制作自己的项目的镜像&#xff0c;一般通过以下两种方式制作镜像&#xff1a;Docker commit、Dockerfile。Docker commitDocker commit一般用做从一个运行状态的容器来创建一个新的镜像。定制镜像应该使用Dockerfile来完成。docker commit 容…

Git场景分析

当前的开发环境如下&#xff0c;我们每个人都对这个项目已经开发一段时间&#xff0c;接下来我们要切换成团队开发模式。 也就是我们由一个团队来完成这个项目实战的内容。团队有组长和若干组员组成(组长就是开发中的项目经理)。 练习场景如下&#xff1a; 1.由组长&#xff0…

LeetCode[1202]交换字符串中的元素

难度&#xff1a;中等题目&#xff1a;给你一个字符串 s&#xff0c;以及该字符串中的一些「索引对」数组 pairs&#xff0c;其中 pairs[i] [a, b]表示字符串中的两个索引&#xff08;编号从 0 开始&#xff09;。你可以 任意多次交换 在 pairs中任意一对索引处的字符。返回在…

java递归问题——汉诺塔

目录 &#x1f332;&#x1f332;什么是汉诺塔&#xff1f; &#x1f430; 当只有1个圆盘的时候&#xff1a; &#x1f430; 当只有2个圆盘的时候&#xff1a; &#x1f430; 当只有3个圆盘的时候&#xff1a; &#x1f332;&#x1f332;汉诺塔代码 &#x1f430;思路 &am…

电脑安全模式怎么进?3种方式教会你!

安全模式经常是电脑死机的时候&#xff0c;我们会选择的一种方式。因为安全模式可以帮助我们修复电脑系统里面的一些错误&#xff0c;电脑安全模式怎么进&#xff1f;其实很简单&#xff0c;主要有以下3种方式&#xff0c;你可以根据你的需要来选择其中一种&#xff01; 操作环…

剑指 Offer 第7天(中午睡起来都十二点了,今天摆了吧)

目录 剑指 Offer 26. 树的子结构 剑指 Offer 27. 二叉树的镜像 剑指 Offer 28. 对称的二叉树 剑指 Offer 26. 树的子结构 输入两棵二叉树A和B&#xff0c;判断B是不是A的子结构。(约定空树不是任意一个树的子结构) B是A的子结构&#xff0c; 即 A中有出现和B相同的结构和节点…

极光厂商通道集成指南

小米集成指南 1、使用JCenter自动化集成步骤 确认AndroidStudio的Project根目录的主gradle中配置了jcenter支持。(新建project默认配置就支持&#xff09; buildscript { repositories { jcenter() } } allprojects {repositories { jcenter() } } 在应用module的gr…

ffmpeg为mkv封装格式的音视频文件添加内挂字幕

现在好莱坞的电影&#xff0c;都是全球看&#xff0c;一个地区的人看电影时&#xff0c;电影屏幕上应该展示对应的本地区语言字幕。故电影画面在不同的地区&#xff0c;需要配置不同的语言字幕。故视频画面里面的字幕应该可以拆出来&#xff0c;不能像老版三国演义&#xff0c;…

数据中心Spine/Leaf+VXLAN的结构

大家过年好&#xff0c;我是技福的小咖老师。今天我们继续聊聊网络架构。 随着业务系统对IT基础设备灵活度要求的不断提升&#xff0c;云计算、大数据以及虚拟化等技术在新型数据中心的建设中发挥着重要作用。如何更好地满足数据中心计算资源灵活调配以及服务扩展&#xff0c;…

C语言块级变量

所谓代码块&#xff0c;就是由{ }包围起来的代码。代码块在C语言中随处可见&#xff0c;例如函数体、选择结构、循环结构等。不包含代码块的C语言程序根本不能运行&#xff0c;即使最简单的C语言程序&#xff08;上节已经进行了展示&#xff09;也要包含代码块。C语言允许在代码…

不就是Java吗之 认识异常

认识异常一、异常的概念与体系结构1.1 异常的概念1.2 异常的体系结构1.3 异常的分类1.3.1 编译时异常(受查异常)1.3.2 运行时异常(非受查异常)二、异常的处理2.1 防御型编程2.1.1 LBYL2.1.2 EAFP2.2 异常的抛出2.3 异常的捕获2.3.1 异常的声明2.3.2 try-catch捕获并处理2.3.3 f…

linux gui版本控制工具对比

linux gui版本控制工具对比qgitungitgitgsublime mergegitKrakengitAhead tkdiff之前一直用windows开发, 最近想用linux开发, 选版本控制工具的时候考察了以下几款可以在linux平台上使用的版本控制工具, 还是觉得tortoise好用. 记录下它们的优缺点. 想起以前一位同事说过的话,…

Elasticsearch:将数据从 Elasticsearch 和 Kibana 导出到 Pandas Dataframe

在这篇文章中&#xff0c;我们将看到如何从 Elasticsearch 索引和 Kibana 的 CSV 报告中导出数据 - post-url 到 pandas 数据帧。 数据的可视化可以在 Kibana 中完成&#xff0c;但如果你想对数据进行更精细的分析并创建更动态的可视化&#xff0c;将数据导出到 pandas datafra…

LeetCode 55. 跳跃游戏 45. 跳跃游戏 II 22. 括号生成 53. 最大子数组和

&#x1f308;&#x1f308;&#x1f604;&#x1f604; 55. 跳跃游戏 一、力扣示例 二、解决办法 三、代码实现 45. 跳跃游戏 II 一、力扣示例 二、解决办法 三、代码实现 22. 括号生成 一、力扣示例 二、解决办法 三、代码实现 53. 最大子数组和 一、力扣示例 …

WebAssembly编译之(3)-WASM编译实战之C/C++导出asm.js及wasm库

引言 上一节我们介绍了Ubuntu下的WASM的编译环境快速搭建。这一节我们继续WASM编译相关的介绍——如何导出C/C编写的函数库 WASM 相关文档&#xff1a; WebAssembly编译之(1)-asm.js及WebAssembly原理介绍 WebAssembly编译之(2)-Ubuntu搭建WASM编译环境 单个C文件(*.cpp)的导出…

每日学术速递1.28

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 今天带来的arXiv上最新发表的3篇AI论文。 Subjects: cs.AI、cs.Cv 1.Revisiting Temporal Modeling for CLIP-based Image-to-Video Knowledge Transferring 标题&#xff1a;重新审视基于CLIP的图像-视…

计讯物联5G工业级路由器在智慧消防的功能解析

据悉&#xff0c;国务院安全生产委员会印发《“十四五”国家消防工作规划》&#xff08;以下简称《规划》&#xff09;&#xff0c;对“十四五”时期消防改革发展作出全面部署。《规划》提出&#xff0c;坚持防消一体、防救并重&#xff1b;加强改革创新&#xff0c;加快消防“…

11 Day : 编写操作系统中断程序,加快时钟

前言&#xff1a;昨天学习了中断&#xff0c;今天就废话不多说&#xff0c;直接编写程序吧 内容更新&#xff1a;之前有朋友说看不太懂我的代码写的是啥&#xff0c;能不能详细讲讲&#xff0c;所以本期开始我会详细讲解代码&#xff0c;也会同步更新之前的博客&#xff0c;大多…

java基础巩固-宇宙第一AiYWM:为了维持生计,做项目经验之~高速项目大数据及机器学习算法方面的思路总结~整起

原始项目可能主要的功能是接收下位机传送来的很多参数&#xff0c;然后将参数以不同形式表达出来&#xff0c;在此过程中会涉及到文件上传下载、excel表格导出…等&#xff0c;但是呢&#xff0c;这么多数据不玩一下岂不是太浪费。于是&#xff0c;额们决定这样来: 项目中有一个…