ITPub博客

首页 > 数据库 > 数据库开发技术 > 高可用: 体验使用Odyssey连接池(一)

高可用: 体验使用Odyssey连接池(一)

原创 数据库开发技术 作者:数据库杂记 时间:2023-05-12 06:15:00 0 删除 编辑

1、前言

关于 Odyssey ,它是一种相对高级的多线程 PostgreSQL 连接池。 内部采用异步的多线程体系结构,使用事件驱动的异步方式来实现 内部逻辑,但是对外提供的接口看起来仍像是同步的过程方式,而没有采用回调的方式来实现,便于开发人员使用。

从支持程度来讲,它的多线程方式比pgbouncer似乎更胜一筹,单个应用能更好的利用CPU,并且可以支持更大规模的并发。

最近在总结PG的一些连接池的使用时,体验了一把Odyssey(奥德赛)连接池。顺便说一句,俄国的工程师水平还是相当不错的。可是看到网上的文档极少,除了github上有些不算很细致的介绍以外。就萌生了写下这篇短文的想法。
基本架构是下图这样的:

  • Instance: 应用程序的入口点,用于系统初始化,读取配置文件,准备日志收集,解析命令行选项,启动System线程和worker线程。

  • System: 用于启动Router, cron和console子系统。

  • router是核心组件,用于处理客户端的注册和转发客户端的请求。它会根据到来的请求,进行连接信息匹配,然后dispatch到worker_pool中的工作线程里头。同时,确保连接的限制和客户端池的排除是有效的。有处理隐含的cancel请求,因为到服务器池的请求必须要与一个client key相匹配。

    Router 是以典型的请求-应答模式工作的:客户端(来自worker线程)发送一个请求消息到router, 然后等待答复。这有可能会成为一个“热点”(但目前来看还不是问题)。

  • Cron: 周期性的服务组件,例如,用来周期性检查连接是否过期,数据库配置是否过时等等

  • Worker和Worker池: Worker线程主是是监听连接队列上的消息,如果有新的连接事件,它会创建一个前端的例程,并处理整个例程的整个生命周期。值得一提的是,每个worker线程,可以处理几千个客户端例程。(这是事件模式的优点,不是?) 而worker池则用于维护一个worker线程的线程池。相当于所有的worker线程都是从池中生成和取出的。便于统一管理。

2、安装启动

我们试一下CentOS7.9下边的PostgreSQL14.7,里头安装Odyssey连接池。

1)、获取源码并编译

它的基本依赖库(包),有cmake3 (注:必须是3)、openssl、以及postgresql-server-dev。

 1sudo yum install cmake3.x86_64
2sudo ln -s /usr/bin/cmake3 /usr/bin/cmake
3
4git clone https://github.com/yandex/odyssey
5
6[05:16:31-postgres@centos1:/pgccc/soft] cd odyssey
7[05:16:31-postgres@centos1:/pgccc/soft/odyssey]
8
9mkdir -p build
10cd build
11[05:16:31-postgres@centos1:/pgccc/soft/odyssey/build]
12
13cmake -DCMAKE_BUILD_TYPE=Release ..
14make
15
16[05:16:06-postgres@centos1:/pgccc/soft/odyssey/build]$ make
17[  0%] Built target libkiwi
18[  1%] Built target libmachinarium
19[  1%] Built target build_libs
20[ 41%] Built target odyssey
21[ 98%] Built target odyssey_test
22[100%] Built target odyssey_stress

2)、在编译上述包以后,相应的可执行文件都不在系统路径里头,我们需要进相应的复制以完成安装。

 1# root用户
