稼動中の 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; } } }
この程度でいいんじゃないかしら。
VMware Player をサービス化する。
- sexe をインストール。
- sexe 起動
- ファイルに vmplayer.exe を指定。
- 起動時オプションに vmx ファイルのフルパスを指定。
- サービスの名前は適当に。
- OK 。サービスがインストールされる。
- 管理ツール→サービスを開き、インストールしたサービスのプロパティを開く。
- ログオン
- アカウントを選択し、自分のアカウントでも入れておく。
- OK 。
- ログオン
- サービスを再起動。
多分これで大丈夫。
何ていえばいいのこのパターン
<?php abstract class CtorProxy { protected function __construct() { $args = func_get_args(); call_user_func_array(array($this, '_ctor'), $args); } protected function _ctor() { // should be overridden. } } class PublicClass extends CtorProxy { public function __construct() { echo __METHOD__; } public function getProtectedClass() { return new ProtectedClass(); } } class ProtectedClass extends CtorProxy { protected function _ctor() { echo __METHOD__; } }
<?php $publicClass = new PublicClass(); // PublicClass::__construct $protectedClass = $publicClass->getProtectedClass(); // ProtectedClass::_ctor $protectedClass = new ProtectedClass(); // fatal error
オブジェクトの生成を制限しまくりたい私にとって、結構有難い。
どっかで既にありそうなパターンなんだけど、何ていう名前なんだろう。
マルチバイト対応 preg_match_all
他に書くこと考えなきゃなあ。
preg_match_all() のマルチバイト文字列版、 mb_ereg_all() 。
- 第 3 引数が省略できない。 (PHP 4 対応の為)
- PREG_OFFSET_CAPTURE 未対応。
- 確か、やたら面倒になりそうだったから。覚えてない。
<?php // coding: UTF-8 require 'mbstring.php'; mb_internal_encoding('UTF-8'); mb_regex_encoding('UTF-8'); $string = <<<EOS 色は匂へど 散りぬるを 我が世誰ぞ 常ならん 有為の奥山 今日越えて 浅き夢見じ 酔ひもせず EOS; $pattern = '([あ-ん])[あ-ん]*'; $count = mb_ereg_all($pattern, $string, $matches, PREG_PATTERN_ORDER, 0); var_dump($count, $matches);続きを読む
PHP の型検査を模倣する。
今日も常用している関数を晒してみる。
- bool cast_arg(mixed &$given, int $expect[, int $offset]) 値の型を検査する。
- http://xif.jp/php/cast_arg.phps
利用方法。
<?php require 'cast_arg.php'; /** * 模倣するのは * * function() expects parameter 1 to be long, array given * Object of class ClassName could not be converted to string * function() supplied resource is not a valid stream resource * function() parameter 1 must be a valid callback * + * in <b>/path/to/callee.php</b> on line <b>#</b><br />\n * * Array to string conversion は出ない。 * (function() expects ... になる) */ function foo($arg) { echo 'gettype(): ', gettype($arg), "\n"; if (!cast_arg($arg, TYPE_LONG, 1)) { echo '$arg is not int', "\n"; echo 'var_dump(): '; var_dump($arg); return false; } echo '$arg is int', "\n"; echo 'var_dump(): '; var_dump($arg); return true; } foo(1); // returns true // gettype(): integer // $arg is int // var_dump(): int(1) foo('1'); // returns true // gettype(): string // $arg is int // var_dump(): int(1) foo('bar'); // returns false // gettype(): string // Warning: foo() expects parameter 1 to be long, string given in ... // $arg is not int // var_dump(): int(0)続きを読む
IP アドレスから携帯キャリアを判別する。
127.0.0.1 のようなドット表記の IP アドレスから、携帯キャリアを判別する関数を生成します。
検索部分は http://d.hatena.ne.jp/tasukuchan/20071231/1199105717 を参考にしました。
異なる部分として
- 全部 PHP 。
- IP アドレスは手動設定。
- フルブラウザの IP アドレスなどは除外したかった。
- クローラ作るのも面倒だし、いっそ手動ということで。
- コードサイズの圧縮。相当小さくなります。
- else がありません。 if と elseif だけ。
- 32bit と 64bit を分けた。
- 必ず int で比較するようにする為。
- 当然、32/64bit 間で互換性はなし。それぞれ別個に生成すること。
- →やっぱり止めた。