Tokyo Tyrant基本規範(5)--教程

Tokyo Tyrant教程

 

1) 基礎使用

    安裝Tokyo Tyrant後,可以通過在終端執行命令'ttserver'來立即啓動服務器。默認,服務器在1978端口監聽,爲on-memory hash database(適合存儲緩存數據)提供訪問服務。

[terminal-1]$ ttserver

 

    在另外一個終端中執行下面的命令以測試存儲操作,'tcrmgr put'調用函數'tcrdbput':

[terminal-2]$ tcrmgr put localhost one first
[terminal-2]$ tcrmgr put localhost two second
[terminal-2]$ tcrmgr put localhost three third

 

    執行下面的命令來一次獲取多條記錄。'tcrmgr mget' 調用函數 'tcrdbget3':

[terminal-2]$ tcrmgr mget localhost one two three

 

    在服務器的終端中按Ctrl-C來終止服務器。

    通過指定後綴爲'.tch'的文件名,我們運行服務器來處理 hash database:

[terminal-1]$ ttserver casket.tch

 

    保存一些記錄

[terminal-2]$ tcrmgr put localhost one first
[terminal-2]$ tcrmgr put localhost two second
[terminal-2]$ tcrmgr put localhost three third

 

    用Ctrl-C終止服務器,然後重新啓動服務器:

[terminal-1]$ ttserver casket.tch

 

    檢查保存的記錄的一致性。

[terminal-2]$ tcrmgr mget localhost one two three

 

    爲了後續的教程,用Ctrl-C終止服務器並刪除數據庫。

[terminal-1]$ rm casket.tch

 

2) 後臺進程

    指定選項"-dmn"以後臺進程的方式運行服務器。此外,可以指定"-pid"選項來指定文件以記錄進程ID。注意後臺進程的當前工作目錄被修改到root目錄。因此,文件路徑參數需要用絕對路徑來表示。

[terminal-1]$ ttserver -dmn -pid /tmp/ttserver.pid /tmp/casket.tch

 

    爲了終止服務器,查看'_pid'指定的進程Id文件併發送SIGTERM 信號給進程。

[terminal-1]$ kill -TERM `cat /tmp/ttserver.pid`

 

    爲了通過操作系統的RC腳本運行服務器,請使用'ttservctl'。對於Linux髮型版本,添加下面的行到/etc/rc.local.

/etc/rc.local

 

    默認,數據庫文件和相關文件被放置在'/var/ttserver'下。因爲'ttservctl'是一個很小的shell腳本,您可以隨意的複製並編輯它。同樣,也可以安裝修改後的腳本到'/etc/init.d'並設置符號鏈接/etc/rc3.d/S98ttserver' and `/etc/rc5.d/S98ttserver'.

 

3) 備份和恢復

    讓我們再次運行服務器以繼續這個教程。

[terminal-1]$ ttserver casket.tch

 

    保存一些記錄。

[terminal-2]$ tcrmgr put localhost one first
[terminal-2]$ tcrmgr put localhost two second
[terminal-2]$ tcrmgr put localhost three third

 

    爲了備份數據庫文件,使用命令'tcrmgr copy'並指定目標路徑。注意備份文件將在服務器上的本地文件系統中創建(不是在客戶端這邊).

[terminal-2]$ tcrmgr copy localhost backup.tch

 

    按Ctrl-C 終止服務器並刪除數據庫

[terminal-1]$ rm casket.tch

 

    從備份文件中恢復數據庫並重啓服務器。

[terminal-1]$ cp backup.tch casket.tch
[terminal-1]$ ttserver casket.tch

 

    檢查存儲的記錄的一致性。

[terminal-2]$ tcrmgr mget localhost one two three

 

    爲了後續的教程,用Ctrl-C終止服務器並刪除數據庫。

[terminal-1]$ rm casket.tch backup.tch

 

4) 更新日誌

    讓我們開啓更新日誌來運行服務器。選項'-ulog'指定包含更新日誌文件的目錄。

[terminal-1]$ mkdir ulog
[terminal-1]$ ttserver -ulog ulog casket.tch

 

    存儲一些記錄.

[terminal-2]$ tcrmgr put localhost one first
[terminal-2]$ tcrmgr put localhost two second
[terminal-2]$ tcrmgr put localhost three third

 

    按Ctrl-C 終止服務器並刪除數據庫

[terminal-1]$ rm casket.tch

 

    備份更新日誌目錄並重新啓動服務器。