2sudo -s
3[05:20:49-root@centos1:/pgccc/soft/odyssey/build]$ mkdir -p /usr/odyssey/{bin, conf}
4[05:25:24-root@centos1:/pgccc/soft/odyssey/build]$ cp -pv ../config-examples/odyssey-dev.conf /usr/odyssey/conf
5‘../odyssey-dev.conf’ -> ‘/usr/odyssey/conf/odyssey-dev.conf’
6[05:26:12-root@centos1:/pgccc/soft/odyssey/build]$ cp -r ../scripts /usr/odyssey/
7
8#建一个链接到基本路径
9[05:27:18-root@centos1:/pgccc/soft/odyssey/build]$ ln -v -s /usr/odyssey/bin/odyssey /usr/bin/odyssey
10‘/usr/bin/odyssey’ -> ‘/usr/odyssey/bin/odyssey’
11
12#看看基本结构
13[05:26:47-root@centos1:/pgccc/soft/odyssey/build]$ tree /usr/odyssey
14/usr/odyssey
15├── bin
16│   └── odyssey
17├── conf
18│   └── odyssey-dev.conf
19└── scripts
20    ├── centos
21    │   └── odyssey.spec
22    ├── debian
23    │   ├── changelog
24    │   ├── config
25    │   ├── control
26    │   ├── init
27    │   ├── install
28    │   ├── logrotate
29    │   └── rules
30    ├── install_ci.sh
31    ├── pgsql_benchmark.sh
32    ├── pgsql_check.sh
33    ├── pgsql_pgbouncer_benchmark.sh
34    └── systemd
35        ├── odyssey.service
36        └── odyssey@.service
37
38#最后将相应目录权限完全赋给postgres用户
39chown -R postgres:postgres /usr/odyssey

3)、试试启动odyssey连接池进程

1# 使用postgres用户, 以后台进程的方式启动一下
2nohup odyssey /usr/odyssey/conf/odyssey-dev.conf &
3
4[05:49:04-postgres@centos1:/pgccc/soft/odyssey]$ ps -ef | grep odyssey | grep -v grep
5postgres  22378  22025  0 05:48 pts/2    00:00:00 odyssey: version 2060 listening and accepting new connections

我们能看到它在监听2060端口。

这个时候,因为我们没有对配置文件做任何修改,所以,还是无法通过连接odyssey连接池来连接到后端的数据库。

3、配置并连接本地数据库

打开配置文件:/usr/odyssey/conf/odyssey-dev.conf,  修改并加入数据库连接相关环节。我在下边修改的部分前边加了提示:

  1pid_file "/tmp/odyssey.pid"
