postgresql分布式數據庫方案stado


http://xmarker.blog.163.com/blog/static/22648405720131125560959/

最近一直在尋找postgresql的分布式解決方案,試過pgpool-ii,plproxy,但都不太滿意,昨天意外發現了一種開源的分布式postgresql解決方案,stado,前身是enterprise公司開發的gridsql(開源,但現在已經停止更新),今天測試后發現和阿里的cobar有點類似,在此分享下安裝和初步試用。

 
(一).下載stado軟件,地址為:http://www.stormdb.com/community/stado
 
(二).規划實驗環境:
主機: pgtest4 pgtest5 pgtest6
ip地址 10.1.1.13 10.1.1.14 10.1.1.15
操作系統 centos6.4 centos6.4 centos6.4
其中pgtest4、pgtest5、pgtest6都是做數據節點,其中pgtest4還做stado節點。
 
(三).創建stado用戶和相關安裝目錄:
[stado@pgtest4 ~]$ tar -zxvf stado_2_5.tar.gz 
[stado@pgtest4 ~]$ chown -R stado:stadogrp stado
[stado@pgtest4 ~]$ chmod 700  stado/bin/*.sh
[stado@pgtest4 ~]$ chmod 775  stado/log
[stado@pgtest4 ~]$ chmod 755  stado/bin/gs-cmdline.sh 
[stado@pgtest4 ~]$ chmod 600  stado/config/*
因為stado代理節點只在pgtest4上安裝就行了,因此只需在pgtest4上安裝,我把stado安裝在/home/stado下了,當然也可以安裝在別處。
 
(四).在每個節點安裝postgresql軟件及數據庫(略)
 
(五)在每個節點數據庫中創建用戶

創建用戶(每個節點):


createuser –d –E stado –U postgres -P

創建.pgpass文件,這樣可以不用輸密碼就能直接連接

/home/postgres@pgtest4$cat .pgpass 
*:*:*:stado:123456
chmod 600 .pgpass

 

(六).在stado節點(pgtest4)上修改配置文件
 
[stado@pgtest4 stado]$ cd /home/stado/stado/config/
[stado@pgtest4 config]$ ls
stado_agent.config  stado.config
[stado@pgtest4 config]$ vim stado.config
xdb.port=6453
xdb.maxconnections=10
xdb.default.dbusername=stado
xdb.default.dbpassword=123456
xdb.default.dbport=5432
xdb.default.threads.pool.initsize=5
xdb.default.threads.pool.maxsize=10
xdb.metadata.database=XDBSYS
xdb.metadata.dbhost=127.0.0.1
xdb.nodecount=3
xdb.node.1.dbhost=pgtest4
xdb.node.2.dbhost=pgtest5
xdb.node.3.dbhost=pgtest6
xdb.coordinator.node=1
修改以上配置即可,其他的可以不用修改。
 
(七).在stado節點(pgtest4)上創建metadata數據庫
 
[stado@pgtest4 bin]$ ./gs-createmddb.sh -u admin -p secret
Executed Statement: create table xsystablespaces ( tablespaceid serial, tablespacename varchar(255) not null, ownerid int not null, primary key(tablespaceid))
Executed Statement: create unique index idx_xsystablespaces_1 on xsystablespaces (tablespacename)
Executed Statement: create table xsystablespacelocs ( tablespacelocid int not null, tablespaceid int not null, filepath varchar(1024) not null, nodeid int not null, primary key(tablespacelocid))
Executed Statement: create unique index idx_xsystablespacelocs_1 on xsystablespacelocs (tablespaceid, nodeid)
....
Executed Statement: create unique index idx_xsyschecks_1 on xsyschecks (constid, seqno)
Executed Statement: alter table xsyschecks add foreign key (constid) references xsysconstraints (constid)
User admin is created
 
(八).啟動stado
 
[stado@pgtest4 bin]$ ./gs-server.sh
Starting....
 
(九).創建用戶數據庫
 
[stado@pgtest4 bin]$ ./gs-createdb.sh -d xtest -u admin -p secret -n 1,2,3 
OK
 
登陸各個節點后應該能看到xtest數據庫,如
__xtest__N2=# \l
                                      List of databases
      Name      |    Owner     | Encoding |   Collate   |    Ctype    |   Access privileges   
----------------+--------------+----------+-------------+-------------+-----------------------
 __xtest__N2    | stado        | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
 
(十).登陸數據庫
第八步創建用戶數據庫后,stado會自動啟動,這時登陸stado管理界面即可做數據操作:
[stado@pgtest4 bin]$ ./gs-cmdline.sh -d xtest -u admin -p secret
Stado -> show databases;
+----------------------------+
| DATABASE |  STATUS | NODES |
+----------------------------+
| xtest    | Started | 1,2,3 |
+----------------------------+
1 row(s).
創建表:
Stado -> CREATE TABLE mytable1 (col1 INT)  PARTITIONING KEY col1 ON ALL;
OK
 
Stado -> INSERT INTO mytable1 VALUES (1);
1 row(s) affected
 
Stado -> INSERT INTO mytable1 VALUES (2);
1 row(s) affected
 
Stado -> SELECT * FROM mytable1;              
+------+
| col1 |
+------+
|    2 |
|    1 |
+------+
2 row(s).
 
Stado -> INSERT INTO mytable1 VALUES (3);
1 row(s) affected
 
Stado ->  SELECT * FROM mytable1;    
+------+
| col1 |
+------+
|    2 |
|    1 |
|    3 |
+------+
3 row(s).
Stado -> show tables;
+----------------------------------------------------+
|  TABLE   | TABLE_PARTITIONING_COLUMN | TABLE_NODES |
+----------------------------------------------------+
| mytable1 | col1                      | 1,2,3       |
+----------------------------------------------------+
1 row(s).
 
以上就是簡單的安裝及測試,下一篇將會介紹常用命令和操作。
 
http://xmarker.blog.163.com/blog/static/22648405720131126350993/
上篇介紹了stado的安裝及配置,本篇簡單介紹下常用命令和表分區用法
(一).停止stado :
如我們在pgtest5這個數據節點上查看stado進程,會發現如下進程在連接到真實的數據庫上:
[root@pgtest5 ~]# ps -ef|grep stado
postgres  1942  1815  0 10:59 ?        00:00:00 postgres: stado __xtest__N2 10.1.1.13(41465) idle
postgres  1943  1815  0 10:59 ?        00:00:00 postgres: stado __xtest__N2 10.1.1.13(41470) idle
postgres  1944  1815  0 10:59 ?        00:00:00 postgres: stado __xtest__N2 10.1.1.13(41471) idle
postgres  1945  1815  0 10:59 ?        00:00:00 postgres: stado __xtest__N2 10.1.1.13(41472) idle
postgres  1946  1815  0 10:59 ?        00:00:00 postgres: stado __xtest__N2 10.1.1.13(41473) idle
root      2085  2064  0 11:23 pts/1    00:00:00 grep stado
 
關閉stado進程:
[stado@pgtest4 bin]$ ./gs-dbstop.sh -d xtest -u admin -p secret
Database(s) xtest stopped.
 
[root@pgtest5 ~]# ps -ef|grep stado
root      4085  2064  0 18:38 pts/1    00:00:00 grep stado
 
(二).啟動stado:
開啟stado進程:
[stado@pgtest4 bin]$ ./gs-dbstart.sh -d xtest -u admin -p secret
Database(s) xtest started.
 
[root@pgtest5 ~]# ps -ef|grep stado
postgres  4101  1815  0 18:41 ?        00:00:00 postgres: stado __xtest__N2 10.1.1.13(41496) idle in transaction
postgres  4102  1815  0 18:41 ?        00:00:00 postgres: stado __xtest__N2 10.1.1.13(41499) idle
postgres  4103  1815  0 18:41 ?        00:00:00 postgres: stado __xtest__N2 10.1.1.13(41502) idle
postgres  4104  1815  0 18:41 ?        00:00:00 postgres: stado __xtest__N2 10.1.1.13(41505) idle
postgres  4105  1815  0 18:41 ?        00:00:00 postgres: stado __xtest__N2 10.1.1.13(41507) idle
root      4112  2064  0 18:42 pts/1    00:00:00 grep stado
 
(三)刪除一個數據庫連接:
[stado@pgtest4 bin]$ ./gs-dbstop.sh -d abc -u admin -p secret
Database(s) abc stopped.
[stado@pgtest4 bin]$ ./gs-dropdb.sh -d abc -u admin -p secret
OK
刪除數據庫及其鏈接需要先停止數據庫的連接進程,然后才能在數據庫中刪除。
 
(四)創建一個stado數據庫
[stado@pgtest4 bin]$ ./gs-createdb.sh -d abc  -u admin -p secret -n 1,2,3
OK
 
(五)創建一個復制模式的表
Stado -> create table t (id int primary key,name text)  REPLICATED ;
OK
 
Stado -> insert into t values(1,'abc');
1 row(s) affected
 
Stado -> insert into t values(2,'bcd');
1 row(s) affected
 
在各個節點上查看數據:
__xtest__N1=# select * from t;
 id | name 
----+------
  1 | abc
  2 | bcd
(2 rows)
 
__xtest__N2=# select * from t;
 id | name 
----+------
  1 | abc
  2 | bcd
(2 rows)
 
(六)創建一個partition模式的表
Stado -> create table t2 (area_id int,area_name varchar(20),descs text)  partitioning key area_id on all;
OK
 
插入數據:
insert into t2 values(10002,'xishan','test');
insert into t2 values(10002,'xishan','fasdasdf');
insert into t2 values(10002,'xishan','testfasdf');
insert into t2 values(10001,'jiangyin','testfasdf');
insert into t2 values(10003,'yichang','test22');
insert into t2 values(10003,'yichang','test22');
insert into t2 values(10003,'yichang','test2yichang');
insert into t2 values(10003,'yichang','test22fasdfas');
 
Stado -> select * from t2;
+-------------------------------------+
| area_id | area_name |     descs     |
+-------------------------------------+
|   10001 | jiangyin  | test          |
|   10002 | xishan    | test          |
|   10001 | jiangyin  | testfasdf     |
|   10002 | xishan    | test          |
|   10003 | yichang   | test22        |
|   10002 | xishan    | fasdasdf      |
|   10003 | yichang   | test22        |
|   10002 | xishan    | testfasdf     |
|   10003 | yichang   | test2yichang  |
|   10003 | yichang   | test22fasdfas |
+-------------------------------------+
10 row(s).
 
在各個節點查看數據分布:
pgtest4:
__xtest__N1=# select * from t2;
LOG:  statement: select * from t2;
 area_id | area_name |     descs     
---------+-----------+---------------
   10001 | jiangyin  | test
   10001 | jiangyin  | testfasdf
   10003 | yichang   | test22
   10003 | yichang   | test22
   10003 | yichang   | test2yichang
   10003 | yichang   | test22fasdfas
(6 rows)
 
pgtest5:
__xtest__N2=# select * from t2;
 area_id | area_name |   descs   
---------+-----------+-----------
   10002 | xishan    | test
   10002 | xishan    | test
   10002 | xishan    | fasdasdf
   10002 | xishan    | testfasdf
(4 rows)
 
pgtest6:
__xtest__N3=# select * from t2;
 area_id | area_name | descs 
---------+-----------+-------
(0 rows)
發現按area_id分區也沒用完全均衡的分區,這個還需要進一步研究。
 
(七)創建一個 ROUND ROBIN 模式的表
Stado -> create table t3 (area_id int ,name varchar2(30)) ROUND ROBIN ON all;
OK
 
Stado -> insert into t3 values(1001,'jiangyi');
1 row(s) affected
 
Stado ->  insert into t3 values(1002,'xishan');
1 row(s) affected
 
Stado -> insert into t3 values(1003,'yichang');
1 row(s) affected
 
Stado -> select * from t3;
+-------------------+
| area_id |  name   |
+-------------------+
|    1003 | yichang |
|    1001 | jiangyi |
|    1002 | xishan  |
+-------------------+
3 row(s).
在pgtest4上查看:
__xtest__N1=# select * from t3;
LOG:  statement: select * from t3;
 area_id |  name   
---------+---------
    1003 | yichang
(1 row)
__xtest__N2=# select * from t3;
 area_id |  name   
---------+---------
    1001 | jiangyi
(1 rows)
__xtest__N3=# select * from t3;
 area_id |  name  
---------+--------
    1002 | xishan
(1 row)
可以看到,這個是輪訓方式進行插入數據的。
 
參考:
 
http://xmarker.blog.163.com/blog/static/2264840572013112105159991/
上兩節分別對stado的安裝配置及常用命令進行了實驗,本篇將進一步對表關聯、分庫方式進行實驗。
(一)創建stado支持的三種類型的表:
根據列值hash分區(partitioning)、輪換分區(roundrobin)、復制模式(replicated),注意,不支持range分區,也就說要按某個列的某些范圍值分區是不支持的。
 
Stado -> create table t_partition (id int,name varchar(30)) partitioning key id on all;
OK
 
Stado ->  insert into t_partition  select generate_series(1,100)::int,'mcl'::varchar(30);
100 row(s) affected
 
Stado -> create table t_replicate (id int,name varchar(30)) replicated;
OK
 
Stado -> insert into t_replicate select generate_series(1,100)::int,'mcl'::varchar(30);
100 row(s) affected
 
Stado -> create table t_roundrobin (id int,name varchar(30)) round robin on all;
OK
 
Stado -> insert into t_roundrobin select generate_series(1,100)::int,'mcl'::varchar(30);
100 row(s) affected
 
以上分別建了三種類型的表,都分別插入100條數據
 
(二)三種表關聯查詢:
Stado -> select * from t_partition a,t_replicate b where a.id=b.id;
+-------------------------+
|  id | name |  id | name |
+-------------------------+
|  11 | mcl  |  11 | mcl  |
|  13 | mcl  |  13 | mcl  |
|  14 | mcl  |  14 | mcl  |
|  22 | mcl  |  22 | mcl  |
....
| 100 | mcl  | 100 | mcl  |
+-------------------------+
100 row(s).
我們看下執行計划:
Stado -> explain select * from t_partition a,t_replicate b where a.id=b.id;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|                                                                                                    Query Plan                                                                                                    |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|                                                                                                                                                                                                                  |
|  Step: 0                                                                                                                                                                                                         |
|  -------                                                                                                                                                                                                         |
|  Target: CREATE UNLOGGED TABLE "TMPTT23_1" ( "id" INT, "name" VARCHAR (30))  WITHOUT OIDS                                                                                                                        |
|  Select: SELECT "a"."id" AS "id","a"."name" AS "name" FROM "t_partition" "a"                                                                                                                                     |
|                                                                                                                                                                                                                  |
|                                                                                                                                                                                                                  |
|  Step: 1                                                                                                                                                                                                         |
|  -------                                                                                                                                                                                                         |
|  Select: SELECT "TMPTT23_1"."id" AS "id","TMPTT23_1"."name" AS "name","b"."id" AS "EXPRESSION1","b"."name" AS "EXPRESSION2" FROM "TMPTT23_1"  CROSS JOIN "t_replicate" "b"   WHERE ("TMPTT23_1"."id" = "b"."id") |
|   Drop:                                                                                                                                                                                                          |
|  TMPTT23_1                                                                                                                                                                                                       |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
12 row(s).
可以看到,join操作分兩步,第一步建unlogged 表TMPTT23_1,並插入t_partition的數據,第二步根據TMPTT23_1數據關聯t_replicate得到最終數據。
 
同樣的,partition表和roundrobin表也可以關聯查到同樣數據,看下執行計划(和上一步類似):
Stado -> explain select * from t_partition a,t_roundrobin b where a.id=b.id;
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|                                                                                                    Query Plan                                                                                                     |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|                                                                                                                                                                                                                   |
|  Step: 0                                                                                                                                                                                                          |
|  -------                                                                                                                                                                                                          |
|  Target: CREATE UNLOGGED TABLE "TMPTT25_1" ( "id" INT, "name" VARCHAR (30))  WITHOUT OIDS                                                                                                                         |
|  Select: SELECT "a"."id" AS "id","a"."name" AS "name" FROM "t_partition" "a"                                                                                                                                      |
|                                                                                                                                                                                                                   |
|                                                                                                                                                                                                                   |
|  Step: 1                                                                                                                                                                                                          |
|  -------                                                                                                                                                                                                          |
|  Select: SELECT "TMPTT25_1"."id" AS "id","TMPTT25_1"."name" AS "name","b"."id" AS "EXPRESSION1","b"."name" AS "EXPRESSION2" FROM "TMPTT25_1"  CROSS JOIN "t_roundrobin" "b"   WHERE ("TMPTT25_1"."id" = "b"."id") |
|   Drop:                                                                                                                                                                                                           |
|  TMPTT25_1                                                                                                                                                                                                        |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
12 row(s).
 
同樣的,roundrobin和replicate也可以查出同樣的數據:
Stado -> explain  select * from t_roundrobin a,t_replicate b where a.id=b.id;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|                                                                                                    Query Plan                                                                                                    |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|                                                                                                                                                                                                                  |
|  Step: 0                                                                                                                                                                                                         |
|  -------                                                                                                                                                                                                         |
|  Target: CREATE UNLOGGED TABLE "TMPTT27_1" ( "id" INT, "name" VARCHAR (30))  WITHOUT OIDS                                                                                                                        |
|  Select: SELECT "a"."id" AS "id","a"."name" AS "name" FROM "t_roundrobin" "a"                                                                                                                                    |
|                                                                                                                                                                                                                  |
|                                                                                                                                                                                                                  |
|  Step: 1                                                                                                                                                                                                         |
|  -------                                                                                                                                                                                                         |
|  Select: SELECT "TMPTT27_1"."id" AS "id","TMPTT27_1"."name" AS "name","b"."id" AS "EXPRESSION1","b"."name" AS "EXPRESSION2" FROM "TMPTT27_1"  CROSS JOIN "t_replicate" "b"   WHERE ("TMPTT27_1"."id" = "b"."id") |
|   Drop:                                                                                                                                                                                                          |
|  TMPTT27_1                                                                                                                                                                                                       |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
12 row(s).
 
從上可以看出,三種分區方式都支持關聯查詢
 
(三)group by查詢
Stado -> select a.id,count(*) from t_partition a,t_partition2 b where a.id=b.id and b.id<30 group by a.id order by 1;
+---------------+
| id | count(*) |
+---------------+
|  1 |        1 |
|  2 |        1 |
|  3 |        1 |
|  4 |        1 |
|  5 |        1 |
|  6 |        1 |
|  7 |        1 |
|  8 |        1 |
|  9 |        1 |
| 10 |        1 |
| 11 |        1 |
| 12 |        1 |
| 13 |        1 |
| 14 |        1 |
| 15 |        1 |
| 16 |        1 |
| 17 |        1 |
| 18 |        1 |
| 19 |        1 |
| 20 |        1 |
| 21 |        1 |
| 22 |        1 |
| 23 |        1 |
| 24 |        1 |
| 25 |        1 |
| 26 |        1 |
| 27 |        1 |
| 28 |        1 |
| 29 |        1 |
+---------------+
29 row(s).
 
partition表和partition表的關聯后group by(注意,t_partition2表和t_partition1表結構一樣,數據是后者的一半),最終分成3步完成:
Stado -> explain select a.id,count(*) from t_partition a,t_partition2 b where a.id=b.id and b.id<30 group by a.id order by 1;
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|                                                                                             Query Plan                                                                                              |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|                                                                                                                                                                                                     |
|  Step: 0                                                                                                                                                                                            |
|  -------                                                                                                                                                                                            |
|  Target: CREATE UNLOGGED TABLE "TMPTT34_1" ( "id" INT)  WITHOUT OIDS                                                                                                                                |
|  Select: SELECT "a"."id" AS "id" FROM "t_partition" "a"                                                                                                                                             |
|                                                                                                                                                                                                     |
|                                                                                                                                                                                                     |
|  Step: 1                                                                                                                                                                                            |
|  -------                                                                                                                                                                                            |
|  Target: CREATE UNLOGGED TABLE "TMPTT34_2" ( "XCOL1" INT, "XCOL2" INT)  WITHOUT OIDS                                                                                                                |
|  Select: SELECT "TMPTT34_1"."id" AS "XCOL1",count(*) AS "XCOL2" FROM "TMPTT34_1"  CROSS JOIN "t_partition2" "b"   WHERE ("b"."id" < 30) AND ("TMPTT34_1"."id" = "b"."id") group by "TMPTT34_1"."id" |
|   Drop:                                                                                                                                                                                             |
|  TMPTT34_1                                                                                                                                                                                          |
|                                                                                                                                                                                                     |
|                                                                                                                                                                                                     |
|  Step: 2                                                                                                                                                                                            |
|  -------                                                                                                                                                                                            |
|  Select: SELECT "XCOL1" AS "id",SUM("XCOL2") AS "EXPRESSION67" FROM "TMPTT34_2"  group by "XCOL1", "XCOL1"                                                                                          |
|   Drop:                                                                                                                                                                                             |
|  TMPTT34_2                                                                                                                                                                                          |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
20 row(s).
 
(四)怎樣實現根據range分庫
很多時候我們可能不希望通過roundrobin或者partition 的hash分區方式分庫,但由於stado沒有提供這種分區,如果我們又有比較明顯的分區條件,比如無錫區域的用戶都會插入到無錫來,蘇州區域的用戶都會插入到蘇州,這樣我們可以用應用程序之間插入到各自對應的后台數據節點,查詢時通過stado匯總各個地區的結果集,一樣可以實現:
 
 Stado -> create table t_area_record(area_id int,area_name varchar(30),name varchar(30)) partitioning key area_id on all;
OK
 
第一個節點作為江陰的數據庫:
__xtest__N1=# insert into t_area_record select 1001,'jiangyin'::varchar(30),generate_series(1,50)||'dba'::varchar(30);
INSERT 0 50
 
第二個節點作為無錫的數據庫:
__xtest__N2=# insert into t_area_record select 1002,'wuxi'::varchar(30),generate_series(1,50)||'dba'::varchar(30);
INSERT 0 50
 
第三個節點作為宜興的數據庫:
__xtest__N3=# insert into t_area_record select 1003,'yixing'::varchar(30),generate_series(1,50)||'dba'::varchar(30);
INSERT 0 50
 
然后在總的stado節點查詢:
Stado -> select area_id,count(*) from t_area_record group by area_id order by 2;
+--------------------+
| area_id | count(*) |
+--------------------+
|    1003 |       50 |
|    1002 |       50 |
|    1001 |       50 |
+--------------------+
3 row(s).
 
Stado ->   select * from t_area_record order by area_id limit 5;
+----------------------------+
| area_id | area_name | name |
+----------------------------+
|    1001 | jiangyin  | 2dba |
|    1001 | jiangyin  | 3dba |
|    1001 | jiangyin  | 4dba |
|    1001 | jiangyin  | 5dba |
|    1001 | jiangyin  | 1dba |
+----------------------------+
5 row(s).
 
可以看出,這樣分庫寫入,而總庫查詢正好彌補了stado沒有partition by range的缺點,而基於mysql的cobar的分區規則則更豐富和靈活,但cobar不能整個匯總,如在cobar查詢select count(*) from  t_area_record會產生三條數據,因為cobar只是簡單的把sql語句發到所在的數據節點,然后結果分別返回而不做進一步處理,但stado顯然是做了處理的:
Stado -> select count(*) from t_area_record;
+----------+
| count(*) |
+----------+
|       150 |
+----------+
1 row(s).
 
Stado -> explain select count(*) from t_area_record;
+-------------------------------------------------------------------------+
|                               Query Plan                                |
+-------------------------------------------------------------------------+
|                                                                         |
|  Step: 0                                                                |
|  -------                                                                |
|  Target: CREATE UNLOGGED TABLE "TMPTT56_1" ( "XCOL1" INT)  WITHOUT OIDS |
|  Select: SELECT count(*) AS "XCOL1" FROM "t_area_record"                |
|                                                                         |
|                                                                         |
|  Step: 1                                                                |
|  -------                                                                |
|  Select: SELECT SUM("XCOL1") AS "EXPRESSION120" FROM "TMPTT56_1"        |
|   Drop:                                                                 |
|  TMPTT56_1                                                              |
+-------------------------------------------------------------------------+
12 row(s).
 
不過還有更好的方式,結合postgres自帶的分區表功能,優化器還能做Constraint Exclusion,也就是約束排除,可以讓優化器更聰明的知道哪些字表需要掃描哪個數據節點,不需要掃描的不會再掃那個分區,下次再寫,該睡覺了。
 
http://xmarker.blog.163.com/blog/static/2264840572013101062120936/
本文簡單介紹postgresql的分庫方案plproxy的安裝及使用,實際分庫以后再深入學習后更新。本實驗使用三個centos6.4虛擬機做服務器,ip分別為10.1.1.2、10.1.1.11、10.1.1.12,其中10.1.1.12位plproxy節點,其他兩個為數據節點。
1.plproxy的原理(參考德哥的相關文章):
 
postgresql分布式方案plproxy使用 - xmarker - x-marker的博客
 
2.下載軟件:
選擇最新版本下載即可,目前最新版本為2.5。
 
3.解壓軟件並進入目錄(在plproxy節點安裝即可):
/postgres/plproxy-2.5@pgtest4$pwd
/postgres/plproxy-2.5
/postgres/plproxy-2.5@pgtest4$ls
AUTHORS  config  COPYRIGHT  debian  doc  Makefile  META.json  NEWS  plproxy.control  plproxy.so  README  sql  src  test 
 
4.安裝:
注意需要用root用戶安裝,並且還要執行postgres用戶的.bash_profile 

 

source /home/postgres/.bash_profile
 
/postgres/plproxy-2.5@pgtest4$make
bison -b src/parser -d src/parser.y
gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fpic -I/usr/local/pgsql/include/server -I/usr/local/pgsql/include -DNO_SELECT=0 -I. -I. -I/usr/local/pgsql/include/server -I/usr/local/pgsql/include/internal -D_GNU_SOURCE   -c -o src/scanner.o src/scanner.c
gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fpic -I/usr/local/pgsql/include/server -I/usr/local/pgsql/include -DNO_SELECT=0 -I. -I. -I/usr/local/pgsql/include/server -I/usr/local/pgsql/include/internal -D_GNU_SOURCE   -c -o src/parser.tab.o src/parser.tab.c
....
gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fpic -shared -o plproxy.so src/scanner.o src/parser.tab.o src/cluster.o src/execute.o src/function.o src/main.o src/query.o src/result.o src/type.o src/poll_compat.o src/aatree.o -L/usr/local/pgsql/lib -Wl,--as-needed -Wl,-rpath,'/usr/local/pgsql/lib',--enable-new-dtags  -L/usr/local/pgsql/lib -lpq
echo "create extension plproxy;" > sql/plproxy.sql
cat sql/plproxy_lang.sql sql/plproxy_fdw.sql > sql/plproxy--2.5.0.sql
touch sql/plproxy--2.3.0--2.5.0.sql
touch sql/plproxy--2.4.0--2.5.0.sql
cat sql/ext_unpackaged.sql > sql/plproxy--unpackaged--2.5.0.sql
/postgres/plproxy-2.5@pgtest4$make install
/bin/mkdir -p '/usr/local/pgsql/lib'
/bin/mkdir -p '/usr/local/pgsql/share/extension'
/bin/mkdir -p '/usr/local/pgsql/share/extension'
/usr/bin/install -c -m 755  plproxy.so '/usr/local/pgsql/lib/plproxy.so'
/usr/bin/install -c -m 644 ./plproxy.control '/usr/local/pgsql/share/extension/'
/usr/bin/install -c -m 644  sql/plproxy--2.5.0.sql sql/plproxy--2.3.0--2.5.0.sql sql/plproxy--2.4.0--2.5.0.sql sql/plproxy--unpackaged--2.5.0.sql'/usr/local/pgsql/share/extension/'

 

 
5.plproxy配置:
在三個節點上分別創建三個庫(此庫用來做代理,sql分發函數等都在這個庫里定義,其中第三個節點的db_plproxy用作plproxy路由):

/postgres/plproxy-2.5@testpg$createdb db_plproxy
postgres=# \l
                                  List of databases
    Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges  
------------+----------+----------+-------------+-------------+-----------------------
db_plproxy | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | ...

 
創建extension,使其支持plproxy語言:

/home/postgres@pgtest4$psql -f /postgres/plproxy-2.5/sql/plproxy.sql db_plproxy
CREATE EXTENSION

在數據庫中創建plpgsql語言:

/home/postgres@pgtest4$createlang plpgsql db_plproxy
createlang: language "plpgsql" is already installed in database "db_plproxy"

按照軟件時默認已經安裝,說明不需要再創建了
 
在第三個節點的db_plproxy庫中創建模式:

create schema plproxy;

 
在第三個節點創建plproxy函數(public模式下):
/home/postgres@pgtest4$psql db_plproxy
psql (9.3.1)
Type "help" for help.
 

CREATE OR REPLACE FUNCTION plproxy.get_cluster_partitions(cluster_name text) RETURNS SETOF text AS $$ IF cluster_name = 'cluster' THEN RETURN NEXT 'dbname=db_plproxy host=10.1.1.2'; RETURN NEXT 'dbname=db_plproxy host=10.1.1.11'; RETURN; END IF; RAISE EXCEPTION 'Unknown cluster'; END; $$ LANGUAGE plpgsql;

此函數是為了得到集群的分區

CREATE OR REPLACE FUNCTION plproxy.get_cluster_version(cluster_name text) RETURNS integer AS $$ BEGIN     IF cluster_name = 'cluster' THEN         RETURN 1;     END IF;     RAISE EXCEPTION 'Unknown cluster'; END; $$ LANGUAGE plpgsql;

此函數是為了得到集群版本

CREATE OR REPLACE FUNCTION plproxy.get_cluster_config(IN cluster_name text, OUT key text, OUT val text) returns setof record as $$ begin key := 'statement_timeout'; val := 60; return next; return; end; $$ language plpgsql;

此函數是為了得到集群配置,以上三個函數都是plproxy內部調用
 
在plproxy節點創建如下函數:

CREATE OR REPLACE FUNCTION ddlexec(query text)   RETURNS SETOF integer AS $BODY$ CLUSTER 'cluster'; RUN ON ALL; $BODY$   LANGUAGE plproxy VOLATILE   COST 100   ROWS 1000; ALTER FUNCTION ddlexec(text)   OWNER TO postgres;

CREATE OR REPLACE FUNCTION dmlexec(query text) 

RETURNS SETOF integer AS
$BODY$
CLUSTER 'cluster';
RUN ON ANY;
$BODY$
  LANGUAGE plproxy VOLATILE
  COST 100
  ROWS 1000;
ALTER FUNCTION dmlexec(text)
  OWNER TO postgres;

   CREATE OR REPLACE FUNCTION dqlexec(query text)
 RETURNS SETOF record AS
$BODY$
CLUSTER 'cluster';
RUN ON ALL;
$BODY$
  LANGUAGE plproxy VOLATILE
  COST 100
  ROWS 1000;
ALTER FUNCTION dqlexec(text)
  OWNER TO postgres;

  上面這三個函數是plproxy內部函數,會調用數據節點同名的函數。
 
在兩個數據節點的數據庫中創建如下函數:
 
 

CREATE OR REPLACE FUNCTION ddlexec(query text)
RETURNS integer AS
$BODY$
declare
ret integer;
begin
execute query;
return 1;
end;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;

CREATE OR REPLACE FUNCTION dmlexec(query text) RETURNS integer AS $BODY$ declare ret integer; begin execute query; return 1; end; $BODY$ LANGUAGE 'plpgsql' VOLATILE COST 100;

CREATE OR REPLACE FUNCTION dqlexec(query text) RETURNS SETOF record AS $BODY$ declare ret record; begin for ret in execute query loop return next ret; end loop; return; end; $BODY$ LANGUAGE 'plpgsql' VOLATILE COST 100 ROWS 1000;

====================================測試===================================
測試:在plproxy節點登陸數據庫,並執行如下:

 

/home/postgres@pgtest4$psql db_plproxy
 
select ddlexec('create table usertable(id integer)');
select dmlexec('insert into usertable values(0)');
select dmlexec('insert into usertable values(1)');
select dmlexec('insert into usertable values(2)');
select dmlexec('insert into usertable values(3)');
select dmlexec('insert into usertable values(4)');
select dmlexec('insert into usertable values(5)');
select dmlexec('insert into usertable values(6)');
select dmlexec('insert into usertable values(7)');
select dmlexec('insert into usertable values(8)');
select dmlexec('insert into usertable values(9)');
select dmlexec('insert into usertable values(10)');
 
節點1數據:

db_plproxy=# select * from usertable;
id
----
  0
  1
  3
  5
  7
  8
  9
10
(8 rows)

節點2數據:

 

db_plproxy=# select * from usertable;
id
----
  2
  4
  6
(3 rows)
但查詢復雜sql時還是比較麻煩的,要把所有返回的列聲明其類型,當字段多時也是挺繁瑣的,比如:

proxy=> select * from dqlexec('select cast(count(userid) as int) as cnt  from user_info ') as (cnt int) ;
  cnt   
--------
125001
125000
(2 rows)

proxy=> select * from dqlexec('select * from user_info where userid=5') as (userid  integer, engname text, cnname text , occupation text, birthday  date , signname text , email text , qq  numeric , crt_time timestamp without time zone , mod_time  timestamp without time zone );
userid | engname | cnname | occupation |  birthday  | signname | email |    qq     |          crt_time          | mod_time 
--------+---------+--------+------------+------------+----------+-------+-----------+----------------------------+----------
      5 | mcl     | test   | DBA        | 1970-01-01 | test     | test  | 276732431 | 2013-11-10 22:59:17.627482 | 
(1 row)

注意上面的count 那條sql,我本意是想查出兩個節點總的數據量,結果返回了兩條記錄,分別輸出各自節點的數據量
 
參考:
 
 
http://my.oschina.net/zhangjiawen/blog/180637
最近在玩Hadoop、Hive、PostgreSql,因此結合上一篇文檔記錄一下本周工作內容,主要是環境的搭建和配置以及數據的生成與導入導出:在VirtualBox中安裝CentOS6.4,並且搭建Hadoop1.2.1和Hive0.12.0,然后在CentOS 6.4中安裝Postgresql9.3,在Windows7下安裝pgAdmin,然后生成一千萬條數據記錄導入到HDFS上並且能夠在Hive進行查詢,最后安裝Sqoop,將數據從HDFS導入到postgresql中。上篇文檔已經記錄了如何搭建hadoop平台,這篇將接着記錄后一部分工作內容。

1 在CentOS 6.4上安裝PostgreSql 9.3

1.1 用yum安裝PostgreSql Server:

CentOS 6.4用yum默認安裝的PostgreSql版本是8.x,比目前最新的9.3差了一代,需要更新yum repository之后,才能用yum安裝。用yum安裝的好處是方便、模塊化,而且以后比較好卸載。

首先到http://yum.postgresql.org/repopackages.php找到對應操作系統的合適的yum repository版本,我使用的服務器環境是CentOS 6.4 x86_64,找到該版本對用的rpm url后,用rpm安裝yum repository:

sudo rpm –i http://yum.postgresql.org/9.3/redhat/rhel-6-x86_64/pgdg-centos93-9.3-1.noarch.rpm

然后就可以通過yum安裝PostgreSql 9.3了:

sudo yum install postgresql93-server postgresql93 postgresql93-contrib postgresql93-devel

這幾個安裝包分別對應的是:

  • postgresql93-server:PostgreSql的服務器端;
  • postgresql93:PostgreSql的客戶端程序和庫;
  • postgresql93-contrib:一些外部擴展;
  • postgresql93-devel:庫和頭文件,對於一般使用,這個是可選的;但是如果后面需要以編譯源文件的形式安裝一些PostgreSql的擴展(例如Multicorn),它們在編譯過程中需要這些文件,那么這個一定要有。

安裝程序會創建postgres用戶和postgres組,為了安全起見,建議將這個用戶禁止從遠程登錄(具體方法請自行查找)。然后設置postgres用戶的密碼:

sudo passwd postgres

至此,postgresql9.3安裝過程完成。

提醒:這個postgres用戶是操作系統的用戶,和后面將會講到的數據庫登錄用戶postgres不是一個東西,千萬不要混淆。

1.2 設置PostgreSql Server:

1.2.1 首先初始化數據庫:

sudo service postgresql-9.3 initdb

對於使用yum安裝的PostgreSql Server,默認配置是服務器會將數據庫的數據文件放在/var/lib/pgsql/9.3/data目錄下,初始化數據庫后,這個目錄下保存有最基本的數據和配置文件;通常這個目錄都是在磁盤的系統分區中,如果服務器有可靠性更高、速度更快的存儲空間(例如磁盤陣列),最好把數據文件目錄移到那里,移動的方法是:假設有一個磁盤陣列已經掛載在了/dwdata下,我們想將數據文件放在/dwdata/data/postgresql/目錄下,則我們需要做如下移動:

sudo mkdir –p /dwdata/data

sudo cp –r /var/lib/pgsql/9.3/data/ /dwdata/data

sudo mv /dwdata/data/data /dwdata/data/postgresql

設置新數據目錄及其所有內容的owner和group為postgres:

sudo chowm –r postgres /dwdata/data/postgresql

sudo chgrp –r postgres /dwdata/data/postgresql

1.2.2 然后修改PostgreSql Server的啟動配置文件/etc/init.d/postgresql-9.3:

Sudo vi /etc/init.d/postgresql-9.3

找到如下字樣的行:

# Set defaults for configuration variables

PGENGINE=/usr/pgsql-9.3/bin

PGPORT=5432

PGDATA=/var/lib/pgsql/9.3/data

PGLOG=/var/lib/pgsql/9.3/pgstartup.log

# Log file for pg_upgrade

PGUPLOG=/var/lib/pgsql/$PGMAJORVERSION/pgupgrade.log

這里面值得改的幾個參數及其含義是:

  • PGPORT:PostgreSql Server蹲守的TCP端口,一般用默認值即可;
  • PGDATA:數據文件目錄,對於DW生產來說,要指定到磁盤陣列上;
  • PGLOG:PostgreSql Server啟動日志的位置,是一個全路徑文件名;
  • PGUPLOG:PostgreSql升級日志的位置,也是一個全路徑文件名;

這里我需要將其中幾個參數修改為新的數據文件目錄:

PGDATA=/dwdata/data/postgresql

PGLOG=/dwdata/data/postgresql/pgstartup.log

PGUPLOG=/dwdata/data/postgresql/pgupgrade.log

PostgreSql就會將數據文件和關鍵的log文件放到創建的數據目錄中。

1.2.3 啟動和停止PostgreSql Server:

上述設置完成后,就可以用下述命令啟動PostgreSql Server了:

sudo service postgresql-9.3 start

下述命令停止PostgreSql Server:

sudo service postgresql-9.3 stop

下述命令檢查PostgreSql Server的運行狀態:

sudo service postgresql-9.3 status

下述命令重新啟動PostgreSql Server:

sudo service postgresql-9.3 restart

1.2.4 配置PostgreSql Server的網絡參數:

PostgreSql Server的配置文件在數據文件目錄中(在這里即為/dwdata/data/postgresql目錄)。最主要的配置文件是postgresql.conf,里面有關於網絡、性能、緩存大小等各類設置,對於具備多塊網卡的服務器來說,最主要的設置是服務器監聽的地址,在配置文件中可以找到如下條目:

#listen_addresses = ‘localhost’ # what IP address(es) to listen on;

# comma-separated list of addresses;

# defaults to ‘localhost’; use ‘*’ for all

# (change requires restart)

一般情況況下,要求PostgreSql Server在所有網卡上均監聽,可以將此條目前的“#”注釋符去掉,並改為:

listen_addresses=’*’即可監聽來自所有網卡的請求。如果需要監聽特定的網卡,則可以用網卡的IP地址替換“*”字符。

如需修改監聽的端口,則可以找到#port=5432這一條目,去掉“#”注釋符並按需要修改之。對於不直接暴露在公網上的服務器,不需要修改這個端口。

上述配置修改后,需要重新啟動PostgreSql Server才能生效。

1.2.5 控制PostgreSql Server的訪問權限:

為了保證安全,PostgreSql Server在安裝后,僅允許來自服務器本機的連接,如果需要對PostgreSql Server進行網絡訪問(比如用另一台服務器訪問,或者用圖形化的管理工具從遠程管理服務器),就需要對訪問權限進行設置。

控制網絡訪問權限的配置文件是pg_hba.conf,在文件末尾會有如下條目:

# TYPE DATABASE USER ADDRESS METHOD

# “local” is for Unix domain socket connections only

local all all peer

# IPv4 local connections:

host all all 127.0.0.1/32 ident

# IPv6 local connections:

……

為了打開PostgreSql Server的外部訪問,需要向文件末尾添加內容。例如:假如我們安裝PostgreSql Server的服務器IP地址是192.168.66.23,我們希望該子網內(即IP為192.168.66.*)所有計算機都能連接這台PostgreSql Server,並且都需要用戶名/密碼登錄,則可以添加如下行:

host all all 192.168.66.1/24 md5

這個例子中,“192.168.66.1/24”表示允許所有IP為“192.168.66.*”的計算機對服務器進行訪問,“24”即IP的掩碼有24個二進制的“1”,就是子網掩碼的概念;例如,如果我們希望所有IP為“192.168.*.*”的計算機對服務器進行訪問,則可以寫為“192.168.1.1/16”。

第一個all表示允許訪問所有數據庫,第二個all表示允許所有用戶名的用戶登錄;這兩個域的設置可以參閱該文件前面長長的說明內容,本文不再贅述。

最后的md5表示用加密后的密碼進行用戶名/密碼匹配的認證,這里的“用戶名”是指數據庫的用戶,而不是操作系統的用戶。常用的幾種其他認證方式有ident(與操作系統的用戶名做映射,采用操作系統的認證,數據庫用戶與操作系統用戶之間的映射在pg_ident.conf文件中配置)、password(在網絡傳送明文密碼認證,不安全)、trust(完全信任)、peer(取客戶端操作系統的用戶名,一般僅用來做本地連接)。

通常,采用數據庫用戶的用戶名和密碼進行認證,即md5。

1.2.6 使用psql命令行界面設置postgres用戶的密碼:

PostgreSql Server安裝后,數據庫中會有一個默認的用戶叫postgres(注意這里是數據庫登陸用戶postgres,不是上面提到的操作系統用戶postgres),具備管理員級別的權限。如果我們想通過圖形化的管理界面登錄到PostgreSql Server上對服務器進行管理,就需要先設置這個用戶的密碼,首先要切換到操作系統的postgres用戶,該用戶具有使用psql進行數據庫管理的權限:

su postgres

然后執行psql,進入PostgreSql Server的命令行界面,提示符是“postgres=#”,這時我們就可以鍵入PostgreSql的命令了,例如用來修改用戶密碼的ALTER USER命令,我們將數據庫用戶postgres的密碼修改為abcdefg:

psql

postgres=#ALTER USER postgres with password ‘abcdefg‘;

ALTER ROLE

postgres=#\q

exit

上面一段命令中,粗體藍色表示我們要鍵入的操作系統命令,灰色表示psql的提示與輸出,藍色表示我們要鍵入的PostgreSql命令。psql界面用\q命令退出。

於是PostgreSql Server具備了一個超級用戶postgres,其密碼是abcdefg。可以從遠程用各種客戶端工具連接這台服務器了。

1.2.7 在客戶端安裝圖形化管理界面並連接PostgreSql Server:

目前PostgreSql比較成熟的圖形化管理界面是PgAdmin,具有Windows、Mac、Linux等多種版本,網站是http://www.pgadmin.org/,支持PostgreSql Server 9.3需要PgAdmin 1.18.0或更高的版本。我們可以用自己的筆記本作為客戶端,安裝管理界面,前提是筆記本與服務器之間的網絡是直接連通的,5432端口能夠正常通信。

下載安裝都是圖形化的。安裝完成並運行,由於尚未連接過任何服務器,所以Server Groups中是空的。

點擊左上角的“Add a connection to a server”按鈕:

 

在彈出的對話框中,填入PostgreSql Server的地址和用戶信息:

Name一欄可以自行填寫易於識別的名字;Host是PostgreSql Server的機器名或IP地址;Port是Server的端口(默認是5432);Service一欄留空;Maintenance DB留默認的postgres即可;Username填入postgres,這是上面被設定過密碼的數據庫用戶;Password填入上面設定的密碼,並勾選Store password。由於我是在Windows下安裝PgAdmin來連接虛擬機中CentOS中的postgresql,因此需要利用VirtualBox的端口轉發規則:Host是我在Windows下的IP地址(cmd->ipconfig);然后在VirtualBox中設置->網絡->端口轉發->插入新規則,如下圖所示添加端口轉發規則,自定義主機端口,子系統IP是CentOS(ifconfig)中的IP地址,子系統端口是postgresql server端口,默認是5432。

 

完成后點擊OK按鈕,即可看到Server Groups列表中多了一台服務器,點擊它,即可一級一級的展開各種數據庫對象:

         在使用pgAdmin連接postgresql數據庫的過程中,總是出現“端口監聽未開啟”等的問題連接不上,經過各種排錯,我把CentIOS中的防火牆關閉,並且關閉了SELinux功能,同時修改了postgresql的配置文件pg-hba.conf,添加host all all 10.0.2.2/24 md5,這樣才最后成功連接。

至此,在CentOSPostgreSql 6上安裝PostgreSql 9.3的過程就成功完成了,而且也具有了能夠管理該PostgreSql Server的圖形化管理界面,可以進行任何服務器管理、監控、用戶增刪、數據查詢、存儲過程編寫和運行等各類工作了。

 

2 將文件放到HDFS上並使用Hive查詢:

現有一份一千萬條數據記錄的文件FakeData,需要部署到HDFS上,先創建一個文件夾命名為FakeDataDir:hadoop dfs –mkdir FakeDataDir

然后使用命令將文件放到HDFS上:hadoop dfs –put FakeData FakeDataDir,

使用命令查看HDFS下的文件:hadoop dfs –ls

 

         進入hive的所在路徑,我的是/usr/local/hive/hive-0.12.0/bin,輸入以下命令:

./hive

 

創建外部表:

create external table if not exists fakedata(JULIAN_DATE string, PLATFORM string,…, LOG_ID double) ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘,’ location ‘/user/root/FakeDataDir’

注意由於LOG_ID字段是一個20位整隨機數,所以使用double類型。

由於數據文件是由逗號分隔,所以TERMINATED BY ‘,’

最后定位數據文件所在位置,被放在HDFS路徑/user/root/FakeDataDir下,注意location只要寫文件所在目錄即可。

         這樣就可以通過hive對數據文件進行查詢了,如下圖所示:

 

 

3 安裝Sqoop1.3.0並將數據從HDFS導入到Postgresql數據庫:

首先需要在postgresql中創建表fakedata;然后在CentOS 6.4上安裝Sqoop:

yum install sqoop

並且下載postgresql-9.3-1100.jdbc41.jar和hadoop-0.20.2-CDH3B4.tar.gz,放入sqoop所在路徑的lib文件夾下/usr/lib/sqoop/lib。同時需要修改配置文件configure-sqoop,將hbase和zookeeper注釋掉檢查:(除非需要使用HBase等Hadoop組件)

 
 

並且確保sqoop所需的HADOOP_HOME正確指向hadoop安裝目錄,執行echo $HADOOP_HOME查看HADOOP_HOME是否正確配置。

然后使用命令將之前部署在HDFS上的數據文件導入postgresql:

./sqoop export --connect jdbc:postgresql://localhost:5432/postgres --username postgres --password 123456 --table fakedata--fields-terminated-by ',' --export-dir /user/root/FakeDataDir

這樣就可以使用pgAdmin在postgresql中進行查詢了。

需要注意的是,sqoop與hadoop可能會出現連接失敗,提示:ident authenation failed for user postgres,這時需要修改postgresql的配置文件pg_hba,conf,修改postgresql的認證方式為trust:

local all all trust

host all all 127.0.0.1/32 trust

這樣終於能夠將postgresql連接到hadoop。

 

       然后我對fakedata文件中的數據進行計算,並需要把計算結果導出到postgresql數據庫中,按照如下步驟進行:

1、通過pgAdmin在postgresql中創建表,建表的字段和數據類型要符合計算結果的字段和數據類型。

2、然后在hive中創建相應的表作為存儲計算結果的臨時表。在瀏覽器輸入localhost:50070,browse the filesystem,hive內部表默認位置在hive安裝路徑conf下的hive-site.xml中規定,設置為/user/hive/warehouse。輸入下面命令建表:

create table success(pv bigint, uv bigint) row format delimited fields terminated by ‘,’;(不設置行分隔符默認為\001,是8進制的ASCII碼序始字符SOH,start of header)

show tables;

desc success;

insert into success select sum(pv), count(distinct uv) from testdata group by julian_date;

3、然后通過sqoop將hive的表中的數據導出到postgresql數據庫中:

./sqoop export –connect jdbc:postgresql://localhost:5432/postgres –username postgres –password 123456 –table testdata –fields-terminated-by ‘,’ –export-dir /user/hive/warehouse/success

注意:由於是初學者,我在實踐過程中在分隔符上栽了大跟頭,還是要注意這些命令的細節!這篇文檔也不完全是自己完成的,當然要感謝提供我材料和解決方案的技術人員!!!

 
 
 
http://download.csdn.net/detail/machen_smiling/8426217

高階技術postgreSQL+pgpool+Ubuntu 實現分布式流復制模式

 http://files.cnblogs.com/files/taosim/postgreSQL_pgpool_Ubuntu%E5%AE%9E%E7%8E%B0%E5%88%86%E5%B8%83%E5%BC%8F%E6%B5%81%E5%A4%8D%E5%88%B6%E6%A8%A1%E5%BC%8F.pdf

 

http://www.ithao123.cn/content-244813.html

標題:postgresql分布式方案plproxy使用 

本文簡單介紹postgresql的分庫方案plproxy的安裝及使用,實際分庫以后再深入學習后更新。本實驗使用三個centos6.4虛擬機做服務器,ip分別為10.1.1.2、10.1.1.11、10.1.1.12,其中10.1.1.12位plproxy節點,其他兩個為數據節點。
1.plproxy的原理(參考德哥的相關文章):
 
postgresql分布式方案plproxy使用 - xmarker - x-marker的博客
 
2.下載軟件:
http://pgfoundry.org/projects/plproxy/
選擇最新版本下載即可,目前最新版本為2.5。
 
3.解壓軟件並進入目錄(在plproxy節點安裝即可):
/postgres/plproxy-2.5@pgtest4$pwd
/postgres/plproxy-2.5
/postgres/plproxy-2.5@pgtest4$ls
AUTHORS  config  COPYRIGHT  debian  doc  Makefile  META.json  NEWS  plproxy.control  plproxy.so  README  sql  src  test 
 
4.安裝:
注意需要用root用戶安裝,並且還要執行postgres用戶的.bash_profile 

 

source /home/postgres/.bash_profile
 
/postgres/plproxy-2.5@pgtest4$make
bison -b src/parser -d src/parser.y
gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fpic -I/usr/local/pgsql/include/server -I/usr/local/pgsql/include -DNO_SELECT=0 -I. -I. -I/usr/local/pgsql/include/server -I/usr/local/pgsql/include/internal -D_GNU_SOURCE   -c -o src/scanner.o src/scanner.c
gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fpic -I/usr/local/pgsql/include/server -I/usr/local/pgsql/include -DNO_SELECT=0 -I. -I. -I/usr/local/pgsql/include/server -I/usr/local/pgsql/include/internal -D_GNU_SOURCE   -c -o src/parser.tab.o src/parser.tab.c
....
gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fpic -shared -o plproxy.so src/scanner.o src/parser.tab.o src/cluster.o src/execute.o src/function.o src/main.o src/query.o src/result.o src/type.o src/poll_compat.o src/aatree.o -L/usr/local/pgsql/lib -Wl,--as-needed -Wl,-rpath,'/usr/local/pgsql/lib',--enable-new-dtags  -L/usr/local/pgsql/lib -lpq
echo "create extension plproxy;" > sql/plproxy.sql
cat sql/plproxy_lang.sql sql/plproxy_fdw.sql > sql/plproxy--2.5.0.sql
touch sql/plproxy--2.3.0--2.5.0.sql
touch sql/plproxy--2.4.0--2.5.0.sql
cat sql/ext_unpackaged.sql > sql/plproxy--unpackaged--2.5.0.sql
/postgres/plproxy-2.5@pgtest4$make install
/bin/mkdir -p '/usr/local/pgsql/lib'
/bin/mkdir -p '/usr/local/pgsql/share/extension'
/bin/mkdir -p '/usr/local/pgsql/share/extension'
/usr/bin/install -c -m 755  plproxy.so '/usr/local/pgsql/lib/plproxy.so'
/usr/bin/install -c -m 644 ./plproxy.control '/usr/local/pgsql/share/extension/'
/usr/bin/install -c -m 644  sql/plproxy--2.5.0.sql sql/plproxy--2.3.0--2.5.0.sql sql/plproxy--2.4.0--2.5.0.sql sql/plproxy--unpackaged--2.5.0.sql '/usr/local/pgsql/share/extension/'

 

 
5.plproxy配置:
在三個節點上分別創建三個庫(此庫用來做代理,sql分發函數等都在這個庫里定義,其中第三個節點的db_plproxy用作plproxy路由):

/postgres/plproxy-2.5@testpg$createdb db_plproxy
postgres=# l
                                  List of databases
    Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges  
------------+----------+----------+-------------+-------------+-----------------------
db_plproxy | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | ...

 
創建extension,使其支持plproxy語言:

/home/postgres@pgtest4$psql -f /postgres/plproxy-2.5/sql/plproxy.sql db_plproxy
CREATE EXTENSION

在數據庫中創建plpgsql語言:

/home/postgres@pgtest4$createlang plpgsql db_plproxy
createlang: language "plpgsql" is already installed in database "db_plproxy"

按照軟件時默認已經安裝,說明不需要再創建了
 
在第三個節點的db_plproxy庫中創建模式:

create schema plproxy;

 
在第三個節點創建plproxy函數(public模式下):
/home/postgres@pgtest4$psql db_plproxy
psql (9.3.1)
Type "help" for help.
 

CREATE OR REPLACE FUNCTION plproxy.get_cluster_partitions(cluster_name text) RETURNS SETOF text AS $$ IF cluster_name = 'cluster' THEN RETURN NEXT 'dbname=db_plproxy host=10.1.1.2'; RETURN NEXT 'dbname=db_plproxy host=10.1.1.11'; RETURN; END IF; RAISE EXCEPTION 'Unknown cluster'; END; $$ LANGUAGE plpgsql;

此函數是為了得到集群的分區

CREATE OR REPLACE FUNCTION plproxy.get_cluster_version(cluster_name text) RETURNS integer AS $$ BEGIN     IF cluster_name = 'cluster' THEN         RETURN 1;     END IF;     RAISE EXCEPTION 'Unknown cluster'; END; $$ LANGUAGE plpgsql;

此函數是為了得到集群版本

CREATE OR REPLACE FUNCTION plproxy.get_cluster_config(IN cluster_name text, OUT key text, OUT val text) returns setof record as $$ begin key := 'statement_timeout'; val := 60; return next; return; end; $$ language plpgsql;

此函數是為了得到集群配置,以上三個函數都是plproxy內部調用
 
在plproxy節點創建如下函數:

CREATE OR REPLACE FUNCTION ddlexec(query text)   RETURNS SETOF integer AS $BODY$ CLUSTER 'cluster'; RUN ON ALL; $BODY$   LANGUAGE plproxy VOLATILE   COST 100   ROWS 1000; ALTER FUNCTION ddlexec(text)   OWNER TO postgres;

CREATE OR REPLACE FUNCTION dmlexec(query text) 

RETURNS SETOF integer AS
$BODY$
CLUSTER 'cluster';
RUN ON ANY;
$BODY$
  LANGUAGE plproxy VOLATILE
  COST 100
  ROWS 1000;
ALTER FUNCTION dmlexec(text)
  OWNER TO postgres;

   CREATE OR REPLACE FUNCTION dqlexec(query text)
 RETURNS SETOF record AS
$BODY$
CLUSTER 'cluster';
RUN ON ALL;
$BODY$
  LANGUAGE plproxy VOLATILE
  COST 100
  ROWS 1000;
ALTER FUNCTION dqlexec(text)
  OWNER TO postgres;

  上面這三個函數是plproxy內部函數,會調用數據節點同名的函數。
 
在兩個數據節點的數據庫中創建如下函數:
 
 

CREATE OR REPLACE FUNCTION ddlexec(query text)
RETURNS integer AS
$BODY$
declare
ret integer;
begin
execute query;
return 1;
end;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;

CREATE OR REPLACE FUNCTION dmlexec(query text) RETURNS integer AS $BODY$ declare ret integer; begin execute query; return 1; end; $BODY$ LANGUAGE 'plpgsql' VOLATILE COST 100;

CREATE OR REPLACE FUNCTION dqlexec(query text) RETURNS SETOF record AS $BODY$ declare ret record; begin for ret in execute query loop return next ret; end loop; return; end; $BODY$ LANGUAGE 'plpgsql' VOLATILE COST 100 ROWS 1000;

====================================測試===================================
測試:在plproxy節點登陸數據庫,並執行如下:

 

/home/postgres@pgtest4$psql db_plproxy
 
select ddlexec('create table usertable(id integer)');
select dmlexec('insert into usertable values(0)');
select dmlexec('insert into usertable values(1)');
select dmlexec('insert into usertable values(2)');
select dmlexec('insert into usertable values(3)');
select dmlexec('insert into usertable values(4)');
select dmlexec('insert into usertable values(5)');
select dmlexec('insert into usertable values(6)');
select dmlexec('insert into usertable values(7)');
select dmlexec('insert into usertable values(8)');
select dmlexec('insert into usertable values(9)');
select dmlexec('insert into usertable values(10)');
 
節點1數據:

db_plproxy=# select * from usertable;
id
----
  0
  1
  3
  5
  7
  8
  9
10
(8 rows)

節點2數據:

 

db_plproxy=# select * from usertable;
id
----
  2
  4
  6
(3 rows)
但查詢復雜sql時還是比較麻煩的,要把所有返回的列聲明其類型,當字段多時也是挺繁瑣的,比如:

proxy=> select * from dqlexec('select cast(count(userid) as int) as cnt  from user_info ') as (cnt int) ;
  cnt   
--------
125001
125000
(2 rows)

proxy=> select * from dqlexec('select * from user_info where userid=5') as (userid  integer, engname text, cnname text , occupation text, birthday  date , signname text , email text , qq  numeric , crt_time timestamp without time zone , mod_time  timestamp without time zone );
userid | engname | cnname | occupation |  birthday  | signname | email |    qq     |          crt_time          | mod_time 
--------+---------+--------+------------+------------+----------+-------+-----------+----------------------------+----------
      5 | mcl     | test   | DBA        | 1970-01-01 | test     | test  | 276732431 | 2013-11-10 22:59:17.627482 | 
(1 row)

注意上面的count 那條sql,我本意是想查出兩個節點總的數據量,結果返回了兩條記錄,分別輸出各自節點的數據量
 
參考:
http://pgfoundry.org/projects/plproxy/
http://blog.163.com/digoal@126/blog/static/163877040201041111304328/
 
 
http://blog.chinaunix.net/uid-15145533-id-2775928.html
目前在數據庫的分布方面,有兩個不同的方向,一種是數據存儲到數據分布算法都完全由自己實現分布式引擎,另一個方向是在底層使用現有成熟的關系型數據庫,上層再實現一套分布式引擎的系統。
前一種中,Cassandra就是其突出代表,而后一種,我們公司的mysql+corbar方案就是其突出代表,其他以PostgreSQL數據庫為基礎的分布式方案有plproxy、pgpool、greenplum、pgmaster等等。
這兩種分布式方案各有優缺點:
第一種方案: 
優點: 
在特定的場景上,性能可能更高一些。
缺點:
1. 不夠成熟。例如Digg公司就是因為把技術架構從原先成熟的LAMP遷移到Cassandra上去,由於Cassandra技術的不穩定,Digg的技術人員
無法解決這些問題,網站遭遇到了重大的打擊,導致了技術副總裁John Quinn的為此而卷鋪蓋走人。見http://www.dbthink.com/?p=639&cpage=1
2. 由於所有都是由自己來實現,所以程序的實現相當復雜,程序的可維護性不好,需要很高的維護成本。
3. 部分功能不完善。不象傳統的關系型數據庫有各種各樣成熟的備份方案,數據的可靠性不高。
 
第二種方案: 
優點: 
1. 方案成熟。由於底層是使用傳統的關系型數據庫,而僅是實現上上層做數據分布的部分,所以一般來說這種方案的實現成本低,程序相對簡單,所以bug也比較少,運行也比較穩定。
2. 維護成本低。由於低層是傳統的關系型數據庫,底層的維護與原先的數據庫維護完全一樣,傳統數據庫的備份方案可以直接使用。
 
從我個人來講,雖然第二種方案看起來創新成度不如第一種,但我是比較傾向於使用第二種方案。原因是第二種方案比較成熟,維護成本低。
另外說一說NoSQL,現在NoSQL很火,有點象病毒一樣在開發人員中傳播,這也很容易理解,因為生活在科技前沿,對於大部分開發人員來講,是令人興奮的,但是企業在實施時必須非常謹慎,不要重蹈Digg的覆轍。
 
 
http://www.2cto.com/database/201302/191606.html
postgresql分布式 數據庫
 
1 分布式事務所用到的兩階段提交協議 
兩階段提交的過程涉及到協調者和參與者。協調者可以看做成事務的發起者,同時也是事務的一個參與者。對於一個分布式事務來說,一個事務是涉及到多個參與者的。具體的兩階段提交的過程如下: 
  www.2cto.com  
第一階段: 
首先,協調者在自身節點的日志中寫入一條的日志記錄,然后所有參與者發送消息prepare T,詢問這些參與者(包括自身),是否能夠提交這個事務; 
參與者在接受到這個prepare T 消息以后,會根據自身的情況,進行事務的預處理,如果參與者能夠提交該事務,則會將日志寫入磁盤,並返回給協調者一個ready T信息,同時自身進入預提交狀態狀態;如果不能提交該事務,則記錄日志,並返回一個not commit T信息給協調者,同時撤銷在自身上所做的數據庫改動;參與者能夠推遲發送響應的時間,但最終還是需要發送的。 
 
第二階段: 
協調者會收集所有參與者的意見,如果收到參與者發來的not commit T信息,則標識着該事務不能提交,協調者會將Abort T 記錄到日志中,並向所有參與者發送一個Abort T 信息,讓所有參與者撤銷在自身上所有的預操作。 
如果協調者收到所有參與者發來prepare T信息,那么協調者會將Commit T日志寫入磁盤,並向所有參與者發送一個Commit T信息,提交該事務。若協調者遲遲未收到某個參與者發來的信息,則認為該參與者發送了一個VOTE_ABORT信息,從而取消該事務的執行。 
  www.2cto.com  
參與者接收到協調者發來的Abort T信息以后,參與者會終止提交,並將Abort T 記錄到日志中;如果參與者收到的是Commit T信息,則會將事務進行提交,並寫入記錄一般情況下,兩階段提交機制都能較好的運行,當在事務進行過程中,有參與者宕機時,他重啟以后,可以通過詢問其他參與者或者協調者,從而知道這個事務到底提交了沒有。當然,這一切的前提都是各個參與者在進行每一步操作時,都會事先寫入日志。 
唯一一個兩階段提交不能解決的困境是:當協調者在發出commit T消息后宕機了,而唯一收到這條命令的一個參與者也宕機了,這個時候這個事務就處於一個未知的狀態,沒有人知道這個事務到底是提交了還是未提交,從而需要數據庫管理員的介入,防止數據庫進入一個不一致的狀態。當然,如果有一個前提是:所有節點或者網絡的異常最終都會恢復,那么這個問題就不存在了,協調者和參與者最終會重啟,其他節點最終也會收到commit T的信息。 
2使用兩階段提交注意事項(德哥一篇文章中的建議) 
2.1. 不要使2PC時間過長,因為有2PC存在的話vacuum不能回收垃圾空間(這個我在之前的博客也有寫到,哪怕是begin;開着不放都不行)。 
2.2. 2PC時間過長還可能造成強制數據庫SHUTDOWN,如 transaction ID wraparound. 
2.3. 2PC時間過長也可能帶來鎖時間過長的問題。 
2.4. 因此沒必要的話建議不要開啟prepared transaction,由應用來實現2PC也是不錯的選擇。 
3 分布式事務到數據文件支持 
Data/fxdb_twophase 
3.1 prepare transaction 
在 prepare transaction 的時候,在數據庫的目錄的 pg_twophase 文件夾生成state file,文件名為事務的XID.要生成state file的主要原因是,在這一過程中,已完成了資源的釋放,把不能釋放的記錄下來,以便2 commit時候釋放. 
3.2 commit prepared 
把state file讀出來解析,接着釋放資源,之后就是記錄日志,並把state file刪除. 
 
3.3 總結fxdb_twophase的作用 
當在prepare transaction成功,之后 系統掛掉,這時state file已創建成功,保留在硬盤上,當系統重啟后,會根據日志和state file重構XA事物,在系統啟動完成后,可以接着 commit prepared 或 rollback prepared 這個事物。 
 
postgresql中兩階段提交實現原理 
TwoPhaseStateData 
/* 
* Two Phase Commit shared state.  Access to this struct is protected 
* by TwoPhaseStateLock. 
*/ 
typedef struct TwoPhaseStateData 
/* Head of linked list of free GlobalTransactionData structs */ 
GlobalTransaction freeGXacts; 
 
