Use pgbouncer connect to GreenPlum’s segment node

3 minute read

背景

pgbouncer是PostgreSQL数据库的轻量级开源连接池,有着非常好的性能。

源码修改部分来自老唐(osdba)写的一篇BLOG,《让pgbouncer可以连接到greenplum的segment上》本文末尾有链接。

下面参照他在BLOG中提到的方法测试了一下,测试如下 :

软件准备 :

1. greenplum环境(本例使用的是3.3.3.4) ,

2. pgbouncer 1.4.2

3. libevent 2.0

操作过程 :

1. 安装libevent :

tar -zxvf libevent-2.0.16-stable.tar.gz   
cd libevent-2.0.16-stable  
./configure && make && make install  

2. 修改pgbouncer源码, 参考osdba的BLOG :

修改src/client.c, (新增第127, 128行)增加对options的支持:

123                 } else if (varcache_set(&client->vars, key, val)) {  
124                         slog_debug(client, "got var: %s=%s", key, val);  
125                 } else if (strlist_contains(cf_ignore_startup_params, key)) {  
126                         slog_debug(client, "ignoring startup parameter: %s=%s", key, val);  
# add start point  
127                 } else if (strcmp(key,"options") == 0 ) {  
128                         slog_debug(client, "ignoring startup parameter: %s=%s", key, val);  
# add stop point  
129                 } else {  
130                         slog_warning(client, "unsupported startup parameter: %s=%s", key, val);  
131                         disconnect_client(client, true, "Unsupported startup parameter: %s", key);  
132                         return false;  
133                 }  

修改src/loader.c文件(新增第192,238-239,348-351行):

172 bool parse_database(void *base, const char *name, const char *connstr)  
173 {  
174         char *p, *key, *val;  
175         PktBuf *msg;  
176         PgDatabase *db;  
177         int pool_size = -1;  
178         int res_pool_size = -1;  
179         int dbname_ofs;  
180   
181         char *tmp_connstr;  
182         const char *dbname = name;  
183         char *host = NULL;  
184         char *port = "5432";  
185         char *username = NULL;  
186         char *password = "";  
187         char *client_encoding = NULL;  
188         char *datestyle = NULL;  
189         char *timezone = NULL;  
190         char *connect_query = NULL;  
191         char *appname = NULL;  
# add start point  
192         char *options = NULL;  
# add stop point  
.....  
206         while (*p) {  
207                 p = cstr_get_pair(p, &key, &val);  
208                 if (p == NULL) {  
209                         log_error("%s: syntax error in connstring", name);  
210                         goto fail;  
211                 } else if (!key[0])  
212                         break;  
213   
214                 if (strcmp("dbname", key) == 0)  
215                         dbname = val;  
216                 else if (strcmp("host", key) == 0)  
217                         host = val;  
218                 else if (strcmp("port", key) == 0)  
219                         port = val;  
220                 else if (strcmp("user", key) == 0)  
221                         username = val;  
222                 else if (strcmp("password", key) == 0)  
223                         password = val;  
224                 else if (strcmp("client_encoding", key) == 0)  
225                         client_encoding = val;  
226                 else if (strcmp("datestyle", key) == 0)  
227                         datestyle = val;  
228                 else if (strcmp("timezone", key) == 0)  
229                         timezone = val;  
230                 else if (strcmp("pool_size", key) == 0)  
231                         pool_size = atoi(val);  
232                 else if (strcmp("reserve_pool", key) == 0)  
233                         res_pool_size = atoi(val);  
234                 else if (strcmp("connect_query", key) == 0)  
235                         connect_query = val;  
236                 else if (strcmp("application_name", key) == 0)  
237                         appname = val;  
# add start point  
238                 else if (strcmp("options", key) == 0)  
239                         options = val;  
# add stop point  
.....  
343         if (appname) {  
344                 pktbuf_put_string(msg, "application_name");  
345                 pktbuf_put_string(msg, appname);  
346         }  
347   
# add start point  
348         if (options) {  
349                 pktbuf_put_string(msg, "options");  
350                 pktbuf_put_string(msg, options);  
351         }  
# add stop point  

3. 编译安装修改过的pgbouncer1.4.2

tar -zxvf pgbouncer-1.4.2.tgz  
cd pgbouncer-1.4.2  
./configure --prefix=/opt/pgbouncer  
gmake  
gmake install  

4. 配置某个需要被pgbouncer连接的greenplum segment节点的pg_hba.conf, reload配置文件,

在pg_hba.conf加入对pgbouncer服务器的允许, 例如 :

host all all 0.0.0.0/0 md5  
pg_ctl reload -D $PGDATA  

5. 配置pgbouncer, 启动

# 在[databases]章节多出的部分是 options='-c gp_session_role=utility'   
vi config.ini   
  
[databases]  
sanpdw = host=172.16.12.12 dbname=digoal port=50001 pool_size=5 options='-c gp_session_role=utility'  
[pgbouncer]  
pool_mode = transaction  
listen_port = 11111  
unix_socket_dir = /opt/pgbouncer/etc  
listen_addr = *  
auth_type = md5  
auth_file = /opt/pgbouncer/etc/users11111.txt  
logfile = /dev/null  
pidfile = /opt/pgbouncer/etc/pgbouncer11111.pid  
max_client_conn = 10000  
reserve_pool_timeout = 0  
server_reset_query =   
admin_users = pgbouncer_admin  
stats_users = pgbouncer_guest  
ignore_startup_parameters = extra_float_digits  
server_lifetime = 60  
server_check_query = select 1  
server_check_delay = 5  
  
  
  
vi users11111.txt   
  
"digoal" "md57bc4a6cbe56da1w1f1cbf27d3d3045d5"  
  
chmod 700 config.ini  
chmod 400 users11111.txt  

启动pgbouncer

export LD_LIBRARY_PATH=/lib64:/usr/lib64:/usr/local/lib64:/lib:/usr/lib:/usr/local/lib  
./pgbouncer/bin/pgbouncer -d -u postgres ./pgbouncer/etc/config.ini  

6. 连接测试

找一台安装了PostgreSQL客户端的机子连接pgbouncer的11111端口 :

psql -h 172.16.13.13 -p 11111 -U digoal -d digoal -W  

输入密码后就登陆到GreenPlum的segment (172.16.12.12:50001)了.

psql -h 172.16.13.13 -p 11111 -U digoal -d digoal -W  
Password for user digoal:   
psql (9.0.1, server 8.2.13)  
WARNING: psql version 9.0, server version 8.2.  
         Some psql features might not work.  
Type "help" for help.  
digoal=>   

小结

1. 这种连接方式可以干什么事情呢? 我想了想, 以前遇到过在主节点无法创建表的情形, 原因是该表名在segment节点存在了, 遇到这种情况可能是删表的时候主节点删除了但是segment节点未删除, 当然这种情况很少见.

2. 在主库无法使用的时候可以利用这种方法对外提供少量服务.

3. 通过这种方式连进去一定要小心操作, 千万别在里面胡乱建表, greenplum的正规操作还是通过master来做比较靠谱.

参考

http://blog.osdba.net/?post=69

Flag Counter

digoal’s 大量PostgreSQL文章入口