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