java通過jedis操作redis(從JedisPool到JedisCluster)
redis作為一個快取資料庫,在絕大多數java專案開發中是必須使用的,在web專案中,直接配合spring-redis,各種配置都直接在spring配置檔案中做了,一般都是使用redis連線池。在非web專案中,通常也是使用的redis連線池。
根據redis的機器數量和叢集方式,又分為以下三種方式:普通單機版的redis,多機器的分片叢集,多機器的cluster叢集方式(redis3版本以上)。
對於單機版的redis使用簡單示例如下:
package com.xxx.redis.redisdemo; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class JedisPoolUtil { private static JedisPool jedisPool; public static JedisPool getJedisPool(){ if(jedisPool == null){ JedisPoolConfig config = new JedisPoolConfig(); config.setMaxIdle(200); config.setMaxIdle(50); config.setMaxWaitMillis(1000 * 100); config.setTestOnBorrow(false); jedisPool = new JedisPool(config, "192.168.42.128",6379); } return jedisPool; } public static String get(String key){ String value = null; JedisPool pool = null; Jedis jedis = null; try{ pool = getJedisPool(); jedis = pool.getResource(); value = jedis.get(key); }catch(Exception e){ e.printStackTrace(); } return value; } public static void set(String key,String value){ JedisPool pool = null; Jedis jedis = null; try{ pool = getJedisPool(); jedis = pool.getResource(); value = jedis.set(key,value); }catch(Exception e){ e.printStackTrace(); } } public static void main(String[] args) { set("name", "xx-jedis"); String name = get("name"); System.out.println(name); } }
這是一個最簡單的demo,實際專案中,會配置redis host,port等資訊,也會根據redis支援的方法和jedis的api,完善更多的方法,如delete,expire,sadd,lpush等等。
當專案增大,需要快取的資料量增大,我們會考慮做分散式叢集,叢集的數量可以根據業務需求擴充套件。資料儲存會均勻分佈在各個分片上。這裡給出一個示例:
package com.xxx.redis.redisdemo; import java.util.ArrayList; import java.util.List; import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisShardInfo; import redis.clients.jedis.ShardedJedis; import redis.clients.jedis.ShardedJedisPool; public class ShardedPoolUtil { private static ShardedJedisPool jedisPool; public static ShardedJedisPool getJedisPool(){ if(jedisPool == null){ JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(200); config.setMaxIdle(50); config.setMaxWaitMillis(1000*100); config.setTestOnBorrow(false); List<JedisShardInfo> shareInfos = new ArrayList<JedisShardInfo>(); shareInfos.add(new JedisShardInfo("192.168.42.128", 6379)); shareInfos.add(new JedisShardInfo("192.168.42.128", 6380)); jedisPool = new ShardedJedisPool(config, shareInfos); } return jedisPool; } public static void set(String key,String value){ ShardedJedisPool pool = null; ShardedJedis jedis = null; try{ pool = getJedisPool(); jedis = pool.getResource(); jedis.set(key, value); }catch(Exception e){ e.printStackTrace(); } } public static String get(String key){ String value = null; ShardedJedisPool pool = null; ShardedJedis jedis = null; try{ pool = getJedisPool(); jedis = pool.getResource(); value = jedis.get(key); } catch (Exception e) { e.printStackTrace(); } return value; } public static void main(String[] args) { String age = "30"; String address = "beijing"; set("age", age); set("address", address); System.out.println(get("age")); System.out.println(get("address")); } }
相對單機版的redis,sharding分散式叢集方式:配置ShardedJedisPool多了設定多個redis伺服器資訊。 資料分佈在哪個機器上,是有演算法的,這裡支援MD5和MURMUR兩種雜湊函式的方式,預設採用的是MURMUR雜湊方法。
這第二種方法,雖然是分散式的,資料分佈在不同的機器上,但是並沒有採用叢集的方式,因為支援redis叢集的是3.0版本及以上,目前redis叢集方式,資料是以槽的方式分佈的,因為需要保證一個master對應至少一個slave節點,所以節點數會比sharding分散式節點多。
redis-cluster這種情況下,java呼叫的方式會發生一些變化,但是還是相似的思路。
package com.xxx.redis.redisdemo;
import java.util.HashSet;
import java.util.Set;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;
public class ClusterPoolUtil {
private static JedisCluster jedisCluster;
private static String hostAndPorts = "192.168.42.128:6379||192.168.42.128:6380||"
+ "192.168.42.128:6381||192.168.42.128:6382||"
+ "192.168.42.128:6383||192.168.42.128:6384";
public static JedisCluster getJedisCluster(){
if(jedisCluster==null){
int timeOut = 10000;
Set<HostAndPort> nodes = new HashSet<HostAndPort>();
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(200);
poolConfig.setMaxIdle(50);
poolConfig.setMaxWaitMillis(1000 * 100);
poolConfig.setTestOnBorrow(false);
String[] hosts = hostAndPorts.split("\\|\\|");
for(String hostport:hosts){
String[] ipport = hostport.split(":");
String ip = ipport[0];
int port = Integer.parseInt(ipport[1]);
nodes.add(new HostAndPort(ip, port));
}
jedisCluster = new JedisCluster(nodes,timeOut, poolConfig);
}
return jedisCluster;
}
public static void set(String key,String value){
JedisCluster jedisCluster = getJedisCluster();
jedisCluster.set(key, value);
}
public static String get(String key){
String value = null;
JedisCluster jedisCluster = getJedisCluster();
value = jedisCluster.get(key);
return value;
}
public static void main(String[] args) {
set("name-1", "value-1");
set("name-2", "value-2");
set("name-3", "value-3");
System.out.println(get("name-1"));
System.out.println(get("name-2"));
System.out.println(get("name-3"));
}
}
redis-cluster叢集安裝好了之後,做好slot分配,就可以開始使用redis儲存和查找了。redis-cluster是redis3開始支援的,他與sharding分片方式不同的是,資料是按照slot槽(16384個slot)分佈的,slot的劃分不是固定的,可以人為指定。這裡使用了六個節點,分為三組,所以slot劃分為3組槽(5461,5461,5460),分別如下:
{
0=192.168.42.128:6382, 5460=192.168.42.128:6382,
5461=192.168.42.128:6380, 10922=192.168.42.128:6380,
10923=192.168.42.128:6384, 16383=192.168.42.128:6384
}
第一組是0-5460,第二組是5461-10922,第三組是10993-16383,從分組中可以看出,6380,6382,6384埠的節點都是master節點,這可以在redis-cluster叢集中檢視:
儲存的key分佈在哪個槽上,可以通過如下方法獲取:
public static int getSlot(String key){
return JedisClusterCRC16.getSlot(key);
}
按照這種方法計算name-1,name-2,name-3的slot槽分別是:10801,6738,2675。按照之前的slot分佈,可以得到name-1,name-2均落在6380上,name-3則落在6382上,我們可以在redis-cluster叢集上通過命令來查詢key,驗證了這個結果: