原文地址:https://blog.csdn.net/gguxxing008/article/details/106356086

逻辑订阅是PostgreSQL10.0开始支持的新功能,PostgreSQL的物理流复制功能十分强大,在容灾、读写分离、HA等场景中都有广泛的使用,那么为什么还需要逻辑订阅呢?
我们先来看看物理流复制和逻辑订阅有哪些区别,主要有以下几点不同:
物理复制目前只能做到整个集群的复制。逻辑订阅可以做到针对某个对象
物理复制的备库只读,不能写入。逻辑订阅读写都可以
,逻辑订阅需要等待事务提交后,发布端才会使用wal_sender进程将decode后的数据发送给订阅端,订阅端流式接收与流式apply,因此逻辑订阅对主库性能影响较大
逻辑复制限制:
DDL不支持
序列数据不支持
大对象数据类型不支持
不支持视图,雾化视图,外部表

逻辑订阅实践:
在使用逻辑订阅之前我们需要对数据库进行一些配置:
发布端:
配置pg_hba.conf,允许订阅端通过流复制连接发布端
wal_level必须设置为logical
max_replication_slots 默认10个,根据情况修改。
发布端的角色必须具备replication权限,或者超级用户权限
订阅端:
创建subscription的用户,必须是超级用户

这些基本的一些准备做好之后,就可以开始配置逻辑订阅了:
1、配置发布端

postgres=# create table t1(id int primary key, info text, crt_time timestamp);
CREATE TABLE
postgres=# create publication testpub1 for table t1;
CREATE PUBLICATION

–查看当前数据库有哪些发布
postgres=# select * from pg_publication;
pubname | pubowner | puballtables | pubinsert | pubupdate | pubdelete
----------+----------+--------------+-----------+-----------+-----------
testpub1 | 10 | f | t | t | t
(1 row)

2、配置订阅端
postgres=# create table t1(id int primary key, info text, crt_time timestamp); --不定义主键 DML会报错
CREATE TABLE
postgres=# create subscription testsub1 connection 'hostaddr=172.18.10.16 port=5432 user=postgres dbname=d2' publication testpub1 with (enabled, create_slot, slot_name='sub1_from_pub1');
NOTICE: created replication slot "sub1_from_pub1" on publisher
CREATE SUBSCRIPTION

–查看有哪些订阅
postgres=# select * from pg_subscription ;
subdbid | subname | subowner | subenabled | subconninfo | subslotname | subsynccommit | subpublications
---------+----------+----------+------------+----------------------------------------------------------------+----------------+---------------+-----------------
16401 | testsub1 | 10 | t | hostaddr=192.168.7.177 port=1921 user=postgres dbname=postgres | sub1_from_pub1 | off | {testpub1}
(1 row)

postgres=# select * from pg_stat_subscription ;
subid | subname | pid | relid | received_lsn | last_msg_send_time | last_msg_receipt_time | latest_end_lsn | latest_end_time
-------+----------+------+-------+--------------+-------------------------------+-------------------------------+----------------+-------------------------------
44943 | testsub1 | 7877 | | 1/76119308 | 2019-09-10 13:20:07.497634+08 | 2019-09-11 01:23:39.104443+08 | 1/76119308 | 2019-09-10 13:20:07.497634+08
(1 row)

数据库插入测试:
–发布端:
postgres=# insert into t1 select t,md5(random()::text),clock_timestamp() from generate_series(1,1000) t;
INSERT 0 1000

然后我们去订阅端查看:
postgres=# select count(*) from t1;
count
-------
100
(1 row)

这里需要注意,目前逻辑订阅不支持DDL语句的同步(pg12开始支持),例如:
–发布端:
postgres=# truncate t1;
TRUNCATE TABLE

再去订阅端查看,数据库还是没有变化
postgres=# select count(*) from t1;
count
-------
1000
(1 row)
因为逻辑订阅实际上和MySQL binglog复制类似,但是DDL是不写表的,那么DDL如何复制呢?
比较简单的一种方法就是:将DDL记录下来,写入表中,在订阅端对这个表创建触发器,在触发器内执行DDL即可。需要被订阅的对象,建上对应的触发器即可。总的来说,PostgreSQL的逻辑订阅目前还是有限局限性,并且和物理流复制相比性能差距较明显,但是对于在某些物理流复制无法实现的场景,使用逻辑订阅还是能够起到很大的作用!

补充几个测试结论:

1、发布端和订阅端的表在没有启用任何约束和索引的情况下,发布端只能写入数据,不能更新,更新会报如下错误:

d1=# update t44 set name='aa' where id =1;
ERROR: cannot update table "t44" because it does not have a replica identity and publishes updates
HINT: To enable updating the table, set REPLICA IDENTITY using ALTER TABLE.

2、消除以上错误一种是在发布端和订阅端的表上添加主键,二种添加唯一索引,在添加replica identify,如果还是不行需要删除发布端再重新建立生效。

create unique index idex_t44_name on t44(name);