/* Number of valid prepXacts entries. */ 
int  numPrepXacts; 
 
/* 
* There are max_prepared_xacts items in this array, but C wants a 
* fixed-size array. 
*/ 
GlobalTransaction prepXacts[1];  /* VARIABLE LENGTH ARRAY */ 
} TwoPhaseStateData;  /* VARIABLE LENGTH STRUCT */ 
GlobalTransactionData 
typedef struct GlobalTransactionData 
PGPROC  proc;  /* dummy proc */ 
BackendId dummyBackendId; /* similar to backend id for backends */ 
TimestampTz prepared_at; /* time of preparation */ 
XLogRecPtr prepare_lsn; /* XLOG offset of prepare record */ 
Oid  owner;  /* ID of user that executed the xact */ 
TransactionId locking_xid; /* top-level XID of backend working on xact */ 
bool  valid;  /* TRUE if fully prepared */ 
char  gid[GIDSIZE]; /* The GID assigned to the prepared xact */ 
#ifdef FOUNDER_XDB_SE 
TransactionId xid; 
#endif 
}GlobalTransactionData; 
TwoPhaseFileHeader 
typedef struct TwoPhaseFileHeader 
uint32  magic;  /* format identifier */ 
uint32  total_len;  /* actual file length */ 
TransactionId xid;  /* original transaction XID */ 
Oid  database;  /* OID of database it was in */ 
TimestampTz prepared_at; /* time of preparation */ 
Oid  owner;  /* user running the transaction */ 
int32  nsubxacts;  /* number of following subxact XIDs */ 
int32  ncommitrels; /* number of delete-on-commit rels */ 
int32  nabortrels;  /* number of delete-on-abort rels */ 
int32  ninvalmsgs;  /* number of cache invalidation messages */ 
bool  initfileinval; /* does relcache init file need invalidation? */ 
char  gid[GIDSIZE]; /* GID for transaction */ 
} TwoPhaseFileHeader; 
Variable 
static THREAD_LOCAL TwoPhaseStateData *TwoPhaseState; 
 
