半个PostgreSQL DBA,热衷于数据库相关的技术。我的ppt分享https://pan.baidu.com/s/1eRQsdAa https://github.com/chenhuajun https://chenhuajun.github.io
分类: Mysql/postgreSQL
2018-10-04 01:34:42
citus的架构中正常只有1个CN节点,有时候CN会成为性能瓶颈。我们可以通过减少分片数,垂直扩容CN节点等手段缓解CN的性能问题,但这些都不能治本。某些业务场景部署多个CN节点是非常必要的。
如果CN上主要的负载来自查询,可以为CN节点配置多个备机,做读写分离,这些备机可以分担读负载。但是这种方案不能称为多CN,它不具有均衡写负载的能力。
怎么实现多CN呢?在citus的具体实现中,CN和worker的区别就在于是否存储了相关的元数据,如果把CN的元数据拷贝一份到worker上,那么worker也可以向CN一样工作,这个多CN的模式早期被称做masterless。
对于当前的citus版本,其实有一个开关,打开后,会自动拷贝CN的元数据到Worker上,让worker也可以当CN用。 这个功能官方被称做Citus MX,也就是下一代的Citus,目前仅在Cloud Beta版中使用。好消息是,社区版虽然没有公开说支持,但也没有从代码上限制这个功能。下面见证一下这个神奇的开关:)
在CN节点的postgresql.conf中添加下面的参数
citus.replication_model='streaming'
在CN节点(cituscn)上添加worker节点
SELECT * from master_add_node('cituswk1', 5432); SELECT * from master_add_node('cituswk2', 5432);
从CN复制元数据到第一个worker节点
SELECT start_metadata_sync_to_node('cituswk1', 5432);
执行上面的函数后,citus CN上的元数据会被拷贝到指定的worker上,并且pg_dist_node表中对应worker的hasmetadata字段值为true,标识这个Worker存储了元数据,以后创建新的分片时,新产生的元素据也会自动同步到这个worker上。
postgres=# select * from pg_dist_node; nodeid | groupid | nodename | nodeport | noderack | hasmetadata | isactive | noderole | nodecluster --------+---------+----------+----------+----------+-------------+----------+----------+------------- 1 | 1 | cituswk1 | 5432 | default | t | t | primary | default 2 | 2 | cituswk2 | 5432 | default | f | t | primary | default (2 rows)
下面看一下效果
在CN节点上创建一个测试分片表
create table tb1(id int primary key, c1 int); set citus.shard_count=8; select create_distributed_table('tb1','id'); insert into tb1 select id,random()*1000 from generate_series(1,100)id;
因为cituswk1带了元数据,可以当CN用,下面这个SQL可以在cituswk1上执行。
postgres=# explain select * from tb1; QUERY PLAN ------------------------------------------------------------------------------ Custom Scan (Citus Real-Time) (cost=0.00..0.00 rows=0 width=0) Task Count: 8 Tasks Shown: One of 8 -> Task Node: host=cituswk1 port=5432 dbname=postgres -> Seq Scan on tb1_102092 tb1 (cost=0.00..32.60 rows=2260 width=8) (6 rows)
为了说明方便,后面把这种带了元数据的worker称之为“扩展worker”。citus会限制某些SQL在扩展worker上执行,比如DDL。
扩展Worker其实把Worker和CN两个角色混在一个节点里,对维护不是很友好。有下面几个表现:
为解决这些问题,我们可以专门定义少数几个节点作为扩展Worker,并且不在上面分配分片,使其纯粹担任CN的角色。具体作法如下:
首先,按通常的方式建好分片表,再使用前面《citus实战系列之三平滑扩容》中介绍的方法把"扩展Worker"上的分片挪走。
对于前面tb1的例子,有4个分片落在扩展worker(worker1)上
postgres=# select * from pg_dist_shard_placement where nodename='cituswk1'; shardid | shardstate | shardlength | nodename | nodeport | placementid ---------+------------+-------------+----------+----------+------------- 102238 | 1 | 0 | cituswk1 | 5432 | 237 102240 | 1 | 0 | cituswk1 | 5432 | 239 102242 | 1 | 0 | cituswk1 | 5432 | 241 102244 | 1 | 0 | cituswk1 | 5432 | 243 (4 rows)
创建分片表
create table tba(id int); set citus.shard_count=8; select create_distributed_table('tba','id');
此时,有6个分片落在"扩展Worker"上。
postgres=# select * from pg_dist_shard_placement where nodename='cituswk1'; shardid | shardstate | shardlength | nodename | nodeport | placementid ---------+------------+-------------+------------+----------+------------- 103081 | 1 | 0 | cituswk1 | 5432 | 1096 103083 | 1 | 0 | cituswk1 | 5432 | 1099 103085 | 1 | 0 | cituswk1 | 5432 | 1102 103097 | 1 | 0 | cituswk1 | 5432 | 1105 (4 rows)
把"扩展Worker"上的分片挪走。
select citus_move_shard_placement(102238,'cituswk1',5432,'cituswk2',5432,'drop'); select citus_move_shard_placement(102240,'cituswk1',5432,'cituswk2',5432,'drop'); select citus_move_shard_placement(102242,'cituswk1',5432,'cituswk2',5432,'drop'); select citus_move_shard_placement(102244,'cituswk1',5432,'cituswk2',5432,'drop');
这是CN的元数据已经更新了,但扩展Worker(worker1)还没有,需要在扩展Worker(worker1)上更新分片位置
postgres=# update pg_dist_shard_placement set nodename='cituswk2' where shardid in (102238,102240,102242,102244); UPDATE 4
先定义后迁移的方式不是特别方便,对于有亲和关系(分片位置分布完全一致)的表,只有第一张表需要这样定义,后续的表可以利用亲和关系指定分片的部署位置。
比如
create table tb2(id int); select create_distributed_table('tb2','id', colocate_with=>'tb1');
上面的colocate_with有3种取值
稳妥起见,在扩展worker上尽量避免会产生分布式事务或死锁的操作。建议只执行这几类SQL,并且不使用事务。