2#updated.  设置为no daemonize,这样方便调试
3daemonize no
4
5#updated. 修改socket dir, 与PG保持一样
6unix_socket_dir "/var/run/postgresql"
7unix_socket_mode "0644"
8
9log_format "%p %t %l [%i %s] (%c) %m\n"
10#updated. 让日志信息输出到屏幕
11log_to_stdout yes
12
13log_syslog no
14log_syslog_ident "odyssey"
15log_syslog_facility "daemon"
16
17log_debug yes
18log_config yes
19log_session yes
20log_query yes
21log_stats yes
22stats_interval 60
23log_general_stats_prom yes
24log_route_stats_prom no
25promhttp_server_port 7777
26
27workers "auto"
28resolvers 1
29
30readahead 8192
31
32cache_coroutine 0
33
34coroutine_stack_size 16
35
36nodelay yes
37
38keepalive 15
39keepalive_keep_interval 75
40keepalive_probes 9
41
42keepalive_usr_timeout 0
43
44listen {
45        host "*"
46        port 6432
47        backlog 128
48        compression yes
49        tls "disable"
50}
51
52
53storage "postgres_server" {
54        type "remote"
55#       host "[localhost]:5555,localhost"
56#updated. 要想支持本地连接,只用127.0.0.1
57        host "127.0.0.1"
58        port 5555
59        target_session_attrs "read-write"
60}
61
62#updated. 完整的数据库连接信息
63#因为auth是"none", 所以不用提供password这一部分信息
64database "mydb" {
65        user "mydb" {
66                authentication "none"
67                storage "postgres_server"
68
69                pool "session"
70                server_lifetime 3600
71
72                log_debug yes
73                pool_discard yes
74
75                quantiles "0.99,0.95,0.5"
76                client_max 1007
77        }
78}
79
80database "db1" {
81        user "user1" {
82                authentication "none"
83
84                storage "postgres_server"
85
86                pool "transaction"
87                pool_ttl 10000
88                server_lifetime 10000
89                pool_size 10
90
91                log_debug yes
92                pool_discard no
93                pool_smart_discard yes
94                pool_reserve_prepared_statement yes
95
96                quantiles "0.99,0.95,0.5"
97                client_max 1007
98        }
99}
100
101database default {
102        user default {
103                authentication "none"
104
105                storage "postgres_server"
106
107                pool "session"
108                pool_size 0
109
110                pool_timeout 0
111
112                pool_ttl 1201
113
114                pool_discard no
115
116                pool_cancel yes
117
118                pool_rollback yes
119#               seconds
120                pool_client_idle_timeout 20
121#               seconds
122                pool_idle_in_transaction_timeout 20
123
124                client_fwd_error yes
125                application_name_add_host yes
126                server_lifetime 1901
127                log_debug no
128
129                quantiles "0.99,0.95,0.5"
130                client_max 107
131        }
132}
133database "postgres" {
134        user "user_aq_internal_pooling" {
135                authentication "none"
136
137                storage "postgres_server"
138
139                pool "session"
140                storage_user "reshke"
141                storage_db "postgres"
142
143                log_debug yes
144                pool_discard yes
145                pool_routing "internal"
146
147                quantiles "0.99,0.95,0.5"
148                client_max 107
149        }
150
151        user "userstmt" {
152                authentication "none"
153
154                storage "postgres_server"
155                storage_password "1"
156                pool "statement"
157                pool_size 1
158
159                pool_timeout 0
160                pool_ttl 60
161                pool_discard no
162                pool_cancel yes
163                pool_rollback yes
164
165                client_fwd_error yes
166
167                application_name_add_host yes
168                reserve_session_server_connection no
169                server_lifetime 3600
170                log_debug no
171
172                quantiles "0.99,0.95,0.5"
173                client_max 107
174        }
175
176        user "useropt" {
177                authentication "none"
178
179                storage "postgres_server"
180                storage_password "1"
181                pool "statement"
182                pool_size 1
183
184                pool_timeout 0
185                pool_ttl 60
186                pool_discard no
187                pool_cancel yes
188                pool_rollback yes
189
190                client_fwd_error yes
191
192                application_name_add_host yes
193                reserve_session_server_connection no
194                server_lifetime 3600
195                log_debug no
196
197                quantiles "0.99,0.95,0.5"
198                client_max 107
199
200#               this overrides anything passed by
201#               PGOPTIONS from client
202                options {
203                        "statement_timeout" "0"
204                }
205        }
206
207        user default {
208                authentication "none"
209                storage "postgres_server"
210                pool "session"
211        }
212}
213storage "local" {
214        type "local"
215}
216
217database "console" {
218        user default {
219                authentication "none"
220                role "admin"
221                pool "session"
222                storage "local"
223        }
224}
225
226
227locks_dir "/tmp/odyssey"
228
229graceful_die_on_errors yes
230enable_online_restart no
231bindwith_reuseport yes

值得一提的是:

 1storage "postgres_server" {
2        type "remote"
3#       host "[localhost]:5555,localhost"
4#updated. 要想支持本地连接,只用127.0.0.1
5        host "127.0.0.1"
6        port 5555
7        target_session_attrs "read-write"
8}
9
10#updated. 完整的数据库连接信息
11#因为auth是"none", 所以不用提供password这一部分信息
12database "mydb" {
13        user "mydb" {
14                authentication "none"
15                storage "postgres_server"
16
17                pool "session"
18                server_lifetime 3600
19
20                log_debug yes
21                pool_discard yes
22
23                quantiles "0.99,0.95,0.5"
24                client_max 1007
25        }
26}

storage "postgres_server"这一部分,

  • target_session_attrs 的值,针对单机单实例的PG而言,只能用:"read-write"。你如果填的是"read-only",它认为你需要访问的是standby结点。这就是两码事。

  • host "127.0.0.1",  访问本机,如果你用"localhost",  也会出错。这里统一采用"127.0.0.1"。到时候在pg_hba.conf里头对应起来就行。

database "mydb",是你真正要访问的后端数据库的相关信息。odyssey会根据你连接串中的信息遍历所有的database进行匹配,然后进去访问验证。相当于一个防火墙配置。

因为我本机启动的是5555端口,所以这里需要调整一下. 重启odyssey以后,看看log:

