Hatena::ブログ(Diary)

ToMmY Makes Love with Codes RSSフィード Twitter

2011-12-10

[][] redis-clojure が糞すぎた件

redis-clojure はその名のとおり clojure から redis を叩くためのものだったはずだが、使い物にならなかった。

今回の問題領域が特殊すぎるからかもしれないので、糞ライブラリとは言わないけどね。テストは通るし。

問題

  • clojure のサーバの timeout はわりと短めに設定されている。
  • クライアントはサーバとの接続が切れていることがわかったら、再接続を試みるべきである。
  • だが! redis-clojure は再接続なんてしなかった。

解決策

  • jredis に逃げる(clj-twitter から twitter4j に逃げたように)
  • ping をおくりまくる
  • なおす

本来は直すべきなんだけど、Connection まわりの設計がよくわからないのと、どうも作者に対応する気がなさそうなので、workaround として ping を投げまくることに。

以下のスニペットのまとめ : https://gist.github.com/1455507

テストスクリプト

サーバログ
[17585] 11 Dec 01:17:47 - Accepted 127.0.0.1:33165
[17585] 11 Dec 01:17:47 - Accepted 127.0.0.1:33166
[17585] 11 Dec 01:17:50 - DB 0: 2 keys (0 volatile) in 4 slots HT.
[17585] 11 Dec 01:17:50 - 2 clients connected (0 slaves), 540980 bytes in use
[17585] 11 Dec 01:17:55 - DB 0: 2 keys (0 volatile) in 4 slots HT.
[17585] 11 Dec 01:17:55 - 2 clients connected (0 slaves), 540980 bytes in use
[17585] 11 Dec 01:18:00 - DB 0: 2 keys (0 volatile) in 4 slots HT.
[17585] 11 Dec 01:18:00 - 2 clients connected (0 slaves), 540964 bytes in use
[17585] 11 Dec 01:18:05 - DB 0: 2 keys (0 volatile) in 4 slots HT.
[17585] 11 Dec 01:18:05 - 2 clients connected (0 slaves), 540988 bytes in use
[17585] 11 Dec 01:18:06 - Client closed connection
[17585] 11 Dec 01:18:06 - Client closed connection

スレッドが違うので、別のクライアントから繋いでいる扱いになっているが、これで接続は維持される。

クライアントログ
wrote0
wrote1

参考 - Ruby バージョン

本当はどういう動きをするのかな、とか参考にしたかったので、 ruby バージョンも書いてみた。

この実装だと fail する。without_reconnect をとりさると fail しないようになる。

# client.rb(243)
    def ensure_connected
      tries = 0


      begin
        connect unless connected?
        tries += 1


        yield
      rescue Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EBADF, Errno::EINVAL
        disconnect


        if tries < 2 && @reconnect
          retry
        else
          raise Errno::ECONNRESET
        end
      rescue Exception
        disconnect
        raise
      end
    end

トランザクションはこのようにラップされていて、エラーがおきたらとりあえず disconnect して一回だけ再試行する。

without_reconnect の指定は @reconnect を折る。


これを clojure に持ち込むなら macro でラップしてやればよいが、 Connection オブジェクトの扱いとか、すべてのエラーを拾ってきて…とか考えるのが面倒になったのであきらめました。

サーバの設定に応じて、おなじスレッド内で起動するとか間隔とかを調節すればよい。


私は heroku で動かしているので、それにあわせる。 Redis To Go のサーバ設定は General Info からアドオンの設定のところで見られる。

例:redis to go nano の設定
# = General ==================================================================
port ****
databases 1


loglevel notice
logfile /mnt/redis.17060.log


# = Security =================================================================
requirepass **********************


# = Limits ===================================================================
maxmemory 5242880
maxmemory-policy volatile-lru
maxmemory-samples 3


maxclients 10
timeout 150 # <= これだね


# = Persistence ==============================================================
dir /home/redis/****


rdbcompression yes
dbfilename dump.rdb


save 900 1
save 300 10
save 60 10000


# = Slowlog ==================================================================
slowlog-log-slower-than -1


# = Advanced Config ==========================================================
hash-max-zipmap-entries 64
hash-max-zipmap-value 512


list-max-ziplist-entries 512
list-max-ziplist-value 64


set-max-intset-entries 512


zset-max-ziplist-entries 128
zset-max-ziplist-value 64


activerehashing yes

fatrowfatrow 2011/12/15 21:04 mmcgranaさんの jedis をベースにした clj-redis というのもありますよ。マイナーなコマンドやパイプラインなどはまだなかったりしますが、jedis を生でいじれるので対応できます。https://github.com/mmcgrana/clj-redis

ToMmYToMmY 2011/12/16 10:42 情報ありがとうございます。

> マイナーなコマンドやパイプラインなどはまだなかったりしますが、jedis を生でいじれるので対応できます。

それは嬉しいですね! 時間があったら試してみます。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/ToMmY/20111210/1323541231
リンク元