redis应用实战(jedis-sentinel,Jedis-cluster原理分析)

Redis Java客户端有很多的开源产品比如Redission、Jedis、lettuce

1.jedis是redis的java实现的客户端,其API提供了比较全面的Redis命令的支持;

2.Redisson实现了分布式和可扩展的Java数据结构,和Jedis相比,功能较为简单,不支持字符串操作,不支持排
序、事务、管道、分区等Redis特性
。Redisson主要是促进使用者对Redis的关注分离,从而让使用者能够将精力更
集中地放在处理业务逻辑上。

3.lettuce是基于Netty构建的一个可伸缩的线程安全的Redis客户端,支持同步、异步、响应式模式。多个线程可以
共享一个连接实例,而不必担心多线程并发问题;

jedis-sentinel原理分析

原理

客户端通过连接到哨兵集群,通过发送Protocol.SENTINEL_GET_MASTER_ADDR_BY_NAME 命令,从哨兵机器中
询问master节点的信息,拿到master节点的ip和端口号以后,再到客户端发起连接。连接以后,需要在客户端建
立监听机制,当master重新选举之后,客户端需要重新连接到新的master节点

源码分析

private HostAndPort initSentinels(Set<String> sentinels, final String masterName) {
    HostAndPort master = null;
    boolean sentinelAvailable = false;
    log.info("Trying to find master from available Sentinels...");
    // 有多个sentinels,遍历这些个sentinels
    for (String sentinel : sentinels) {
    // host:port表示的sentinel地址转化为一个HostAndPort对象。
    final HostAndPort hap = HostAndPort.parseString(sentinel);
    log.fine("Connecting to Sentinel " + hap);
    Jedis jedis = null;
    try {
        // 连接到sentinel
        jedis = new Jedis(hap.getHost(), hap.getPort());
        // 根据masterName得到master的地址,返回一个list,host= list[0], port =// list[1]
        List<String> masterAddr = jedis.sentinelGetMasterAddrByName(masterName);
        // connected to sentinel...
        sentinelAvailable = true;

 

if (masterAddr == null || masterAddr.size() != 2) {
    log.warning("Can not get master addr, master name: " + masterName + ".Sentinel: " + hap+ ".");
    continue;
}
    // 如果在任何一个sentinel中找到了master,不再遍历sentinels
    master = toHostAndPort(masterAddr);
    log.fine("Found Redis master at " + master);
    break;
} catch (JedisException e) {
    // resolves #1036, it should handle JedisException there's another chance
    // of raising JedisDataException
    log.warning("Cannot get master address from sentinel running @ " + hap + ".
    Reason: " + e+ ". Trying next one.");
} finally {
    if (jedis != null) {
    jedis.close();
}
}
}
// 到这里,如果master为null,则说明有两种情况,一种是所有的sentinels节点都down掉了,一种是master节点没有被存活的sentinels监控到
if (master == null) {
    if (sentinelAvailable) {
    // can connect to sentinel, but master name seems to not
    // monitored
    throw new JedisException("Can connect to sentinel, but " + masterName+ " seems to be not monitored...");

} else {
throw new JedisConnectionException("All sentinels down, cannot determine where is
"
+ masterName + " master is running...");
}
}
//如果走到这里,说明找到了master的地址
    log.info("Redis master running at " + master + ", startingSentinellisteners...");
//启动对每个sentinels的监听为每个sentinel都启动了一个监听者MasterListener。MasterListener本身是一个线程,它会去订阅sentinel
上关于master节点地址改变的消息。

for (String sentinel : sentinels) {
    final HostAndPort hap = HostAndPort.parseString(sentinel);
    MasterListener masterListener = new MasterListener(masterName, hap.getHost(),
    hap.getPort());
    // whether MasterListener threads are alive or not, process can be stopped
    masterListener.setDaemon(true);
    masterListeners.add(masterListener);
    masterListener.start();
}
    return master;
}
从哨兵节点获取master信息的方法
public List<String> sentinelGetMasterAddrByName(String masterName) {
    client.sentinel(Protocol.SENTINEL_GET_MASTER_ADDR_BY_NAME, masterName);
    final List<Object> reply = client.getObjectMultiBulkReply();
    return BuilderFactory.STRING_LIST.build(reply);
}

Jedis-cluster原理分析

连接方式

Set<HostAndPort> hostAndPorts=new HashSet<>();
HostAndPort hostAndPort=new HostAndPort("192.168.**.***",****);
HostAndPort hostAndPort1=new HostAndPort("192.168.**.***",****);
HostAndPort hostAndPort2=new HostAndPort("192.168.**.***",****);
HostAndPort hostAndPort3=new HostAndPort("192.168.**.***",****);
hostAndPorts.add(hostAndPort);
hostAndPorts.add(hostAndPort1);
hostAndPorts.add(hostAndPort2);
hostAndPorts.add(hostAndPort3);
JedisCluster jedisCluster=new JedisCluster(hostAndPorts,6000);
jedisCluster.set("ma","hello");

原理分析

程序启动初始化集群环境

1.读取配置文件中的节点配置,无论是主从,无论多少个,只拿第一个,获取redis链接实例

2.用获取的redis连接实例执行clusterNodes()方法,实际执行redis服务端cluster noder命令,获取主从配置信息

3.解析主从配置信息,先把所有节点存放到nodes的map集合中,key为节点的ip:port,value为当前节点的jedisPool

4.解析主节点分配的slots区间段,把slot对应的索引值作为key,第三步中拿到的jedisPool作为value,存储在
slots的map集合中

就实现了slot槽索引值与jedisPool的映射,这个jedisPool包含了master的节点信息,所以槽和节点是对应的,与
redis服务端一致

从集群环境存取值
1)、把key作为参数,执行CRC16算法,获取key对应的slot值
2)、通过该slot值,去slots的map集合中获取jedisPool实例
3)、通过jedisPool实例获取jedis实例,最终完成redis数据存取工作

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值