zoukankan      html  css  js  c++  java
  • PostgreSQL分布式架构之——PL/Proxy

    1. PL/Proxy的介绍

    1.1 PL/Proxy概述

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

    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

    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

  • 相关阅读:
    九个PHP有用功能
    ajax的上拉功能
    jquery 插件
    任务08(全体)——第一次半月学习总结
    任务02——安装 Intellj IDEA,编写一个简易四则运算小程序,并将代码提交到 GitHub
    任务01——谈谈对参与工作室的预期
    任务08
    任务03
    任务02
    任务01
  • 原文地址:https://www.cnblogs.com/lottu/p/9182804.html
Copyright © 2011-2022 走看看