PostgreSQL分布式架构之PL/Proxy篇

1. PL/Proxy的介绍

1.1 PL/Proxy概述

PL/Proxy是一款能在PostgreSQL数据库实现数据库水平拆分的软件;可以理解分布式架构(shared nothing);但是不是真正的分布式数据库软件;也是一款能在PostgreSQL数据库实现SQL语言复制(replication)
分布式架构图如下:


Proxy.png

1.2 PL/Proxy集群配置

PL/Proxy既能配置成“CONNECT”模式又能配置成“CLUSTER”模式

  1. 在"CONNECT"模式中;PL/Proxy直接把请求路由(run on n)到指定的数据库。
  2. 在"CLUSTER"模式中;PL/Proxy可以支持数据水平分区,即shared nothing。也可以实现SQL语言复制(run on all)。
在配置“CLUSTER”模式有两种方式:
1. 集群configuration API
2. SQL/MED
由于SQL/MED配置简单,性能又好。所以通选第二种方式(SQL/MED)。

1.3 PL/Proxy特性介绍

  1. PL/Proxy把需要对数据库SQL访问转换为对PostgreSQL函数调用。
  2. PL/Proxy后端数据库节点数必须是2的N次方。

2. PL/Proxy安装

2.1 编译安装

执行“source /home/postgres/.bashrc”加载环境变量;目的确保来自postgresql bin目录的pgconfig在您的路径中

tar -zxvf plproxy-2.7.tar.gz
cd plproxy-2.7
source /home/postgres/.bashrc
make
make install

2.2 创建PL/Proxy扩展

在这里我选“proxy”数据库作为路由代理数据库。

[postgres@Postgres201 ~]$ psql
psql (9.6.0)
Type "help" for help.

postgres=# create database proxy;
CREATE DATABASE
postgres=# \c proxy
You are now connected to database "proxy" as user "postgres".
proxy=# create extension plproxy;
CREATE EXTENSION
proxy=# \dx
                               List of installed extensions
  Name   | Version |   Schema   |                       Description                        
---------+---------+------------+----------------------------------------------------------
 plpgsql | 1.0     | pg_catalog | PL/pgSQL procedural language
 plproxy | 2.7.0   | public     | Database partitioning implemented as procedural language
(2 rows)

3. PL/Proxy的配置

本实验的配置环境如下:

主机名 IP 角色 数据库名 用户
PostgreSQL201 192.168.1.201 proxy node proxy lottu
PostgreSQL202 192.168.1.202 data node pl_db0 lottu
PostgreSQL202 192.168.1.202 data node pl_db1 lottu
PostgreSQL202 192.168.1.202 data node pl_db2 lottu
PostgreSQL202 192.168.1.202 data node pl_db3 lottu

修改数据节点的pg_hba.conf

要确保PL/Proxy节点能访问所有数据库。
host    all             all             192.168.1.0/24        trust
当然在线上数据库大家可以这样配置,例如:
host    all             lottu             192.168.1.201/24        md5

采用SQL/MED方式配置集群【在PL/Proxy节点操作
创建一个使用plproxy FDW的服务器来完成的。服务器的选项是PL/Proxy配置设置和集群分区列表。

[postgres@Postgres201 ~]$ psql proxy lottu
psql (9.6.0)
Type "help" for help.

