akishin999の日記

調べた事などを書いて行きます。

Redis で Sharding してみた

Redis の Sharding は現状クライアントサイド、つまりライブラリ依存で実現されています。
ここでは RubyJava のライブラリで実際に Sharding を試してみました。

redis-rb

redis/redis-rb · GitHub
https://github.com/redis/redis-rb

Ruby から Redis を使うための標準的なライブラリです。
gem コマンド一発でインストールできます。

# gem install redis --no-rdoc --no-ri

redis-rb で Sharding するには Redis::Distributed クラスを使います。
Redis::Distributed を使って Sharding するサンプルコードは以下のようになります。

# -*- coding: utf-8 -*-
require 'redis'
require 'redis/distributed'

redis_hosts = %W(
  redis://192.0.2.1:6379/0
  redis://192.0.2.1:6380/0
  redis://192.0.2.1:6381/0
)

redis = Redis::Distributed.new(redis_hosts)

KEYS = ('a'..'z').map {|c| c * 3}
VALUES = (100..1000).to_a

# ランダムな値を Redis に設定
KEYS.each { |key|
  p "#{key} : #{redis.node_for(key).id}"
  redis.set(key, VALUES[rand(VALUES.size)])
}

# 設定した値を取得
KEYS.each { |key|
  p "#{key} : #{redis.get(key)}"
}

java

xetorthio/jedis · GitHub
https://github.com/xetorthio/jedis

Java から Redis を使うためのライブラリとしては Jedis があります。
Jedis を使って Sharding するサンプルコードは以下のようになります。

import java.util.ArrayList;
import java.util.List;

import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;

public class JedisExample3 {

    public static void main(String[] args) {
        // Redis サーバのリストを作成
        List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
        shards.add(new JedisShardInfo("192.0.2.1", 6379));
        shards.add(new JedisShardInfo("192.0.2.1", 6380));
        shards.add(new JedisShardInfo("192.0.2.1", 6381));
        
        // サーバのリストから ShardedJedis オブジェクトを生成
        ShardedJedis jedis = new ShardedJedis(shards);
        
        // 値を取得
        for(char ch = 'a'; ch <= 'z'; ch++) {
            String key = new String(new char[3]).replace('\0', ch);
            System.out.printf("get result : %s\n", jedis.get(key));
        }
    }
}

上のサンプルコードを動かしてみるとわかりますが、redis-rb で登録したデータを Jedis から取得することが出来ません。

前述した通り、Redis の Sharding はクライアント依存なので、ライブラリの ConsistentHashing の実装方式が異なると、あるライブラリで登録したデータを別のライブラリを使って取り出す事が出来ません。
その場合、大抵のライブラリでは ConsistentHashing の実装クラスが差替え可能になっているので、その部分を自前で実装することになります。

ここでは Jedis から redis-rb で分散させたデータを取得するため、以下のようなクラスを書いてみました。

以下のようにこのクラスを使用するように変更すると redis-rb で登録したデータを Jedis 側で取得できるようになります。

import java.util.ArrayList;
import java.util.List;

import redis.clients.jedis.JedisShardInfo;

public class JedisExample3 {

    public static void main(String[] args) {
        // Redis サーバのリストを作成
        List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
        shards.add(new JedisShardInfo("192.0.2.1", 6379));
        shards.add(new JedisShardInfo("192.0.2.1", 6380));
        shards.add(new JedisShardInfo("192.0.2.1", 6381));
        
        // サーバのリストから ShardedJedis オブジェクトを生成
        RubyCompatibleShardedJedis jedis = new RubyCompatibleShardedJedis(shards);
        
        // 値を取得
        for(char ch = 'a'; ch <= 'z'; ch++) {
            String key = new String(new char[3]).replace('\0', ch);
            System.out.printf("get result : %s\n", jedis.get(key));
        }
    }
}

クライアントサイドの Sharding は導入は楽ですが、複数の言語やライブラリから使おうとすると意外と面倒臭そうですね。
色んな言語から使う可能性があるなら twemproxy を使った方が楽かも知れません。


Redis Cookbook
Redis Cookbook
posted with amazlet at 13.06.05
Tiago Macedo Fred Oliveria
Oreilly & Associates Inc
売り上げランキング: 27,988

Redis in Action
Redis in Action
posted with amazlet at 13.06.05
Josiah L. Carlson
Manning Pubns Co
売り上げランキング: 43,263