PostgreSQL client's startup packet different between logical and normal stream replication

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介:
我们知道PostgreSQL 9.4新增了逻辑流复制的功能, 在客户端连接数据库服务器时, 通过发送给数据库的startup packet来判断是否要数据库启动wal sender, 并且如何来识别是逻辑复制还是普通的流复制.
数据库处理启动包的代码9.3和9.4的区别 : 
PostgreSQL 9.4的
ProcessStartupPacket@src/backend/postmaster/postmaster.c
/*
 * Read a client's startup packet and do something according to it.
 *
 * Returns STATUS_OK or STATUS_ERROR, or might call ereport(FATAL) and
 * not return at all.
 *
 * (Note that ereport(FATAL) stuff is sent to the client, so only use it
 * if that's what you want.  Return STATUS_ERROR if you don't want to
 * send anything to the client, which would typically be appropriate
 * if we detect a communications failure.)
 */
static int
ProcessStartupPacket(Port *port, bool SSLdone)
...
                        if (strcmp(nameptr, "database") == 0)
                                port->database_name = pstrdup(valptr);
                        else if (strcmp(nameptr, "user") == 0)
                                port->user_name = pstrdup(valptr);
                        else if (strcmp(nameptr, "options") == 0)
                                port->cmdline_options = pstrdup(valptr);
                        else if (strcmp(nameptr, "replication") == 0)
                        {
                                /*
                                 * Due to backward compatibility concerns the replication
                                 * parameter is a hybrid beast which allows the value to be
                                 * either boolean or the string 'database'. The latter
                                 * connects to a specific database which is e.g. required for
                                 * logical decoding while.
                                 */
                                if (strcmp(valptr, "database") == 0)
                                {
                                        am_walsender = true;
                                        am_db_walsender = true;
                                }
                                else if (!parse_bool(valptr, &am_walsender))
                                        ereport(FATAL,
                                                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                                         errmsg("invalid value for parameter \"replication\""),
                                                         errhint("Valid values are: false, 0, true, 1, database.")));
                        }
                        else
                        {
                                /* Assume it's a generic GUC option */
                                port->guc_options = lappend(port->guc_options,
                                                                                        pstrdup(nameptr));
                                port->guc_options = lappend(port->guc_options,
                                                                                        pstrdup(valptr));
                        }
在9.4中, replication=database字符串时, 启动walsender, 并且连接到一个数据库, 逻辑复制必须连接到一个数据库 这是和9.3的差异
                                        am_walsender = true;
                                        am_db_walsender = true;
replication=0或1时, am_walsender=0/1, am_db_walsender = 默认的false.

9.4根据am_db_walsender标示是否逻辑复制.
        /*
         * Normal walsender backends, e.g. for streaming replication, are not
         * connected to a particular database. But walsenders used for logical
         * replication need to connect to a specific database. We allow streaming
         * replication commands to be issued even if connected to a database as it
         * can make sense to first make a basebackup and then stream changes
         * starting from that.
         */
        if (am_walsender && !am_db_walsender)
                port->database_name[0] = '\0';


PostgreSQL 9.3的
ProcessStartupPacket@src/backend/postmaster/postmaster.c
ProcessStartupPacket@src/backend/postmaster/postmaster.c
                        if (strcmp(nameptr, "database") == 0)
                                port->database_name = pstrdup(valptr);
                        else if (strcmp(nameptr, "user") == 0)
                                port->user_name = pstrdup(valptr);
                        else if (strcmp(nameptr, "options") == 0)
                                port->cmdline_options = pstrdup(valptr);
                        else if (strcmp(nameptr, "replication") == 0)
                        {
                                if (!parse_bool(valptr, &am_walsender))
                                        ereport(FATAL,
                                                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                                         errmsg("invalid value for boolean option \"replication\"")));
                        }
                        else
                        {
                                /* Assume it's a generic GUC option */
                                port->guc_options = lappend(port->guc_options,
                                                                                        pstrdup(nameptr));
                                port->guc_options = lappend(port->guc_options,
                                                                                        pstrdup(valptr));
                        }

PostgreSQL 9.3 没有am_db_walsender 这个变量. 因为9.3不支持logical replication. 这个变量时9.4新增的.

从上面的内容可以看到, 我们在启动包中加入这些信息, 服务端是如何来处理的.
例如加入replication=database, 那么就表示这是一个逻辑复制链接, 数据库服务端要启动一个wal sender.
而如果加入其它的, 如database=mydbname, 则表示要连接到哪个数据库.
user=username则表示用哪个用户连接.
例如, 使用psql可以设置一些变量, 包括options :
pg94@db-172-16-3-150-> psql "user=digoal"
psql: FATAL:  role "digoal" does not exist
pg94@db-172-16-3-150-> psql "user=postgres"
psql (9.4devel)
Type "help" for help.

pg94@db-172-16-3-150-> psql "options=-B=1024kB"
psql: FATAL:  parameter "shared_buffers" cannot be changed without restarting the server

这个options是postgres 的options. 在psql中设置没有效果.
详见man postgres

其它还可以设置guc的变量
pg94@db-172-16-3-150-> psql "encoding=sql_"
psql: invalid connection option "encoding"
pg94@db-172-16-3-150-> psql "client_encoding=sql_a"
psql (9.4devel)
Type "help" for help.
digoal=# show client_encoding;
 client_encoding 
-----------------
 UTF8
(1 row)


设置流复制连接 : 
pg94@db-172-16-3-150-> psql "replication=database"
psql: FATAL:  no pg_hba.conf entry for replication connection from host "[local]", user "postgres", SSL off

因为没有配置, 报连接不上, 修改pg_hba.conf后重试
local replication all trust
vi postgresql.conf
wal_level = logical
max_wal_senders = 10
pg_ctl restart -m fast

