數據庫集羣:N個數據庫堆到一塊兒,找一個當個頭頭,管理全部的數據庫並讓它們協同工做。固然了,要不要找個頭頭,找幾個頭頭,如何協做等等問題這些均可以商量和約定,所以,也就造成了不一樣的數據庫集羣。html
若是數據庫系統是PostgreSQL,這個集羣就是PostgreSQL數據庫集羣。前端
PostgreSQL數據庫管理集羣的方法有不少,有人提出了PL/Proxy方式的集羣(這纔是本文的重點)。這個PL/Proxy方式的集羣是這樣的:有不少安裝了PostgreSQl數據庫的計算機,有臺計算機是頭頭,咱們把這個頭頭叫作proxy,其餘的叫作database0,database1……。linux
以三臺機器的集羣爲例子,看看PostgreSQL集羣的架構是什麼。算法
proxy節點:proxy節點實際上也是一個PostgreSQL數據庫 節點,可是全部數據均不存放到proxy節點上,主要作三件事情:sql
1.接受用戶的sql查詢;數據庫
2.分析用戶的sql查詢並轉換成集羣上執行的SQL語句;ubuntu
3.合併集羣執行sql的結果,而後返回給用戶。vim
說白了,就是把用戶的sql語句交給database0,database1去執行,而後合併執行結果返回給用戶。windows
database1節點和 database2節點:瀏覽器
就是普通的數據庫節點,接收proxy節點的sql查詢請求並返回結果給proxy節點,是真正存放數據的節點。
集羣結構圖,結構更清晰一些:
開始建立一個數據庫集羣吧,需求以下:
1.建立一個如集羣結構圖所示的集羣,數據庫集羣中均操做同一個數據庫「arvindb」;
2.用戶經過客戶端操做proxy節點在集羣中建立一個表user(說白了就是要經過集羣的方法在Database0和Database1的arvindb中建立一個叫作user的表);
3.用戶經過客戶端操做proxy節點在集羣上插入多個記錄信息到集羣的user表上(須要把插入操做分佈到兩個Database節點上);
4.用戶經過客戶端操做proxy節點在集羣上查詢集羣上的全部user記錄;
(版本號須要留意一下,版本不一樣的話,可能會致使狀況大不相同)
操做性較強的步驟:
第一步:建立三個空的虛擬機器並把這三臺虛擬機的網卡設置搞定(好比,是否橋接,是否NAT之類)(有錢的話,本身買三臺電腦,3條網線和一個集線器)。
能夠建立虛擬機的軟件如VMWare, VirtualPC, Xen等等,本文的實驗用的是VMWare.
第二步:三個虛擬機所有安裝Ubuntu-12.04
第三步:三個虛擬機所有安裝PostgreSQL數據庫系統
如何安裝和配置請參見Ubuntu下 Postgresql-9.1安裝及配置
第四步:將每臺服務器的設定成容許任何機器使用任何帳號訪問任何數據庫
root@ubuntuserver:~# vi /etc/postgresql/9.1/main/pg_hba.conf
—>改變行:host all all 0.0.0.0 0.0.0.0 md5
—>修改成:host all all 0.0.0.0 0.0.0.0 trust
若是沒有此行則添加此行,具體說明參見Ubuntu下 Postgresql-9.1安裝及配置。
第五步:三個虛擬機所有建立數據庫Arvindb:
root@ubuntuserver:~# psql –U postgres -h 127.0.0.1
postgres=# create database 「arvindb」;
建立數據庫的詳細方法請參見Ubuntu下 Postgresql-9.1安裝及配置
PS:如今的三臺機器都能提供數據庫服務了,並且在任何一臺機器使用客戶端均可以自由的訪問其餘數據庫服務器中的」arvindb」數據庫,不過他們還不是集羣,僅僅是能夠相互訪問的數據庫服務器而已,他們之間沒有任何協做關係。下面建立PL/Proxy方式的協做關係(建立PostgreSQL 數據庫集羣)。
第六步:在 proxy 節點上安裝過程語言plproxy(安裝 plproxy 必須使用 root 用戶,不然不能正常安裝)
root@ubuntuserver:~# sudo apt-get install postgresql-9.1-plproxy
下面是解釋,不想了解的話,能夠直接跳過。
這一步的目的是:使proxy節點知道怎樣指揮集羣(實驗中,就是指揮database0和database1),換句話就是說,讓prxoy知道三件事情:
怎樣把用戶的SQL請求發送給集羣的節點;
怎樣接受集羣的處理結果;
怎樣將處理後的結果返回給用戶。
這一步的實質是:複製plproxy.so文件到目錄」/user/lib/postgresql/9.1lib」的下面;複製plproxy.sql文件到目錄」/usr/share/postgresql-9.1-plproxy」下面(這個目錄是安裝程序建立的,plproxy.sql文件是給下一步建立plproxy語言使用的,不是必須的,徹底能夠在須要的時候本身寫相應的SQL語句)。這兩個文件的存在是這一步安裝成功的一個標誌。
須要注意的是:安裝過程語言是對數據庫系統而言的,能夠認爲僅僅是複製了一些須要的文件而已,以後使用這個過程語言的以前,還要分別爲每個須要使用此過 程語言的數據庫建立這個語言(說白了,就是還要告訴每一個數據庫到那裏找相應的文件plproxy.so文件,下一步有解釋)。
執行後在文件瀏覽器中的效果是:
root@ubuntuserver:~# psql -U postgres -h 127.0.0.1 -f /usr/share/postgresql/9.1/contrib /plproxy.sql Arvindb
這條語句的實質是:在數據庫系統表pg_language中添加一行記錄。
執行後在pgAdmin3客戶端觀看到的效果是:
固然要是你嫌每次都要建立語言麻煩,你能夠將過程語言建立到template1數據庫中,這樣每次建立數據庫的時候,所的語言都自動建立好了(建立數據庫 的過程實際上就是複製templated1模板數據苦的過程)。
下面是解釋,不想了解的話,能夠直接跳過。
這一步的目的是告訴數據庫」 arvindb」遇到plproxy的過程函數時候怎麼處理。
文件plproxy.sql的內容以下:
– handler function
CREATE FUNCTION plproxy_call_handler () RETURNS language_handler
AS ‘$libdir/plproxy’ LANGUAGE C;
– language
CREATE LANGUAGE plproxy HANDLER plproxy_call_handler;
解釋一下:
–handler function之下的代碼的做用是建立一個函數,名字叫作plproxy_call_handler,返回類型是language_handler,他的定義在文件夾」$libdir」之下的plproxy.so文件中plproxy.so是一個由C語言編譯而成的.so文件;
– language之下的代碼的做用是建立一個過程語言,過程語言的名稱是plproxy,處理這個過程語言的函數是plproxy_call_handler,過程語言的源代碼就是這個函數的參數。
可見,實際上過程語言就是一個「C」語言函數的字符串參數。
這裏有必要說起一下過程語言的前世此生(過程語言的官方解釋見http://www.pgsqldb.org/pgsqldoc-cvs/xplang.html 。:
在PostgresSQL數據庫系統裏,除了使用系統自帶的函數(如count(), max()等)外,還能夠使用你本身編寫的函數。編寫函數的語言能夠是sql或C語言,也能夠是指定的過程語言(好比plproxy過程語言,plpgsql過程語言,你也能夠本身寫一個過程語言)。編寫sql語言/C語言/plproxy過程語言的函數的例子以下:
CREATE OR REPLACE FUNCTION fun_sql_test()
RETURNS INTEGER AS
$BODY$
SELECT 1;
$BODY$
LANGUAGE‘sql‘ VOLATILE
—————————–
CREATE OR REPLACE FUNCTION fun_c_test()
RETURNS INTEGER AS
‘$libdir/c_test’, ‘fun_c_test’
LANGUAGE ‘c‘ VOLATILE
—————————–
CREATE OR REPLACE FUNCTION fun_plproxy_test()
RETURNS integer AS
$BODY$
CLUSTER ‘jiwan’;
RUN ON ALL;
$BODY$
LANGUAGE ‘plproxy‘ VOLATILE
—————————–
這樣就建立了三個函數fun_sql_test(),fun_c_test()和fun_plproxy_test()。
對於fun_sql_test(),執行很簡單:
0.用戶執行fun_sql_test()函數;
1.執行$BODY$語句包圍的sql語句;
2.返回一個整形的數值1。
對於fun_c_test(),執行的順序是:
0.用戶執行fun_c_test()函數;
1.到$libdir目錄(這段文字會被PostgreSQL替換成PostgreSQL的庫目錄:「/user/lib/postgresql/8.5/lib「)加載c_test.so文件(.so文件是linux系統的共享文件,至關於windows下的.dll文件);
2.執行c_test.so中的fun_c_test()函數。
3.返回一個整形的數值。
對於fun_plproxy_test(),執行的順序是(第1步加載.so文件的執行時間不必定正確,僅僅是爲了說明過程語言的執行原理,下同):
0.用戶執行fun_plproxy_test()函數;
1.根據plproxy過程語言的配置加載plproxy.so文件( 根據以前「create language」語句中的參數’$libdir/plproxy’);
2.提取$BODY$語句包圍的語句 (這個就是所謂的過程語言源代碼):CLUSTER ‘jiwan’; RUN ON ALL;
3.根據plproxy過程語言的配置調用過程語言的語言句柄函數plproxy_call_handler並把上一步中提取的過程語句做爲它的參數;
4.返回一個整形的數值。
可見,實際上過程語言就是一個「C」語言函數的字符串參數。不論是誰寫的過程語言, PostgreSQL中的函數的處理方式大體都是這樣的:
0.用戶執行某種過程語言的函數;
1.根據過程語言的配置加載相應的.so文件;
2.將函數體中的源代碼(簡單的說,就是一段文本)抽取出來(函數體中的文本須要根據相應的.so文件的約定去書寫,你不按照它的約定,它就會狀告你說:編譯錯誤);
3.根據過程語言的配置調用語言句柄函數並把以前提取的過程語句做爲它的參數。
目前在標準的 PostgreSQL 發佈裏有四種過程語言可用: PL/pgSQL, PL/Tcl, PL/Perl和 PL/Python等等過程函數。
固然,你也能夠本身寫一個模塊用於解析函數體中的源代碼,簡單的說,就是你本身寫一個.so文件,把這個.so文件複製到目錄「/user/lib/postgresql/8.5/lib「的下面(這個不是必須的,不過呢,plpgsql.so在這個目錄下面,plproxy.so文件也在這個目錄下面,就跟一下風吧!)。咱們把複製.so文件的 這一步操做叫作安裝過程語言(多玄乎啊,嚇唬小白必須學會這個詞!)這個.so文件中應該包含語言句柄函數和驗證器函數(這個可選)。
root@ubuntuserver:~# sudo -u postgres psql Arvindb
Arvindb=# create language plpgsql;
或者:sudo -u postgres createlang plpgsql 「Arvindb」
下面是解釋,不想了解的話,能夠直接跳過。
關於過程語言plpgsql和plproxy之間的關係:
之因此建立plpgsql語言,是由於plproxy過程語言自己須要調用plproxy目錄下的三個由plpgsql過程語言定義的三個函數。
plpgsql 是postgresql自帶的過程語言(含義是,安裝 postgresql數據庫的時候plpgsq.so文件就會被安裝到postggresql的lib文件夾下,對於apt-get install postgresql方式安裝的9.1版本數據庫系統的lib文件夾是/usr/lib/postgresql/9.1)。
自帶的含義就是「HANDLER plpgsql_call_handler」; 和「VALIDATOR plpgsql_validator;」 這兩個函數應該是數據庫系統爲plpgsql過程語言默認設置的handler函數和validator函數(這個是個人猜想,尚未證明),因此建立plpgsql的時候不須要指定handler函數和validator函數(當 然,validator函數本省就是可選的)。有圖有真相:
若是數據庫系統中的模板數據template1沒有建立plpgsql過程語言的話,每個數據庫要使用plpgsql語言以前,都須要建立該語言,以數據庫arvindb爲例的語句是:
root@ubuntuserver:~#sudo -u postgres createlang plpgsql 「Arvindb」
plproxy 是用於集羣的過程語言,定義了RUN ON ALL/ANY/0/1/2/3….等等函數,安裝該語言的語句:
CREATE PROCEDURAL LANGUAGE ‘plproxy’ HANDLER plproxy_call_handler;
固然了,plproxy不是系統自帶的過程語言,是經過apt-get install postgresql-9.1-plproxy安裝的過程語言(實際上主要就是下載了plproxy.so文件),爲了告訴數據庫過程語言的狀況,因此需 要編寫plproxy_call_handler:
CREATE OR REPLACE FUNCTION plproxy_call_handler() RETURNS language_handler AS
‘$libdir/plproxy’, ‘plproxy_call_handler’
LANGUAGE ‘c’ VOLATILE
plproxy 過程語言在定義plproxy.get_cluster_config, plproxy.get_cluster_partitions, plproxy.get_cluster_version三個函數的時候使用的也是plpgsql過程語言。
root@ubuntuserver:~# sudo -u postgres psql -d 「Arvindb」
Arvindb=# create schema plproxy;
下面是解釋,不想了解的話,能夠直接跳過。
關於schema:schema的中文含義就是一個目錄(可能不許確),是用來組織數據庫中的各個對象的(PostgreSQL是ORDBMS,O就是對象的意思,好比數據表,函數等等),系統默認有一個public的schema,全部對象默認建立的位置都是public下,使用public下的對象也不須要前綴(好比public下有一個user的表,那麼public.user等價於user)。plproxy這個schema是proxy過程語言所須要的schema(proxy語言須要調用這個schema下的三函數,具體緣由下面會說到)。其實建立schema的實質是:在系統的schemata數據表中添加一行數據。
執行後在pgAdmin3客戶端觀看到的效果是:
get_cluster_config
get_cluster_partitions
get_cluster_version
root@ubuntuserver:~# sudo -u postgres psql Arvindb
建立函數的SQL代碼以下:
CREATE OR REPLACE FUNCTION plproxy.get_cluster_config(IN cluster_name text, OUT "key" text, OUT val text)
RETURNS SETOF record AS
$BODY$
BEGIN
key := 'statement_timeout'; //就是給 key 變量賦值,賦的值爲’statement_timeout’
val := 60; //就是給 val 變量賦值,賦的值爲 60
RETURN NEXT;
RETURN;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100
ROWS 1000;
CREATE OR REPLACE FUNCTION plproxy.get_cluster_partitions(cluster_name text)
RETURNS SETOF text AS
$BODY$
BEGIN
IF cluster_name = 'arvincluster' THEN //cluster_name 是羣集的名字
RETURN NEXT 'dbname=hldb host=10.3.12.2'; //數據庫節點的數據庫名和 IP 地址
RETURN NEXT 'dbname=hldb host=10.3.12.3'; //數據庫節點的數據庫名和 IP 地址
RETURN;
END IF;
RAISE EXCEPTION 'Unknown cluster'; //–若是羣集名不存在,拋出異常,這個是在數據庫內部處理的,最終會寫入日誌中。‘Unknown cluster’是報錯信息
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100
ROWS 1000;
CREATE OR REPLACE FUNCTION plproxy.get_cluster_version(cluster_name text)
RETURNS integer AS
$BODY$
BEGIN
IF cluster_name = ' arvincluster ' THEN
RETURN 1;
END IF;
RAISE EXCEPTION 'Unknown cluster';
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
下面是解釋,不想了解的話,能夠直接跳過。
三個函數的做用:
plproxy.get_cluster_config: 這個函數實際上是獲取不一樣的集羣的配置,咱們這裏能夠給不一樣的集羣(好比Arvindb等)不一樣的相似超時時間、長短鏈接等的設置。
plproxy.get_cluster_partitions: 這個函數是讓plproxy能夠找到對應的集羣,「Arvindb 」是集羣的名稱,根據本身的須要指定,這個名稱在後面查詢的時候要用到;」dbname」, 「host」 等參數就是PostgreSQL標準的數據庫鏈接串的配置方法,本試驗中就是database0節點和database1節點的信息告訴proxy節點。
plproxy.get_cluster_version: 這個函數實際上是plproxy用於判斷是否給前端返回已經cache過的結果用的,這樣,由於函數自己能夠動態更新(無需down機),那麼咱們能夠經過從新建立函數,返回不一樣RETURN的值,實現cache的失效控制。
plproxy過程語言設計的目的是實現數據庫集羣,集羣受proxy節點管理,proxy獲取集羣的信息(好比節點的IP地址等等信息)的方法就 是調用上面建立的三個函數,因此配置集羣信息的方法就是建立/修改這三個函數。
使用plproxy過程語言的用戶不須要顯式的調用這三個函數,可是在調用plproxy過程語言定義的函數的時候,plproxy過程本身會在內部調用目錄plproxy下的這三個函數:
I.對於plproxy.get_cluster_config和plproxy.get_cluster_partitions函數,內部調用一次後就 再也不調用;
以plproxy.get_cluster_partitions爲例子的實驗是:
a.執行plproxy 過程語言定義的函數–>成功;
b.刪除plproxy.get_cluster_partitions函 數,調用plproxy過程語言定義的函數,執行成功。
一個特殊狀況:若是刪除plproxy.get_cluster_partitions函數以前,數據庫系統從未執行過任何plproxy過程語言定義的 函數,執行plproxy過程語言定義的函數將會失敗).
另一個實驗是:
a.執行plproxy 過程語言定義的函數–>成功;(集羣信息爲「dbname=Arvindb host=10.13.19.55」和dbname=Arvindb host=10.13.19.70)
b.修改plproxy.get_cluster_partitions函 數(集羣信息爲「dbname=Arvindb host=10.13.19.55」和dbname=Arvindb host=10.13.19.71, 調用plproxy過程語言定義的函數,執行成功。可是使用的集羣信息仍然是:「dbname=Arvindb host=10.13.19.55」和dbname=Arvindb host=10.13.19.70)。
II.對於plproxy.get_cluster_version函數,執行plproxy過程語言定義的函數的時候,內部每次都會調用plproxy.get_cluster_version函數。 實驗的方法可與參考前面的方法。
總結一下:若是修改了plproxy.get_cluster_config和plproxy.get_cluster_partitions函 數,想當即生效 的話,就須要重啓postgresql服務(其餘方法尚未深究過):/etc/init.d/postgresql-8.4 restart
從網上參考的資料,以及相關pdf中參看的代碼會有一些問題:字符不對 ,一樣爲單引號,可是pdf中的單引號是‘(看清楚:不是正確的’),等等之類很難發現的錯誤,嚴重影響了工做進度。
再補充一下:下面的實驗代表 postgresql下的函數定義/修改/刪除是及時生效的:
建立一個函數:
CREATE OR REPLACE FUNCTION fun_test() RETURNS integer AS
$BODY$ SELECT 33; $BODY$
LANGUAGE ‘sql’ VOLATILE COST 100;
執行這個函數:
select fun_test();———> 正常執行
刪除這個函數:
DROP FUNCTION fun_test;
執行這個函數:
select fun_test(); ——–>執行失敗:找不到函數fun_test();
public.ddlexec(sql_request text)
public.dmlexec(sql_request text)
public.dqlexec(sql_request text)
root@ubuntuserver:~# sudo -u postgres psql Arvindb
建立的sql代碼是:
CREATE OR REPLACE FUNCTION ddlexec(query text)
RETURNS SETOF integer AS
$BODY$
CLUSTER 'arvincluster';
RUN ON ALL;
$BODY$
LANGUAGE 'plproxy' VOLATILE
COST 100
ROWS 1000;
CREATE OR REPLACE FUNCTION dmlexec(query text)
RETURNS SETOF integer AS
$BODY$
CLUSTER 'arvincluster';
RUN ON ANY;
$BODY$
LANGUAGE 'plproxy' VOLATILE
COST 100
ROWS 1000;
CREATE OR REPLACE FUNCTION dqlexec(query text)
RETURNS SETOF record AS
$BODY$
CLUSTER 'arvincluster';
RUN ON ALL;
$BODY$
LANGUAGE 'plproxy' VOLATILE
COST 100
ROWS 1000; ROWS 1000;執行後在pgAdmin3客戶端觀看到的效果是:
下面是解釋,不想了解的話,能夠直接跳過。
這三個函數的做用就是:用戶經過調用者三個函數操縱集羣(好比select ddlexec(‘create table usertable’)就會在集羣的database0和database1上同時建立一個表usertable)。
這三個函數都是plproxy過程語言的函數,函數中的RUN指令會調用集羣節點上的同名函數,因此還需爲集羣上的數據庫節點database0和database1建立同名的函數(只要同名,不須要也是plproxy過程語言定義)。
RUN ON指令以後的的ALL表示在集羣上的全部數據庫節點上運行(本試驗就是database0和databse1都要執行)
RUN ON指令以後的的ANY表示在集羣上的任取一個數據庫節點上運行(本試驗就是database0和databse1中任意取一個執行)
RUN ON 以後也能夠是一個數字: 表示在幾號節點上運行,好比 RUN ON 0/RUN ON 1。也能夠本身寫一個算法決定如何分配任務: 好比RUN ON hashtext(表的主鍵值)&1。表示將表的主鍵(文本類型)計算出一個hash值,然和1作與運算。就能夠根據主鍵分配數據庫節點。
root@ubuntuserver:~# sudo -u postgres psql Arvindb
Arvindb=# create language plpgsql;
或者:sudo -u postgres createlang plpgsql 「Arvindb」
建立的緣由是:database0和database1節點須要建立一些函數,這些函數是plpgsql過程語言定義的。
public.ddlexec(sql_request text)
public.dmlexec(sql_request text)
public.dqlexec(sql_request text)
root@ubuntuserver:~# sudo -u postgres psql Arvindb
建立的SQL語句以下:
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;執行後在pgAdmin3客戶端觀看到的效果是:
Arvindb=# select ddlexec('create table usertable(id integer)');
root@ubuntuserver:~# sudo -u postgres psql Arvindb
select dmlexec(‘insert into usertable values(0)’);
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)');
能夠經過pgAdmin3看到建立的結果(數據存到那個節點取決於分配算法):
select * from dqlexec('select * from usertable') as (id integer);
注意:必需要有as以後的內容,緣由是, plpgsql過程語言的record返回類型須要有列定義。
能夠經過pgAdmin3看到建立的結果:
續:
可能出現的問題 |
解決方案 |
用apt-get安裝時,沒法找到安裝包 |
(1) 更新安裝源地址,建議用百度安裝源 輸入命令 :sudo vim /etc/apt/sources.list(安裝源本身找,刪除原有代碼,複製到裏面就能夠了) (2) 查看網絡是否鏈接,ip、netmask、getway、dns是否正確配置 輸入命令:sudo vim /etc/network/interfaces (3) 更新apt-get 輸入命令:apt-get update |
運行引用代碼時,提示出現錯誤 |
(1) 雙引號,或單引號使用錯誤,手動更改成符合要求的。 (2) 丟失分號(;)應特別注意。 |
apt-get安裝pgadmin3時,沒有出現圖形界面 |
(1)建議獨立下載pgadmin3並安裝 |
……. |
………. |
著:通過做者實踐檢驗,能夠正常實施.如有疑問,請加QQ;505024705
或e-mail:hl_linux@yahoo.cn