0%

人不上班是不会死的!不加班也是!

用无限适用于未来的方法
置换体内星辰河流

最近又陷入到了 jvm 这个深渊中,大多数地方都只是说了说 gc 的算法以及内存的结构等等,倒是很少看到关于何时进行 GC 有详细的说明,又说eden区不够分配新对象就minor gc ,old gen 不够分配新对象就full gc。也有说这个东西是无法预测的。

不过根据 RednaxelaFX 的知乎回答,大概理解了一些。

GC 的分类其实是这样:

  • Partial GC:并不收集整个GC堆的模式

    • Young GC:只收集young gen的GC

    • Old GC:只收集old gen的GC。只有CMS的concurrent collection是这个模式

    • Mixed GC:收集整个young gen以及部分old gen的GC。只有G1有这个模式

  • Full GC:收集整个堆,包括young gen、old gen、perm gen(如果存在的话)等所有部分的模式。

Major GC通常是跟full GC是等价的,收集整个GC堆。但因为HotSpot VM发展了这么多年,外界对各种名词的解读已经完全混乱了,当有人说“major GC”的时候一定要问清楚他想要指的是上面的full GC还是old GC。

关于GC的时机是这样触发:

  • young gc :也就是常说的 minor gc,会在 young gen 的 eden 区满了触发,也就是剩余空间不足以加载新对象时
  • full gc :
    • serial GC:
      1. 在 serial GC 实现中,在触发一次 young gc 之前,会根据历史GC统计数据,计算之前平均每次 young gc 晋升到 old gen 的对象大小,当 old gen 剩余空间比这个平均值小时,会进行一次 full gc 。(此时会取消这次 young gc,因为除了 CMS 的并发GC,大多数的 full gc 包含了对 young gen 以及其他的堆空间的 gc。)
      2. 在 perm gen 没有足够空间时
      3. 执行 System.gc()时,根据资料这个命令是建议JVM执行GC,而不是一定会执行。
      4. heap dump带GC。
    • Parallel Scavenge 框架下,执行full GC 之前会触发一次 young GC,以让程序在两次GC之间可以运行一下下,减少 full GC 的暂停时间,减少了 full GC的工作量。
    • 并发GC:以CMS为例子,定时检查 old gen 的使用量,超过了一定比例就进行一次 CMS GC。可以根据-XX:CMSInitiatingOccupancyFraction 设置比例,以及设置-XX:+UseCMSInitiatingOccupancyOnly设置仅超过比例GC,不然可能会在低于这个比例时也进行GC。

关于拆包装包这块,以前一直是一知半解,也觉得没有什么需要特别写出来的必要,反正是 JAVA 自带的性质。
最近发现里面还是有一些以前不曾在意的机制的,简单说一下。

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
public static void main(String[] args) {
System.out.println(new Integer(1) == new Integer(1)); //1

System.out.println(new Integer(1) == 1); //2

System.out.println(new Integer(1) + new Integer(1) == 2); //3

Integer a = 1;
Integer b = 1;
System.out.println(a==b); //4

Integer a1 = 128;
Integer b1 = 128;
System.out.println(a1==b1); //5

int a2 = new Integer(1236);
Integer b2 = new Integer(1236);
System.out.println(a2==b2); //6

}
可以得到结果:
false //1
true //2
true //3
true //4
false //5
  1. 因为自动装包机制,a 和 b 实际指向的是对象的内存地址。而两个 new 出来的对象地址一定不相等
  2. 因为自动拆包机制,当包装类型与基础类型比较时,会进行拆包,对基础类型的值进行比较,所以相等
  3. 当包装类型进行计算时,会进行自动拆包,故比较的是值,而不是地址,为true。
  4. 因为基础类型的缓存机制,int类型会缓存[-128,127]的值,int a = 1,实际上是类似于调用了 int a = Integet.valueOf(1),如果缓存中存在,则会直接返回该对象,并不会new,所以同一个对象的内存引用地址一样,故相等
  5. 同上,只是128超出了缓存的范围,因此是new出来的,所以两个对象引用地址不同。
  6. 声明时是 int, int a2 = new Integer(1236) 实际上是 int a2 = new Integer(1236).intValue(); 且当包装类型与基础类型比较时,会自动拆表比较值。

根据自身理解,自动拆包有一下几种情况:

  1. 当存在算术符号时
  2. 当包装类型与基础类型比较时
  3. 声明对象时使用基础类型声明时

自动包装有以下几种情况:

  1. 声明对象为包装类型时,包括new,和直接给定值。区别在于,new的时候一定是一个新的对象,而后者通常调用了XXX.valueOf(a),有可能会从缓存中直接获取。
    • int a = new Integer(1);
    • int a = 1;

更详细的文档请看: https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html

Tips

包装类型缓存范围如下:

类型 范围
Byte,Short,Integer,Long [-128,127]
Character [0,127] 前128个字符
Boolean true,false
Float, Double 无缓存

环境

安装 docker 就不多说了

Elasticsearch 以及 ik, kibana 版本一定要一致,此次使用的版本是7.9.0

Elasticsearch

1
2
docker pull elasticsearch:7.9.0
docker run --network=dnetwork -d -p 9200:9200 -p 9300:9300 -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -e "discovery.type=single-node" --name es elasticsearch:7.9.0

