搜索
您的当前位置:首页正文

PostgreSQL分布式架构之——PLProxy

来源:知库网
PostgreSQL分布式架构之——PLProxy

1. PL/Proxy的介绍

1.1 PL/Proxy概述

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

1.2 PL/Proxy集群配置

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

在\"CONNECT\"模式中;PL/Proxy直接把请求路由(run on n)到指定的数据库。

在\"CLUSTER\"模式中;PL/Proxy可以⽀持数据⽔平分区,即shared nothing。也可以实现SQL语⾔复制(run on all)。  在配置“CLUSTER”模式有两种⽅式:集群configuration APISQL/MED

1.3 PL/Proxy特性介绍

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

2. PL/Proxy安装

2.1 编译安装

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

tar -zxvf plproxy-2.7.tar.gzcd plproxy-2.7

source /home/postgres/.bashrcmake

make install

2.2 创建PL/Proxy扩展

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

[postgres@Postgres201 ~]$ psqlpsql (9.6.0)

Type \"help\" for help.

postgres=# create database proxy;CREATE DATABASEpostgres=# \\c proxy

You are now connected to database \"proxy\" as user \"postgres\".proxy=# create extension plproxy;CREATE EXTENSIONproxy=# \\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的配置

  本实验的配置环境如下:

主机名

PostgreSQL201PostgreSQL202PostgreSQL202PostgreSQL202PostgreSQL202

  修改数据节点的pg_hba.conf

IP

192.168.1.201192.168.1.202192.168.1.202192.168.1.202192.168.1.202

⾓⾊proxy nodedata nodedata nodedata nodedata node

数据库名proxypl_db0pl_db1pl_db2pl_db3

⽤户lottulottulottulottulottu

要确保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 lottupsql (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 plproxyproxy-# 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 SERVERproxy=# \\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 MAPPINGproxy=# \\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 数据⽔平拆分测试

在每个数据节点创建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

在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\"。在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)测试

选择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

在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

执⾏之后trunc_user();数据已经清理了。

proxy=# SELECT TRUNC_USER(); trunc_user ------------ 1 1 1 1(4 rows)

  其实在这⾥我们已经验证数据复制(replication)测试。为了更好解释;我们选择insert函数接⼝来。在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');

我们看看每个数据节点的数据。

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)测试。

我们在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 allowedproxy=# 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. 参考⽂档

因篇幅问题不能全部显示,请点此查看更多更全内容

Top