alter table t44 replica identity using index idex_t44_name;

Logical Decoding测试补充:
测试前需要先设置2个参数:
wal_level=logical,需要重启
max_replication_slots 默认10个,根据情况修改。

1、创建一个复制槽,名称为logical_slot,使用插件:test_decoding
2=# SELECT pg_create_logical_replication_slot('logical_slot', 'test_decoding'); --物理复制用的是pg_create_physical_replication_slot('test_slot');
pg_create_logical_replication_slot
------------------------------------
(logical_slot,2/F003C6A8)
(1 row)

2、查看当前复制槽状态
d2=# select * from pg_replication_slots where slot_name='logical_slot';
-[ RECORD 1 ]-------+--------------
slot_name | logical_slot
plugin | test_decoding
slot_type | logical
datoid | 65249
database | d2
temporary | f
active | f
active_pid |
xmin |
catalog_xmin | 379478
restart_lsn | 2/F003C670
confirmed_flush_lsn | 2/F003C6A8

3、执行过insert看下效果,我们的insert已经被解析出来
d2=# insert into t1 values(1,'a');
INSERT 0 1
d2=# SELECT * FROM pg_logical_slot_peek_changes('logical_slot', NULL, NULL);
lsn | xid | data
------------+--------+--------------------------------------------------------------------
2/F003C6A8 | 379482 | BEGIN 379482
2/F003C6A8 | 379482 | table public.t1: INSERT: id[integer]:1 name[character varying]:'a'
2/F003C7A8 | 379482 | COMMIT 379482
(3 rows)
4、再执行个ddl
d2=# create table t2(id int,name varchar(10));
CREATE TABLE
d2=#
d2=#
d2=# SELECT * FROM pg_logical_slot_peek_changes('logical_slot', NULL, NULL);
lsn | xid | data
------------+--------+--------------------------------------------------------------------
2/F003C6A8 | 379482 | BEGIN 379482
2/F003C6A8 | 379482 | table public.t1: INSERT: id[integer]:1 name[character varying]:'a'
2/F003C7A8 | 379482 | COMMIT 379482
2/F003C810 | 379483 | BEGIN 379483
2/F00544C0 | 379483 | COMMIT 379483
(5 rows)
这里只看到了事务的开始和结束,但是无法看到ddl操作

5、消费逻辑复制槽后的变化
d2=# SELECT * FROM pg_logical_slot_get_changes('logical_slot', NULL, NULL);
lsn | xid | data
------------+--------+----------------------------------------------------------------------
2/F003C6A8 | 379482 | BEGIN 379482
2/F003C6A8 | 379482 | table public.t1: INSERT: id[integer]:1 name[character varying]:'a'
2/F003C7A8 | 379482 | COMMIT 379482
2/F003C810 | 379483 | BEGIN 379483
2/F00544C0 | 379483 | COMMIT 379483
2/F00544F8 | 379484 | BEGIN 379484
2/F00544F8 | 379484 | table public.t2: INSERT: id[integer]:21 name[character varying]:'2a'
2/F0054568 | 379484 | COMMIT 379484
(8 rows)

d2=#
d2=# SELECT * FROM pg_logical_slot_get_changes('logical_slot', NULL, NULL); --无法二次消费
lsn | xid | data
-----+-----+------
(0 rows)

d2=#
d2=# SELECT * FROM pg_logical_slot_peek_changes('logical_slot', NULL, NULL); --change内没有内容
lsn | xid | data
-----+-----+------
(0 rows)

5、删除复制槽
postgres=# SELECT pg_drop_replication_slot('logical_slot');
pg_drop_replication_slot
--------------------------

(1 row)

解读
逻辑复制使用复制槽和解码插件来发送数据库中的操作,并转成人们可以理解的格式。
pg_logical_slot_get_changes和pg_logical_slot_peek_changes 的区别是前者消费这些changes,而后者以只读的方式查看,而不会remove。

以下这些插件可以使用:
test_decoding – the default plugin;
wal2json – shows the changes in JSON format ;
decoder_raw – reconstructs the query that has applied the change.
decoderbufs, 一个PostgreSQL逻辑解码器输出插件,用于将数据作为协议缓冲区传送
ali_decoding 阿里巴巴研发的
————————————————
版权声明:本文为CSDN博主「gguxxing008」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/gguxxing008/article/details/106356086

