Skip to content

Instantly share code, notes, and snippets.

@cb372
Created December 15, 2012 07:43
Show Gist options
  • Save cb372/4291969 to your computer and use it in GitHub Desktop.
Save cb372/4291969 to your computer and use it in GitHub Desktop.
Finagle Advent Calendar 2012 (http://connpass.com/event/1524/) - Day 15 - Fedis

Fedisとは?

finagle-redisを使ったRedisのモックサーバです。

コードはGithub上にあります。

finagle-redisとは?

  • Redisプロトコル用のFinagle Codec
  • RedisプロトコルをしゃべるFinagleクライアント
  • Naggati (後述)
  • ユーティリティもろもろ

Fedisの主なクラス、パッケージ

  • Server - Finagleサーバを起動させるメインクラス

  • service.RedisService - Finagle Serviceの実装:

      def apply(req: SessionAndCommand): Future[Reply] = {
        // RedisのDBを選択
        val db = dbs(req.session.db)
        
        req.cmd match {
          // DBの戻り値(Future[Reply])をそのまま返す
          case Get(key) => db.get(key)
          case Set(key, value) => db.set(key, value)
          // ... 他のコマンド ...
        }
      }
    
  • codec.RedisServerCodec - finagle-redisのCodecの拡張版

  • filter._ - セッション管理用のFinagle Filter

  • handler.ClientAddressInjector - セッション管理用のNettyハンドラ

  • db._ - Redis DBの実装 (Finagleと無関係)

セッション管理

Redisは接続中のクライアントごとにセッションを立て、下記のような情報を記憶します:

  • クライアントがAUTHコマンドで認証に成功したこと
  • クライアントがどのDBを使用しているか(Redisサーバに複数のDBがあり、SELECTコマンドで切り替えできる)

しかしFinagleは基本的にステートレスであり、セッションに対応しません。しかもクライアントのアドレスを知る方法もありません。

そのため、Finagleの裏にあるNettyのパイプラインをいじって次のハンドラを注入します。このハンドラはクライアントのアドレスを抽出してFedisに渡すので、セッション管理は可能になります。

class ClientAddressInjector extends SimpleChannelUpstreamHandler {

  override def messageReceived(ctx: ChannelHandlerContext, e: MessageEvent) {
    val oldMsg = e.getMessage.asInstanceOf[Command]
    val newMsg = CmdFromClient(oldMsg, e.getRemoteAddress)

    ctx.sendUpstream(new UpstreamMessageEvent(e.getChannel, newMsg, e.getRemoteAddress))
  }

}

Naggati

Naggatiとは、非同期I/Oを気にせずにNettyチャンネルからデータを復元するための便利なライブラリです。Play 2.0のIterateeと同じような考えで作られています。

Naggatiは別のプロジェクトであるが、なぜかfinagle-redis配下にもコピペされてます。com.twitter.finagle.redis.naggatiパッケージにあります。

Fedisは直接Naggatiを利用しませんが、別のプロジェクトで使ったことがあります。Nettyを扱うのであれば、Naggatiをおすすめします。

テスト

ScalaTestのFlatSpecを使っています。Fedisの目的はRedisの仕様を真似ることですから、スペック系のテストはとても向いてます。

時刻関係のテストにcom.twitter.util.Timeを使います。すろとこんな感じでテストを書けます:

withTimeAt(1000L) { _ =>
  // ... do something ...
}
withTimeAt(2000L) { _ =>
  // ... test assertion ...
}
withCurrentTimeFrozen { _ =>
  // ... do something ...
}

Twitterさんのライブラリについて

Twitterのライブラリに依存するにあたって気をつけなければならないこと:

  • バージョン管理はむちゃくちゃです。最近Twitterが完全に(?)Scala 2.9に移行してだいぶマシになったが、半年前はひどかった.

  • Twitterのプロジェクト間の依存関係についてドキュメントがほとんどありません。何時間も http://maven.twttr.com をブラウズしたり、pom.xmlを読んだり、依存関係と必要なバージョンを推測しました。

  • Twitterの社内GitリポとGithubとの同期は定期的ではなく、「気が向いたら同期する」みたいな感じです。GithubにあるコードはMavenからダウンロードするコードより2、3リリース遅れてることがあります。

Fedisの今後

Fedisの開発は十分満足したし、誰にも使われてないから、今後あまり時間を費やすつもりはありません。ただ、コマンドをもう少し揃えられたらいいなと思うので、ヒマな時にちょこちょこ手をつけるかもしれません。

Finagleを勉強がてらコマンドを増やしてみたいという方がいれば、もちろんpull requestを歓迎します!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment