MongoDB的な何か。 ログ出力について

最近、MongoDBのソースコードを読もうと思いました。
理由は、使うかもしれないから。です。
自分が一番気になる箇所は、DiskI/O(バッファとかの扱い方、flushのタイミングなど)ですが、
まずは基本的なログ出力から確認してみました。(まぁ、デバックコードとか入れるときのためです)
そもそも、C++は未だかつてやったことがないです。。。

今回確認したソースのバージョンは MondoDB 2.0.4 です。
MongoDBの起動時のログファイルより。
Wed Apr 4 21:44:43 [initandlisten] MongoDB starting : pid=XXXX port=XXXXX dbpath=/home/mongodb/data 64-bit host=XXX
なので。。

db.cpp

                          • -

417 Nullstream& l = log();
418 l << "MongoDB starting : pid=" << pid << " port=" << cmdLine.port << " dbpath=" << dbpath;
419 if( replSettings.master ) l << " master=" << replSettings.master;
420 if( replSettings.slave ) l << " slave=" << (int) replSettings.slave;
421 l << ( is32bit ? " 32" : " 64" ) << "-bit host=" << getHostNameCached() << endl;
422 }

                          • -

なので、log()を追う必要があります。

log.h

                          • -

362 inline Nullstream& log() {
363 return Logstream::get().prolog();
364 }

                          • -

inline使ってました。。。まぁ log だからそんなもんでしょうか。

log.h

                          • -

275 Logstream& prolog() {
276 return *this;
277 }
.....
299 public:
300 static Logstream& get() {
301 if ( StaticObserver::_destroyingStatics ) {
302 cout << "Logstream::get called in uninitialized state" << endl;
303 }
304 Logstream *p = tsp.get();
305 if( p == 0 )
306 tsp.reset( p = new Logstream() );
307 return *p;
308 }

                          • -

となってます。

うーん。まぁ細かいところは追いませんが、こんな感じ。

PostgreSQL Conference 2012 に参加してきました!

PostgreSQL Conference 2012 に参加してきました!

いろいろと興味深い話が聞けてよかったです。

その中でも一番興味を持った項目が pgpool-II のオンラインメモリクエリキャッシュ

簡単にまとめると、pgpool-II 側で PostgreSQL に以前発行したSQL
Fetch 結果をキャッシュし、キャッシュが有効であれば PostgreSQL
らのデータの読み込みせずに pgpool-II 側でキャッシュからデータを返
すというもの。

キャッシュのバックエンドに使えるものは以下の二つ。

  • shmem(共有メモリ)
  • memcached
    • pgpool-II を複数台構成する場合には memcached のみサポート。

memcached をキャッシュとして使用するのは非常に興味深いです。
libmemcache を使用しているとのことで、libmemcache から使えるものであれば、例えば kumoFS でも問題ないとのこと。こりゃ便利!と思いましたが、もちろん制約がある。
以下のケースにおいてキャッシュクリアが正常に行われない。

  • drop table ... cascade/ truncate table ... cascade
  • trigger により更新されたデータ
  • view がネストしている表

pgpool-II のオンラインメモリクエリキャッシュでは、delete や update が流れた場合には、その対象の表のキャッシュをクリアし、新しい結果をセットする動作になっている。

しかし、これが cascadeつきのSQLであった場合には、キャッシュクリアされない。例えば、partition table を削除する際に drop table ... cascade 構文を実施した場合等がこれに該当する。

このようなSQLを実施すると PostgreSQL 側が自動で必要な table を操作し、削除してくため pgpool-II からしてみれば、勝手に PostgreSQL が動いて削除するものなんて検知しようがないよ。といったためです。


pgpool-II 側にキャッシュ対象の表を指定することもできるみたいですし、手動でのキャッシュクリアもできることを検討しているみたい。



うまく利用すれば、パフォーマンスはかなり期待できる。が、今度はmemcachedサーバの運用も+α必要となる。
実際に使えるようになるには、いろいろと悩ませる箇所も非常に多いと思う。



