Postgres的-XL是一个基于PostgreSQL数据库的横向扩展开源SQL数据库集群,具有足够的灵活性来处理不同的数据库工作负载:
- *完全ACID,保持事务一致性*
- OLTP 写频繁的业务
- 需要MPP并行性商业智能/大数据分析
- 操作数据存储
- Key-value 存储
- GIS的地理空间
- 混合业务工作环境
- 多租户服务提供商托管环境
- Web 2.0
Global Transaction Monitor (GTM)
全局事务管理器,确保群集范围内的事务一致性。 GTM负责发放事务ID和快照作为其多版本并发控制的一部分。
集群可选地配置一个备用GTM,以改进可用性。此外,可以在协调器间配置代理GTM, 可用于改善可扩展性,减少GTM的通信量。
GTM Standby
GTM的备节点,在pgxc,pgxl中,GTM控制所有的全局事务分配,如果出现问题,就会导致整个集群不可用,为了增加可用性,增加该备用节点。当GTM出现问题时,GTM Standby可以升级为GTM,保证集群正常工作。
GTM-Proxy
GTM需要与所有的Coordinators通信,为了降低压力,可以在每个Coordinator机器上部署一个GTM-Proxy。
Coordinator
协调员管理用户会话,并与GTM和数据节点进行交互。协调员解析,并计划查询,并给语句中的每一个组件发送下一个序列化的全局性计划。
为节省机器,通常此服务和数据节点部署在一起。
Data Node
数据节点是数据实际存储的地方。数据的分布可以由DBA来配置。为了提高可用性,可以配置数据节点的热备以便进行故障转移准备。
总结:gtm是负责ACID的,保证分布式数据库全局事务一致性。得益于此,就算数据节点是分布的,但是你在主节点操作增删改查事务时,就如同只操作一个数据库一样简单。Coordinator是调度的,将操作指令发送到各个数据节点。datanodes是数据节点,分布式存储数据。
准备三台Centos7服务器(或者虚拟机),集群规划如下:
主机名 | IP | 角色 | 端口 | nodename | 数据目录 |
---|---|---|---|---|---|
Pg1 | 192.168.0.125 | GTM | 6666 | gtm | /DATA/gtm |
pg2 | 192.168.0.127 | Coordinator | 1921 | coord1 | /DATA/coord1 |
Datanode | 11921 | Datanode | /DATA/dn1 | ||
pg3 | 192.168.0.128 | Coordinator | 1925 | coord2 | /DATA/coord2 |
Datanode | 11922 | Datanode | /DATA/dn2 |
在每台机器的 /etc/hosts中加入以下内容:
192.168.0.125 pg1
192.168.0.126 pg2
192.168.0.127 pg3
pg1上部署gtm,gtm_sandby测试环境暂未部署。
Coordinator与Datanode节点一般部署在同一台机器上。实际上,GTM-proxy,Coordinator与Datanode节点一般都在同一个机器上,使用时避免端口号与连接池端口号重叠!规划pg2,pg3作为协调节点与数据节点。
以下操作,对每个服务器节点都适用。
关闭防火墙:
[root@localhost ~]# systemctl stop firewalld.service
[root@localhost ~]# systemctl disable firewalld.service
selinux设置:
[root@localhost ~]#vim /etc/selinux/config
设置SELINUX=disabled,保存退出。
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of three two values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
安装依赖包:
[root@localhost ~]# yum install -y flex bison readline-devel zlib-devel openjade docbook-style-dsssl
重启服务器!一定要重启!
每个节点都建立用户postgres,并且建立.ssh目录,并配置相应的权限:
[root@localhost ~]# useradd postgres
[root@localhost ~]# passwd postgres
[root@localhost ~]# su - postgres
[root@localhost ~]# mkdir ~/.ssh
[root@localhost ~]# chmod 700 ~/.ssh
仅仅在pg1节点配置,pg2,pg3不执行如下操作:
[root@localhost ~]# su - postgres
[postgres@localhost ~]# ssh-keygen -t rsa
[postgres@localhost ~]# cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
[postgres@localhost ~]# chmod 600 ~/.ssh/authorized_keys
将刚生成的认证文件拷贝到pg2到pg3中,使得pg1可以免密码登录pg2~pg3的任意一个节点:
[postgres@localhost ~]# scp ~/.ssh/authorized_keys postgres@pg2:~/.ssh/
[postgres@localhost ~]# scp ~/.ssh/authorized_keys postgres@pg3:~/.ssh/
对所有提示都不要输入,直接enter下一步。直到最后,因为第一次要求输入目标机器的用户密码,输入即可。
pg1-pg3每个节点都需安装配置。切换回root用户下,执行如下步骤安装
[root@localhost ~]# tar -zxvf postgres-xl-9.5r1.3.tar.gz
[root@localhost ~]# cd postgres-xl-9.5r1.3
[root@localhost ~postgres-xl-9.5r1.3]# ./configure --prefix=/home/postgres/pgxl9.5/
[root@localhost ~postgres-xl-9.5r1.3]# make
[root@localhost ~postgres-xl-9.5r1.3]# make install
[root@localhost ~postgres-xl-9.5r1.3]# cd contrib/
[root@localhost ~contrib]# make
[root@localhost ~contrib]# make install
cortrib中有很多postgres很牛的工具,一般要装上。如ltree,uuid,postgres_fdw等等。
进入postgres用户,修改其环境变量,开始编辑
[root@localhost ~]#su - postgres
[postgres@localhost ~]#vim .bashrc
在打开的文件末尾,新增如下变量配置:
export PGHOME=/home/postgres/pgxl9.5
export LD_LIBRARY_PATH=$PGHOME/lib:$LD_LIBRARY_PATH
export PATH=$PGHOME/bin:$PATH
按住esc,然后输入:wq!保存退出。输入以下命令对更改重启生效。
[root@localhost ~]# source .bashrc
#输入以下语句,如果输出变量结果,代表生效
[root@localhost ~]# echo $PGHOME
#应该输出/home/postgres/pgxl9.5代表生效
如上操作,除特别强调以外,是pg1-pg3节点都要配置安装的。
pg1-pg3每个节点创建DATA如下:
[root@localhost~]# cd /home/postgres
[root@postgres~]# mkdir DATA
[root@localhost~]# chown -R postgres.postgres /home/postgres
在pg1机器上,切换到postgres用户下执行初始化:
[root@localhost ~]# su - postgres
[postgres@localhost ~]# initgtm -Z gtm -D /home/postgres/DATA/gtm
打开编辑gtm.conf文件:
[postgres@localhost ~]# vim /home/postgres/DATA/gtm/gtm.conf
设置如下:
nodename = 'gtm' #节点名称,任意指定,不能与其他节点重复
listen_addresses = '*' #GTM监听的ip地址,*代表监听所有的集群ip
port =6666 #gtm监控的端口号
startup = ACT #act代表gtm是主库,如果是standy,设置为'STANDBY'
于pg2上执行以下命令:
[root@localhost ~]# su - postgres
[root@localhost ~]# initgtm -Z gtm_proxy -D /home/postgres/DATA/gtm_proxy --nodename gtm_proxy1
#pg3上起名字叫gtm_proxy2
修改gtm_proxy.conf文件配置如下:
nodename='gtm_proxy1'
port=6666
gtm_host='pg1'
gtm_port=6666
pg3上设置同理如上。
在pg2上执行如下命令:
initdb -D /home/postgres/DATA/coord --nodename coord1 -E UTF8 --locale=C -U postgres -W
#pg3上节点名称执行这句时写coord2
修改postgresql.conf与pg_hba.conf文件配置如下:
[postgres@localhost ~]#
vim /home/postgres/DATA/coord/postgresql.conf
打开设置如下:
# - Connection Settings -
listen_addresses = '*'
port = 5432
max_connections = 100
# DATA NODES AND CONNECTION POOLING
#----------------------------------
pooler_port = 6667
max_pool_size = 100
# GTM CONNECTION
#--------------------------
gtm_host = 'pg1' #gtm所在的主机地址
gtm_port = 6666 #gtm配置中,gtm端口号配置为6666
pgxc_node_name = 'coord1'
设置pg_hba.conf
[postgres@localhost ~]#
vim /home/postgres/DATA/coord/pg_hba.conf
只对IPv4设置如下描述,后面要改成trust:
# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 0.0.0.0/0 trust
# IPv6 local connections:
host all all ::1/128 trust
在pg2中生成coord2,并配置,步骤如上。注意节点名称都要将coord1换成当下的coord2。
pg2中初始化dn1,要在postgres用户下执行。
[root@localhost ~]# su - postgres
[postgres@localhost ~]# initdb -D /home/postgres/DATA/dn --nodename dn1 -E UTF8 --locale=C -U postgres -W
#pg3中是dn2
配置postgresql.conf,pg_hba.conf:
[postgres@localhost ~]# vim /home/postgres/DATA/dn/postgresql.conf
内容更改如下:
CONNECTIONS AND AUTHENTICATION
#------------------------------------
listen_addresses = '*'
port =5433
max_connections = 100
# DATA NODES AND CONNECTION POOLING
#----------------------------------------------
pooler_port = 6668 # 同一台机器要使用不同的连接池端口,如coord1与dn1部署同一个机器,coord1是6667,dn1是6668
max_pool_size = 100
# GTM CONNECTION
#-----------------------------
gtm_host = 'pg1'
gtm_port = 6666 #gtm端口号
pgxc_node_name = 'dn1'
[postgres@localhost ~]# vim /home/postgres/DATA/dn/pg_hba.conf
只对IPv4设置如下描述,后面要改成trust:
# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 0.0.0.0/0 trust
# IPv6 local connections:
host all all ::1/128 trust
配置完dn1,同理配置dn2,注意dn1替换成dn2。
启动顺序是GTM-GTM Standby-GTM-Proxy-Datanodes-Coordinators。
在pg1机器上,在postgres用户下启动gtm
[postgres@localhost ~]# gtm_ctl start -Z gtm -D /home/postgres/DATA/gtm
在pg2机器上,启动gtm-proxy:
[postgres@localhost ~]# gtm_ctl start -Z gtm_proxy -D /home/postgres/DATA/gtm_proxy
同理启动pg3上的gtm-proxy。
在pg2上启动dn1示范如下:
[postgres@localhost ~]# pg_ctl start -Z datanode -D /home/postgres/DATA/dn
同理启动pg3上的dn。
在pg2机器上,启动coordinator节点coord:
[postgres@localhost ~]# pg_ctl start -Z coordinator -D /home/postgres/DATA/coord
同理启动pg3上的coord。
如上文所述,用户需对每台机器的配置文件修改,需先启动gtm,然后挨个启动每台机器的gtm_proxy,coordinator,datanode,随着节点的增加,会非常麻烦。当然pgxc/xl考虑到这样,于是提供一个pgxc_ctl脚本读取配置自动化启动服务。
[postgres@localhost ~]# pgxc_ctl
PGXC prepare ---执行该命令将会生成一份配置文件模板
PGXC ^C ---按ctrl c退出。
在pgxc_ctl文件夹中存在一个pgxc_ctl.conf文件,编辑如下:
pgxlDATA=/home/postgres/DATA
pgxcInstallDir=/home/postgres/pgxl9.5
pgxcOwner=postgres
#---- GTM Master -----------------------------------------
gtmName=gtm
gtmMasterServer=pg1
gtmMasterPort=6666
gtmMasterDir=$pgxlDATA/gtm
gtmSlave=n #没配置slave
#---- GTM-Proxy Master -------
gtmProxyDir=$pgxlDATA/gtm_proxy
gtmProxy=y
gtmProxyNames=(gtm_proxy1 gtm_proxy2)
gtmProxyServers=(pg2 pg3)
gtmProxyPorts=(6666 6666)
gtmProxyDirs=($gtmProxyDir $gtmProxyDir)
#---- Coordinators ---------
coordMasterDir=$pgxlDATA/coord
coordNames=(coord1 coord2)
coordPorts=(5432 5432)
poolerPorts=(6667 6667)
coordPgHbaEntries=(0.0.0.0/0)
coordMasterServers=(pg2 pg3)
coordMasterDirs=($coordMasterDir $coordMasterDir)
coordMaxWALsernder=0 #没设置备份节点,设置为0
coordMaxWALSenders=($coordMaxWALsernder $coordMaxWALsernder) #数量保持和coordMasterServers一致
coordSlave=n
#---- Datanodes ----------
datanodeMasterDir=$pgxlDATA/dn
primaryDatanode=dn1 # 主数据节点
datanodeNames=(dn1 dn2)
datanodePorts=(5433 5433)
datanodePoolerPorts=(6668 6668)
datanodePgHbaEntries=(0.0.0.0/0)
datanodeMasterServers=(pg2 pg3)
datanodeMasterDirs=($datanodeMasterDir $datanodeMasterDir)
datanodeMaxWalSender=0
datanodeMaxWALSenders=($datanodeMaxWalSender $datanodeMaxWalSender)
datanodeSlave=n
如上配置,都没有配置slave,具体生产环境,请阅读配置文件,自行配置。
第一次启动集群,需要初始化,初始化如下:
[postgres@pg1 pgxc_ctl]$ pgxc_ctl -c /home/postgres/pgxc_ctl/pgxc_ctl.conf init all
初始化后会直接启动集群。
以后启动,直接执行如下命令:
[postgres@pg1 pgxc_ctl]$ pgxc_ctl -c /home/postgres/pgxc_ctl/pgxc_ctl.conf start all
停止集群如下:
[postgres@pg1 pgxc_ctl]$ pgxc_ctl -c /home/postgres/pgxc_ctl/pgxc_ctl.conf stop all
这几个主要命令暂时这么多,更多请从pgxc_ctl –help中获取更多信息。
在pg2以postgres用户下进入psql。coord1配置端口号是5432,直接以psql加端口号进入配置。
[postgres@localhost]$ psql -p 5432
psql (PGXL 9.5r1.3, based on PG 9.5.4 (Postgres-XL 9.5r1.3))
Type "help" for help.
postgres=# select * from pgxc_node;
postgres=# alter node coord1 with (type=coordinator,host='pg2', port=5432);
postgres=# create node coord2 with (type=coordinator,host='pg3', port=5432);
postgres=# create node dn1 with (type=datanode, host='pg2',port=5433,primary,preferred);
postgres=# create node dn2 with (type=datanode, host='pg3',port=5433);
postgres=#select pgxc_pool_reload();
postgres=# select * from pgxc_node;
配置pg1上的coord2如下,以当初配置的1925端口号进入psql:
[postgres@localhost]$ psql -p 1925
psql (PGXL 9.5r1.3, based on PG 9.5.4 (Postgres-XL 9.5r1.3))
Type "help" for help.
postgres=# select * from pgxc_node;
postgres=# create node coord1 with (type=coordinator,host='pg2', port=5432);
postgres=# alter node coord2 with (type=coordinator,host='pg3', port=5432);
postgres=# create node dn1 with (type=datanode, host='pg2',port=5433,primary,preferred);
postgres=# create node dn2 with (type=datanode, host='pg3',port=5433);
postgres=#select pgxc_pool_reload();
postgres=# select * from pgxc_node;
通过coord1,coord2配置,总结规律是每个节点配置都是一模一样的,所以分别配置dn1,dn2。
dn1如下:
[postgres@localhost]$ psql -p 1925
psql (PGXL 9.5r1.3, based on PG 9.5.4 (Postgres-XL 9.5r1.3))
Type "help" for help.
postgres=# select * from pgxc_node;
postgres=# create node coord1 with (type=coordinator,host='pg2', port=5432);
postgres=# create node coord2 with (type=coordinator,host='pg3', port=5432);
postgres=# alter node dn1 with (type=datanode, host='pg2',port=5433,primary,preferred);
postgres=# create node dn2 with (type=datanode, host='pg3',port=5433);
postgres=#select pgxc_pool_reload();
postgres=# select * from pgxc_node;
dn2如下:
[postgres@localhost]$ psql -p 1925
psql (PGXL 9.5r1.3, based on PG 9.5.4 (Postgres-XL 9.5r1.3))
Type "help" for help.
postgres=# select * from pgxc_node;
postgres=# create node coord1 with (type=coordinator,host='pg2', port=5432);
postgres=# create node coord2 with (type=coordinator,host='pg3', port=5432);
postgres=# create node dn1 with (type=datanode, host='pg2',port=5433,primary,preferred);
postgres=# alter node dn2 with (type=datanode, host='pg3',port=5433);
postgres=#select pgxc_pool_reload();
postgres=# select * from pgxc_node;
其他有节点依次如上规则配置集群信息。
只能在pg1中coord1,coord2节点中操作,pg2,pg3数据节点都是只读的,所以我们选择coord1(端口号为1921)中创建测试数据。
[postgres@localhost]$ psql -p 5432
psql (PGXL 9.5r1.3, based on PG 9.5.4 (Postgres-XL 9.5r1.3))
Type "help" for help.
postgres=# create table test1(id integer,name varchar(20));
postgres=# insert into test1(id,name) values(1,'测试');
postgres=# insert into test1(id,name) values(2,'测试');
postgres=# insert into test1(id,name) values(3,'测试');
postgres=# insert into test1(id,name) values(4,'测试');
postgres=# insert into test1(id,name) values(5,'测试');
postgres=# insert into test1(id,name) values(6,'测试');
postgres=# insert into test1(id,name) values(7,'测试');
postgres=# insert into test1(id,name) values(8,'测试');
通过我的本机测试发现,在coord2,dn1,dn2节点中都已创建了一个test1表。且coord1=coord2,而dn1中test1表有5条数据,dn2有3条。
总结:coord1,coord2这种协调处理节点,是操作数据库的主节点,拥有完整的数据视图。
dn1到dn2是数据节点,只读的,存储数据,由coordinator协调分配存储到哪个节点,所以不同节点分配到的数据数量不一。(一开始我以为错了,原来我理解错了分布式)。
注意:由于所有的数据节点组成了完整的数据视图,所以一个数据节点down机,整个pgxl都启动不了了,所以实际生产中,为了提高可用性,一定要配置数据节点的热备以便进行故障转移准备。
在配置的时候一定要细心,避免端口号之类的配置错误。
在创建测试数据时,我曾遇到以下错误:
错误一:
LOG: MultiXact member wraparound protections are now enabled
LOG: database system is ready to accept connections
FATAL: lock file "/tmp/.s.PGPOOL.6667.lock" already exists
HINT: Is another postmaster (PID 3649) using socket file "/tmp/.s.PGPOOL.6667"?
LOG: pool manager process (PID 8906) exited with exit code 1
原因:pg2机器上的coord1,dn1的postgresql.conf的连接池端口号pooler_port 都设置为6667了,导致冲突。注意,同一台机器上,一般会部署coord,datanode,避免他们的端口号,连接池端口号冲突即可。为了减少麻烦,作者将所有不同机器上的coord端口都定为5432,datanode的端口定为5433。(作者每台机器只部署了一个coord,datanode,如果有多个自己注意设置下端口号)
错误二
postgres=# create table test1(id integer,name varchar(20));
ERROR: Could not begin transaction on data node.
原因:原因是可能是coord,datanode绑定的gtm是localhost,没有绑定到gtm所在的主机。检查下gtm,coord,datanode的配置文件中的gtm_host是否正确。
错误三:
postgres=# create table test1(id integer,name varchar(20));
LOG: failed to connect to node, connection string (host=192.168.0.125 port=1925 dbname=postgres user=postgres application_name=pgxc sslmode=disable options='-c remotetype=coordinator -c parentnode=coord1 -c DateStyle=iso,mdy -c timezone=prc -c geqo=on -c intervalstyle=postgres -c lc_monetary=C'), connection error (fe_sendauth: no password supplied
)
WARNING: can not connect to node 16384
WARNING: Health map updated to reflect DOWN node (16384)
LOG: Pooler could not open a connection to node 16384
LOG: failed to acquire connections
STATEMENT: create table test1(id integer,name varchar(20));
ERROR: Failed to get pooled connections
HINT: This may happen because one or more nodes are currently unreachable, either because of node or network failure.
Its also possible that the target node may have hit the connection limit or the pooler is configured with low connections.
Please check if all nodes are running fine and also review max_connections and max_pool_size configuration parameters
STATEMENT: create table test1(id integer,name varchar(20));
原因:这个是由于某些环境或配置出了问题,我的就是pg_hba.conf配置出了问题,Ipv4要改成 0:0:0:0/0 trust才行。
但这仅仅是一个问题,开发者搭建环境遇到这个错误,一定要检查如下:
- * 各个机器的防火墙是否关闭?*
- * 各个机器的SELINUX状态是否是disabled?*
- * 各个机器的ssh免密登录是否成功?*
- * 各个节点的pg_hba.conf,postgresql.conf是否配置为信任登录?是否有IP限制?*
- 超过某些节点的最大连接数?(对于我们测试环境来说,肯定不会是这个问题)
错误四:
[postgres@pg1 bin]$ pgxc_ctl -c /home/postgres/pgxc_ctl/pgxc_ctl.conf start all
bash:gtm_ctl :command not found...
bash:pg_ctl:command not found...
原因是作者第一次将环境变量配置到全局的/etc/profile了,在通过ssh操作事,环境变量会变,应配置到对应用户下的.bashrc,后来改配置到postgres用户下,配置.bashrc即可。
作者搭建pgxl是为地理大数据做技术预研的,使用postgis作为空间数据,欢迎postgis开发者参与交流。