lsyncdで複数のホストに対して同期を取る

lsyncdの同期先を複数のホストにするときのconf設定。
意外に情報がなかったんでちょっとメモ。

/etc/lsyncd.conf

OSはCentの5.6でrpmforgeを使ってyum installしたときのlsyncd。


サンプルをコピーして

# cp -ip /usr/share/doc/lsyncd/lrsync.lua /etc/lsyncd.conf


サンプル中のstatusIntervallがstatusIntervalのタイポってまじなの・・・?(「l」が一個多い)
まぁどうでもいいけど


編集後

#cat /etc/lsyncd.conf
----
-- User configuration file for lsyncd.
--
-- Simple example for default rsync.
--
settings = {
        statusFile = "/tmp/lsyncd.stat",
        statusInterval = 1,
}

sync{
        default.rsync, 
        # syncさせるディレクトリ
        source="/foo/bar/", 
        # 宛先ホストと対象ディレクトリ
        target="192.168.1.2:/foo/bar/",
}

sync{
        default.rsync, 
        source="/foo/bar/", 
        target="192.168.1.3:/foo/bar/",
}

sync{
        default.rsync, 
        source="/foo/bar/", 
        target="192.168.1.4:/foo/bar/",
}

こんな感じで単純にsync{ }を複数つくってやればいいみたいです。

MySQL5.0系のSSL接続について

実家から水が大量に届いたよ!…どうしたらいいんだこれは


MySQLではクライントとの通信にSSL接続が可能ですが、この設定にハマるにハマったのでメモ。


経緯としては、5.0.67を5.0.91にアップデートしたところ、
5.0.67では正常に接続できていたものが、5.0.91では接続エラーがでました。

結論的にはSSL証明書に原因があり、証明書をつくり直すことにより対応しました。
そこに至るまでの試行錯誤もろもろ

エラー内容

MySQL-5.0.91でSSL接続するとこんな感じでエラーがでます。

$ mysql -uuser --ssl-ca=/foo/bar/ca-cert.pem                                                                       
ERROR 2026 (HY000): SSL connection error

エラー内容としてはこれだけで特にログファイルには出力されません。
warningレベルを変えたりしましたが、ログには出力されないようです。


古いバージョンでは接続できたことから、リリースノートを検索してSSL関連で変更がなかったか調べます。
その結果5.0.88で変更があったことがわかりました。


てことで5.0.88と5.0.87をダウンロード/インストールして、接続確認を行いました。
(その際に使用したSSLの証明書は同じです)
でやはり
5.0.88→接続不可
5.0.87→接続可能
の結果だったので、5.0.87との違いを意識しつつ調べていきます。

デバッグ

上述の通りログレベルの変更では調査不可能なのでデバッグモードにて調べます。
デバッグモードはconfigure時に --with-debug=full を付加することにより使用できます。

$./configure --prefix=/usr/local/mysql-5.0.xx_debug --with-openssl --with-debug=full

こんな感じ。prefixは適当で。


デバッグの使用方法はマニュアル通りです。

クライアントを実行する前に、MYSQL_DEBUG 環境変数を指定してください。

shell> MYSQL_DEBUG=d:t:O,/tmp/client.trace
shell> export MYSQL_DEBUG

その結果、クライアントによってトレースファイルが /tmp/client.trace に生成されます。

http://dev.mysql.com/doc/refman/4.1/ja/debugging-client.html

なので

$ MYSQL_DEBUG=d:t:O,/tmp/client_5.0.xx.trace
$ export MYSQL_DEBUG

としておいて、MySQLに接続します。

$ mysql -uroot --ssl-ca=/etc/mysql/newcerts/ca-cert.pem

-------------------------------------------------------
MYSQL_DEBUG found. libmysql started with the following:
d:t:O,/tmp/client_5.0.xx.trace
-------------------------------------------------------

これで、トレースログが指定した場所にはかれます。
でエラー箇所をみてみると

 >report_errors
 | error: OpenSSL: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed:s3_clnt.c:912:
 | error: error: error:00000005:lib(0):func(0):DH lib
 | info: socket_errno: 0
 <report_errors

となっており、エラーを出しているのは、s3_clnt.cであることがわかります。
s3_clnt.cは、MySQLではなくOpenSSLのソースコードなので、
実際にエラーをだしているのは、MySQLではなくOpenSSLであることがわかりました。


さらにエラー内容の"SSL3_GET_SERVER_CERTIFICATE:certificate verify failed"は
サーバ証明書の検証に失敗した時に出るエラーなので、だいぶ原因が特定できてきました。


で成功してる5.0.87で同じくトレースログをとって、5.0.87では何の認証チェックをしているかを見てみます。

>vio_verify_callback
| enter: ok: 0  ctx: 0xbf85f8f8
| info: cert: /C=GB/ST=Berkshire/L=Newbury/O=My Company Ltd
| error: verify error: 18  'self signed certificate'
| exit: 1
<vio_verify_callback

↑ここの部分。
そうです。これオレオレ証明書なんです。ここでエラーを返してたようです。これで原因がわかりました。