[terminal-1]$ mv ulog ulog-back
[terminal-1]$ mkdir ulog
[terminal-1]$ ttserver -ulog ulog casket.tch

 

    在客戶端使用'tcrmgr restore'命令從備份的更新日誌中恢復數據庫

[terminal-2]$ tcrmgr restore localhost ulog-back

 

    檢查存儲的記錄的一致性。

[terminal-2]$ tcrmgr mget localhost one two three

 

    爲了後續的教程,用Ctrl-C終止服務器並刪除數據庫。

[terminal-1]$ rm -rf casket.tch ulog ulog-back

 

5) 複製

    複製是同步兩臺或更多數據庫服務器的機制,實現高可用性和高完整性。複製源服務器被稱爲"master"而所有目標服務器都被稱爲"slave"。複製需要以下前提條件:

1. master必須記錄更新日誌

2. master必須指定唯一的服務器ID

3. 每個slave必須記錄更新日誌,因爲在master當機時它將成爲master

4. 每個slave必須指定唯一的服務器ID,因爲在master當機時它將成爲master

5. 每個slave必須指定它的master服務器的地址和端口號

6. 每個slave必須指定複製時間戳文件

 

    這個章節將描述何如建立一個master(使用端口1978)和一個slave(使用端口1979)的複製。首先,讓我們運行master服務器。

[terminal-1]$ mkdir ulog-1
[terminal-1]$ ttserver -port 1978 -ulog ulog-1 -sid 1 casket-1.tch

 

    下一步,在另一個終端運行slave服務器。

[terminal-2]$ mkdir ulog-2
[terminal-2]$ ttserver -port 1979 -ulog ulog-2 -sid 2 -mhost localhost -mport 1978 -rts 2.rts casket-2.tch

 

    在master中存儲一些記錄。

[terminal-3]$ tcrmgr put -port 1978 localhost one first
[terminal-3]$ tcrmgr put -port 1978 localhost two second
[terminal-3]$ tcrmgr put -port 1978 localhost three third

 

    在master和slave中檢查存儲記錄的一致性。

[terminal-2]$ tcrmgr mget -port 1978 localhost one two three
[terminal-2]$ tcrmgr mget -port 1979 localhost one two three

 

    讓我們模擬master崩潰的情況。Ctrl-C終止master並刪除數據庫文件。

[terminal-1]$ rm casket-1.tch

 

    Ctrl-C終止slave並重啓作爲master。

[terminal-2]$ ttserver -port 1979 -ulog ulog-2 -sid 2 casket-2.tch

 

    添加新的slave(使用端口1980)。

[terminal-1]$ mkdir ulog-3
[terminal-1]$ ttserver -port 1980 -ulog ulog-3 -sid 3 -mhost localhost -mport 1979 -rts 3.rts casket-3.tch

 

    在新的master和新的slave中檢查存儲記錄的一致性。

[terminal-2]$ tcrmgr mget -port 1979 localhost one two three
[terminal-2]$ tcrmgr mget -port 1980 localhost one two three

 

    Ctrl-C終止兩個服務器並刪除數據庫和相關文件。

[terminal-1]$ rm -rf casket-1.tch ulog-1 1.rts
[terminal-2]$ rm -rf casket-2.tch ulog-2 2.rts
[terminal-1]$ rm -rf casket-3.tch ulog-3 3.rts

 

    Tokyo Tyrant支持"雙master"複製可以提供更高的可用性。要實現它,運行兩個服務器各自複製對方。注意同時更新兩個master可能導致數據庫不一致。默認,服務器不報錯即使檢測到不一致。'-rcc'選項將使得服務器檢查一致性並在檢測到不一致時停止服務。

 

6) 按需設置複製

    可以爲正在運行的數據庫服務設置複製而不必停工。首先,爲備份操作準備下面的腳本並保存爲"ttbackup.sh",設置好可執行權限(0755)。

 

#! /bin/sh
srcpath="$1"
destpath="$1.$2"
rm -f "$destpath"
cp -f "$srcpath" "$destpath"

 

下一步,讓我們開啓更新日誌來啓動master。

[terminal-1]$ mkdir ulog-1
[terminal-1]$ ttserver -port 1978 -ulog ulog-1 -sid 1 casket-1.tch

 

    往master中存入一些記錄。

[terminal-2]$ tcrtest write -port 1978 localhost 10000

 

    檢查存儲的記錄的一致性。

[terminal-2]$ tcrmgr list -port 1978 -pv localhost

 

    備份數據庫