4 分布式事務創建 
4.1 Where the transcation id is come from? 
Each global transaction is associated with a global transaction 
identifier (GID). The client assigns a GID to a postgres transaction with the PREPARE TRANSACTION command. 
4.2 Where the transaction is stored in server? 
We keep all active global transactions in a shared memory array.When the PREPARE TRANSACTION command is issued, the GID is reserved for the transaction in the array. This is done before a WAL entry is made, because the reservation checks for duplicate GIDs and aborts the transaction if there already is a global transaction in prepared state with the same GID. 
4.3 global transaction has a dummy PGPROC 
A global transaction (gxact) also has a dummy PGPROC that is entered 
into the ProcArray array; this is what keeps the XID considered 
running by TransactionIdIsInProgress.  It is also convenient as a 
PGPROC to hook the gxact's locks to. 
5 分布式事務Commit 
recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT_PREPARED, rdata); 
 
/* Always flush, since we're about to remove the 2PC state file */ 
XLogFlush(recptr); 
/* 
* Mark the transaction aborted in clog.  This is not absolutely necessary 
* but we may as well do it while we are here. 
*/ 
TransactionIdAbortTree(xid, nchildren, children); 
 
5分布式事務Recovery 
In order to survive crashes and shutdowns, all prepared transactions must be stored in permanent storage. This includes locking information, pending notifications etc. All that state information is written to the per-transaction state file in the pg_twophase directory. 
5.1RecoverPreparedTransactions 
In order to survive crashes and shutdowns, all prepared transactions must be stored in permanent storage. This includes locking information, pending notifications etc. All that state information is written to the per-transaction state file in the pg_twophase directory. 
5.2RecoverPreparedTransactions 
Scan the pg_twophase directory and reload shared-memory state for each 
prepared transaction 
5.3lock_twophase_standby_recover 
Re-acquire a lock belonging to a transaction that was prepared, when starting up into hot standby mode. 
 
 
http://www.oschina.net/question/109945_13806