proxy=# \c
You are now connected to database "proxy" as user "lottu".
proxy=# CREATE SERVER cluster_srv1 FOREIGN DATA WRAPPER plproxy
proxy-#         OPTIONS (
proxy(#                 connection_lifetime '1800',
proxy(#                 disable_binary '1',
proxy(#                 p0 'dbname=pl_db0 host=192.168.1.202',
proxy(#                 p1 'dbname=pl_db1 host=192.168.1.202',
proxy(#                 p2 'dbname=pl_db2 host=192.168.1.202',
proxy(#                 p3 'dbname=pl_db3 host=192.168.1.202'
proxy(#                 );
CREATE SERVER
proxy=# \des
           List of foreign servers
     Name     | Owner | Foreign-data wrapper 
--------------+-------+----------------------
 cluster_srv1 | lottu | plproxy
(1 row)

proxy=# grant usage on FOREIGN server cluster_srv1 to lottu;  
GRANT

创建用户映射
proxy=# create user mapping for lottu server cluster_srv1 options (user 'lottu');
CREATE USER MAPPING
proxy=# \deu
  List of user mappings
    Server    | User name 
--------------+-----------
 cluster_srv1 | lottu
(1 row) 

配置完成!在"CLUSTER"模式中;才需要上述配置;在"CONNECT"模式中是不需要的。

4. PL/Proxy测试

PL/Proxy把需要对数据库SQL访问转换为对PostgreSQL函数调用;这就需要使用者有良好的编程功底。
在数据节点创建测试样本表

create table users(userid int, name text);

4.1 "CLUSTER"模式测试

4.1.1 数据水平拆分测试

  1. 在每个数据节点创建insert函数接口
pl_db0=> CREATE OR REPLACE FUNCTION insert_user(i_id int, i_name text)
pl_db0-> RETURNS integer AS $$
pl_db0$>        INSERT INTO users (userid, name) VALUES ($1,$2);
pl_db0$>        SELECT 1;
pl_db0$> $$ LANGUAGE SQL;
CREATE FUNCTION
  1. 在PL/Proxy数据库创建同名的insert函数接口
proxy=# CREATE OR REPLACE FUNCTION insert_user(i_id int, i_name text)
proxy-# RETURNS integer AS $$
proxy$#     CLUSTER 'cluster_srv1';
proxy$#     RUN ON ANY;
proxy$# $$ LANGUAGE plproxy;
CREATE FUNCTION

为什么要同名的函数呢?若不是同名的话;需要在函数里面添加一个"TRAGET INSERT_USER";表明从数据节点调用函数"INSERT_USER"。

  1. 在PL/Proxy数据库创建读的函数get_user_name()
proxy=# CREATE OR REPLACE FUNCTION get_user_name()
RETURNS TABLE(userid int, name text) AS $$
    CLUSTER 'cluster_srv1';
    RUN ON ALL ;
SELECT userid,name FROM users;
$$ LANGUAGE plproxy;
CREATE FUNCTION

Ok;现在函数接口开发完成;我现在来调用函数插入10条记录。

SELECT insert_user(1001, 'Sven');
SELECT insert_user(1002, 'Marko');
SELECT insert_user(1003, 'Steve');
SELECT insert_user(1004, 'lottu');
SELECT insert_user(1005, 'rax');
SELECT insert_user(1006, 'ak');
SELECT insert_user(1007, 'jack');
SELECT insert_user(1008, 'molica');
SELECT insert_user(1009, 'pg');
SELECT insert_user(1010, 'oracle');

由于函数执行的是"RUN ON ANY";表明插入数据是随机选取数据节点。我们看看每个数据节点的数据

pl_db0=> select * from users;
 userid |  name  
--------+--------
   1005 | rax
   1006 | ak
   1008 | molica
   1009 | pg
(4 rows)

pl_db1=> select * from users;
 userid | name  
--------+-------
   1002 | Marko
   1004 | lottu
(2 rows)

pl_db2=> select * from users;
 userid |  name  
--------+--------
   1007 | jack
   1010 | oracle
(2 rows)

pl_db3=> select * from users;
 userid | name  
--------+-------
   1001 | Sven
   1003 | Steve
(2 rows)

可以看出10条数据已经切分到每个数据节点。(10条取样太少,导致数据不均匀)。我们在proxy节点查询下。

proxy=# SELECT USERID,NAME FROM GET_USER_NAME();
 userid |  name  
--------+--------
   1005 | rax
   1006 | ak
   1008 | molica
   1009 | pg
   1002 | Marko
   1004 | lottu
   1007 | jack
   1010 | oracle
   1001 | Sven
   1003 | Steve
(10 rows)

4.1.2数据复制(replication)测试

  1. 选择users表作为实验对象;我们先清理表users数据;在数据节点创建truncatet函数接口
pl_db0=> CREATE OR REPLACE FUNCTION trunc_user()
pl_db0-> RETURNS integer AS $$
pl_db0$>        truncate table users;
pl_db0$>        SELECT 1;
pl_db0$> $$ LANGUAGE SQL;
CREATE FUNCTION
  1. 在PL/Proxy数据库创建同名的truncate函数接口
proxy=# CREATE OR REPLACE FUNCTION trunc_user()
proxy-# RETURNS SETOF integer AS $$
proxy$#     CLUSTER 'cluster_srv1';
proxy$#     RUN ON ALL;
proxy$# $$ LANGUAGE plproxy;
CREATE FUNCTION
  1. 执行之后trunc_user();数据已经清理了。
proxy=# SELECT TRUNC_USER();
 trunc_user 
------------
          1
          1
          1
          1
(4 rows)

其实在这里我们已经验证数据复制(replication)测试。为了更好解释;我们选择insert函数接口来。

  1. 在PL/Proxy数据库创建函数接口 insert_user_2
proxy=# CREATE OR REPLACE FUNCTION insert_user_2(i_id int, i_name text)
proxy-# RETURNS SETOF integer AS $$
proxy$#     CLUSTER 'cluster_srv1';
proxy$#     RUN ON ALL;
proxy$# TARGET insert_user;
proxy$# $$ LANGUAGE plproxy;
CREATE FUNCTION

我们选择这几条语句

proxy=# SELECT insert_user_2(1004, 'lottu');
proxy=# SELECT insert_user_2(1005, 'rax');
proxy=# SELECT insert_user_2(1006, 'ak');
proxy=# SELECT insert_user_2(1007, 'jack');
  1. 我们看看每个数据节点的数据。
pl_db0=> select * from users;
 userid | name  
--------+-------
   1004 | lottu
   1005 | rax
   1006 | ak
   1007 | jack
(4 rows)

pl_db1=> select * from users;
 userid | name  
--------+-------
   1004 | lottu
   1005 | rax
   1006 | ak
   1007 | jack
(4 rows)

pl_db2=> select * from users;
 userid | name  
--------+-------
   1004 | lottu
   1005 | rax
   1006 | ak
   1007 | jack
(4 rows)

pl_db3=> select * from users;
 userid | name  
--------+-------
   1004 | lottu
   1005 | rax
   1006 | ak
   1007 | jack
(4 rows)

每个节点的数据都是一样的。完成了数据复制(replication)测试。

  1. 我们在proxy节点查询下。只要在任意数据节点读取数据即可;我们先编辑函数。
proxy=# CREATE OR REPLACE FUNCTION get_user_name_2()
proxy-# RETURNS TABLE(userid int, name text) AS $$
proxy$#     CLUSTER 'cluster_srv1';
proxy$#     RUN ON ANY ;
proxy$# SELECT userid,name FROM users;
proxy$# $$ LANGUAGE plproxy; 
CREATE FUNCTION
proxy=# SELECT USERID,NAME FROM GET_USER_NAME_2();
 userid | name  
--------+-------
   1004 | lottu
   1005 | rax
   1006 | ak
   1007 | jack
(4 rows)

4.2 "CONNECT"模式测试

使用"CONNECT"模式;PL/Proxy不需要上述的配置;直接使用即可。

proxy=# CREATE OR REPLACE FUNCTION get_user_name_3()
proxy-# RETURNS TABLE(userid int, name text) AS $$
proxy$#     CONNECT 'dbname=pl_db0 host=192.168.1.202';
proxy$# CONNECT 'dbname=pl_db1 host=192.168.1.202';
proxy$# SELECT userid,name FROM users;
proxy$# $$ LANGUAGE plproxy; 
ERROR:  PL/Proxy function lottu.get_user_name_3(0): Compile error at line 3: Only one CONNECT statement allowed
proxy=# CREATE OR REPLACE FUNCTION get_user_name_3()
proxy-# RETURNS TABLE(userid int, name text) AS $$
proxy$#     CONNECT 'dbname=pl_db0 host=192.168.1.202';
proxy$# SELECT userid,name FROM users;
proxy$# $$ LANGUAGE plproxy; 
CREATE FUNCTION 
proxy=# SELECT USERID,NAME FROM GET_USER_NAME_3();
 userid | name  
--------+-------
   1004 | lottu
   1005 | rax
   1006 | ak
   1007 | jack
(4 rows)

只允许一个“CONNECT statement”;用法很简单;作用很鸡肋。

5. 总结

PL/Proxy的语法本文差不多都涉及到了。至于通过“集群configuration API”方式配置集群,本文不讲解了;其实配置也很简单。

6. 参考文档

https://yq.aliyun.com/articles/59372?spm=a2c4e.11153940.blogcont59345.17.46039916yDaqtq

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容

  • PL/Proxy可以在CONNECT模式或CLUSTER模式下使用。在“连接”模式下,PL/Proxy充当到另一个...
    只有香如故阅读 2,568评论 0 1
  • feisky云计算、虚拟化与Linux技术笔记posts - 1014, comments - 298, trac...
    不排版阅读 3,805评论 0 5
  • About:PostgreSQL About 《PostgreSQL 源码分析系列》 PostgreSQL 源码分...
    ty4z2008阅读 8,150评论 1 40
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,563评论 18 139
  • 你选择你想要看到的一切 跟随哪一个人 推开哪一扇门 透过白色面具 徐徐拼凑出一个你眼中的世界 至于这世界是虚是实 ...
    饭花阅读 342评论 0 1