PostgreSQL分布式架构之——PL/Proxy

1. PL/Proxy的介绍

1.1 PL/Proxy概述

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

1.2 PL/Proxy集群配置

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

  1. 在"CONNECT"模式中;PL/Proxy直接把请求路由(run on n)到指定的数据库。
  2. 在"CLUSTER"模式中;PL/Proxy能够支持数据水平分区,即shared nothing。也能够实现SQL语言复制(run on all)。

  在配置“CLUSTER”模式有两种方式:数据库

  1. 集群configuration API
  2. 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的配置

  本实验的配置环境以下:bash

主机名 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"模式中是不须要的oracle

4. PL/Proxy测试

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

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

相关文章
相关标签/搜索