hiredis使ってみた

luaでresty.redis使ってるんですが、どうも安定しないのでhiredisを使おうと思う。
まずはhsetとhgetallのサンプル書いて動作確認してみた。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis/hiredis.h>
 
int main(void) {
 
  char       *key1 = "aaaa";
  char       *key2 = "bbbb";
  char       *val  = "1111";
  redisReply *reply;
  int         i;
 
  redisContext *c = redisConnect("127.0.0.1", 6379);
  if (c->err) {
    printf("redisConnect Error: %s\n", c->errstr);
    return (-1);
  }
 
  // HSET                                                                                                                                                                           
  reply = redisCommand(c, "HSET %s %s %s", key1, key2, val);
  freeReplyObject(reply);
 
  // HGETALL                                                                                                                                                                        
  reply = redisCommand(c, "HGETALL %s", key1);
  if ( reply->type == REDIS_REPLY_ERROR ) {
    printf("redisCommand Error: %s\n", c->errstr);
  }
  else if (reply->type == REDIS_REPLY_ARRAY) {
    printf("hgetall: %s\n", key1);
    for ( i=0; i<reply->elements; i++ ) {
      if ( (i % 2) == 0 ) {
        printf("hkey: %s, ", reply->element[i]->str);
      }
      else {
        printf("value: %s\n", reply->element[i]->str);
      }
    }
  }
  freeReplyObject(reply);
 
  return (0);
}

$ ./a.out
hgetall: aaaa
hkey: bbbb, value: 1111

RedisがDisk書き込みのタイミングで接続出来なくなる

Redisはデフォルトで定期的にDiskへバックアップをとるようになっていますが、
このタイミングでクライアントからRedisに対して接続出来なくなるようです。

僅かな差分であれば、一瞬で終るのですが、
それなりの更新があると書き込みにかかる時間も増えるのでその間、ずっと繋がらなくなります。

マニュアルには、

BGSAVE()
データベースの保存をバックグラウンドで行います。 OK コードは直ちに返って来ます。Redisはフォークし、親のプロセスはクライアントに対して処理をし続け、子のプロセスはデータベースをディスクに保存したあと死にます。クライアントから保存が無事に終わったかを LASTSAVE コマンドを使って確認することが出来ます。

とあるので、疑問だったのですが、
親プロセスが処理を「受け」続けるとは書いていないので、間違ってはいないのかな。

ということで、Disk書き込みを無効にして、スレーブの方でDisk保存するようにしました。
もし再起動などの際に、Diskに保存したい場合は、BGSAVE()を手動で発行すればOK。

Redisの処理能力の限界

sysctlで、ファイルディスクリプタやsomaxconn、ポートレンジの対応はした上でですが、
Redisの処理能力の限界がだいたい分かった。

Redisはシングルスレッドなので、マルチコアはあまり意味がないのでEC2のm1.mediumを使ってるんですが、
このインスタンスでだいたい、instantaneous_ops_per_secが12000辺りで頭打ちになる。
この時のCPU使用率が90%超えなので、CPUバウンドでしょう。

—-
この記事は、
ec2でredisを使う場合はhvmで書いたように、仮想化方式がPra-Virtualでのものなので、HVMだとかなりパフォーマンスが向上します。
c3のCPUであれば、35000~40000req/secほど出ます。

クロスサイトなAjaxでヘッダーを取得する

クロスサイトなAjaxで、ヘッダーを取得する際にちょっとはまったのでメモ。

例えば、
Ajax

  $.ajax({ type:       "GET",
           url:        "http://url",
           dataType:   "text",
           ifModified: true,
           cache:      true,           
           success: function(data, status, xhr) {
             var etag = xhr.getResponseHeader("ETag");
             alert(etag);
           },
  });

こんな感じでETagヘッダーを取得したいAjaxがあるとして、
下記のようなレスポンスヘッダーだと、Javascriptで取得出来るヘッダーがかなり限られたものだけになります。

レスポンスヘッダー

Access-Control-Allow-Headers: ETag
Access-Control-Allow-Origin: http://url
Access-Control-Allow-Credentials: true

