为了方便,只搭建一主一从。首先准备两台服务器,信息如下:
IP | 角色 | 端口 |
---|---|---|
192.168.0.31 | master | 5432 |
pgpool-II | 9999 | |
192.168.0.32 | slave | 5432 |
一、基础环境配置
host设置
1
2
3# 修改vi /etc/hosts, 增加以下内容
192.168.0.31 master
192.168.0.32 slave安装
PostgreSQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
rpm -Uvh https://yum.postgresql.org/10/redhat/rhel-7-x86_64/pgdg-centos10-10-2.noarch.rpm
yum install postgresql10-server postgresql10
/usr/pgsql-10/bin/postgresql-10-setup initdb
systemctl enable postgresql-10.service
systemctl start postgresql-10.service
su - postgres -c "psql"
psql (10.0)
Type "help" for help.
postgres=#
postgres=# \password postgres
postgres=# show data_directory;
listen_addresses = '*' # 表示开放外网访问
sudo firewall-cmd --add-service=postgresql --permanent
sudo firewall-cmd --reload
systemctl restart postgresql-10.servicepgpool-II
1
2
3
4
5
6
7
8
9
10
11# 安装
yum install http://www.pgpool.net/yum/rpms/3.7/redhat/rhel-7-x86_64/pgpool-II-release-3.7-1.noarch.rpm
yum install pgpool-II-pg10
# 可选
yum install pgpool-II-pg10-debuginfo
yum install pgpool-II-pg10-devel
yum install pgpool-II-pg10-extensions
#启动
systemctl enable pgpool.service
systemctl start pgpool.service
二、流复制
Master
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15# 创建用于复制的用户
su - postgres
psql
postgres=# CREATE ROLE pgrepuser REPLICATION LOGIN PASSWORD 'pgreppass';
# 编辑文件 (vi /var/lib/pgsql/10/data/pg_hba.conf)
# host replication pgrepuser 0.0.0.0/0 md5
# 编辑文件 (vi /var/lib/pgsql/10/data/postgresql.conf),修改配置(根据实际情况填写)
wal_level = hot_standby
archive_mode = on
max_wal_sender = 4
wal_keep_segments = 10
# 重启数据库
systemctl restart postgresql-10.serviceSlave
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24# 停止服务
systemctl stop postgresql-10.service
su - postgres
# 使用 pg_basebackup 生成备库
#1. 清空 $PGDATA 目录
rm -rf /var/lib/pgsql/10/data
# pg_basebackup 命令生成备库
pg_basebackup -D /var/lib/pgsql/10/data -Fp -Xs -v -P -h master -U pgrepuser
# 编辑文件 (vi /var/lib/pgsql/10/data/postgresql.conf)
hot_standby = on
# 新建文件 (vi /var/lib/pgsql/10/data/recovery.conf)
standby_mode = 'on'
primary_conninfo = 'host=master port=5432 user=pgrepuser password=pgreppass'
trigger_file = 'failover.now'
recovery_target_timeline = 'latest'
# 重启数据库
systemctl restart postgresql-10.service
#验证:在master新增数据slave节点可以看到数据。
三、读写分离
pgpool配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66cd /etc/pgpool-II
cp -pv pgpool.conf.sample-stream pgpool.conf
# 修改 vi pgpool.conf
listen_addresses = '*'# 外网访问
# 0为主库
backend_hostname0 = 'master
backend_port0 = 5432
backend_weight0 = 0 # 分配比例
backend_data_directory0 = '/var/lib/pgsql/10/data'
backend_flag0 = 'ALLOW_TO_FAILOVER'
backend_hostname1 = 'slave'
backend_port1 = 5432
backend_weight1 = 1
backend_data_directory1 = '/var/lib/pgsql/10/data'
backend_flag1 = 'ALLOW_TO_FAILOVER'
#hba认证
enable_pool_hba = on
# 执行log
log_statement = on
log_per_node_statement = on
# 流复制
sr_check_user = 'replicator' # 流复制账号
sr_check_password = '123456' # 流复制密码
# 函数默认分发到从节点,过滤如下
black_function_list = 'currval,lastval,nextval,setval,funcw_.*'
# 修改 vi pool_hba.conf
host all all 0.0.0.0/0 md5
# 修改 vi pcp.conf
pcp:e10adc3949ba59abbe56e057f20f883e # 密码为123456
# 生成pool_passwd
pg_md5 123456
# 与 postgresql 用户密码一致
pg_md5 -m -u postges postgres
# 启动pgpool
# systemctl restart pgpool.service
pgpool -n -d > /etc/pgpool-II/pgpool.log 2>&1 &
# 连接
su - postgres
psql postgres -h master -p 9999 -U postgres
# 节点信息
postgres=# show pool_nodes;
node_id | hostname | port | status | lb_weight | role | select_cnt | load_balance_node | replication_delay
---------+----------+------+--------+-----------+---------+------------+-------------------+-------------------
0 | master | 5432 | up | 0.000000 | primary | 28 | false | 0
1 | slave | 5432 | up | 1.000000 | standby | 6 | true | 0
# 查看日志
tail -f /etc/pgpool-II/pgpool.log
# 下面是测试情况:
# select 1;
2017-10-30 06:38:25: pid 3637: LOG: DB node id: 1 backend pid: 3658 statement: select * from test where id = 1;
# update test set name = 'test' where id = 2;
DB node id: 0 backend pid: 8032 statement: update test set name = 'test' where id = 2;
#/*REPLICATION*/select 1; # 强制master节点执行
DB node id: 0 backend pid: 8032 statement: /*REPLICATION*/select 1;
# DB node id,0表示主节点执行,1表示从节点
四、错误解决
端口占用
1
2
3
4
5
62017-10-30 01:50:21: pid 3790: FATAL: failed to bind a socket: "/tmp/.s.PGSQL.9998"
2017-10-30 01:50:21: pid 3790: DETAIL: bind socket failed with error: "Address already in use"
# 非正常结束导致的,删除以下目录即可
rm -f /tmp/.s.PGSQL.9999
rm -f /tmp/.s.PGSQL.9898
五、后续优化
宕机主从切换
1
2# 修改 vi pgpool.conf
follow_master_command = '/etc/pgpool-II/failover_stream.sh'新建切换脚本
1
2
3
4
5
6
7
8
9
10
11
# Failover command for streaming replication.
# Arguments: $1: new master hostname.
new_master=$1
trigger_command="$PGHOME/bin/pg_ctl promote -D $PGDATA"
# Prompte standby database.
/usr/bin/ssh -T $new_master $trigger_command
exit 0;pgpool集群
配置虚拟ip(delegate_IP),使用WATCHDOG监控,服务A宕机时,服务B自动接管虚拟IP对外提供服务。
六、基于ShardingJDBC实现读写分离
新建一个Spring Boot工程,添加必要的依赖,其pom.xml定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.demo</groupId>
<artifactId>shardingjdbcdemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>shardingjdbcdemo</name>
<description>Demo project for ShardingJDBC Demo</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<sharding-jdbc.version>1.5.4.1</sharding-jdbc.version>
<mybatis-spring-boot-starter.version>1.1.1</mybatis-spring-boot-starter.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--支持面向方面的编程即AOP,包括spring-aop和AspectJ-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 引入sharding-jdbc核心模块 -->
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>${sharding-jdbc.version}</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>定义DataSource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44package com.demo.shardingjdbc.config;
import com.dangdang.ddframe.rdb.sharding.api.MasterSlaveDataSourceFactory;
import com.dangdang.ddframe.rdb.sharding.api.strategy.slave.MasterSlaveLoadBalanceStrategyType;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.sql.Driver;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
public class DataSourceConfig {
"shardingDataSource") (name =
"spring.datasource") (prefix=
public DataSource getDataSource() throws SQLException {
return buildDataSource();
}
private DataSource buildDataSource() throws SQLException {
BasicDataSource masterDataSource0 = createDataSource("jdbc:postgresql://192.168.0.31:5432/master");
// 构建读写分离数据源, 读写分离数据源实现了DataSource接口, 可直接当做数据源处理. masterDataSource0, slaveDataSource00, slaveDataSource01等为使用DBCP等连接池配置的真实数据源
Map<String, DataSource> slaveDataSourceMap0 = new HashMap<>();
BasicDataSource slaveDataSource00 = createDataSource("jdbc:postgresql://192.168.0.31:5432/slave");
slaveDataSourceMap0.put("slaveDataSource00", slaveDataSource00);
// 可选择主从库负载均衡策略, 默认是ROUND_ROBIN, 还有RANDOM可以选择, 或者自定义负载策略
DataSource masterSlaveDs0 = MasterSlaveDataSourceFactory.createDataSource("ms_0", "masterDataSource0", masterDataSource0, slaveDataSourceMap0, MasterSlaveLoadBalanceStrategyType.ROUND_ROBIN);
return masterSlaveDs0;
}
private static BasicDataSource createDataSource(final String dataSourceUrl) {
BasicDataSource result = new BasicDataSource();
result.setDriverClassName(Driver.class.getName());
result.setUrl(dataSourceUrl);
result.setUsername("postgres");
result.setPassword("");
return result;
}
}