データベースの負荷を減らすには、スキーマをいくら効率が良いものにしても、SQLをいくら簡単なものにしてもアクセスが多いことが一番のネックになる。そのため、今までは、そもそもDBへのアクセス回数を減らすため、APサーバからDBへそもそもcallしないようにする。システムを作らなければならなかった。
そのためには、アプリケーション側でキャッシュを用意し、動作させる必要があり、開発管理運用が大変になっていったが、この pgpool-II の新機能をうまく利用することでアプリケーション側でのキャッシュは必要なくなるかもしれない。そうしたら、構成もシンプルになるし開発工数も減る。ハッピーだ。

Release Date は、2012年5月を予定している。


後日、PostgreSQL 9.2 の新機能についても記載したいと思います。

PostgreSQL 9.1.2 pgpool-II-3.1.1 がリリース

PostgreSQL 9.1.2 および pgpool-II-3.1.1 がリリースされました。
pgpool-II については、memory leak の bug が fix されているため、pgpool-II-3.1系を使う場合には、
バーッジョンアップは必須ですね。

PostgreSQL 9.1.2 にも多くのBugfixがされています。

詳細はリリースノートをご確認下さい。
PostgreSQL: Documentation: 9.1: Release 9.1.2

index 再構築 Primary key

先日、PostgreSQLでのIndex再構築方法についてご紹介いたしました。
主にオンラインシステムでは、create index conccurently を使うことになるかと思いますが、主キーの場合には方法が少しかわります。
といっても、一行SQLが増えるだけですが。

以下のように変更します。

create table hoge(col1 int primary key, col2 varchar(10));
create unique index concurrently pk02_hoge on hoge(col1);
alter table hoge add primary key using index pk02_hoge;

concurrently で作成した索引に対して、alter table で新旧の索引を入れ替えることができます。
ただし、このコマンドはPostgreSQL9.1以上でのみ有効です。

それ以下のバージョンの場合では、reindexする必要があります。
ご注意ください。

複数サーバにsshログインする方法

サーバを構築する際にいつも悩むのが、、、同じ構築方法なのになんで何台もオペレーションしないといけないということ。

テンプレートを作ってdump->restoreしてください。と言われればそれまでなのだが、dumpとなるとバージョン管理だったり、イメージ格納ディスクだったりrestore時はそもそもNETWORKにつながらない状態なのでいろいろと大変なのだ。

そんな時のために、sudo対応のexpectでコマンドを発行するスクリプトを作成した。
これをサーバリストでも作ってそのリストとおりにwhileで回せばやりたいことができる。


便利だ。次はログファイルにでも作業内容を落とすとしよう。



#!/bin/sh

SCRIPT=$0

usage(){
cat < -l -c ''
-u execute user name(*)
-l target host
-c execute command(*)
-p password
-h print this help and exit
(*) required
EOF

return 0
}

__check(){

if [ -z "${_USER}" ] || [ -z "${_COMMAND}" ] || [ -z "${_PASSWD}" ]; then
usage
return 1
fi

return 0
}

__getpasswd(){
echo -n "password: "
stty -echo
read _PASSWD
stty echo
echo ""
return 1
}

while getopts f:u:c:ph opt
do
case ${opt} in
'u') _USER=${OPTARG} ;;
'l' ) _HOST=${OPTARG} ;;
'c') _COMMAND=${OPTARG} ;;
'p') __getpasswd ;;
'h') usage && exit 1 ;;
'?') usage && exit 1 ;;
esac
done

__check
if [ $? != 0 ]; then
echo "$SCRIPT is aborted..."
exit 1
fi

expect -c "
set timeout 1
spawn ssh ${_HOST} -l ${_USER}
expect {
\"Are you sure you want to continue connecting (yes/no)?\" {
send \"yes\r\"
expect \"password:\" {
send \"${_PASSWD}\r\"
}
}
\"${_USER}@${_HOST}'s password:\" {
send \"${_PASSWD}\r\"
}
}

expect {
\"$ \" {
send \"${_COMMAND}\r\"
expect {
\"password for ${_USER}:\" {
send \"${_PASSWD}\r\"
}
\"Password:\" {
send \"${_PASSWD}\r\"
}
}
}
}

expect {
\"$ \" {
send \"logout\r\"
}
}
"