支付寶(杭州)正在招聘以下職位,有意向請聯系: qq:30673044,

簡歷請發至郵箱:ivan.li328@gmail.com

Postgresql DBA (15W - 25W)

工作地點: 杭州

職位描述:

1、負責Postgresql數據庫架構設計;

2、負責數據庫管理維護,監控及性能優化;

3、負責數據庫運維標准化,規范化;

4、數據庫規范化文檔編寫及管理;

5、配合公司產品和項目數據庫設計;

6、前瞻性數據庫技術與解決方案研究。

任職要求:

1、三年以上數據庫開發或DBA工作經驗

2、精通Postgresql數據庫體系架構設計及高可用性解決方案;

3、精通Postgresql數據庫管理,備份及性能調優;

4、精通Postgresql事務處理機制;

5、精通Linux系統管理與維護;

6、熟悉Shell/Perl等腳本語言;

7、有海量數據庫構架經驗者優先。

 

分布式數據庫開發工程師(Hadoop)—P6/P7 (20W - 35W)

工作地點:杭州
職位描述:

開發支付寶分布式數據庫系統 
協助部門制定產品計划,持續改善產品 


職位要求:
1.有扎實的計算機理論基礎, 對數據結構及算法有較強的功底 
2.熟練掌握C++/Java編程語言 
3.對分布式原理有較深的理解 

4.熟悉一種開源關系型數據庫的實現(mysql/postgres等) 
5.熟悉MapReduce及Hadoop的使用,能解決Hadoop的復雜問題 
6.熟悉Hive的實現 

 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM