凯发app官方网站-凯发k8官网下载客户端中心 | | 凯发app官方网站-凯发k8官网下载客户端中心
  • 博客访问: 1582002
  • 博文数量: 43
  • 博客积分: 169
  • 博客等级: 入伍新兵
  • 技术积分: 1162
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-08 15:35
文章分类

全部博文(43)

文章存档

2021年(1)

2019年(4)

2016年(6)

2015年(8)

2013年(19)

2012年(5)

相关博文
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·

分类: java

2019-08-05 16:25:28

jedis第一讲-凯发app官方网站

 

jedis是开源的面向javaredis数据库客户端工具包之一,目前github版本是3.1.0 ()。对于spring boot项目来说,starter-data-redis:1.5.12.release  版本所依赖的redis client包是2.9.0版本。从maven的依赖引用上看,官方引用最多的也是此版本。所以本文在源码讲解上也是依据2.9.0版本进行说明的。

众所周知,所有项目对于redis数据库的依赖无非出于以下两种原因:一方面,依赖其内存数据库特性,将redis作为分布式缓存使用,同时以降低对关系型数据库的ops操作;另一方面,依赖其单线程执行的特性,以实现分布式锁的功能。大多数业务场景,我们还是将redis作为了文本型的缓存服务器在使用,以提高请求的相应效率,降低平响时间,增加服务的吞吐。但是,今天我们聊一下在集群环境下,集群整体不可用时,产生的redis超时过长,最终拖慢请求的场景。

5主5从 redis集群
在大多数应用中,我们都会采取redis集群的方式,以保证服务的高可用和高吞吐,有时也会多个应用服务连接一个redis集群。已达到资源的高利用率。在正常情况下集群方式提高了redis整体的吞吐能力,同时通过主-从方式可以实现故障偏移(主节点挂掉,由从节点升级为主节点)。在集群模式下,redis 16384slot会被平摊到5个主节点上,此时也起到了负载均衡的效果,将流量进行了分流。(这也添加了另外一个名词:热key问题)。已上为集群模式相比单例模式带来的优势。然而,今天我们要聊的就是这种集群模式下,由于集群整体不可用时,jedis一次请求操作超时远远超出设置的 timeout 时间问题。

redis集群不可用

正常情况下,如果集群中某一台机器挂掉,redis集群会执行故障偏移策略,将其对应的从节点升级为主节点,超时时间将为一个timeout,。然而,当整个集群与应用服务之间出现了网络断链时,超时时间=timeout * 集群节点数(主从)。这是为什么呢?是因为在集群模式下,如果某个节点挂掉,集群会执行故障偏移,偏移过程中涉及到新的主节点选举以及新的从节点加入。jedis为了能够获取到新的集群信息,会从原始的集群信息列表中某一个节点开始遍历,如果能够连接该节点,就从该节点获取整个集群的配置信息和slot分布。如果当前节点已经断连,jedis会获取另外一个节点信息获取集群配置,直到遍历到最后一个节点为止。所以在整个过程中如果整个集群断连,那么一次请求timeout时间 >= timeout * 节点数。

jedis client(2.9.0)版本关于上述业务处理的代码主要在jedisclustercommand类的runwithretries方法中。

该方法有四个参数:

key :  要进行操作的key

attempts : 请求重试次数

trytrandomnode : 是否尝试随机选择一个节点进行

asking  :  是否处理asking 链接(可以了解一下asking  moved 区别)

具体方法体如下:

如果重试次数attempts <= 0则直接抛异常,该操作是用来做递归程序终止的判定条件。如果不满足条件 ,则判断是否支持asking方式获取链接。否则执行else操作:

否则判断是否尝试随机获取一个节点获取链接 tryrandomnode, 否则通过当前key获取slot,再通过slot获取slot所在节点的connection

如果在获取链接时或者执行execute操作时出现异常,则执行异常处理机制,此处的异常处理分为:

1、jedisnoreachableclusternodeexception  说明jedis在初始化时没有获取到任何集群信息,即在服务启动时集群就是不可用的,所以这种状态下,必须检查redis集群的可用性,并重启应用服务。

2、jedisconnectionexception   说明jedis在获取链接时出现异常,主要原因是因为jedis在获取连接时默认会ping一下连接以保证目标节点是可用的,如果ping过程失败,则抛出该异常。

这个异常是今天我们要研究的重点内容,主要说明为什么集群不可用时,提效缓存,引发了超时问题?图中展示代码是在jedisconnectionexception的时候,jedis client会执行如下步骤:
1、
释放connection链接

2、判断设置的重试次数是否<=1,如果为false,则调用runwithretries方法递归调用进行重试访问,如果为true,则会调用connectionhandler对象的renewslotcache()方法:

该类是一个abstract类,内部属性jedisclusterinfocache类对象。renewslotcache()方法内部调用cache对象的renewclusterslots(null)方法:

该方法内部才是真正超时根源。从方法内容可以看出存在一个for循环操作,循环内部是通过遍历缓存中redis节点列表(包含主节点从节点),通过与节点通信的方式获取最新的集群信息,如果访问某个节点出现异常,则访问下一个节点,直到最后一个节点。要知道在一个集群整体都挂断时,此处的for循环一定会遍历所有节点,最终在都访问不同的状态下返回。那为什么会导致超时呢?大家想一想,jedis的配置,一般状态下我们对于线上应用配置的redis maxwaittimes参数 一般都是50ms ,如果整个集群不可用时,如果是5 5从的集群,那么 50*12 = 600ms (为什么是12呢,12 = 10(节点数) 2 attempts),所以一个请求最低在redis这一层就报销了600ms。所以redis集群整体的不可用对服务带来的影响是非常大的。希望在以后的开发中牢记这点。
3、jedisredirectionexception  该异常主要原因有两个。一种是由于moved操作导致的(slot不在被访问节点,在另外一个节点时,当前节点返回moved错误,并附带上目标节点ip 端口),另外一种是asking导致的(在节点进行迁移过程中,如果被访问的slot属于正在迁移节点,并且此时,访问的key不在当前节点,会返回asking错误,让client访问目标节点获取数据)。这两种情况虽然结果一直,即都需要跳转到另外一个节点获取最终结果,但是原因是截然不同的。如果客户端使用jedis时,并且在集群环境下,一般不会出现moved错误,因为jedisclient端 就已经通过crc16(key)计算好了slot以及slot具体分布在哪个节点上,所以一般不会出现moved问题。当然只有一种情况就是当被访问的key所在主节点挂掉时,集群进行故障偏移,jedis需要通过其他节点重新获取最新集群信息时,有可能会出现moved问题。再有2就是通过命令行链接集群时,redis-cli  -c  ip:port  时,如果访问的key不在该节点上时,server会返回 moved错误。

所以从源码中大家会发现,集群模式下,如果server端给jedis返回jedismoveddataexception错误时,jedis什么都没有执行(do nothing),这就很符合上面提到的结论。
阅读(285483) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
")); function link(t){ var href= $(t).attr('href'); href ="?url=" encodeuricomponent(location.href); $(t).attr('href',href); //setcookie("returnouturl", location.href, 60, "/"); }
网站地图