つまり、レスポンス自体はされていてブラウザも受け取っているのですが、
Javascriptに渡されるヘッダーが限られたものになります。
ということで、ブラウザに対してJavascriptに渡してよいヘッダーを、Access-Control-Expose-Headersヘッダーで指定します。

Access-Control-Allow-Headers: ETag
Access-Control-Allow-Origin: http://url
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: ETag

これでJavascriptから指定したヘッダーが取得出来るようになります。
尚、*(アスタリスク)の指定も可能です。

LuaJIT2をnginxで使うメモ

lua_resty_stringを使うのにLuaJIT2が必要だったので、インストールした時のメモ

LuaJIT2.0.0のインストール

$ wget http://luajit.org/download/LuaJIT-2.0.0.tar.gz
$ tar zxvf LuaJIT-2.0.0.tar.gz
$ cd LuaJIT-2.0.0
$ vi src/luaconf.h # 必要ならば定数の変更
$ make PREFIX=/usr/local/luajit
$ sudo make install PREFIX=/usr/local/luajit
$ vi /etc/ld.so.conf.d/luajit.conf
—–
/usr/local/luajit/lib
—–
$ sudo ldconfig

LuaJIT使用でnginxをコンパイル

$ cd /usr/local/src/nginx-1.2.6
$ export LUAJIT_LIB=/usr/local/luajit/lib
$ export LUAJIT_INC=/usr/local/luajit/include/luajit-2.0
$ ./configure -user=nginx –prefix=/usr/local/nginx_app -with-http_stub_status_module -add-module=../lua-nginx-module -with-http_ssl_module –-with-debug
$ make
$ sudo make install

速度比較 lua vs perl

luaには、厳密には配列は無く、テーブルという唯一のデータ構造で配列を実現しています。
連想配列のような感じですが、関数を入れて擬似的なクラスのように振る舞わせることもできます。
データ構造としては複雑そうで、単純な配列操作をした場合、遅いのではないかと疑問に思ったので、Perlと比較してみました。

等差数列の和を、わざと無駄なやり方で計算させてます(配列への代入と参照を毎回させています)

lua

local max = 10000000
local ary = {}
for i=1, max do
    if i > 1 then
        ary[i] = ary[i-1] + i
    else
        ary[i] = i;
    end
end
print(string.format("%d\n", ary[max]));

perl

my $max = 10000000;
my @ary = ();
for (1..$max) {
    if ($_ > 1) {
        $ary[$_] = $ary[$_ - 1] + $_;
    } else {
        $ary[$_] = $_;
    }
}
print sprintf("%d\n", $ary[$max]);

実行時間を計ってみた結果

$ time lua lua.lua
50000005000000

real 0m1.540s
user 0m0.782s
sys 0m0.426s

$ time perl perl.pl
50000005000000

real 0m5.031s
user 0m3.532s
sys 0m0.526s

杞憂でした。ダントツでluaの方が速かったです。
あとは文字列操作も気になるので、今度試してみます。

LUA_MAXCAPTURES

LUA_MAXCAPTURES
luaで、パターンマッチングの最大数を定義している定数

string.matchで、
too many captures
とエラーになるので、調べてみたら、マッチングの最大数が定数で定義されてた。

luaconf.hを下記のように編集して再コンパイルして解決

#define LUA_MAXCAPTURES 512

nginxのif

nginxのifは、複数条件(&&みたいな)が出来ないし、ネストも出来ないので工夫が必要。

携帯かつ特定のURLだった場合にリダイレクトさせたかったので、下記のようにしてみました。

set $ketai_url “”;
if ( $http_user_agent ~* “DoCoMo|KDDI|Vodafone|SoftBank” ) {
set $ketai_url $request_uri;
}

if ( $ketai_url ~* “/some/request/uri” ) {
rewrite ^(.*) http://irako.net/lp redirect;
}

Lenovoのx201にUbuntu 10.04 LTS 64bitを入れたメモ

lenovoのx201にfedora入れて仕事してたんですが、どうもモッサリしているので、ubuntuにしてみました。
そのメモです。

1. USBメモリからBOOT F12でブートデバイス選択
2. OSのインストール自体は、次へ次へみたいな感じで、得に悩むこともなく30分程度で終了
3. firefox8.0.1を入れる

# cd /tmp
# wget ‘ftp://63.245.208.138/pub/mozilla.org/firefox/releases/8.0.1/linux-i686/en-US/firefox-8.0.1.tar.bz2’
# tar jxvf firefox-8.0.1.tar.bz2
# mv firefox /usr/lib64/firefox8.0.1
# cd /usr/bin
# rm -f firefox
# ln -s /usr/lib64/firefox8.0.1 firefox

4. syncしてブクマ等復活
5. skypeを入れる 公式にubuntu10.4(64bit)用のdebファイルがあるので一発
6. 無線のドライバを入れる

# cd /tmp
# wget ‘http://intellinuxwireless.org/iwlwifi/downloads/iwlwifi-6050-ucode-41.28.5.1.tgz’
# tar zxvf iwlwifi-6050-ucode-41.28.5.1.tgz
# mv iwlwifi-6050-ucode-41.28.5.1/iwlwifi-6050-5.ucode /lib/firmware/
# shutdown -r now

7. mozcを入れる

# add-apt-repository ppa:japanese-testers/mozc
# apt-get update
# apt-get install ibus-mozc

iBusをリスタート
「iBusの設定」→「インプットメソッド」→「インプットメソッドの選択」→「日本語」でMozcを選択
Mozcを一番上に

ブックマークはsyncできるし、メールはGmailなので楽ですね。

YAPC::Asia Tokyo 2011

YAPC::Asiaに行ってきたので簡単にレポートします。

写真 11-10-14 11 40 36

▽ さきにまとめ

Perlの祭典と行っても、Perlについてのセッションは多くありません。
Perlを使ったシステム、というか、Web系技術全般といった感じです。
Web技術を引っ張ってきたPerl界らしい祭典ですね。
各セッションについては、勿論内容自体が勉強になることも多かったですが
それよりも、沢山刺激を受けたことが自分にとって良かった所だと思います。

▽ 14(Fri) 一日目

Perl 5.16 and beyond. (Jesse Vincent)
Perl5のこれまでの反省と今後の対応の話。

Webアプリケーション高速化
高速化についての様々な手法。
特に印象に残ったのは、先回りしてキャッシュを生成しておくという仕組み。

SmartPhone development guide with Node/CoffeeScript and….
これからはNode。viewをjavascriptで書いてるのだから、サーバサイドも同じので書きたくなるよね。というお話。

Perlで構築された中規模サイトのDC引っ越し記録
今回優勝したセッション
内容は無停止でシステムを論理移転したお話。
特に勉強になったのは、静的ファイルのフォールバックの仕組みについて。

Mobageオープンプラットフォームの事件簿
モバゲーのTextDataAPI(とてもリクエストが多い)のトラブル対応について。
レプリケーションが追いつかないほどのDELETE&INSERTには正直驚きました。

Mobageソーシャルゲームにおける大規模サーバ運用
mobage のインフラ側の話と、DevOpsの話。

LT
各自5分でいろんな発表。
基本的にネタだけど、Perl文化のようなものを感じられる楽しい時間。
Perl歴一週間のsixapart広報の女の子の発表が、とても面白かった。

▽ 15(Sat) 二日目

大規模環境における、マニアックなキャッシュ利用
memcachedは結構取得に失敗するので、ちゃんとリトライしましょうという話。

ぼくがかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく
最強のフレームワークとは、実装のない設計思想ですねという話。

画像Hacks
画像のパターン認識の話。

Perlで無理ゲーム攻略
同じく画像のパターン認識の話。

闇のEメール伝説
SMTPってちっともSimpleじゃないよねという話

Perlスクリプトをqdbでデバッグ
qdbでデバッグする話

Hello Embed Perl!
組み込みPerlの話。

Managing A band Of Hackers
エンジニアのマネージメントの話。