pg94@db-172-16-3-150-> psql "replication=database"
psql (9.4devel)
Type "help" for help.
digoal=# create table test(id int);
ERROR:  syntax error
digoal=# select 1;
ERROR:  syntax error
digoal=# \set VERBOSITY verbose
digoal=# create table test(id int);
ERROR:  42601: syntax error
LOCATION:  replication_yyerror, repl_scanner.l:214

注意到, 在startup packet中标识了replication这个变量后, 语法解析会加入repl_scanner.l的部分, 所以只支持流复制协议的语法.
流复制协议的语法参考 :
例如 :
digoal=# IDENTIFY_SYSTEM;
      systemid       | timeline |   xlogpos   | dbname 
---------------------+----------+-------------+--------
 6010111239203060891 |        1 | 18/52969CB0 | digoal
(1 row)

digoal=# TIMELINE_HISTORY 1;
ERROR:  58P01: could not open file "pg_xlog/00000001.history": No such file or directory
LOCATION:  SendTimeLineHistory, walsender.c:457
digoal=# CREATE_REPLICATION_SLOT slotname PHYSICAL;
ERROR:  53400: all replication slots are in use
HINT:  Free one or increase max_replication_slots.
LOCATION:  ReplicationSlotCreate, slot.c:243


vi postgresql.conf
max_replication_slots = 10
pg_ctl restart -m fast
pg94@db-172-16-3-150-> psql "replication=database"
psql (9.4devel)
Type "help" for help.

digoal=# CREATE_REPLICATION_SLOT slotname PHYSICAL;
 slot_name | consistent_point | snapshot_name | output_plugin 
-----------+------------------+---------------+---------------
 slotname  | 0/0              |               | 
(1 row)



好了, 写到这里, 大家要了解流复制协议, 可以看看文档, 代码


[参考]
2. src/backend/postmaster/postmaster.c
3. src/backend/replication/repl_scanner.l
相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
SQL Oracle 关系型数据库
PostgreSQL JOIN limit 优化器 成本计算 改进 - mergejoin startup cost 优化
标签 PostgreSQL , join , limit , startup cost , cbo , 优化器改进 背景 PostgreSQL limit N的成本估算,是通过计算总成本A,以及估算得到的总记录数B得到: (N/B)*A 大概意思就是占比的方法计算 对于单表查询...
1167 0
|
SQL 关系型数据库 PostgreSQL
|
2月前
|
关系型数据库 分布式数据库 数据库
成都晨云信息技术完成阿里云PolarDB数据库产品生态集成认证
近日,成都晨云信息技术有限责任公司(以下简称晨云信息)与阿里云PolarDB PostgreSQL版数据库产品展开产品集成认证。测试结果表明,晨云信息旗下晨云-站群管理系统(V1.0)与阿里云以下产品:开源云原生数据库PolarDB PostgreSQL版(V11),完全满足产品兼容认证要求,兼容性良好,系统运行稳定。
|
2月前
|
关系型数据库 分布式数据库 数据库
PolarDB常见问题之数据库不能自己减少节点如何解决
PolarDB是阿里云推出的下一代关系型数据库,具有高性能、高可用性和弹性伸缩能力,适用于大规模数据处理场景。本汇总囊括了PolarDB使用中用户可能遭遇的一系列常见问题及解答,旨在为数据库管理员和开发者提供全面的问题指导,确保数据库平稳运行和优化使用体验。
|
2月前
|
缓存 关系型数据库 分布式数据库
PolarDB常见问题之数据库cpu突然飙高如何解决
PolarDB是阿里云推出的下一代关系型数据库,具有高性能、高可用性和弹性伸缩能力,适用于大规模数据处理场景。本汇总囊括了PolarDB使用中用户可能遭遇的一系列常见问题及解答,旨在为数据库管理员和开发者提供全面的问题指导,确保数据库平稳运行和优化使用体验。
|
3月前
|
关系型数据库 分布式数据库 数据库
阿里云PolarDB登顶2024中国数据库流行榜:技术实力与开发者影响力
近日,阿里云旗下的自研云原生数据库PolarDB在2024年中国数据库流行度排行榜中夺冠,并刷新了榜单总分纪录,这一成就引起了技术圈的广泛关注。这一成就源于PolarDB在数据库技术上的突破与创新,以及对开发者和用户的实际需求的深入了解体会。那么本文就来分享一下关于数据库流行度排行榜的影响力以及对数据库选型的影响,讨论PolarDB登顶的关键因素,以及PolarDB“三层分离”新版本对开发者使用数据库的影响。
83 3
阿里云PolarDB登顶2024中国数据库流行榜:技术实力与开发者影响力
|
2月前
|
关系型数据库 分布式数据库 数据库
PolarDB PostgreSQL版:Oracle兼容的高性能数据库
PolarDB PostgreSQL版是一款高性能的数据库,具有与Oracle兼容的特性。它采用了分布式架构,可以轻松处理大量的数据,同时还支持多种数据类型和函数,具有高可用性和可扩展性。它还提供了丰富的管理工具和性能优化功能,为企业提供了可靠的数据存储和处理解决方案。PolarDB PostgreSQL版在数据库领域具有很高的竞争力,可以满足各种企业的需求。
|
9天前
|
关系型数据库 OLAP 分布式数据库
「杭州*康恩贝」4月26日PolarDB开源数据库沙龙,开启报名!
4月26日周五,PolarDB开源社区联合康恩贝将共同举办开源数据库技术沙龙,本次沙龙我们邀请了众多数据库领域的专家,期待大家的参与!
「杭州*康恩贝」4月26日PolarDB开源数据库沙龙,开启报名!