jedis客户端操作redis主要三种模式:单台模式、分片模式(ShardedJedis)、含有哨兵的分片模式(JedisSentinel)、集群模式(BinaryJedisCluster),分片模式是一种轻量级集群。
1、单台模式:直接通过jedis获取实例就可以
2、分片模式:
JedisPoolConfig config =new JedisPoolConfig(); config.setMinIdle(minIdel); config.setMaxIdle(intMaxIdel); config.setMaxTotal(maxSize); config.setMaxWaitMillis(readTimeOut); config.setMaxIdle(intMaxIdel); config.setTestWhileIdle(checkAlive); ShardedJedisPool sharedPool = new ShardedJedisPool(config,jdsInfoList);‘ sharedPool.getResource();3、含有哨兵的分片模式
由于程序连接配置了主服务器的连接,但是此时主服务器挂调,哨兵会将从服务器变成主服务器,但程序是不知道的,出现无法连接异常。Jedis提供了对jedis sentinel pool的封装,所以发生主从切换的时候,web server都不需要重新配置和deploy,对客户端完全透明。高可用性的极佳体现啊。
import org.junit.Test; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisSentinelPool; public class TestSentinel { @Test public void test1() { JedisPoolConfig poolConfig = new JedisPoolConfig(); String masterName = "mymaster"; Set<String> sentinels = new HashSet<String>(); sentinels.add("192.168.1.97:26379"); sentinels.add("192.168.1.96:26379"); JedisSentinelPool jedisSentinelPool = new JedisSentinelPool(masterName, sentinels, poolConfig); HostAndPort currentHostMaster = jedisSentinelPool.getCurrentHostMaster(); System.out.println(currentHostMaster.getHost()+"--"+currentHostMaster.getPort());//获取主节点的信息 Jedis resource = jedisSentinelPool.getResource(); String value = resource.get("a"); System.out.println(value);//获得键a对应的value值 resource.close(); } }4、集群模式
import java.util.HashSet; import java.util.Set; import org.junit.Test; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPoolConfig; public class TestCluster { @Test public void test1() throws Exception { JedisPoolConfig poolConfig = new JedisPoolConfig(); Set<HostAndPort> nodes = new HashSet<HostAndPort>(); HostAndPort hostAndPort = new HostAndPort("192.168.1.99", 7000);//只给集群里一个实例就可以 HostAndPort hostAndPort1 = new HostAndPort("192.168.1.99", 7001); HostAndPort hostAndPort2 = new HostAndPort("192.168.1.99", 7002); HostAndPort hostAndPort3 = new HostAndPort("192.168.1.99", 7003); HostAndPort hostAndPort4 = new HostAndPort("192.168.1.99", 7004); HostAndPort hostAndPort5 = new HostAndPort("192.168.1.99", 7005); nodes.add(hostAndPort); nodes.add(hostAndPort1); nodes.add(hostAndPort2); nodes.add(hostAndPort3); nodes.add(hostAndPort4); nodes.add(hostAndPort5); JedisCluster jedisCluster = new JedisCluster(nodes, poolConfig);//JedisCluster中默认分装好了连接池. //redis内部会创建连接池,从连接池中获取连接使用,然后再把连接返回给连接池 String string = jedisCluster.get("a"); System.out.println(string); } } 初始化 代码:
private void initializeSlotsCache(Set<HostAndPort> startNodes, GenericObjectPoolConfig poolConfig) { //遍历所有从配置文件读取的节点 for (HostAndPort hostAndPort : startNodes) { Jedis jedis = new Jedis(hostAndPort.getHost(), hostAndPort.getPort()); try { cache.discoverClusterNodesAndSlots(jedis); //这个break是个重点,虽然使用的for循环遍历,但是此处的break让此循环立刻跳出 break; } catch (JedisConnectionException e) { // try next nodes } finally { if (jedis != null) { jedis.close(); } } } for (HostAndPort node : startNodes) { cache.setNodeIfNotExist(node); } } 注意上面代码段for循环里面的break: 它让for循环立刻跳出,导致for循环实际上只执行了一次,也就是说只使用了配置文件中所有节点配置的第一个,如此说来,集群配置文件中节点配置一个和配置多个效果一致。 同时还要注意到:通过获取的第一个节点配置实例化了一个Jedis jedis,如果配置文件中第一个节点指向的服务挂机或无法连接,将导致程序无法使用整个集群,虽然redis集群中其它节点是可用的。
补充:
不管是主从还是分片集群模式注意设置:
config.setTestOnBorrow(false);
config.setTestOnReturn(false);
这样的话在每次发送请求的时候就不用去ping一下服务端是否可用了,降低流量请求,理论上可减少一半
总结连接模板:
主从 // 数据库链接池配置 JedisPoolConfig config = new JedisPoolConfig(); //最大连接数, 应用自己评估,不要超过Redis每个实例最大的连接数 config.setMaxTotal(100); //最大空闲连接数, 应用自己评估,不要超过Redis每个实例最大的连接数 config.setMaxIdle(50); config.setMinIdle(20); config.setMaxWaitMillis(6 * 1000); config.setTestOnBorrow(false); config.setTestOnReturn(false); String host = "*192.168.0.1"; //域名 String password = "please input your password"; //密码 int port = 2222; //端口 int timeout = 3000; //建立连接超时时间 JedisPool pool = new JedisPool(config, host, port, timeout, password); Jedis jedis = null; try { jedis = pool.getResource(); /// ... do stuff here ... for example jedis.set("foo", "bar"); String foobar = jedis.get("foo"); System.out.println(foobar); jedis.set("name", "zhangsan"); System.out.println(jedis.get("name")); } finally { if (jedis != null) { jedis.close(); } } /// ... when closing your application: pool.destroy(); //分片集群 import redis.clients.jedis.*; import java.util.HashSet; import java.util.Set; // 数据库连接池配置 JedisPoolConfig config = new JedisPoolConfig(); //最大连接数, 应用自己评估,不要超过Redis每个实例最大的连接数 config.setMaxTotal(100); //最大空闲连接数, 应用自己评估,不要超过Redis每个实例最大的连接数 config.setMaxIdle(50); config.setMinIdle(20); config.setMaxWaitMillis(6 * 1000); config.setTestOnBorrow(false); config.setTestOnReturn(false); // Redis集群的节点集合 Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>(); jedisClusterNodes.add(new HostAndPort("192.168.0.1", 2222)); //域名 端口 jedisClusterNodes.add(new HostAndPort("192.168.0.2", 3333)); jedisClusterNodes.add(new HostAndPort("192.168.0.3", 4444)); int timeout = 2000; //连接建立超时时间 int maxAttempts = 5; //最多重定向次数 JedisCluster jedisCluster = new JedisCluster(jedisClusterNodes, timeout, maxAttempts, config); String keyPrefix = "__test"; String value = ""; for (int i=1; i <= 10; i++){ String key = keyPrefix+i; value = "value"+i; System.out.println(value); // 存数据 jedisCluster.set(key, value); // 取数据 value= jedisCluster.get(key); System.out.println(key + "=" + value); //删除数据 jedisCluster.del(key); value = jedisCluster.get(key); System.out.println(key + "=" + value); System.out.println(); }