发布订阅
数据库的发布订阅(Publish-Subscribe,简称 Pub/Sub)是一种消息传递模式,其中发布者将消息发送给一个或多个订阅者,而订阅者则接收并处理该消息。在这种模式下,发布者和订阅者之间是松耦合的,它们之间不需要直接通信,因此可以提高应用程序的可扩展性和灵活性。
在数据库中,发布订阅功能通常被用于实时数据更新、缓存同步、业务事件通知等场景。例如,当数据库中某个表的数据发生变化时,可以通过发布订阅功能实时通知订阅者,从而实现实时数据同步和处理。另外,也可以通过发布订阅功能来实现业务事件的通知,例如某个订单被取消、某个库存数量不足等等。
通常,数据库的发布订阅功能由两部分组成:发布者和订阅者。发布者负责发布消息,而订阅者则订阅相应消息以达到数据同步的目的。发布者和订阅者之间可以存在多对多的关系,即一个发布者可以向多个订阅者发布消息,而一个订阅者也可以订阅多个消息/数据。
应用场景
发布订阅功能具有多种典型的应用场景:
-
数据同步:当一个数据库需要与另一个数据库保持同步时,发布订阅功能可以用来将数据更改发送到订阅者数据库。例如,当一个网站需要将数据从一个地理位置传输到另一个地理位置时,发布订阅功能可以用来确保两个数据库之间的数据同步。
-
业务数据分发:发布订阅功能可以用来将业务数据分发到不同的系统或业务流程中。例如,当一个银行需要将客户账户信息分发到多个业务系统中时,发布订阅功能可以用来将数据分发到相应的系统中,确保各个业务流程之间的数据一致性。
-
数据备份:发布订阅功能可以用来备份数据。例如,当一个数据库需要备份到另一个数据库时,发布订阅功能可以用来将数据备份到订阅者数据库中,以便在主数据库出现故障时恢复数据。
-
实时数据处理:发布订阅功能可以用来实现实时数据处理。例如,当一个网站需要对来自不同用户的数据进行处理时,发布订阅功能可以用来将数据传输到处理程序中进行处理,以便实现实时数据分析和决策。
名词解释
-
发布:在数据库中,发布通常指的是将一个数据库对象设置为可供其他租户访问的状态。这是数据共享和复制的一个重要步骤,发布的对象可以被其他租户订阅并获取数据。
-
订阅:订阅是指一个数据库选择接收和复制发布的数据库对象的数据。
-
发布端(Pub):发布端是执行发布操作的数据库。发布端负责创建和管理发布的对象,以及管理订阅该发布对象的数据库的访问权限。
-
订阅端(Sub):订阅端是订阅发布对象的租户。
-
发布对象:发布对象是在发布端创建并设置为可发布的数据库对象,即数据库。这些对象的数据可以被订阅端访问和复制。
-
订阅对象:订阅对象是在订阅端复制和存储的发布对象。订阅对象的数据会根据发布端的数据进行更新。
发布订阅范围说明
发布/订阅应用范围
发布端(Pub)和订阅端(Sub)均为 MatrixOne 的租户。
可发布/可订阅权限范围
- 发布端(Pub)只有 ACCOUNTADMIN 或 MOADMIN 角色可以创建发布与订阅。
- 订阅端(Sub)由 ACCOUNTADMIN 或 MOADMIN 角色操作访问订阅数据权限。
发布/订阅数据范围
- 一个发布只能与单一数据库关联。
- 发布和订阅只在数据库级别实现,目前还不支持直接进行表级别的发布和订阅。
- 订阅端对订阅库只具备读取权限。
- 若发布端(Pub)调整了发布的分享范围,那些不在新范围内的订阅端(Sub)如果已经创建了订阅库,那么对这个订阅库的访问将无效。
- 若发布端(Pub)修改了发布内容,那订阅端(Sub)无需额外操作,即可看到更新
- 若发布端(Pub)尝试删除已经发布的数据库,那么此次删除将不会成功。
- 若发布端(Pub)删除了发布,但订阅库中的对应对象仍存在,此时订阅端(Sub)访问这个对象会触发错误,需要由订阅端(Sub)删除对应的订阅。
- 若发布端(Pub)删除了发布对象,但在订阅库中的对应对象仍然存在,此时订阅端(Sub)访问这个对象会触发错误,需要由订阅端(Sub)删除对应的订阅对象。
发布订阅示例
本章节将给出一个示例,介绍当前在 MatrixOne 集群中,存在 3 个租户,sys、acc1 与 acc2,按照操作顺序对三个租户进行操作:
-
发布者:sys 租户创建数据库 sub1 与表 t1,并发布 pub1:
create database sub1; create table sub1.t1(a int,b int); create publication pub1 database sub1; mysql> show publications; +-------------+----------+---------------------+-------------+-------------+----------+ | publication | database | create_time | update_time | sub_account | comments | +-------------+----------+---------------------+-------------+-------------+----------+ | pub1 | sub1 | 2024-04-23 10:28:15 | NULL | * | | +-------------+----------+---------------------+-------------+-------------+----------+ 1 row in set (0.01 sec)
-
订阅者:acc1 和 acc2 都创建订阅库 syssub1,于是得到共享的数据表 t1:
-- all 选项可以看到所有有权限的订阅,未订阅的 sub_time, sub_name 为 null,不加 all 只能看到已订阅的发布信息。 mysql> show subscriptions all; +----------+-------------+--------------+---------------------+----------+----------+ | pub_name | pub_account | pub_database | pub_time | sub_name | sub_time | +----------+-------------+--------------+---------------------+----------+----------+ | pub1 | sys | sub1 | 2024-04-23 10:28:15 | NULL | NULL | +----------+-------------+--------------+---------------------+----------+----------+ 1 row in set (0.01 sec) -- acc1 和 acc2 创建订阅库的 sql 语句一致,此处不做赘述 create database syssub1 from sys publication pub1; use syssub1; mysql> show subscriptions; +----------+-------------+--------------+---------------------+----------+---------------------+ | pub_name | pub_account | pub_database | pub_time | sub_name | sub_time | +----------+-------------+--------------+---------------------+----------+---------------------+ | pub1 | sys | sub1 | 2024-04-23 10:28:15 | syssub1 | 2024-04-23 10:35:13 | +----------+-------------+--------------+---------------------+----------+---------------------+ 1 row in set (0.00 sec) mysql> show tables; +--------------------+ | Tables_in_syssub1 | +--------------------+ | t1 | +--------------------+ 2 rows in set (0.02 sec)
-
发布者:sys 租户创建数据表 t2:
create table sub1.t2(a text);
-
订阅者:acc1 和 acc2 得到共享的数据表 t1 和 t2:
use syssub1; mysql> show tables; +-------------------+ | Tables_in_syssub1 | +-------------------+ | t1 | | t2 | +-------------------+ 2 rows in set (0.01 sec)
-
发布者:sys 租户创建数据库 sub2 与表 t1,并发布 pub2 给租户 acc1
create database sub2; create table sub2.t1(a float); create publication pub2 database sub2 account acc1;
-
订阅者:acc1 和 acc2 都创建订阅库 syssub2,acc1 得到共享的数据表 t1;acc2 创建订阅库 syssub2 失败:
- acc1
mysql> show subscriptions all; +----------+-------------+--------------+---------------------+----------+---------------------+ | pub_name | pub_account | pub_database | pub_time | sub_name | sub_time | +----------+-------------+--------------+---------------------+----------+---------------------+ | pub1 | sys | sub1 | 2024-04-23 10:28:15 | syssub1 | 2024-04-23 10:30:43 | | pub2 | sys | sub2 | 2024-04-23 10:40:54 | NULL | NULL | +----------+-------------+--------------+---------------------+----------+---------------------+ 2 rows in set (0.01 sec) create database syssub2 from sys publication pub2; use syssub2; mysql> show subscriptions all; +----------+-------------+--------------+---------------------+----------+---------------------+ | pub_name | pub_account | pub_database | pub_time | sub_name | sub_time | +----------+-------------+--------------+---------------------+----------+---------------------+ | pub2 | sys | sub2 | 2024-04-23 10:40:54 | syssub2 | 2024-04-23 10:42:31 | | pub1 | sys | sub1 | 2024-04-23 10:28:15 | syssub1 | 2024-04-23 10:30:43 | +----------+-------------+--------------+---------------------+----------+---------------------+ 2 rows in set (0.01 sec) mysql> show tables; +--------------------+ | Tables_in_syssub2 | +--------------------+ | t1 | +--------------------+ 2 rows in set (0.02 sec)
- acc2
-- acc2 看不到 pub2,因为没有订阅权限 mysql> show subscriptions all; +----------+-------------+--------------+---------------------+----------+---------------------+ | pub_name | pub_account | pub_database | pub_time | sub_name | sub_time | +----------+-------------+--------------+---------------------+----------+---------------------+ | pub1 | sys | sub1 | 2024-04-23 10:28:15 | syssub1 | 2024-04-23 10:35:13 | +----------+-------------+--------------+---------------------+----------+---------------------+ 1 row in set (0.01 sec) mysql> create database syssub2 from sys publication pub2; ERROR 20101 (HY000): internal error: the account acc2 is not allowed to subscribe the publication pub2
-
发布者:sys 租户修改发布 pub2 给全部租户:
alter publication pub2 account all; mysql> show publications; +-------------+----------+---------------------+---------------------+-------------+----------+ | publication | database | create_time | update_time | sub_account | comments | +-------------+----------+---------------------+---------------------+-------------+----------+ | pub2 | sub2 | 2024-04-23 10:40:54 | 2024-04-23 10:47:53 | * | | | pub1 | sub1 | 2024-04-23 10:28:15 | NULL | * | | +-------------+----------+---------------------+---------------------+-------------+----------+ 2 rows in set (0.00 sec)
-
订阅者:acc2 创建订阅库 syssub2 成功,得到共享的数据表 t1:
-- acc2 现在能看到 pub2 了 mysql> show subscriptions all; +----------+-------------+--------------+---------------------+----------+---------------------+ | pub_name | pub_account | pub_database | pub_time | sub_name | sub_time | +----------+-------------+--------------+---------------------+----------+---------------------+ | pub1 | sys | sub1 | 2024-04-23 10:28:15 | syssub1 | 2024-04-23 10:35:13 | | pub2 | sys | sub2 | 2024-04-23 10:40:54 | NULL | NULL | +----------+-------------+--------------+---------------------+----------+---------------------+ 2 rows in set (0.00 sec) create database syssub2 from sys publication pub2; use syssub2; mysql> show subscriptions all; +----------+-------------+--------------+---------------------+----------+---------------------+ | pub_name | pub_account | pub_database | pub_time | sub_name | sub_time | +----------+-------------+--------------+---------------------+----------+---------------------+ | pub2 | sys | sub2 | 2024-04-23 10:40:54 | syssub2 | 2024-04-23 10:50:43 | | pub1 | sys | sub1 | 2024-04-23 10:28:15 | syssub1 | 2024-04-23 10:35:13 | +----------+-------------+--------------+---------------------+----------+---------------------+ 2 rows in set (0.00 sec) mysql> show tables; +--------------------+ | Tables_in_syssub2 | +--------------------+ | t1 | +--------------------+ 2 rows in set (0.02 sec)
-
发布者:sys 租户删除发布 pub1:
drop publication pub1; mysql> show publications; +-------------+----------+---------------------+---------------------+-------------+----------+ | publication | database | create_time | update_time | sub_account | comments | +-------------+----------+---------------------+---------------------+-------------+----------+ | pub2 | sub2 | 2024-04-23 10:40:54 | 2024-04-23 10:47:53 | * | | +-------------+----------+---------------------+---------------------+-------------+----------+ 1 row in set (0.00 sec)
-
订阅者:acc1、acc2 连接 syspub1 失败:
mysql> use syssub1; ERROR 20101 (HY000): internal error: there is no publication pub1
-
发布者:sys 租户新建数据库 sub1_new,并重新以 pub1 发布
create database sub1_new; use sub1_new; create table t3(n1 int); insert into t3 values (1); create publication pub1 database sub1_new; mysql> show publications; +-------------+----------+---------------------+---------------------+-------------+----------+ | publication | database | create_time | update_time | sub_account | comments | +-------------+----------+---------------------+---------------------+-------------+----------+ | pub2 | sub2 | 2024-04-23 10:40:54 | 2024-04-23 10:47:53 | * | | | pub1 | sub1_new | 2024-04-23 10:59:11 | NULL | * | | +-------------+----------+---------------------+---------------------+-------------+----------+ 2 rows in set (0.00 sec)
-
订阅者:acc1、acc2 连接 syspub1,可以看到 pub1 新的内容,就是说如果发布方更改了发布的内容,订阅方不用做任何操作即可看到更新。
use syssub1; mysql> show subscriptions; +----------+-------------+--------------+---------------------+----------+---------------------+ | pub_name | pub_account | pub_database | pub_time | sub_name | sub_time | +----------+-------------+--------------+---------------------+----------+---------------------+ | pub2 | sys | sub2 | 2024-04-23 10:40:54 | syssub2 | 2024-04-23 10:42:31 | | pub1 | sys | sub1_new | 2024-04-23 10:59:11 | syssub1 | 2024-04-23 10:30:43 | +----------+-------------+--------------+---------------------+----------+---------------------+ 2 rows in set (0.01 sec) mysql> show tables; +-------------------+ | Tables_in_syssub1 | +-------------------+ | t3 | +-------------------+ 1 row in set (0.01 sec) mysql> select * from t3; +------+ | n1 | +------+ | 1 | +------+ 1 row in set (0.01 sec)
-
订阅者:acc1 删除订阅:
-- 通过 drop database 删除订阅 drop database syssub1; mysql> show subscriptions; +----------+-------------+--------------+---------------------+----------+---------------------+ | pub_name | pub_account | pub_database | pub_time | sub_name | sub_time | +----------+-------------+--------------+---------------------+----------+---------------------+ | pub2 | sys | sub2 | 2024-04-23 10:40:54 | syssub2 | 2024-04-23 10:42:31 | +----------+-------------+--------------+---------------------+----------+---------------------+ 1 row in set (0.00 sec)
-
发布者:sys 租户删除已发布的数据库之前,要先删除其对应的发布:
mysql> drop database sub1_new; ERROR 20101 (HY000): internal error: can not drop database 'sub1_new' which is publishing mysql> drop publication pub1; Query OK, 0 rows affected (0.00 sec) mysql> drop database sub1_new; Query OK, 1 row affected (0.03 sec)
-
发布者:sys 租户修改发布内容:
alter publication pub2 comment "this is pub2";--修改comments mysql> show publications; create database new_sub2; create table new_sub2.new_t (xxx int); insert into new_sub2.new_t values (123); alter publication pub2 database new_sub2;--修改database mysql> show publications; +-------------+----------+---------------------+---------------------+-------------+--------------+ | publication | database | create_time | update_time | sub_account | comments | +-------------+----------+---------------------+---------------------+-------------+--------------+ | pub2 | new_sub2 | 2024-04-23 10:40:54 | 2024-04-23 11:04:20 | * | this is pub2 | +-------------+----------+---------------------+---------------------+-------------+--------------+ 1 row in set (0.00 sec)
-
订阅者:acc1、acc2 查看订阅,能看到发布数据库修改后的内容:
mysql> show subscriptions; +----------+-------------+--------------+---------------------+----------+---------------------+ | pub_name | pub_account | pub_database | pub_time | sub_name | sub_time | +----------+-------------+--------------+---------------------+----------+---------------------+ | pub2 | sys | new_sub2 | 2024-04-23 10:40:54 | syssub2 | 2024-04-23 10:42:31 | +----------+-------------+--------------+---------------------+----------+---------------------+ 1 row in set (0.00 sec) use syssub2; mysql> show tables; +-------------------+ | Tables_in_syssub2 | +-------------------+ | new_t | +-------------------+ 1 row in set (0.00 sec) mysql> select * from new_t; +------+ | xxx | +------+ | 123 | +------+ 1 row in set (0.00 sec)