【转载】PostgreSQL逻辑订阅logical的更多相关文章

  1. PostgreSQL逻辑订阅

    测试环境:PostgreSQL 13.2 1.逻辑订阅简介 由于物理复制只能做到这个集群的复制,不能正对某个对象(表)进行复制,且物理复制的备库只能读,不能写.相反,逻辑订阅同时支持主备库读写,且可以 ...

  2. PostgreSQL逻辑复制使用记录

    之前逻辑复制刚刚出来的时候就使用过,但是没有进行整理,这次一个项目需要逻辑复制的自动迁移,再次拾起逻辑复制. 在此之前有两个疑问: 1)同一个表,既有流复制,又有逻辑复制,这样数据会有两份吗? --不 ...

  3. PostgreSQL逻辑复制之pglogical篇

    PostgreSQL逻辑复制之slony篇 一.pglogical介绍 pglogical 是 PostgreSQL 的拓展模块, 为 PostgreSQL 数据库提供了逻辑流复制发布和订阅的功能. ...

  4. Windows 环境搭建 PostgreSQL 逻辑复制高可用架构数据库服务

    本文主要介绍 Windows 环境下搭建 PostgreSQL 的主从逻辑复制,关于 PostgreSQl 的相关运维文章,网络上大多都是 Linux 环境下的操作,鲜有在 Windows 环境下配置 ...

  5. PostgreSQL逻辑复制之slony篇

    Slony是PostgreSQL领域中最广泛的复制解决方案之一.它不仅是最古老的复制实现之一,它也是一个拥有最广泛的外部工具支持的工具,比如pgAdmin3.多年来,Slony是在PostgreSQL ...

  6. PostgreSQL逻辑复制解密

    在数字化时代的今天,我们都认同数据会创造价值.为了最大化数据的价值,我们不停的建立着数据迁移的管道,从同构到异构,从关系型到非关系型,从云下到云上,从数仓到数据湖,试图在各种场景挖掘数据的价值.而在这 ...

  7. PostgreSQL逻辑复制槽

    Schema | Name | Result data type | Argument data types | Type ------------+------------------------- ...

  8. 转载:逻辑回归的python实现

    转载自:http://blog.csdn.net/zouxy09/article/details/20319673 一.逻辑回归(LogisticRegression) Logistic regres ...

  9. PostgreSQL逻辑复制到kafka-实践

    kafka 安装 wget http://mirror.bit.edu.cn/apache/kafka/2.3.0/kafka_2.12-2.3.0.tgz cp kafka_2.12-2.0.1.t ...

  10. postgresql逻辑备份工具pg_dump和pg_resotre学习

    (一)pg_dump备份 pg提供了pg_dump和pg_dumpall命令进行数据库的备份,pg_dumpall是将整个pg集群转储到一个脚本文件中,而pg_dump命令可以选择一个数据库或者部分表 ...

随机推荐

  1. 服务器5M带宽下载速计算

    5M贷款的服务器实际下载速度不是5M每秒,而是640KB/S,是由于服务商口中的宽带指的是bit(比特),而下载速度使用的单位是Byte(字节),1Byte(字节)=8bit(比特),所以,宽带和下载 ...

  2. hover状态下改变图片颜色的方式 悬停图片切换;css变量;悬停svg图片改变颜色;VUE

    由外部json文件,按照配置方式引入图片路径时,需要一些值得注意的语法来动态引入和改变图片 1.图片路径设置 ,按照img标签动态引入图片 <img src=''/> 路径不引入变量,此时 ...

  3. 【翻译】了解Flink-对DataStream API的介绍 -- Learn Flink-Intro to the DataStream API

    目录 流式可以传输什么? Java元组和POJO 元组 POJO Scala元组和case classes 一个完整的例子 流执行环境 基本的stream sources 基本的stream sink ...

  4. 1.CD冷却效果

    CD冷却效果.. 一.将需要用到的图片复制到 PS 中做去色处理,将图片保存为 PNG 格式.如下 二.将制作好的图片导入 Unity 中,做成图集 三.在虚拟按键上添加 UI - Image 制作 ...

  5. PC端 图片宽度是百分比,动态设置图片高度为 6:9

    我们知道图片宽度可以设置  百分比,但是高度要给一个固定值  不然不生效,并且产品要求图片显示必须是9:6,这开始确实难倒我了 后面想了一下用js  获取图片宽度  动态的计算高度就行了,超简单 se ...

  6. 35.Linux 性能监控常用命令

    内存 top CPU yum install -y sysstat mpstat 网络 netstat //参数说明 //-n:拒绝显示别卖,能显示数字的全部转化数字 //-l:仅列出Listen(监 ...

  7. .NET在单台Windows2008下百万TCP连接测试

    测试客户端: 客户端程序建立TCP连接,发送一条几个字节的数据. 虚拟机8台,PC机8台,服务器1台. 设置MaxUserPort=60000,有一台机没有设置约在1.5万左右.最后因为差一点到100 ...

  8. python 的sys.argv 和 sys.path.append() 用法和PYTHONPATH环境变量

    sys.argv 我们编写一个测试用例test.py ,内容如下 imoprt sys a = sys.argv b = len(sys.argv) c = sys.argv[0] d = sys.a ...

  9. 记一次SpringBoot整合Redis的Bug

    SpringBoot整合Redis遇见的坑 <!--Redis配置开始--> <dependency> <groupId>org.springframework.b ...

  10. Echart 使用

    查看前端面试题小程序 大量面试题和答案,请微信查看 // var list = [1,1,54,5,5,85,8,8,5,5,8,8,85,8,8,5,5,85,88,85,8,88,8,8,8,8, ...