で、まぁコードを最後まで追ってないのでたぶんの部分があるんですけど、
リリースノートやコードの差分なんかみると、ここの認証チェックの部分を5.0.88からはOpenSSL側にまかせたみたいですね。
逆にいうと5.0.87以前はMySQL側でやっていて(vio_verify_callback)、こいつはオレオレ証明でも通しちゃうみたいです。
たぶん

てことで

Webと違って証明書がブラウザに表示されるわけじゃないからって、証明書を適当に作ると痛い目にあうんですね。わかります。
なのでまじめにっていうか

http://dev.mysql.com/doc/refman/5.1/ja/secure-create-certs.html

ここのページでいう
ca-cert.pemをつくるときと、server-req.pemやclient-req.pemを作るときに入れる
SSLの情報(Country NameやOrganization Name等々)を別々の名前にしたりしてまじめに作りましょうって話で解決しました。
(エンター連打じゃだめよってこと)

ちなみに

MySQL 5.1.11からはコマンドオプションとして--ssl-verify-server-certが追加され、検証の有無を選択できるようです。

slaveからダンプをとった場合のCHANGE MASTER TOについて

MySQLのslaveサーバからcronで一日一回ダンプファイルを取得してて、
そのダンプファイルを使ってどこかのサーバにリストアした場合、
新しくレプリケーションを開始する際に発行するCHANGE MASTER TOコマンドは一体何を指定したらいいんだろう?


例えばmasterサーバでダンプを取得する場合、mysqldumpコマンドのオプションとして
「--master-data=2」を指定してやると、dumpファイル中にCHANGE MASTERコマンドが付加される。
これは非常に便利なんだけど、あくまでshow master statusの値を取っているので
slaveサーバでこれつけてもまったく意味がない。


slaveでダンプとるときも、こんな便利オプションないかなーと思ってたんですが、
MySQL 5.5から--dump-slaveってのが追加されるようです。

--dump-slave[=value]

This option is similar to --master-data except that it is used to dump a replication slave server to produce a dump file that can be used to set up another server as a slave that has the same master as the dumped server. It causes the dump output to include a CHANGE MASTER TO statement that indicates the binary log coordinates (file name and position) of the dumped slave's master (rather than the coordinates of the dumped server, as is done by the --master-data option). These are the master server coordinates from which the slave should start replicating. This option was added in MySQL 5.5.3.

http://dev.mysql.com/doc/refman/5.5/en/mysqldump.html#option_mysqldump_dump-slave

MySQL 5.5もいつの間にかrc版になっていて、リリースも近いようですが、
今現在つかってるMySQL5.1系の場合でも同じようなことがやりたい!
ってことで--dump-slaveオプションが何をやってるか少し調べてみました。

mysqldump.c

MySQL-5.5.6-rcをダウンロード/展開してmysqldump.cを見てみます。(関係ありそうなとこだけ)

./mysql-5.5.6-rc/client/mysqldump.c

  {"dump-slave", OPT_MYSQLDUMP_SLAVE_DATA,
   "This causes the binary log position and filename of the master to be "
   "appended to the dumped data output. Setting the value to 1, will print"
   "it as a CHANGE MASTER command in the dumped data output; if equal"
   " to 2, that command will be prefixed with a comment symbol. "
   "This option will turn --lock-all-tables on, unless "
   "--single-transaction is specified too (in which case a "
   "global read lock is only taken a short time at the beginning of the dump "
   "- don't forget to read about --single-transaction below). In all cases "
   "any action on logs will happen at the exact moment of the dump."
   "Option automatically turns --lock-tables off.",
   &opt_slave_data, &opt_slave_data, 0,
   GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL, 0, 0, 0},

まずここ。
んで主な処理は↓の3つですね。

 if (opt_slave_data && do_stop_slave_sql(mysql))
   goto err;
  if (opt_slave_data && do_show_slave_status(mysql))
    goto err;
  if (opt_slave_data && do_start_slave_sql(mysql))
    goto err;

名前からしてわかるけど、主な流れとしては
stop_slave → show_slave_status → start_slave
みたいですね。 詳細は↓

do_stop_slave_sql
static int do_stop_slave_sql(MYSQL *mysql_con)
{
  (省略)
  /* now, stop slave if running */
  if (mysql_query_with_error_report(mysql_con, 0, "STOP SLAVE SQL_THREAD"))
    return(1);
  return(0);
}

でまずは"STOP SLAVE SQL_THREAD"の発行。
うお!STOP SLAVEじゃなくてSTOP SLAVE SQL_THREADなのか。。
たしかにSQL_THREADだけ止めとけば、SQLは実行されないからbinログのポジションは変動しませんね。

do_show_slave_status

でここがきもなんだけど