index 再構築方法

最新バージョンでは、索引の再構築の必要性は低くなっているものの、
しなくていいわけではない。
そのため、PostgreSQL で index を再構築について改めて確認してみた。

方法は以下3つ。

  1. reindex
  2. create index
  3. create index concurrently

まず、それぞれの操作について確認する

1. reindex - DML, select ともにLOCKされる
2. create index - DML は LOCK される。select は実施可能
3. create index concurrently - DML,select 可能

1. 実施は簡単なのだが、reindex によってすべての操作がLOCKされるため、メンテナンス中でないと実施できないオペレーション。オンラインシステムは使うことはほぼ不可能であろう。

2. create index は、selectは可能だが、DMLはLOCKされる。そのため、OLTPのシステムで使用するのはメンテナンス以外で使用することはないだろう。これをみると create index を行うならば reindex を採用する方がいいはずだ。

3.create index concurrently は、実施中にDML/select どちらも受け付けることができる。欠点としては作成に時間がかかることだが、オンラインシステムでは、concurrently以外に採用できる可能性は低い。
*1

一般的なINDEXへの対処法のため、primary key の場合にはまた処理が異なる。primary keyについては、また今度。

*1:補足:
create index や concurrently で作成した場合には、作成後もとの索引をdropする必要があるので忘れないように。

postgresql-9.1.1 にてはまる。

PostgreSQL-9.1.1 を DL し、textsearch_ja にて 全文検索を行おうと設定を行っていました。
textsearch_ja についてはこちらを参照(http://textsearch-ja.projects.postgresql.org/index-ja.html)

今までのリリースとおりに、textsearch_ja.sql まで実行完了、そしてtsearch2 を入れようとしたところ、
あれ。$PGHOME/share/contrib の下にファイルがない
ということで探したところ $PGHOME/share/extension/tsearch2--1.0.sql になっていた。
まぁここまではOK。
そして以下のように対象のSQLを実行


psql -f share/extension/tsearch2--1.0.sql
CREATE DOMAIN
CREATE DOMAIN
CREATE DOMAIN
CREATE DOMAIN
CREATE FUNCTION
psql:share/extension/tsearch2--1.0.sql:21: ERROR: could not access file "MODULE_PATHNAME": No such file or directory
psql:share/extension/tsearch2--1.0.sql:27: ERROR: could not access file "MODULE_PATHNAME": No such file or directory
....
あれ。おかしい。おかしい。。おかしい。。。
でも、動けばいいかということで、全文検索の確認を行うも

postgres=# SELECT to_tsvector('japanese', 'ユーザとユーザーは正規化されます。ミラーとミラは別扱い。');
ERROR: invalid input syntax for type oid: "japanese"
LINE 1: SELECT to_tsvector('japanese', 'ユーザとユーザーは?...
見事to_tsvector処理でエラー。oid を english にしてもエラー。入れ方が悪かったかと思い2時間ほど繰り返す。が、結果同じ。
にしてもよくよく見ると$PGHOME/share/extensionの下の*.sqlファイルすべてMODULE_PATHNAMEが置き換わってない。
それぞれのPATHNAME全部変更はいくらなんでも面倒だ。ということでPostgreSQL-9.0.5 をおとなしく使うことにしました。
※通常なら、$libdir/xxxxx になります。そして、PostgreSQL-9.0.5 なら素直に一発で構築完了でした。時間が。。。



簡単に本件を調べてみましたが、以下のforumの記事でも問題点としてあがっていた事象でした。
http://postgresql.1045698.n5.nabble.com/Extensions-vs-PGXS-MODULE-PATHNAME-handling-td3382870.html

簡単なことですが、pg_config で出てくる、pgxs.mk の MODULE_PATHNAMEの置換の正規表現周りということ。

9.1.Xから、extensionとしていろいろ変更したため、MODULE_PATHNAMEが書き換わらなくなったのですね。
9.1.2では直るかなー。

                          • -

追記)

9.1.X からは create extension にてFUNCTIONを作成するようです。
コマンドは以下
psql# create extension tsearch2;
新機能に書いてありますね。。。