稼動中の ttserver をデュアルマスタ化した。

現状

192.168.1.1:1978 で ttserver が稼動中。
バックアップも何もないので、二重化したい。

目標

192.168.1.1:1978 (Server.A) と 192.168.1.2:1978 (Server.B) でデュアルマスタ化して、バックアップついでに可用性も確保する。

方法

Server.A の起動コマンドを確認する

まず、 Server.A は -sid -ulog オプションがついている必要がある。
ついていなければ、再起動する。
再起動は十分早いので、稼動中でも別に良い……んじゃ……ないかな。

# Server.A の起動コマンド
/usr/local/bin/ttserver \
-host 192.168.1.1 \
-port 1978 \
-sid 1 \
-ulog /var/ttserver/ulog-1 \
/var/ttserver/casket.tch
Server.A のバックアップを取る

まずバックアップスクリプトを作成する。
スクリプトの場所はどこでもいい。
ここでは /path/to/script.sh とする。
また、バックアップファイルが作成されるディレクトリを、 /path/to/backup とする。

#!/bin/sh
BACKUP=/path/to/backup # バックアップディレクトリ
SRCPATH="$1"
BASENAME=`basename "$SRCPATH"`
DESTPATH="$BACKUP/$BASENAME.$2"
rm -f "$DESTPATH"
cp -f "$SRCPATH" "$DESTPATH"

バックアップする。
バックアップ作成中は、データベースがロックされるので注意。

/usr/local/bin/tcrmgr copy -port 1978 192.168.1.1 '@/path/to/script.sh'

これで、 /path/to/backup/casket.tch.XXX が作成される。
なお、 XXX は 16 桁のタイムスタンプ。
これをそのまま Server.B に送る。

Server.B を設定する

Server.A から送られてきたバックアップファイルを、 /path/to/backup/casket.tch.XXX とする。

BACKUP=/path/to/backup/casket.tch.XXX

# データベースファイルと更新ログを置くディレクトリを作成。
mkdir -p /var/ttserver/ulog-2

# ファイル名が cas.ket.tch.XXX である等、 . が 2 つ以上含まれている場合は失敗するので注意。
BASENAME=`basename "$BACKUP" | cut -d. -f1,2`
RTS=`basename "$BACKUP" | cut -d. -f3`

mv $BACKUP /var/ttserver/$BASENAME
echo "$RTS" > /var/ttserver/2.rts

# 起動。
/usr/local/bin/ttserver \
-host 192.168.1.2 \
-port 1978 \
-sid 1 \
-ulog /var/ttserver/ulog-2 \
-mhost 192.168.1.1 \
-mport 1978 \
-rts /var/ttserver/2.rts \
/var/ttserver/casket.tch

これで Server.A => Server.B のレプリケーションが出来る。

Server.A を設定する

Server.B => Server.A のレプリケーションを設定する。

# これだけ。
/usr/local/bin/tcrmgr setmst -port 1978 -mport 1978 192.168.1.1 192.168.1.2
終了

バックアップ作成さえ何とかなれば、無停止でデュアルマスタ構成に出来るよ!
やったね!

今後の課題

バックアップの作成がネックだけど、 cp じゃなくて LVM のスナップショットにすれば、何とか出来るかも。

運用について

運用時は、常に Server.A に対して更新するようにする。
Server.A に対する更新が失敗した場合のみ、 Server.B に対して更新する。

<?php
function get_tt()
{
    try {
        return new TokyoTyrant('192.168.1.1', 1978);
    } catch (Exception $e) {
        try {
            return new TokyoTyrant('192.168.1.2', 1978);
        } catch (Exception $e) {
            return null;
        }
    }
}

この程度でいいんじゃないかしら。