読者です 読者をやめる 読者になる 読者になる

Scala用のRedisクライアントについて調べてみた

Scala

仕事でRedisを使いそうなのでScala用のRedisクライアントについて調べてみました。

READMEに書いてある内容とソースコードを流し読みして書いてますので実際に動かしての感想ではありません。使用例もREADMEに書いてあるものからの抜粋です。

Sedis

  • Jedis(Java用のRedisクライアント)のScalaラッパー
  • 1ファイルのみで構成されており処理はJedisを呼んでるだけなので非常にシンプル
  • ブロッキングAPIのみ
  • コネクションプール装備(Jedisのもの)
  • パイプラインは未対応?(JedisのAPIを直接呼び出せばよい??)
  • Play2のプラグイン(キャッシュAPIでRedisを使えるようにするもの)はこれを使っている
 import org.sedis._
 import redis.clients.jedis._
 val pool = new Pool(new JedisPool(new JedisPoolConfig(), "localhost", 6379, 2000))

 pool.withJedisClient { client =>
   Dress.up(client).get("single").isDefined.must(be(true))
   Dress.up(client).get("single").get.must(be("foo"))
   val r: List[String] = Dress.up(client).lrange("test",0,2)·
   r.size.must(be(2))
   r.toString.must(be("List(bar, foo)"))
   val s: List[String] = Dress.up(client).sort("test")
   s.size.must(be(2))
   s.toString.must(be("List(bar, foo)"))
}   

//or using implicits
import Dress._
pool.withClient { client => 
  client.get("single").isDefined.must(be(true))
  client.get("single").get.must(be("foo"))
  client.lindex("test",0).must(be("bar"))
  val r: List[String] = client.lrange("test",0,2)
  r.size.must(be(2))
  r.toString.must(be("List(bar, foo)"))
  val s: List[String] = client.sort("test")
  s.size.must(be(2))
  s.toString.must(be("List(bar, foo)"))
}

scala-redis

import com.redis._
import com.redis._

val r = new RedisClient("localhost", 6379)
r.set("key", "some value") // => true
r.get("key") // => Some(some value)
// Akka setup
implicit val system = ActorSystem("redis-client")
implicit val executionContext = system.dispatcher
implicit val timeout = Timeout(5 seconds)

// Redis client setup
val client = RedisClient("localhost", 6379)

// Set
val numKeys = 3
val (keys, values) = (1 to numKeys map { num => ("key" + num, "value" + num) }).unzip
val writes = keys zip values map { case (key, value) => client.set(key, value) }

Future.sequence(writes).futureValue

rediscala

import redis.RedisClient
import scala.concurrent.Await
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

implicit val akkaSystem = akka.actor.ActorSystem()

val redis = RedisClient()

val futurePong = redis.ping()
println("Ping sent!")
futurePong.map(pong => {
  println(s"Redis replied with a $pong")
})
Await.result(futurePong, 5 seconds)

akkaSystem.shutdown()

結論

どのライブラリもすでにあまりやることがないのかコミットは活発ではありませんが、メンテは継続されているように見えます。最も最近コミットされているのはSedisですがしょぼい機能追加のPRなので参考にならなそう。scala-redisは今年5月、rediscalaは今年2月がそれぞれ最後のコミットになっています。

Sedisは機能面ではダントツで貧弱ですが、Play2でキャッシュAPIの範囲内での利用で済むのであればPlay2プラグイン経由でSedisを使うのがよいかもしれません。

scala-redisとrediscalaは機能面ではだいたい同じような感じ。ブロッキングならscala-redis、ノンブロッキングならscala-redis-nbもしくはrediscalaのどちらかを選べばよさそうです。