static int do_show_slave_status(MYSQL *mysql_con)
{
  MYSQL_RES *slave;
  const char *comment_prefix=
    (opt_slave_data == MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL) ? "-- " : "";
  if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
  {
    if (!ignore_errors)
    {
      /* SHOW SLAVE STATUS reports nothing and --force is not enabled */
      my_printf_error(0, "Error: Slave not set up", MYF(0));
    }
    mysql_free_result(slave);
    return 1;
  }
  else
  {
    MYSQL_ROW row= mysql_fetch_row(slave);
    if (row && row[9] && row[21])
    {
      /* SHOW MASTER STATUS reports file and position */      if (opt_comments)
        fprintf(md_result_file,
                "\n--\n-- Position to start replication or point-in-time "
                "recovery from (the master of this slave)\n--\n\n");

      fprintf(md_result_file, "%sCHANGE MASTER TO ", comment_prefix);

      if (opt_include_master_host_port)
      {
        if (row[1])
          fprintf(md_result_file, "MASTER_HOST='%s', ", row[1]);
        if (row[3])
          fprintf(md_result_file, "MASTER_PORT='%s', ", row[3]);
      }
      fprintf(md_result_file,
              "MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n", row[9], row[21]);

      check_io(md_result_file);
    }
    mysql_free_result(slave);
  }
  return 0;
}

ぐ…省略できるところがない。。
えーと上のほうでまず"SHOW SLAVE STATUS"を発行して…

      fprintf(md_result_file,
              "MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n", row[9], row[21]);

      check_io(md_result_file);

↑ここかな。
show slave statusの結果を配列にいれて、
row[9]とrow[21]をそれぞれMASTER_LOG_FILEとMASTER_LOG_POSとすると。
長いけどshow slave statusの結果はこんな感じだから…

mysql> show slave status \G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.1.XX
                  Master_User: foo
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: bin-log.000001
          Read_Master_Log_Pos: 1000000
               Relay_Log_File: relay-log.0000001
                Relay_Log_Pos: 1000000
        Relay_Master_Log_File: bin-log.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 1000000
              Relay_Log_Space: 1000000
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
1 row in set (0.00 sec)

mysql> 

配列の9番目と21番目だからー
MASTER_LOG_FILE が Relay_Master_Log_File の bin-log.000001
MASTER_LOG_POS が Exec_Master_Log_Pos の 1000000
だね。

do_start_slave_sql
static int do_start_slave_sql(MYSQL *mysql_con)
{
  (省略)
  /* now, start slave if stopped */
  if (mysql_query_with_error_report(mysql_con, 0, "START SLAVE"))
  {
    my_printf_error(0, "Error: Unable to start slave", MYF(0));
    return 1;
  }
  return(0);
}

で、最後に"START SLAVE"を実行してやると。

まとめると。

slaveからダンプをとった場合のCHANGE MASTER TOは

  1. STOP SLAVE SQL_THREAD
  2. SHOW SLAVE STATUS
    • Relay_Master_Log_FileとExec_Master_Log_Posの値を取る
  3. mysqldump
  4. START SLAVE

としてやったときの値になると。
うん、これぐらいならperlでスクリプト書けそうだな。
MySQL 5.5がでたら--dump-slaveオプションを使おう。

インフラエンジニアがSegmentation fault をなんとか治してみる

普段Webサーバを運用していて、めんどくさいトラブルのひとつに「Segmentation fault」があります。
あれー?なんか500エラーがでるなーなんて思ってログを見るとSegmentation faultになってるときは死にたくなります。


そもそもSegmentation faultはメモリ上にあるデータに対して不正が行われたときに起こるもので、
インフラエンジニアにとってはなかなか手がだせないところでもあります。


それでもなんとかして治さないといけないわけなので
せめてどのプログラムが悪さしてるかどうかぐらいは調べ上げてみます。

apacheでのログ

apache + mod_perl での環境です。
こんな感じでエラーがでます。

#tail error_log 
[notice] child pid 26028 exit signal Segmentation fault (11)
[notice] child pid 26029 exit signal Segmentation fault (11)
[notice] child pid 26030 exit signal Segmentation fault (11)
[notice] child pid 26031 exit signal Segmentation fault (11)

完全に死んでます。ほんとうにありがとうございました。

coreをはかせる

Segmentation faultがでてもこれ以上の情報がないのでcoreファイルを吐かせてデバッグしていきます。

ulimit設定

ulimit -aを打ってでる結果で、core file sizeの値が0の場合、 coreファイルの容量が制限されてます。

$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 16249
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) unlimited
virtual memory          (kbytes, -v) unlimited
file locks

なので、ulimitコマンドでこの値を変えてやる必要があるわけですが、ulimitはプロセス毎(pid毎)の値なのでログオフすると元に戻ってしまいます。
値を変えるには/etc/profileを書き換えると簡単なのでいつもこっちで変えてしまいます。

$ diff /etc/profile.b /etc/profile
30c30
< # ulimit -S -c 0 > /dev/null 2>&1
---
> ulimit -c unlimited > /dev/null 2>&1
$

「-c unlimited」で無制限に
変更したら一度ログアウト→ログインします。

$ ulimit -a
core file size          (blocks, -c) unlimited
(略)
apacheの設定

apacheは一行加えて終了

CoreDumpDirectory /tmp

Coreファイルを吐く場所は適宜。再起動を忘れずに

Coreファイルを解析してみる