安装成功后,可以看到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
root@ubuntu:~# curl  localhost:9200
{
"name" : "8b9d30ea5a68",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "htfsXjtCTpiLnJhakFKhOw",
"version" : {
"number" : "7.9.0",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "a479a2a7fce0389512d6a9361301708b92dff667",
"build_date" : "2020-08-11T21:36:48.204330Z",
"build_snapshot" : false,
"lucene_version" : "8.6.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}

kibana

kibana 是一个简单的 ES 可视化管理工具。

1
2
docker pull kibana:7.9.0
docker run --network=dnetwork --name kibana --link=elasticsearch:8b9d30ea5a68 -p 5601:5601 -d kibana:7.9.0

安装成功后访问浏览器 localhost:5601 可以看到界面。

ES简单使用

简单概念

ElasticSearch的索引即index,可以理解为MySQL的 Table (6.x之前可以理解为database, 6.x之后可理解为table)。因为之前在 index 和文档之间有一层 type(类型),且可以创建多个mapping,而7.0没有了,一个 index 也只能有一个 mapping。

索引

索引名必须全小写。
创建文档时,也会自动生成索引。

新增索引

PUT: /{index_name}

path parameters:
  • index_name:
    • 全小写
    • 不能包含, /, *, ?, “, <, >, |, (空白符), ,, #
    • 7.0 之前可能包含’:’,但是7.0+不支持
    • 不能以 -, _, + 开头
    • 不能为. 或者 ..
    • 不能超过255 byte,一个汉字2个byte
    • 名字不能以 . 开头,因为默认 . 开头的会被隐藏,通常只用于系统插件。
      query parameters:
  • wait_for_active_shards(可选,字符串):任意正整数(1 到 number_of_replicas+1)或者all,默认1.等待碎片副本数达到后,执行后续操作。
  • master_timeout(可选,时间单位(d,h,m,s,ms,micros,nanos)):指定连接master node 的超时时间,默认30s。
  • timeout(可选,时间单位(d,h,m,s,ms,micros,nanos)): 指定响应超时时间,默认30s。
request body:
  • aliases(可选): index 别名,
  • mappings(可选): (mapping 对象)如果指定了,可以包含三个属性:
    • Field names
    • Field data types
    • Mapping parameters
  • settings(可选): 配置index
    举个例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    PUT /my-index-000001
    {
    "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 2,
    "index.write.wait_for_active_shards": "2"
    },
    "mappings": {
    "properties": {
    "field1": { "type": "text" }
    }
    },
    "aliases": {
    "alias_1": {},
    "alias_2": {
    "filter": {
    "term": { "user.id": "kimchy" }
    },
    "routing": "shard-1"
    }
    }
    }

    删除索引

    DELETE /{index_name}
    path parameters:
  • index_name
    • 可以逗号分割
    • 可以使用 wildcard 匹配
    • 不能使用 alias。
    • _all 或者 * 可以删除所有索引。如果要禁止此行为,需要设置 action.destructive_requires_name 为 true。
      在 elasticsearch.yml 中修改或者使用 cluster update settings API
      query parameters:
  • allow_no_indices: 当通配符表达式或者_all, 仅能匹配到关闭的索引时。抛出异常。默认true。
  • expand_wildcards:all/open/closed/hidden/none, 默认open
  • ignore_unavailable: 默认true, missing 或者 close 的索引不会在响应中。
  • master_timeout(可选,时间单位(d,h,m,s,ms,micros,nanos)):指定连接master node 的超时时间,默认30s。
  • timeout(可选,时间单位(d,h,m,s,ms,micros,nanos)): 指定响应超时时间,默认30s。
    查询索引
    GET: /_cat/indices/?v 可以查看 ES 所有索引,以及他的相关信息,比如占用空间等等。
    查看单个索引详细信息
    GET: /{index_name}
    path parameters:
  • index_name
    • 可以逗号分割
    • 可以使用 wildcard 匹配
    • _all 或者 * 可以删除所有索引。
query parameters:
  • allow_no_indices
    当通配符表达式或者_all, 仅能匹配到关闭的索引时。抛出异常。默认true
  • expand_wildcards:all/open/closed/hidden/none, 默认open
  • flat_settings: 如果为 true, 以 flat foramt 返回所有 settings。默认为false。
  • include_defaults: 是否包括默认 settings。默认false
  • include_type_name: 7.0之后移除,为 true 。一个 mapping 类型则指定一个mapping body。默认false。
  • ignore_unavailable: 默认true, missing 或者 close 的索引不会在响应中。
  • local: 如果true, 只会接口本地节点的信息。默认false,也就是从 master 节点接收信息。
  • master_timeout(可选,时间单位(d,h,m,s,ms,micros,nanos)):指定连接master node 的超时时间,默认30s。

Documents 文档:

documents 其实也类似 sql 中的一条数据。index则有点像表,是数据的集合。

新增数据(index)

新增数据有如下接口:

1
2
3
4
5
6
7
PUT /<target>/_doc/<_id>

POST /<target>/_doc/

PUT /<target>/_create/<_id>

POST /<target>/_create/<_id>

新增时请使用 POST /<target>/_create/<_id>,不要使用PUT /<target>/_doc/<_id>。经过测试已存在的记录的时,前者不会新增,且会响应出错,后者会使其版本号+1。

Path parameters
  • target: 必填,目标数据流或者索引名字。
  • _id: 非必填,文档ID,以下接口下必填
    1
    2
    3
    PUT /<target>/_doc/<_id>
    PUT /<target>/_create/<_id>
    POST /<target>/_create/<_id>
    若要自动生成文档ID,使用接口/<target>/_doc/。并忽略此参数

    Request body

    请求体,也就是文档 _source。 json格式。

这种艺术真的很难领悟

java -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=18081 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.rmi.port=18081 -Djava.rmi.server.hostname=120.197.152.99 -jar X.jar

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

repmgr教程

简介

repmgr是一个开源工具套件,用于管理PostgreSQL服务器集群中的复制和故障转移。它使用工具来增强PostgreSQL的内置热备份功能,以设置备用服务器,监控复制以及执行管理任务,例如故障转移或手动切换操作。

前期准备

两台装有 postgresql 9.5 的服务器。

1. 安装

1.1 下载源码包https://repmgr.org/download/repmgr-5.0.0.tar.gz
1.2 解压

1
tar -zxvf repmgr-5.0.0.tar.gz

1.3 进入目录并编译
安装编译所需库

  • flex
  • libedit-dev
  • libkrb5-dev
  • libpam0g-dev
  • libreadline-dev
  • libselinux1-dev
  • libssl-dev
  • libxml2-dev
  • libxslt1-dev
    1
    apt install flex libedit-dev libkrb5-dev libpam0g-dev libreadline-dev libselinux1-dev libssl-dev libxml2-dev libxslt1-dev
    1
    ./configure && make install

    2. 配置

    可复制 sample, sample 位于解压的根目录 repmgr.conf.sample。
    1
    cp repmgr.conf.sample /etc/postgresql/repmgr.conf
    修改以下关键信息
    1
    2
    3
    4
    5
    6
    node_id=1
    node_name='138'
    conninfo='host=db1 user=postgres dbname=postgres password=d connect_timeout=2'
    data_directory='/var/lib/postgresql/9.5/main'
    pg_bindir='/usr/lib/postgresql/9.5/bin'
    repmgr_bindir='/usr/lib/postgresql/9.5/bin'
    1
    2
    3
    4
    5
    6
    node_id=2
    node_name='139'
    conninfo='host=db2 user=postgres dbname=postgres password=d connect_timeout=2'
    data_directory='/var/lib/postgresql/9.5/main'
    pg_bindir='/usr/lib/postgresql/9.5/bin'
    repmgr_bindir='/usr/lib/postgresql/9.5/bin'

    3. 从库复制主库

    主库中创建extension,psql 连接数据库后输入
    1
    create extension repmgr
    创建流复制角色
    1
    CREATE ROLE repl login replication encrypted password 'd'

3.1 修改主库配置
postgresql.conf, 和一般的流复制配置无异

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
listen_addresses = '*' # 监听来自任何地址的请求
archive_mode = on # 开启归档
archive_command = 'cp %p /var/lib/postgresql/pg_archive/%f' # 归档 logfile segment 命令 %p 代表需要归档的文件路径,%f 归档文件名,此目录需要属于postgres角色,一面权限不足。
wal_level = hot_standby # 归档开启热备用 minimal, archive, hot_standby, or logical
max_wal_senders = 10 # 最大wal发送者数量。通常和从库数量一致。
wal_keep_segments = 256 # 保留的最大日志文件段。一个16MB。
wal_sender_timeout = 60s # 发送超时时间
max_connections = 100 # 这个设置要注意下,从库的max_connections必须要大于主库的。(不知道)。最大连接数。
wal_log_hints = on # 不然会导致主服务器挂掉之后恢复出问题。pg_rewind
# 从库配置
hot_standby = on # 在恢复期间是否允许查询
max_standby_archive_delay = 30s # 读取 archive WAL时,取消查询时的最大延迟,-1 无限
#max_standby_streaming_delay = 30s # 读取streaming wal 取消查询的最大延迟,-1 无限
wal_receiver_status_interval = 10s # 发送回复的间隔
hot_standby_feedback = off # 从 standby 状态发送信息以防止冲突
wal_receiver_timeout = 60s # 接收 master 等待的时间,默认 milliseconds
wal_retrieve_retry_interval = 5s # 尝试失败后重新检索 WAL 的间隔

pg_hba.conf

1
2
3
4
# local      DATABASE  USER  METHOD  [OPTIONS]
# host DATABASE USER ADDRESS METHOD [OPTIONS]
host replication repl 0.0.0.0/0 md5
host replication postgres 0.0.0.0/0 md5

3.2 主库注册到 repmgr,并查看

1
2
3
4
5
repmgr -f /etc/postgresql/repmgr.conf primary register
INFO: connecting to primary database...
NOTICE: attempting to install extension "repmgr"
NOTICE: "repmgr" extension successfully installed
NOTICE: primary node record (ID: 1) registered
1
2
3
4
repmgr cluster show -f /etc/postgresql/repmgr.conf
ID | Name | Role | Status | Upstream | Location | Priority | Connection string
----+------+---------+-----------+----------+----------+----------+---------------------------------------------------------------------
1 | 138 | primary | * running | | default | 100 | host=db1 user=postgres dbname=postgres password=d connect_timeout=2

3.3 从库配置
将密码连接信息存储在.pgpass文件

1
vim ~/.pgpass

输入以下信息,格式为 host:port:DBName:username:password

1
2
db1:5432:postgres:postgres:d
db2:5432:postgres:postgres:d

然后设置权限chmod 600 ~/.pgpass
clone 执行,执行前需要清空 pgdata 目录

1
repmgr -h db1 -U postgres -d postgres -f /etc/postgresql/repmgr.conf standby clone

你会发现目录生成了,且 recovery.conf 也生成了。
启动从库

1
pg_ctl -D . start

然后注册从库

1
2
3
4
5
6
repmgr standby register -f /etc/postgresql/repmgr.conf
INFO: connecting to local node "139" (ID: 2)
INFO: connecting to primary database
WARNING: --upstream-node-id not supplied, assuming upstream node is primary (node ID 1)
INFO: standby registration complete
NOTICE: standby node "139" (ID: 2) successfully registered

查看节点

1
2
3
4
5
repmgr cluster show -f /etc/postgresql/repmgr.conf
ID | Name | Role | Status | Upstream | Location | Priority | Connection string
----+------+---------+-----------+----------+----------+----------+---------------------------------------------------------------------
1 | 138 | primary | * running | | default | 100 | host=db1 user=postgres dbname=postgres password=d connect_timeout=2
2 | 139 | standby | running | 138 | default | 100 | host=db2 user=postgres dbname=postgres password=d connect_timeout=2

4.配置自动failover(如果使用了 pgpool failover,则不要使用 repmgr 的failover)

  1. 因为自动 failover 基于repmgrd,首先需要包含其关联库,postgresql.conf,配置下面一行,需要重启
    1
    shared_preload_libraries ='repmgr'
    主从都需要重启:
    1
    pg_ctl -D . restart
  2. 配置repmgr.conf,配置在上面配置的基础上添加(主从都需要)
    1
    2
    3
    4
    failover=automatic # 开启自动故障转移
    promote_command='/usr/lib/postgresql/9.5/bin/repmgr standby promote -f /etc/postgresql/repmgr.conf --log-to-file'
    follow_command='/usr/lib/postgresql/9.5/bin/repmgr standby follow -f /etc/postgresql/repmgr.conf --log-to-file --upstream-node-id=%n'
    #上面这两个命令必须绝对路径
  3. 主备均要启动 repmgrd 服务
    配置如果改了,则需要 kill 掉,然后重新启动.
    1
    repmgrd -f /etc/postgresql/repmgr.conf
  4. 测试
    1. 主库挂掉
      1
      pg_ctl -D . stop
  5. 2 副库则看到
    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
    [2020-02-13 20:14:49] [INFO] checking state of node 1, 6 of 6 attempts
    [2020-02-13 20:14:49] [WARNING] unable to ping "user=postgres password=d connect_timeout=2 dbname=postgres host=db1 fallback_application_name=repmgr"
    [2020-02-13 20:14:49] [DETAIL] PQping() returned "PQPING_NO_RESPONSE"
    [2020-02-13 20:14:49] [WARNING] unable to reconnect to node 1 after 6 attempts
    [2020-02-13 20:14:49] [INFO] 0 active sibling nodes registered
    [2020-02-13 20:14:49] [INFO] primary and this node have the same location ("default")
    [2020-02-13 20:14:49] [INFO] no other sibling nodes - we win by default
    [2020-02-13 20:14:49] [NOTICE] this node is the only available candidate and will now promote itself
    [2020-02-13 20:14:49] [INFO] promote_command is:
    "/usr/lib/postgresql/9.5/bin/repmgr standby promote -f /etc/postgresql/repmgr.conf --log-to-file"
    [2020-02-13 20:14:49] [NOTICE] promoting standby to primary
    [2020-02-13 20:14:49] [DETAIL] promoting server "139" (ID: 2) using "/usr/lib/postgresql/9.5/bin/pg_ctl -w -D '/var/lib/postgresql/9.5/main' promote"
    LOG: received promote request
    [2020-02-13 20:14:49] [NOTICE] LOG: redo done at 0/5000028
    waiting up to 60 seconds (parameter "promote_check_timeout") for promotion to complete
    LOG: last completed transaction was at log time 2020-02-13 04:13:29.417036-08
    LOG: selected new timeline ID: 2
    LOG: archive recovery complete
    LOG: MultiXact member wraparound protections are now enabled
    LOG: database system is ready to accept connections
    LOG: autovacuum launcher started
    [2020-02-13 20:14:50] [NOTICE] STANDBY PROMOTE successful
    [2020-02-13 20:14:50] [DETAIL] server "139" (ID: 2) was successfully promoted to primary
    [2020-02-13 20:14:50] [INFO] 0 followers to notify
    [2020-02-13 20:14:50] [INFO] switching to primary monitoring mode
    [2020-02-13 20:14:50] [NOTICE] monitoring cluster primary "139" (ID: 2)
    可以看到副库已经变成了主库
    1
    2
    3
    4
    5
    6
    7
    8
    postgres@ubuntu:~/9.5/main$ repmgr cluster show -f /etc/postgresql/repmgr.conf
    ID | Name | Role | Status | Upstream | Location | Priority | Connection string
    ----+------+---------+-----------+----------+----------+----------+---------------------------------------------------------------------
    1 | 138 | primary | - failed | | default | 100 | host=db1 user=postgres dbname=postgres password=d connect_timeout=2
    2 | 139 | primary | * running | | default | 100 | host=db2 user=postgres dbname=postgres password=d connect_timeout=2

    WARNING: following issues were detected
    - unable to connect to node "138" (ID: 1)
  6. 3 恢复
    也就是将主库设置为新的从库
    创建 recovery.conf 文件。
    内部配置和备用库基本一样
    1
    2
    3
    standby_mode = 'on' # 热备份mode
    primary_conninfo = 'user=repl password=d host=192.168.56.139 port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres' # 连接信息
    recovery_target_timeline = 'latest' # 复制最新数据
    启动
    1
    pg_ctl start
    可以看到
    1
    2
    3
    4
    5
    postgres@ubuntu:~/9.5/main$ repmgr cluster show -f /etc/postgresql/repmgr.conf
    ID | Name | Role | Status | Upstream | Location | Priority | Connection string
    ----+------+---------+-----------+----------+----------+----------+-------------------------------------------------------------------- -
    1 | 138 | standby | running | | default | 100 | host=db1 user=postgres dbname=postgres password=d connect_timeout=2
    2 | 139 | primary | * running | | default | 100 | host=db2 user=postgres dbname=postgres password=d connect_timeout=2
    成功切换

问题

  1. apt 安装后并配置数据库会导致启动数据库时could not access file “repmgr”: No such file or directory
    It means the repmgr extension code is not installed in the PostgreSQL application directory. This typically happens when using PostgreSQL packages provided by a third-party vendor, which often have different filesystem layouts.

    Either use PostgreSQL packages provided by the community or 2ndQuadrant; if this is not possible, contact your vendor for assistance.
    简单就是说用的可能时第三方的包,还是从官网下载包并编译安装吧。

  2. 提示未输入密码

    1
    2
    3
    4
    5
    6
    ERROR: connection to database failed
    DETAIL:
    fe_sendauth: no password supplied

    ERROR: unable to establish necessary replication connections
    HINT: check replication permissions on the source server

    检查 pg_hba.conf,以及 ~/.pgpass 是否输入正确的用户密码。没找到问题,然后重新初始化数据库部署了一次,就好了。

    常用命令

    参考:

  3. https://repmgr.org/docs/repmgr.html

  4. http://www.cslingjun.com/2019/11/27/PostgreSQL%E9%AB%98%E5%8F%AF%E7%94%A8%E9%9B%86%E7%BE%A4repmgr/

pg_pool使用

简介

Pgpool-II 是一个位于 PostgreSQL服务器和 PostgreSQL数据库客户端之间的中间件,Pgpool-II提供了连接池(Connection Pooling)、复制(Replication)、负载均衡(Load Balancing)、缓存(In Memory Query Cache)、看门狗(Watchdog)、超出限制链接(Limiting Exceeding Connections)等功能,可以基于这些特性来搭建PostgreSQL高可用集群。

pg_pool安装

  1. 首先前往https://www.pgpool.net/mediawiki/index.php/Downloads,下载对应的源码包,并解压。

  2. 进入解压的根目录,安装。

    1
    2
    3
    4
    apt install postgresql-server-dev-9.5 # 安装插件前需要安装 pg-dev
    ./configure --prefix=/opt/pgpool
    make
    make install

    –prefix 为安装后的目录前缀,也就是根目录
    若出现
    configure 错误
    checking for PQexecPrepared in -lpq… no
    configure: error: libpq is not installed or libpq is old
    是由于找不到 pg lib 库,可添加参数-with-pgsql=pgsql lib路径。
    安装后如果找不到命令,要么进入 /opt/pgpool/bin 执行。
    推荐引入环境变量, /etc/profile

    1
    2
    export PGPOOL=/opt/pgpool
    export PATH=$PATH:$PGPOOL/bin

    最好将目录所有者也修改

    1
    chown -R postgres.postgres /opt/pgpool
  3. 进入解压后的目录,安装相关函数。
    比如:/home/d/pgpool-II-3.7.12/src/sql。
    分别进入pgpool_adm,pgpool-recovery,pgpool-regclass文件夹,进行 make & make install。
    检查: 进入/usr/share/postgresql/9.5/extension目录,查看是否有相关函数文件。

  4. 配置
    根据安装路径不同,配置文件的路径也不一样,比如例子中配置文件路径在/opt/pgpool/etc。
    有时候也可能不再安装路径,而在/usr/local/etc。要区分到底使用的是哪一个路径的配置。
    可通过直接执行 pgpool 根据获取安装路径。
    复制一份 sample 用于修改。

    1
    2
    3
    cp pcp.conf.sample pcp.conf
    cp pgpool.conf.sample pgpool.conf
    cp pool_hba.conf.sample pool_hba.conf

    4.1 pcp.conf
    执行 pg_md5 用户的密码,比如

    1
    2
    postgres@ubuntu:/opt/pgpool/etc$ pg_md5  d
    8277e0910d750195b448797616e091ad

    编辑 pcp.conf, 在末尾输入 USERID:MD5PASSWD。
    eg:

    1
    postgres:8277e0910d750195b448797616e091ad

    4.2 pool_hba.conf
    任何地址连接任何用户的全部使用 md5 验证

    1
    2
    local   all         all                               md5
    host all all 0.0.0.0/0 md5

    4.3 pgpool.conf
    仅列出简要部分

    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
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    # - pgpool Connection Settings -
    listen_addresses = '*'
    port = 9999

    # - Backend Connection Settings -

    backend_hostname0 = 'db1'
    backend_port0 = 5432
    backend_weight0 = 1
    backend_data_directory0 = '/var/lib/postgresql/9.5/main'
    backend_flag0 = 'ALLOW_TO_FAILOVER'

    backend_hostname1 = 'db2'
    backend_port1 = 5433
    backend_weight1 = 1
    backend_data_directory1 = '/var/lib/postgresql/9.5/main'
    backend_flag1 = 'ALLOW_TO_FAILOVER'

    # - Authentication -
    enable_pool_hba = on
    pool_passwd = 'pool_passwd'
    authentication_timeout = 60

    #------------------------------------------------------------------------------
    # FILE LOCATIONS
    #------------------------------------------------------------------------------

    pid_file_name = '/opt/pgpool/pgpool.pid'
    logdir = '/var/log/pgpool'
    # 以上这两个目录均要设置所有者为执行命令的用户,此例子中是 postgres

    #------------------------------------------------------------------------------
    # LOAD BALANCING MODE
    #------------------------------------------------------------------------------

    load_balance_mode = on

    #------------------------------------------------------------------------------
    # MASTER/SLAVE MODE
    #------------------------------------------------------------------------------

    master_slave_mode = on
    master_slave_sub_mode = 'stream'

    # - Streaming -
    sr_check_period = 5
    sr_check_user = 'postgres'
    sr_check_password = 'd'
    sr_check_database = 'postgres'
    delay_threshold = 0

    #------------------------------------------------------------------------------
    # HEALTH CHECK GLOBAL PARAMETERS
    #------------------------------------------------------------------------------

    health_check_period = 10
    health_check_timeout = 20
    health_check_user = 'postgres'
    health_check_password = 'd'
    health_check_database = 'postgres'
    health_check_max_retries = 0
    health_check_retry_delay = 1
    connect_timeout = 10000

    #------------------------------------------------------------------------------
    # FAILOVER AND FAILBACK
    #------------------------------------------------------------------------------
    failover_command = '/opt/pgpool/failover_stream.sh %H %R'


    #------------------------------------------------------------------------------
    # WATCHDOG 看门狗
    #------------------------------------------------------------------------------

    # - Enabling -

    use_watchdog = on
    # Activates watchdog
    # (change requires restart)

    # -Connection to up stream servers -

    trusted_servers = ''
    # trusted server list which are used
    # to confirm network connection
    # (hostA,hostB,hostC,...)
    # (change requires restart)
    ping_path = '/bin'
    # ping command path
    # (change requires restart)

    # - Watchdog communication Settings -

    wd_hostname = 'db1' # 此看门狗IP,即本机
    wd_port = 9000
    wd_priority = 1
    wd_authkey = ''
    wd_ipc_socket_dir = '/tmp'

    # - Virtual IP control Setting -

    delegate_IP = '192.168.56.122' # 浮动IP
    if_cmd_path = '/sbin' # if命令执行的路径
    if_up_cmd = 'ip addr add $_IP_$/24 dev ens33 label ens33:0'
    if_down_cmd = 'ip addr del $_IP_$/24 dev ens33'
    # shutdown delegate IP command
    # (change requires restart)
    arping_path = '/usr/sbin'
    # arping command path
    # (change requires restart)
    arping_cmd = 'arping -U $_IP_$ -w 1 -I ens33'
    # arping command
    # (change requires restart)
    # 需要给命令 chmod u+s ,以赋予执行时的 ROOT 权限。

    # -- heartbeat mode --

    wd_heartbeat_port = 9694
    wd_heartbeat_keepalive = 2
    wd_heartbeat_deadtime = 30

    # 可填写多个终端
    heartbeat_destination0 = 'db2' # 终端0 IP
    heartbeat_destination_port0 = 9694 # 终端0 端口
    heartbeat_device0 = 'ens33'

    # -- query mode --

    wd_life_point = 3
    wd_lifecheck_query = 'SELECT 1'
    wd_lifecheck_dbname = 'postgres'
    wd_lifecheck_user = 'postgres'
    wd_lifecheck_password = 'd'


    # - Other pgpool Connection Settings -
    # 其他 pool 连接

    other_pgpool_hostname0 = 'db2'
    other_pgpool_port0 = 5432
    other_wd_port0 = 9000

    配置 pool_passwd

    1
    pg_md5 -p -m -u postgres pool_passwd

    日志目录创建以及所有者更改

    1
    2
    root@ubuntu:/var/log# mkdir pgpool
    root@ubuntu:/var/log# chown postgres.postgres pgpool

    创建 故障转移脚本
    vim /opt/pgpool/failover_stream.sh

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #! /bin/sh 
    # Failover command for streaming replication.
    # Arguments: $1: new master hostname.

    new_master=$1
    new_data=$2
    trigger_command="$PGHOME/bin/pg_ctl promote -D $2"

    # Prompte standby database.
    /usr/bin/ssh -T $new_master $trigger_command

    exit 0;

    配置 ssh 密钥

    1
    2
    3
    ssh-keygen -t rsa
    cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
    chmod 600 ~/.ssh/authorized_keys

    最好都手动连接一下,免得要你写 yes。
    修改 hosts
    vim /etc/hosts
    后面添加

    1
    2
    3
    192.168.56.139 db1
    192.168.56.138 db2
    192.168.56.177 vip

    ip 相关命令赋予权限

    1
    2
    3
    chmod u+s /sbin/ip
    apt install arping
    chmod u+s /usr/sbin/arping

    不同服务器上配置文件大致相同, 主要是 pgpool.conf 修改一下部分:

    1
    2
    3
    wd_hostname = ''  修改为本机IP
    heartbeat_destination0 = '' # 修改为其他 pool 服务器IP
    other_pgpool_hostname0 = '' # 修改为其他pool 服务器IP

    启动

    1
    pgpool -n -D

    启动后,可以看到多了一个IP,也就是浮动IP。也就代表成功了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    postgres@ubuntu:~/9.5/main$ ip addr
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
    valid_lft forever preferred_lft forever
    2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:ca:40:8f brd ff:ff:ff:ff:ff:ff
    inet 192.168.56.139/24 brd 192.168.56.255 scope global ens33
    valid_lft forever preferred_lft forever
    inet 192.168.56.122/24 scope global secondary ens33:0
    valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:feca:408f/64 scope link
    valid_lft forever preferred_lft forever

测试

测试数据库挂掉

启动

1
2
3
4
postgres@ubuntu:~$ pgpool -n -D
postgres@ubuntu:~/9.5/main$ pgpool -D . start

(2 rows)

1
postgres@ubuntu:~/9.5/main$ pgpool -D . start

连接数据库

1
2
3
4
5
6
postgres@ubuntu:~/9.5/main$ psql -U postgres -h vip -p 9999
postgres=# show pool_nodes;
node_id | hostname | port | status | lb_weight | role | select_cnt | load_balance_node | replication_delay
---------+----------+------+--------+-----------+---------+------------+-------------------+-------------------
0 | db1 | 5432 | up | 0.500000 | primary | 0 | true | 0
1 | db2 | 5432 | up | 0.500000 | standby | 0 | false | 0

关闭主数据库

1
postgres@ubuntu:~/9.5/main$ pg_ctl -D . stop

检查结果

1
2
3
4
5
6
7
postgres@ubuntu:~/9.5/main$ psql -U postgres -h vip -p 9999
postgres=# show pool_nodes;
node_id | hostname | port | status | lb_weight | role | select_cnt | load_balance_node | replication_delay
---------+----------+------+--------+-----------+---------+------------+-------------------+-------------------
0 | db1 | 5432 | down | 0.500000 | standby | 0 | false | 0
1 | db2 | 5432 | up | 0.500000 | primary | 0 | true | 0
(2 rows)

以上结果显示,db1(旧主)已经 down, 且 role 由 primary 变成 standby。db2 role 由 standby 变成 primary。也就是切换成功了。

恢复(以下操作均在 旧master 上面执行)

先倒带

1
pg_rewind --target-pgdata=/var/lib/postgresql/9.5/main --source-server='host=192.168.56.138 port=5432 user=postgres password=d dbname=postgres' -P

重命名recovery.done => recovery.conf,并配置。值得注意的是 host 要填写新的 master 的IP。

1
2
3
4
5
postgres@ubuntu:~/9.5/main$ mv recovery.done recovery.conf
postgres@ubuntu:~/9.5/main$ cat recovery.conf
standby_mode = 'on'
primary_conninfo = 'user=repl password=d host=192.168.56.138 port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres'
recovery_target_timeline = 'latest'

启动

1
postgres@ubuntu:~/9.5/main$ pg_ctl -D . start

附加到pgpool

1
pcp_attach_node -d -U postgres -h vip -p 9898 -n 0

查看结果

1
2
3
4
5
6
7
postgres@ubuntu:~/9.5/main$ psql -U postgres -h vip -p 9999
postgres=# show pool_nodes;
node_id | hostname | port | status | lb_weight | role | select_cnt | load_balance_node | replication_delay
---------+----------+------+--------+-----------+---------+------------+-------------------+-------------------
0 | db1 | 5432 | up | 0.500000 | standby | 0 | false | 0
1 | db2 | 5432 | up | 0.500000 | primary | 0 | true | 0
(2 rows)

以上结果显示 db1 已经启动。
在新master 上执行

1
2
3
4
5
6
postgres@ubuntu:~$ psql
select * from pg_stat_replication;
pid | usesysid | usename | application_name | client_addr | client_hostname | client_port | backend_start | backend_xmin | state | sent_location | write_location | flush_location | replay_location | sync_priority | sync_state
-------+----------+---------+------------------+----------------+-----------------+-------------+-------------------------------+--------------+-----------+---------------+----------------+----------------+-----------------+---------------+------------
47886 | 16384 | repl | walreceiver | 192.168.56.139 | | 53320 | 2020-02-09 20:27:17.640766-08 | | streaming | 0/1A000368 | 0/1A000368 | 0/1A000368 | 0/1A000368 | 0 | async
(1 row)

显示新的备份服务器已经关联到新的master服务器。
完美!

测试 pgpool 挂掉

主启动,副启动, 除了pgpool.conf 有些许不同,其他基本一样。

1
2
postgres@ubuntu:~$ pgpool -n -D
postgres@ubuntu:~/9.5/main$ pgpool -D . start

停止主 pgpool, 还是不知道为什么停止很久还是无法停止。
我的临时解决方式是以 pgpool -n 方式启动, 然后 ctrl+c 将它停止。
直接 kill 会导致很多问题,有很多其他的任务无法被关闭。只能重启。

1
pgpool -m fast stop

master server ip

1
2
3
4
5
6
7
8
9
10
11
12
13
postgres@ubuntu:~/9.5/main$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:ca:40:8f brd ff:ff:ff:ff:ff:ff
inet 192.168.56.139/24 brd 192.168.56.255 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:feca:408f/64 scope link
valid_lft forever preferred_lft forever

副服务器IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@ubuntu:/var/log# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:0c:df:8d brd ff:ff:ff:ff:ff:ff
inet 192.168.56.138/24 brd 192.168.56.255 scope global ens33
valid_lft forever preferred_lft forever
inet 192.168.56.122/24 scope global secondary ens33:0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe0c:df8d/64 scope link
valid_lft forever preferred_lft forever

可以看到服务器 IP 已经浮动到副服务器上。

恢复

恢复很简单,只要重新启动 pgpool 即可。

1
pgpool -n -D

如下结果,即代表连接成功,否则状态可能为 SHUTDOWN。

1
2
3
4
5
6
postgres@ubuntu:/opt/pgpool/bin$ pcp_watchdog_info
Password:
2 YES db1:9999 Linux ubuntu db1

db1:9999 Linux ubuntu db1 9999 9000 4 MASTER
db2:9999 Linux ubuntu db2 9999 9000 7 STANDBY

测试 pgpool 以及 postgresql 数据库

简单粗暴,直接 shutdown master 服务器。

1
shutdown now

检查备用服务器IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
postgres@ubuntu:~/9.5/main$  ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:0c:df:8d brd ff:ff:ff:ff:ff:ff
inet 192.168.56.138/24 brd 192.168.56.255 scope global ens33
valid_lft forever preferred_lft forever
inet 192.168.56.122/24 scope global secondary ens33:0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe0c:df8d/64 scope link
valid_lft forever preferred_lft forever

数据库状态

1
2
3
4
5
6
7
postgres@ubuntu:~/9.5/main$ psql -U postgres -h vip -p 9999
postgres=# show pool_nodes;
node_id | hostname | port | status | lb_weight | role | select_cnt | load_balance_node | replication_delay
---------+----------+------+--------+-----------+---------+------------+-------------------+-------------------
0 | db1 | 5432 | down | 0.500000 | standby | 0 | false | 0
1 | db2 | 5432 | up | 0.500000 | primary | 0 | true | 0
(2 rows)

正常工作。

恢复

开机, 其实就是以上两个恢复操作都来一遍。
恢复数据库,主要就是四个步骤:

  1. 倒带(pg_rewind);
  2. 编辑 recovery.conf;
  3. 启动(pg_ctl);
  4. 附加到 pgpool (pcp_attach_node)。
    恢复 pgpool 就更简单了,只有启动。(pgpool)
    不再赘述。
    检查 pgpool。
    1
    2
    3
    4
    5
    6
    postgres@ubuntu:/opt/pgpool/bin$ pcp_watchdog_info
    Password:
    2 YES db2:9999 Linux ubuntu db2

    db2:9999 Linux ubuntu db2 9999 9000 4 MASTER
    db1:9999 Linux ubuntu db1 9999 9000 7 STANDBY
    检查数据库
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    postgres@ubuntu:/opt/pgpool/bin$ psql -U postgres -h vip -p 9999
    Password for user postgres:
    psql (9.5.19)
    Type "help" for help.

    postgres=# show pool_nodes;
    node_id | hostname | port | status | lb_weight | role | select_cnt | load_balance_node | replication_delay
    ---------+----------+------+--------+-----------+---------+------------+-------------------+-------------------
    0 | db1 | 5432 | up | 0.500000 | standby | 0 | false | 0
    1 | db2 | 5432 | up | 0.500000 | primary | 1 | true | 0
    (2 rows)
    成功恢复!

附录:

  1. 配置文件介绍
    pgpool.conf:

    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
    listen_addresses: 监听来自哪里的请求
    port: pgpool 的主程序端口
    backend_hostname0:后端数据库连接0的hostname
    backend_port0:后端数据库0连接的port
    backend_weight0:后端数据库0连接的权重
    backend_data_directory0:后端数据库0的data 目录
    backend_flag0:控制后端的行为,可ALLOW_TO_FAILOVER(允许故障转移),DISALLOW_TO_FAILOVE(不允许故障转移),ALWAYS_MASTER(永远为主)
    #0可以依次递增

    enable_pool_hba: 是否开启pool_hba,他会前往目录寻找pool_hba.conf 文件。类似pg的hba配置,用于限制用户连接以及权限
    log_destination:log放在哪,有syslog和stderr。
    还有记录什么的参数。
    pid_file_name:pid 文件名。喜爱那个对于pgpool.conf的路径或者绝对路径
    logdir: 记录pgpool状态的文件。
    master_slave_mode: off or on 开启或者关闭主从模式
    master_slave_sub_mode: 主从子模式,分别为stream,slony,logical 默认stream

    sr_check_period: 流复制检查周期,默认0禁用
    sr_check_user: 流复制检查所用用户,即使金庸也要填写。
    sr_check_password: 流复制检查用户的密码
    sr_check_database: 流复制检查的数据库
    delay_threshold:未将查询调度给备用节点之前的阈值,单位为字节。不太理解

    健康检查全局参数
    health_check_period: 健康检查周期,0禁用
    health_check_timeout: 健康检查超时时间。
    health_check_user: 健康检查用户
    health_check_password: 健康检查密码
    health_check_database: 健康检查数据库
    health_check_max_retries: 放弃前健康检查最大重试失败次数
    health_check_retry_delay: 失败后间隔多少秒重试
    connect_timeout: 放弃连接前的超时时间。0表示无超市时间。单位为ms。仅用健康检查,不用于连接backend。

    failover_command:故障转义命令。 部分参数如下:
    # Executes this command at failover
    # Special values:
    # %d = node id
    # %h = host name
    # %p = port number
    # %D = database cluster path
    # %m = new master node id
    # %H = hostname of the new master node
    # %M = old master node id
    # %P = old primary node id
    # %r = new master port number
    # %R = new master database cluster path
    # %% = '%' character

    use_watchdog: 是否开启看门狗
    wd_hostname: 此看门狗的hostname
    wd_port: 看门口的port

    delegate_IP: 虚拟IP
    if_cmd_path = '/sbin' if_up/down_cmd的目录
    if_up_cmd = 'ip addr add $_IP_$/24 dev eth0 label eth0:0' 启动delegate_IP的命令
    if_down_cmd = 'ip addr del $_IP_$/24 dev eth0' 关闭delegate_IP的命令
    arping_path = '/usr/sbin' arping 的目录
    arping_cmd = 'arping -U $_IP_$ -w 1 -I eth0' arping 的命令
    需要 chmod u+s XXX,让它可以被其他角色执行。

    心跳模式
    wd_heartbeat_port:接收心跳信号的端口
    wd_heartbeat_keepalive: 间隔多久发送心跳信号,单位秒
    wd_heartbeat_deadtime: 心跳信号停滞时间间隔
    heartbeat_destination0: 目标0的 hostname或者ip,用于发送心跳信号
    heartbeat_destination_port0: 目标0的端口。
    heartbeat_device0: NIC设备名称,比如(eth0),猜测是网卡名字。用于发送心跳信号,仅在非空时有效。且 pgpool 具有root权限。

    查询模式
    wd_life_point: 生命检查重试次数
    wd_lifecheck_query: 从看门狗到pgpool的生命检查查询
    wd_lifecheck_dbname: 生命检查连接的数据库
    wd_lifecheck_user: 监听pgpool生命检查用户
    wd_lifecheck_password: 生命检查密码

    其他pgpool的连接设置
    other_pgpool_hostname0: pool0 的 host
    other_pgpool_port0: pool0 的 port
    other_wd_port0: pool0 的 看门狗 port

    异常

  2. MD5 authentication is not supported in replication and master-slave modes.
    首先需要将 pgpool.conf 设置 enable_pool_hba = on。 然后参要一下表格。
    简单的解决方法就是将所有 pool_hba.conf 以及 pg_hba.conf 的登陆认证均设置为MD5。

pg_hba.conf pool_hba.conf pool_passwd result
md5 md5 yes md5 auth
md5 md5 no “MD5” authentication with pgpool failed for user “XX”
md5 trust yes/no MD5 authentication is unsupported in replication, master-slave and parallel mode
trust md5 yes no auth
trust md5 no “MD5” authentication with pgpool failed for user “XX”
trust trust yes/no no auth
  1. 即使postgresql 启动了,status 却仍然显示 down。
    重现步骤: 配置好 backend1,运行pgpool,然后停止此 postgresql 数据库。
    这时候即使重新启动了postgresql 数据库, pgpool 还是会一直设置 backend1 为 down。
    倘若只有一个 backend,就会导致无法连接 pgpool。
    找到一个设置状态的地方, 也就是logdir 配置的路径。找了好久好久,才发现可以在 logdir 配置的目录设置 backend 状态。
    但是目前发现只能手动设置解决此问题,还未找到更好的方式。
    找到了更好的方法:
    1. 启动时添加 -D 参数,清除状态启动。
    2. 使用 pcp_attach_node 再次附加上去。

疑问

  1. pgpool stop 停止很久但是无法关闭。
    在具有浮点IP的机器上关闭 pgpool 很久还是没有关闭。发现有一个原因是因为连接没有关闭,但是有时候连接关闭了,还添加了 -m fast 参数还是无法关闭。还未找到原因。
    经过配置发现 开启 watchdog 会导致此问题。use_watchdog = off 则不会
    提示如下。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    2020-02-10 01:25:38: pid 28280: LOG:  Watchdog is shutting down
    2020-02-10 01:25:38: pid 28280: LOG: waiting for escalation process to exit before starting de-escalation
    2020-02-10 01:25:39: pid 28280: LOG: waiting for escalation process to exit before starting de-escalation
    2020-02-10 01:25:40: pid 28280: LOG: waiting for escalation process to exit before starting de-escalation
    2020-02-10 01:25:41: pid 28280: LOG: waiting for escalation process to exit before starting de-escalation
    2020-02-10 01:25:42: pid 28280: LOG: waiting for escalation process to exit before starting de-escalation
    2020-02-10 01:25:43: pid 28280: LOG: escalation process does not exited in time
    2020-02-10 01:25:43: pid 28280: DETAIL: starting the de-escalation anyway
    2020-02-10 01:25:43: pid 40639: LOG: watchdog: de-escalation started
    2020-02-10 01:25:43: pid 40639: LOG: successfully released the delegate IP:"192.168.56.122"
    2020-02-10 01:25:43: pid 40639: DETAIL: 'if_down_cmd' returned with success
    初步猜测是 watchdog 关闭出现了问题。目前只发现可以 ctrl+c 能干净的终止。

命令简介

  1. pgpool
    -C memqcache_method 为 memcached 时,清除查询缓存
    -n 不以守护模式运行
    -m :
    fast: 快速关闭
    smart: 关闭查询之后再关闭
    immediate: 和fast类似
    -X: 打开断言检查,调试帮助
    -d, –debug 开启debug调试
  2. pcp_attach_node
    -U, –username=NAME username for PCP authentication
    -h, –host=HOSTNAME pgpool-II host
    -p, –port=PORT PCP port number
    -w, –no-password never prompt for password
    -W, –password 强制密码认证
    -n, –node-id=NODEID 节点ID
    -d, –debug 开启 debug 信息
    -v, –verbose 输出详细的信息
  3. pg_ctl
    -D data目录,如果没有指明,默认环境变量 PGDATA。
    -s 只打印 error
    -t 超时时间
    -V 版本信息
    -w 等待直到程序完成
    -W 不等待,也就是 -w 相反
    -c 允许 postgres 生成核心文件
    -l log 文件名
    -m :
    fast: 直接退出
    smart: 等待连接断开后之后再关闭
    immediate 立即关闭,无需完全关闭,导致重启后恢复。
  4. pg_rewind
    -D, –target-pgdata=DIRECTORY 目标data目录,本地
    –source-pgdata=DIRECTORY 源data目录,远程
    –source-server=CONNSTR 连接字符串,eg:’host=192.168.56.138 port=5432 user=postgres password=d dbname=postgres’
    -n, –dry-run 不修改任何东西的启动
    -P, –progress 写进程信息
    –debug 写大量debug信息

参考

  1. https://www.jianshu.com/p/ef183d0a9213
  2. https://www.pgpool.net/docs/pgpool-II-3.5.4/doc/pgpool-zh_cn.html
  3. https://www.pgpool.net/docs/37/en/html/