[terminal-2]$ tcrmgr copy -port 1978 localhost '@./ttbackup.sh'

 

    確認備份文件被保存爲"casket-1.tch.xxxxx"("xxxxx"爲備份文件的時間戳)。然後,使用備份文件運行slave。

[terminal-2]$ ls
[terminal-2]$ cp casket-1.tch.xxxxx casket-2.tch
[terminal-2]$ echo xxxxx > 2.rts
[terminal-2]$ mkdir ulog-2
[terminal-2]$ ttserver -port 1979 -ulog ulog-2 -sid 2 -rts 2.rts casket-2.tch

 

    注意上面的操作並不是指定master爲slave。作爲教程,讓我們模擬當你正在設置複製時,有一些記錄被用戶存儲進master。

[terminal-3]$ tcrmgr put -port 1978 localhost one first
[terminal-3]$ tcrmgr put -port 1978 localhost two second
[terminal-3]$ tcrmgr put -port 1978 localhost three third

 

    檢查master和slave的差異。

[terminal-3]$ tcrmgr inform -port 1978 localhost
[terminal-3]$ tcrmgr inform -port 1979 localhost

 

    給slave指定master,這樣將啓動複製並解決這個差異。

[terminal-3]$ tcrmgr setmst -port 1979 -mport 1978 localhost localhost

 

    確認slave知道master並且解決了差異。

[terminal-3]$ tcrmgr inform -port 1979 -st localhost

 

    Ctrl-C終止兩個服務器並刪除數據庫和相關文件。

[terminal-1]$ rm -rf casket-1.tch casket-1.tch.* ulog-1 1.rts ttbackup.sh
[terminal-2]$ rm -rf casket-2.tch ulog-2 2.rts

 

7) 調整

    如果使用hash database,設置調增參數"#bnum=xxx"來改進性能。它指定bucket 數量,應該要比存儲的記錄數多。

 

    如果使用B+ tree database,設置調整參數"#lcnum=xxx#bnum=yyy"來改進性能。前一個參數指定緩存的葉節點的最大數量,應該和系統容許的內存容量一樣大。後一個參數指定bucket 的數量,應該比要存儲的記錄數的1/128大。

 

    如果有非常大量的客戶端訪問服務器,確認已清除每個進程的文件描述符數量的限制。在大多數系統中默認設置爲1024。如果沒有,使用'ulimit'來清理它。

 

    爲了處理服務波峯時間的突發請求,可以用複製來聯合使用on-memory hash/tree database和file hash/tree database。master服務器處理on-memory database,它可以從容處理波峯時間的突發請求。但是on-memory database不保證數據的持久化,用於複製的slave通過將記錄存儲到文件數據庫中來彌補這個缺陷。

 

8) Lua擴展

    如果你需要比已有更加複雜的數據庫操作,請使用Lua擴展。舉例,準備下列腳本並保存爲"test.lua"。這裏有一個名爲"fibonacci"的函數,返回key的費伯那其數字(注:數列中每個數字是前兩個數字的和)

function fibonacci(key, value)
   local num = tonumber(key)
   local large = math.pow((1 + math.sqrt(5)) / 2, num)
   local small = math.pow((1 - math.sqrt(5)) / 2, num)
   return (large - small) / math.sqrt(5)
end

 

    讓我們啓動服務器,讓它讀取這個腳本文件

[terminal-1]$ ttserver -ext test.lua

 

    在客戶端命令中調用這個函數。

[terminal-2]$ tcrmgr ext localhost fibonacci 1
[terminal-2]$ tcrmgr ext localhost fibonacci 2
[terminal-2]$ tcrmgr ext localhost fibonacci 3
[terminal-2]$ tcrmgr ext localhost fibonacci 4
[terminal-2]$ tcrmgr ext localhost fibonacci 5
[terminal-2]$ tcrmgr ext localhost fibonacci 6

 

    Fibonacci可以通過其他算法來產生。添加下列腳本到"test.lua"。這裏有函數"fibnext"可以從數據庫中返回下一個費伯那其數字。狀態信息被保存在數據庫中。

function fibnext(key, value)
   local cur = tonumber(_get("fibcur"))
   if not cur then
      _put("fibold", 0)
      _put("fibcur", 1)
      return 1
   end
   local old = tonumber(_get("fibold"))
   _put("fibold", cur)
   cur = old + cur
   _put("fibcur", cur)
   return cur
end

 

    然後,重啓服務器並測試新的算法。