1[06:45:13-postgres@centos1:/usr/odyssey/conf]$ nohup odyssey odyssey-dev.conf &
2[1] 39856

看看相关日志:

 1[06:00:22-postgres@centos1:/pgccc/soft/odyssey]$ tail -f nohup.out
222526 2023-05-09T22:00:20Z info [none none] (rules)   storage                           postgres_server
322526 2023-05-09T22:00:20Z info [none none] (rules)   type                              remote
422526 2023-05-09T22:00:20Z info [none none] (rules)   host                              [localhost]:5555,centos1,[192.168.0.6]:5555
522526 2023-05-09T22:00:20Z info [none none] (rules)   port                              5555
622526 2023-05-09T22:00:20Z info [none none] (rules)   log_debug                         no
722526 2023-05-09T22:00:20Z info [none none] (rules)   log_query                         no
822526 2023-05-09T22:00:20Z info [none none] (rules)   options:                         todo
922526 2023-05-09T22:00:20Z info [none none] (rules)
1022526 2023-05-09T22:00:20Z info [none none] (server) listening on 0.0.0.0:6432
1122526 2023-05-09T22:00:20Z info [none none] (server) listening on [::]:6432

我们在本地数据库里准备一下mydb:

 1[06:47:32-postgres@centos1:/var/lib/pgsql/14/data]$ psql
2psql (14.7)
3Type "help" for help.
4
5postgres=# create database mydb;
6CREATE DATABASE
7postgres=# create user mydb with password 'test123';
8CREATE ROLE
9postgres=# grant all privileges on database mydb to mydb;
10GRANT
11
12postgres=# select usename, passwd from pg_shadow where usename = 'mydb';
13 usename |                                                                passwd
14
15-------------
16---------
17 mydb    | SCRAM-SHA-256$4096:nrsSRLtpBRvwipSIDJ5ZQw==$hYAEW/Qn7Z8hxPt4lstHOPerzKFJQqoTTMViYnE4xMU=:MJsYAH3clQm8gIg4SAfiPRnhxC8KqsXCdF4K
18MtLhR2Q=
19(1 row)
20
21-- 顺便看一下防火墙配置,默认应该是scram-sha-256
22postgres=# \! cat 14/data/pg_hba.conf
23cat: 14/data/pg_hba.conf: No such file or directory
24postgres=# \! cat /var/lib/pgsql/14/data/pg_hba.conf
25local   all             all                                     trust
26host    all             all             127.0.0.1/32            trust
27host    all             all             samenet                 scram-sha-256
28host    all             all             ::1/128                 trust
29local   replication     all                                     trust
30host    replication     all             127.0.0.1/32            trust
31host    replication     all             samenet                 scram-sha-256
32host    replication     all             ::1/128                 trust
33
34--确认一下password_encryption
35postgres=# show password_encryption ;
36 password_encryption
37---------------------
38 scram-sha-256
39(1 row)

我们尝试着连一下:

 1[06:44:44-postgres@centos1:/var/lib/pgsql/14/data]$ psql -h localhost -p 6432 -U mydb
2psql (14.7)
3Type "help" for help.
4
5mydb=> \d
6Did not find any relations.
7mydb=> create table t123(id int);
8CREATE TABLE
9mydb=> insert into t123 values(1);
10INSERT 0 1
11mydb=> select * from t123;
12 id
13----
14  1
15(1 row)

至此,这个本机机器上访问本机的连接池基本配置验证完毕。

后续,我们再进一步介绍,如何连接远程数据库,并带有相关验证方法,如: "md5", "scram-sha-256"等。同一个odyssey进程是可以配置访问很多不同的数据库的。甚至配备连接多个不同的主机。功能还是非常强大的。

甚至,如果在熟悉配置项如何配置的情况下,感觉它比pgbouncer还来得简单。

TODO:  介绍Odyssey连接池支持远程DB host, 支持scram-sha-256验证方式;同时支持读、读-写模式;基于Session和基于Transaction的区别。

4、参考

[1] https://github.com/yandex/odyssey
[2] https://github.com/yandex/odyssey/blob/master/documentation/internals.md




原文作者:数据库杂记;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2019-04-22

  • 博文量
    276
  • 访问量
    160349