PL/Proxy是一款能在PostgreSQL數據庫實現數據庫水平拆分的軟件;能夠理解分佈式架構(shared nothing);可是不是真正的分佈式數據庫軟件;也是一款能在PostgreSQL數據庫實現SQL語言複製(replication)
分佈式架構圖以下:node
PL/Proxy既能配置成「CONNECT」模式又能配置成「CLUSTER」模式sql
在配置「CLUSTER」模式有兩種方式:數據庫
執行「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
在這裏我選「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)
本實驗的配置環境以下: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
PL/Proxy把須要對數據庫SQL訪問轉換爲對PostgreSQL函數調用;這就須要使用者有良好的編程功底。
在數據節點建立測試樣本表app
create table users(userid int, name text);
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
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"。
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)
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
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
proxy=# SELECT TRUNC_USER(); trunc_user ------------ 1 1 1 1 (4 rows)
其實在這裏咱們已經驗證數據複製(replication)測試。爲了更好解釋;咱們選擇insert函數接口來。
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=# 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)
使用"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」;用法很簡單;做用很雞肋。
PL/Proxy的語法本文差很少都涉及到了。至於經過「集羣configuration API」方式配置集羣,本文不講解了;其實配置也很簡單。
https://yq.aliyun.com/articles/59372?spm=a2c4e.11153940.blogcont59345.17.46039916yDaqtq