[terminal-2]$ tcrmgr ext localhost fibnext
[terminal-2]$ tcrmgr ext localhost fibnext
[terminal-2]$ tcrmgr ext localhost fibnext
[terminal-2]$ tcrmgr ext localhost fibnext
[terminal-2]$ tcrmgr ext localhost fibnext
[terminal-2]$ tcrmgr ext localhost fibnext

 

As you see, the called function receives two string parameters of the key and the value. The return value is sent back to the client. You can use such built-in functions for database operations as "_put", "_out", "_get", and so on. There is a sample file `ext/senatus.lua'.

 

    如你所見,被調用的函數接收兩個字符串參數,key和value。返回值被髮送回客戶端。你可以始終諸如"_put", "_out", "_get"等內建函數來進行數據庫操作。這裏有一個實例文件'ext/senatus.lua'。

 

9) 使用memcached 客戶端

    這個章節描述如何使用Perl的mamcached客戶端類庫(Cache::Memcached)來訪問Tokyo Tyrant。和平常一樣運行Tokyo Tyrant服務器,下面的腳本是一個典型例子。

 

use Cache::Memcached;
my $memd = Cache::Memcached->new();
$memd->set_servers(['localhost:1978']);
$memd->set('one', 'first');
$memd->set('two', 'second');
$memd->set('three', 'third');
my $val = $memd->get('one');
printf("one: %s\n", $val);
$val = $memd->get_multi('one', 'two', 'three');
printf("one: %s\n", $val->{one});
printf("two: %s\n", $val->{two});
printf("three: %s\n", $val->{three});
$memd->delete('one');

 

10) 使用HTTP 客戶端

    這個章節介紹如何使用Perl的HTTP客戶端類庫(LWP::UserAgent)來訪問Tokyo Tyrant。和平常一樣運行Tokyo Tyrant服務器,下面的腳本是一個典型例子。

 

use LWP::UserAgent;
my $ua = LWP::UserAgent->new(keep_alive => 1);
my $baseurl = 'http://localhost:1978/';
my $req;
$req = HTTP::Request->new(PUT => $baseurl . 'one', [], 'first');
$ua->request($req);
$req = HTTP::Request->new(PUT => $baseurl . 'two', ["X-TT-PDMODE" => 1], 'second');
$ua->request($req);
$req = HTTP::Request->new(PUT => $baseurl . 'three', ["X-TT-PDMODE" => 2], 'third');
$ua->request($req);
$req = HTTP::Request->new(GET => $baseurl . 'one');
my $res = $ua->request($req);
if($res->is_success()){
    printf("%s\n", $res->content());
}
$req = HTTP::Request->new(DELETE => $baseurl . 'one');
$res = $ua->request($req);
$req = HTTP::Request->new(POST => $baseurl . 'foo',
  ["X-TT-XNAME" => "echo", "X-TT-XOPTS" => 1], 'bar');
$res = $ua->request($req);
if($res->is_success()){
    printf("%s\n", $res->content());
}

 

11) 持久化而支持過期的緩存

    如果你想位你的web應用緩存類似session信息這樣的數據,但是想避免因服務器當機而造成的數據丟失,Tokyo Tyrant是一個方案,也就是說,持久化而支持過期的緩存。它需要下面的前提條件:

1. 服務器必須開啓table database

2. 客戶端保存每條記錄時要使用過期數據列

3. 數據庫在過期數據列上要有索引

4. 數據庫要開啓自動重新組合

5. 服務器必須週期性的調用通過Lua擴展提供的用戶自定義函數

 

    首先,爲過期準備下面的腳本並保存爲"ttexpire.lua"。當"X"列的數值超過當前日期時將使記錄過期。

 

function expire()
   local args = {}
   local cdate = string.format("%d", _time())
   table.insert(args, "addcond\0x\0NUMLE\0" .. cdate)
   table.insert(args, "out")
   local res = _misc("search", args)
   if not res then
      _log("expiration was failed", 2)
   end
end

 

    啓動服務器,table database方式,其中有一個"x"列是有索引的,並計劃每秒鐘調用一次expiration 函數。

[terminal-1]$ ttserver -ext ttexpire.lua -extpc expire 1.0 "casket.tct#idx=x:dec#dfunit=8"

 

    在另外一個終端中存儲測試記錄。

[terminal-2]$ now=`date +%s`
for((i=1;i<=60;i++)); do
tcrmgr put -sep '|' localhost "$i" "x|$((now+i))"
done

 

    確認數據正在被過期機制刪除:

[terminal-2]$ tcrmgr list -pv -sep '|' localhost


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章