わざとエラーを出し、Segmentation faultがでていれば、/tmp配下にcoreファイルができているはずです。
Coreファイルの解析はgdbコマンドを使用します。


gdbコマンドは

gdb <commnd> -c <(core)file>

で使用します。
まぁ実際に打ってみましょう。


今回はapacheでエラーがでたので上のにはapacheのコマンドがはいります。

#gdb /usr/local/apache2/bin/httpd -c /tmp/core.30864

こんな感じ。
実際打つと

#gdb /usr/local/apache2/bin/httpd -c /tmp/core.30864
GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-23.el5_5.2)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /usr/local/apache2/bin/httpd ...(no debugging symbols found)...done.
Reading symbols from /lib/libm.so.6...(no debugging symbols found)...done.
.........
......
...
<略>

こんな感じでトレースしていって。。

<略>
...
......
.........
Reading symbols from /lib/libselinux.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/libselinux.so.1
Reading symbols from /lib/libsepol.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/libsepol.so.1
Core was generated by `/usr/local/apache2/bin/httpd '.
Program terminated with signal 11, Segmentation fault.
#0  0x0061faa4 in SSL_CTX_ctrl () from /lib/libssl.so.6
(gdb)

こんな感じでSegmentation faultのエラーが発生して、
(gdb)というプロンプトが返ります。


gdbコマンドは高度なデバッガでプログラムができる人はいろいろデバッグできるのですが
とりあえず
(gdb)where
と打ってみましょう。落ちてるところがわかります。


こんな感じ。

(gdb) where
#0  0x0061faa4 in SSL_CTX_ctrl () from /lib/libssl.so.6
#1  0xb721f6f7 in XS_Crypt__SSLeay__CTX_new (cv=0xb92a828) at SSLeay.xs:133
#2  0x0810ed51 in Perl_pp_entersub ()
#3  0x08108ede in Perl_runops_standard ()
#4  0x080bdfcb in Perl_call_sv ()
#5  0x08069414 in perl_call_handler ()
#6  0x08069b29 in perl_run_stacked_handlers ()
#7  0x0806b071 in perl_handler ()
#8  0x0808b7cb in ap_invoke_handler ()
#9  0x080a0cee in ?? ()
#10 0x0ae30fc4 in ?? ()
#11 0x08179e99 in ?? ()
#12 0xbff5f558 in ?? ()
#13 0x080add23 in ap_ctx_new ()
#14 0x080a0e4b in ap_process_request ()
#15 0x080963ce in ?? ()
#16 0x0ae30fc4 in ?? ()
#17 0x00000004 in ?? ()
#18 0x0ae30fc4 in ?? ()
#19 0xbff5f864 in ?? ()
#20 0x00000004 in ?? ()
#21 0x4cb7f3d2 in ?? ()
#22 0x00000000 in ?? ()
(gdb) 

でまぁここからちょっとわかりくいんですが、#0と#1みると

#0  0x0061faa4 in SSL_CTX_ctrl () from /lib/libssl.so.6
#1  0xb721f6f7 in XS_Crypt__SSLeay__CTX_new (cv=0xb92a828) at SSLeay.xs:133

となっていて、なんかSSLeay.xsで落ちてるっぽいってわかります。
xsってのはPerlがCを使うためのモジュールなんで、なんかこいつが犯人っぽい。

てな具合でなんとか悪さしてるプログラムは見つけることができました。

あとは

ほんとはここまできたら、スーパーデバッグタイムなんだけど、
正直プログラマーじゃないと厳しいし、まずは犯人プログラムをアップデートしたり、
リコンパイルしてみるといいと思う。


ちなみに↑で紹介したエラーはcpanから最新のCrypt::SSLeayを持ってきて入れなおしたらあっさり直りました。


例外として、すごい調べたけどまったく原因がわからなくて
とりあえずサーバを再起動したらエラーが解消したってこともありました。
まぁそういう日もあるよね。

Tracをfcgiで動す

なんか久しぶりにTracをインストールしたら
古いバージョンと色々変わってたので作業メモ。

環境

OS: CentOS 5.5 (64bit)
Apache: 2.2.16
fastcgi: 2.4.6
Trac: Trac-0.12.ja1

Tracに必要なpythonライブラリ インスト

# yum install python-clearsilver.x86_64 python-sqlite2.x86_64 python-setuptools.noarch python-genshi.x86_64

python-sqliteはpython-sqlite2を入れないとTracのインストール時に

TracError: Cannot load Python bindings for SQLite

って怒られた。

Tracのインスト

以下のURLで日本語版が公開されているので、今回はこれを利用させて頂きました。

http://www.i-act.co.jp/project/products/products.html

# wget http://www.i-act.co.jp/project/products/downloads/Trac-0.12.ja1.zip
# unzip Trac-0.12.ja1.zip 
# cd Trac-0.12.ja1
# python setup.py install

古いバージョンはいろんなものをインストールしまくってけど最近のやつは必要最低限らしい。

Trac用ディレクトリの作成

# cd /path/to
# mkdir trac
# cd trac
# trac-admin myproject initenv
Creating a new Trac environment at /path/to/trac/myproject

Trac will first ask a few questions about your environment 
in order to initialize and prepare the project database.

 Please enter the name of your project.
 This name will be used in page titles and descriptions.

Project Name [My Project]> 
 
 Please specify the connection string for the database to use.
 By default, a local SQLite database is created in the environment
 directory. It is also possible to use an already existing
 PostgreSQL database (check the Trac documentation for the exact
 connection string syntax).

Database connection string [sqlite:db/trac.db]> 

Creating and Initializing Project
 Installing default wiki pages
<以下略>

レポジトリの設定はinitenvでやらなくなったっぽい。

これでインスト完了だが中身はスカスカ。昔は(ry
中身は別途↓のコマンドで作成。

# trac-admin myproject deploy /tmp/deploy
直接うつせないのでとりあえずtmpとかに

# cd myproject
# mv /tmp/deploy/cgi-bin .
# mv /tmp/deploy/htdocs .

Tracのインストールは大体終了

fastcgiで動かす

httpd.confで

# FastCGI
LoadModule fastcgi_module modules/mod_fastcgi.so
AddHandler fastcgi-script .fcgi
Include conf/extra/httpd-trac.conf

てしといて
httpd-trac.confで

FastCgiConfig -initial-env TRAC_ENV=/path/to/trac/myproject

ScriptAlias /trac /path/to/trac/myproject/cgi-bin/trac.fcgi
<Location "/trac">
    SetHandler fastcgi-script
    Order deny,allow
    Deny from all
    Allow from (適当に許可IP)
</Location>

kestrelをインストールする

kestrelはメッセージキューの一種でtwitterでも利用されているらしい。
たまたまインストールする機会があったので作業メモ。

環境

OS: CentOS 5.5 (64bit)
jdk: 1.6.0
kestrel: http://github.com/robey/kestrel

git

kestrelのbuildはsbtってのを使うんだけど(後述)、
build処理の中でgitを呼び出してるらしく、gitがインストされていなとエラーになりました。

まぁkestrelのソース自体githubにあるのでこの機会に入れてしまいます。

# yum install git.x86_64

例によってCentOSのデフォのレポジトリでは入ってないかもしれない。
その時は、DAG(rpmforge)のレポジトリを追加もしくはソースからインストールする。

sbt

sbtはscalaのbuildツール。makeコマンドみたいなもん。
googlecodeからダウンロードできる。
インストールってゆうかコマンド作るって感じ。そのまま実行してもまぁいい。

$ wget http://simple-build-tool.googlecode.com/files/sbt-launch-0.7.4.jar
$ vi sbt
$
$ cat sbt
java -Xmx512M -jar `dirname $0`/sbt-launch-0.7.4.jar "$@"
$
$chmod u+x sbt
$

パスは適宜通す。
めんどくさい場合は

$ java -Xmx512M -jar sbt-launch-0.7.4.jar foo bar

みたく直接コマンドを作っても良い。

kestre

ソースコードはgithubにあるのでそこからダウンロード。
どうせなんでgitコマンドを使う。
インストールディレクトリは/usr/local配下とする。

# cd /usr/local/
# git clone git://github.com/robey/kestrel.git
# cd kestrel/
# sbt clean update package-dist
Getting Scala 2.7.7 ...
downloading http://repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.7.7/scala-compiler-2.7.7.jar ...
        [SUCCESSFUL ] org.scala-lang#scala-compiler;2.7.7!scala-compiler.jar (16737ms)
downloading http://repo1.maven.org/maven2/org/scala-lang/scala-library/2.7.7/scala-library-2.7.7.jar ...
        [SUCCESSFUL ] org.scala-lang#scala-library;2.7.7!scala-library.jar (9260ms)
:: retrieving :: org.scala-tools.sbt#boot-scala
        confs: [default]
        2 artifacts copied, 0 already retrieved (9911kB/45ms)
Getting org.scala-tools.sbt sbt_2.7.7 0.7.4 ...
downloading http://databinder.net/repo/org.scala-tools.sbt/sbt_2.7.7/0.7.4/jars/sbt_2.7.7.jar ...
        [SUCCESSFUL ] org.scala-tools.sbt#sbt_2.7.7;0.7.4!sbt_2.7.7.jar (2382ms)
downloading http://repo1.maven.org/maven2/com/jcraft/jsch/0.1.31/jsch-0.1.31.jar ...
        [SUCCESSFUL ] com.jcraft#jsch;0.1.31!jsch.jar (1069ms)
downloading http://repo1.maven.org/maven2/org/scala-tools/testing/test-interface/0.5/test-interface-0.5.jar ...
        [SUCCESSFUL ] org.scala-tools.testing#test-interface;0.5!test-interface.jar (175ms)
downloading http://repo1.maven.org/maven2/org/apache/ivy/ivy/2.1.0/ivy-2.1.0.jar ...
        [SUCCESSFUL ] org.apache.ivy#ivy;2.1.0!ivy.jar (2584ms)
downloading http://databinder.net/repo/org.scala-tools.sbt/compile_2.7.7/0.7.4/jars/compile_2.7.7.jar ...
        [SUCCESSFUL ] org.scala-tools.sbt#compile_2.7.7;0.7.4!compile_2.7.7.jar (798ms)
downloading http://databinder.net/repo/org.scala-tools.sbt/launcher-interface/0.7.4/jars/launcher-interface.jar ...
        [SUCCESSFUL ] org.scala-tools.sbt#launcher-interface;0.7.4!launcher-interface.jar (306ms)
downloading http://databinder.net/repo/org.scala-tools.sbt/interface/0.7.4/jars/interface.jar ...
        [SUCCESSFUL ] org.scala-tools.sbt#interface;0.7.4!interface.jar (457ms)
downloading http://databinder.net/repo/org.scala-tools.sbt/ivy_2.7.7/0.7.4/jars/ivy_2.7.7.jar ...
        [SUCCESSFUL ] org.scala-tools.sbt#ivy_2.7.7;0.7.4!ivy_2.7.7.jar (767ms)
downloading http://databinder.net/repo/org.scala-tools.sbt/io_2.7.7/0.7.4/jars/io_2.7.7.jar ...
        [SUCCESSFUL ] org.scala-tools.sbt#io_2.7.7;0.7.4!io_2.7.7.jar (460ms)
downloading http://databinder.net/repo/org.scala-tools.sbt/classpath_2.7.7/0.7.4/jars/classpath_2.7.7.jar ...
        [SUCCESSFUL ] org.scala-tools.sbt#classpath_2.7.7;0.7.4!classpath_2.7.7.jar (306ms)
downloading http://databinder.net/repo/org.scala-tools.sbt/compiler-interface/0.7.4/jars/compiler-interface-bin.jar ...
        [SUCCESSFUL ] org.scala-tools.sbt#compiler-interface;0.7.4!compiler-interface-bin.jar (313ms)
downloading http://databinder.net/repo/org.scala-tools.sbt/compiler-interface/0.7.4/jars/compiler-interface-src.jar ...
        [SUCCESSFUL ] org.scala-tools.sbt#compiler-interface;0.7.4!compiler-interface-src.jar (305ms)
downloading http://databinder.net/repo/org.scala-tools.sbt/control_2.7.7/0.7.4/jars/control_2.7.7.jar ...
        [SUCCESSFUL ] org.scala-tools.sbt#control_2.7.7;0.7.4!control_2.7.7.jar (303ms)
downloading http://repo1.maven.org/maven2/jline/jline/0.9.94/jline-0.9.94.jar ...
        [SUCCESSFUL ] jline#jline;0.9.94!jline.jar (907ms)
downloading http://databinder.net/repo/org.scala-tools.sbt/precompiled-2.8.0.rc2_2.8.0.RC2/0.7.4/jars/compiler-interface-bin.jar ...
        [SUCCESSFUL ] org.scala-tools.sbt#precompiled-2.8.0.rc2_2.8.0.RC2;0.7.4!compiler-interface-bin.jar (608ms)
:: retrieving :: org.scala-tools.sbt#boot-app
        confs: [default]
        15 artifacts copied, 0 already retrieved (4096kB/27ms)
[info] Recompiling plugin definition...
[info]    Source analysis: 1 new/modified, 0 indirectly invalidated, 0 removed.
[info] 
[info] Updating plugins...
[info] downloading http://maven.twttr.com/com/twitter/standard-project/0.7.5/standard-project-0.7.5.jar ...
[info]  [SUCCESSFUL ] com.twitter#standard-project;0.7.5!standard-project.jar (539ms)
[info] downloading http://maven.twttr.com/ivysvn/ivysvn/2.1.0/ivysvn-2.1.0.jar ...
[info]  [SUCCESSFUL ] ivysvn#ivysvn;2.1.0!ivysvn.jar (4057ms)
[info] :: retrieving :: plugin-definition#plugin-definition_2.7.7 [sync]
[info]  confs: [compile, runtime, test, provided, system, optional, sources, javadoc]
[info]  2 artifacts copied, 0 already retrieved (2996kB/21ms)
[success] Plugins updated successfully.
[info] 
[info]  Extracted source plugin ./lib_managed/scala_2.7.7/standard-project-0.7.5.jar ...
[info] Recompiling plugin...
[info]    Source analysis: 13 new/modified, 0 indirectly invalidated, 0 removed.
[info] Recompiling project definition...
[info]    Source analysis: 1 new/modified, 0 indirectly invalidated, 0 removed.
[info] Standard project rules 0.7.5 loaded (2010-09-21).
[info] Building project kestrel 1.2.2 against Scala 2.7.7
[info]    using KestrelProject with sbt 0.7.4 and Scala 2.7.7
[info] 
[info] == clean-thrift ==
[info] == clean-thrift ==
[info] 
[info] == clean-dist ==
[info] == clean-dist ==
[info] 
[info] == clean ==
[info] == clean ==
[success] Successful.
[info] 
[info] Total time: 0 s, completed Sep 23, 2010 11:05:13 AM
[info] 
[info] == update ==
[info] downloading http://mirrors.ibiblio.org/pub/mirrors/maven2/org/slf4j/slf4j-jdk14/1.5.2/slf4j-jdk14-1.5.2.jar ...
[info]  [SUCCESSFUL ] org.slf4j#slf4j-jdk14;1.5.2!slf4j-jdk14.jar (1059ms)
[info] downloading http://www.lag.net/nest/com/twitter/xrayspecs/1.0.7/xrayspecs-1.0.7.jar ...
[info]  [SUCCESSFUL ] com.twitter#xrayspecs;1.0.7!xrayspecs.jar (579ms)
[info] downloading http://mirrors.ibiblio.org/pub/mirrors/maven2/org/scala-tools/testing/specs/1.6.2.1/specs-1.6.2.1.jar ...
[info]  [SUCCESSFUL ] org.scala-tools.testing#specs;1.6.2.1!specs.jar (9830ms)
[info] downloading http://www.lag.net/nest/com/twitter/twitteractors/1.0.0/twitteractors-1.0.0.jar ...
[info]  [SUCCESSFUL ] com.twitter#twitteractors;1.0.0!twitteractors.jar (1528ms)
[info] downloading http://scala-tools.org/repo-releases/net/lag/naggati/0.7.3/naggati-0.7.3.jar ...
[info]  [SUCCESSFUL ] net.lag#naggati;0.7.3!naggati.jar (7984ms)
[info] downloading http://scala-tools.org/repo-releases/net/lag/configgy/1.5.3/configgy-1.5.3.jar ...
[info]  [SUCCESSFUL ] net.lag#configgy;1.5.3!configgy.jar (668ms)
[info] downloading http://mirrors.ibiblio.org/pub/mirrors/maven2/org/apache/mina/mina-core/2.0.0-M6/mina-core-2.0.0-M6.jar ...
[info]  [SUCCESSFUL ] org.apache.mina#mina-core;2.0.0-M6!mina-core.jar(bundle) (5540ms)
[info] downloading http://mirrors.ibiblio.org/pub/mirrors/maven2/org/slf4j/slf4j-api/1.5.2/slf4j-api-1.5.2.jar ...
[info]  [SUCCESSFUL ] org.slf4j#slf4j-api;1.5.2!slf4j-api.jar (350ms)
[info] downloading http://www.lag.net/repo/org/scala-tools/vscaladoc/1.1-md-3/vscaladoc-1.1-md-3.jar ...
[info]  [SUCCESSFUL ] org.scala-tools#vscaladoc;1.1-md-3!vscaladoc.jar (1505ms)
[info] :: retrieving :: net.lag#kestrel [sync]
[info]  confs: [compile, runtime, test, provided, system, optional, sources, javadoc]
[info]  9 artifacts copied, 0 already retrieved (4300kB/26ms)
[info] == update ==
[success] Successful.
[info] 
[info] Total time: 167 s, completed Sep 23, 2010 11:08:00 AM
[info] 
[info] == compile-thrift-ruby ==
[info] == compile-thrift-ruby ==
[info] 
[info] == compile-thrift-java ==
[info] == compile-thrift-java ==
[info] 
[info] == compile ==
[info]   Source analysis: 13 new/modified, 0 indirectly invalidated, 0 removed.
[info] Compiling main sources...
[info] Compilation successful.
[info]   Post-analysis: 139 classes.
[info] == compile ==
[info] 
[info] == copy-test-resources ==
[info] == copy-test-resources ==
[info] 
[info] == test-compile ==
[info]   Source analysis: 11 new/modified, 0 indirectly invalidated, 0 removed.
[info] Compiling test sources...
[info] Compilation successful.
[info]   Post-analysis: 592 classes.
[info] == test-compile ==
[info] 
[info] == copy-resources ==
[info] == copy-resources ==
[info] 
[info] == write-build-properties ==
[info] == write-build-properties ==
[info] 
[info] == copy-scripts ==
[info] == copy-scripts ==
[info] 
[info] == test-start ==
[info] == test-start ==
[info] 
[info] == net.lag.kestrel.PersistentQueueSpec ==
[info] PersistentQueueSpec
[info] PersistentQueue should
[info]   + add and remove one item
[info]   + resist adding an item that's too large
[info]   + flush all items
[info]   + rotate journals
[info]   + rotate journals with an open transaction
[info]   + recover the journal after a restart
[info]   + honor max_age
[info]   + allow max_journal_size and max_memory_size to be overridden per queue
[info]   + drop into read-behind mode
[info]     + on insert
[info]     + on startup
[info]     + during journal processing, then return to ordinary times
[info]   + handle timeout reads
[info]   + correctly interleave transactions in the journal
[info]   + recover a journal with open transactions
[info]   + recreate the journal file when it gets too big
[info]   + don't recreate the journal file if the queue itself is still huge
[info]   + report an age of zero on an empty queue
[info] PersistentQueue with no journal should
[info]   + create no journal
[info]   + lose all data after being destroyed
[info] PersistentQueue with item/size limit should
[info]   + honor max_items
[info]   + honor max_size
[info]   + drop older items when discard_old_when_full is set
[info] == net.lag.kestrel.PersistentQueueSpec ==
[info] 
[info] == net.lag.kestrel.QueueCollectionSpec ==
[info] QueueCollectionSpec
[info] QueueCollection should
[info]   + create a queue
[info]   + load from journal
[info]   + queue hit/miss tracking
[info]   + proactively load existing queue files
[info]   + ignore partially rolled queue files
[info]   + delete a queue when asked
[info]   + fanout queues
[info]     + generate on the fly
[info]     + preload existing
[info]     + delete on the fly
[info]   + move expired items from one queue to another
[info] == net.lag.kestrel.QueueCollectionSpec ==
[info] 
[info] == net.lag.kestrel.memcache.MemCacheCodecSpec ==
[info] MemCacheCodecSpec
[info] Memcache Decoder should
[info]   + 'get' request chunked various ways
[info]   + 'set' request chunked various ways
[info]   + 'quit' exits the session
[info] == net.lag.kestrel.memcache.MemCacheCodecSpec ==
[info] 
[info] == net.lag.kestrel.JournalSpec ==
[info] JournalSpec
[info] Journal should
[info]   + walk
[info]   + recover from corruption
[info] == net.lag.kestrel.JournalSpec ==
[info] 
[info] == net.lag.kestrel.ServerSpec ==
[info] ServerSpec
[info] Server should
[info]   + configure per-queue
[info]   + set and get one entry
[info]   + set with expiry
[info]   + set and get binary data
[info]   + commit a transactional get
[info]   + abort a transactional get
[info]   + auto-rollback a transaction on disconnect
[info]   + auto-commit cycles of transactional gets
[info]   + age
[info]   + peek
[info]   + rotate logs
[info]   + collect stats
[info]   + return a valid response for an unknown command
[info]   + disconnect and reconnect correctly
[info]   + flush expired items
[info] == net.lag.kestrel.ServerSpec ==
[info] 
[info] == test-complete ==
[info] == test-complete ==
[info] 
[info] == <anonymous> ==
[info] == <anonymous> ==
[info] 
[info] == package ==
[info] Packaging ./target/kestrel-1.2.2.jar ...
[info] Packaging complete.
[info] == package ==
[info] 
[info] == make-pom ==
[info] Wrote /usr/local/kestrel/target/kestrel-1.2.2.pom
[info] == make-pom ==
[info] 
[info] == test-finish ==
[info] Passed: : Total 54, Failed 0, Errors 0, Passed 54, Skipped 0
[info]  
[info] All tests PASSED.
[info] == test-finish ==
[info] 
[info] == test-cleanup ==
[info] == test-cleanup ==
[info] 
[info] == package-dist ==
[info] Packaging ./dist/kestrel-1.2.2.zip ...
[info] Packaging complete.
[info] == package-dist ==
[success] Successful.
[info] 
[info] Total time: 18 s, completed Sep 23, 2010 11:08:18 AM
[info] 
[info] Total session time: 201 s, completed Sep 23, 2010 11:08:18 AM
[success] Build completed successfully.
#

これでbuildできました。

とりあえず

とりあえず起動させるだけならjava -jarで直接実行するだけ大丈夫です。

java -jar /usr/local/kestrel/dist/kestrel-1.2.2/kestrel-1.2.2.jar &

または./dist/kestrel-1.2.2/scripts配下にあるkestrel.shを実行してやります。
(※環境によって若干修正必要あり)
kestrel.shで実行した場合は下記のようなプロセスになりました。

$ ps aux | grep java
root      4103  0.0  0.4 2471452 115380 ?      Sl   12:59   0:00 /root/jdk1.6.0_06/bin/java -server -verbosegc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -Xmx2048m -Xms1024m -XX:NewSize=256m -jar /usr/local/kestrel/dist/kestrel-1.2.2/kestrel-1.2.2.jar
$

動作確認はデフォルトのポートとして22133ポートが起動するのでtelnetでアクセスします。

$ telnet localhost 22133
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
STATS
STAT uptime 10769
STAT time 1285225152
STAT version 1.2.2
STAT curr_items 0
STAT total_items 0
STAT bytes 0
STAT curr_connections 1
STAT total_connections 1
STAT cmd_get 0
STAT cmd_set 0
STAT cmd_peek 0
STAT get_hits 0
STAT get_misses 0
STAT bytes_read 6
STAT bytes_written 0
END
quit
Connection closed by foreign host.
$ 

最後に

ケストレルっていったら「イエス、ケストレル」だろjk

ソースから入れたapacheのconfigureオプションを調べる

なんか毎回忘れるのでメモ。

ソールから入れたapacheのconfigureオプションを調べるには以下のファイルを調べる。

$ cat /usr/local/apache2/build/config.nice
#! /bin/sh
#
# Created by configure

"./configure" \
"--prefix=/usr/local/apache2" \
"--with-mpm=worker" \
"--enable-ssl" \
"--enable-rewrite" \
"--enable-proxy" \
"$@"

こんなんでいいんです。