redis集群方案有哪些
Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个负责一部分hash槽,举个例子,比如当前集群有3个,那么:Redis数据量日益增大,而且使用的公司越来越多,不仅用于做缓存,同时趋向于存储这块,这样必促使集群的发展,各个公司也在收集适合自己的集群方案,目前行业用的比较多的是下面几种集群架构,大部分都是采用分片技术,解决单实例内存增大带来的一系列问题。
redis-cli连接集群 redis连接集群命令
redis-cli连接集群 redis连接集群命令
本篇文章简单介绍五种方案:
cluster方案
twemproxy方案
哨兵模式
codis
客户端分片
cluser方案
从redis 3.0版本开始支持redis-cluster集群,redis-cluster采用无中心结构,每个保存数据和整个集群状态,每个都和其他连接。redis-cluster是一种服务端分片技术。
redis-cluster架构图
redis-cluster特点:
每个都和n-1个通信,这被称为集群总线(cluster bus)。它们使用特殊的端口号,即对外服务端口号加10000。所以要维护好这个集群的每个信息,不然会导致整个集群不可用,其内部采用特殊的二进制协议优化传输速度和带宽。
redis-cluster把所有的物理映射到[0,16383]slot(槽)上,cluster负责维护node--slot--value。
集群预分好16384个桶,当需要在redis集群中插入数据时,根据CRC16(KEY) mod 16384的值,决定将一个key放到哪个桶中。
客户端与redis直连,不需要连接集群所有的,连接集群中任何一个可用即可。
redis-trib.rb脚本(rub语言)为集群的管理工具,比如自动添加,规划槽位,迁移数据等一系列作。
的fail是通过集群中超过半数的检测失效时才生效。
整个cluster被看做是一个整体,客户端可连接任意一个进行作,当客户端作的key没有分配在该上时,redis会返回转向指令,指向正确的。
为了增加集群的可访问性,的方案是将node配置成主从结构,即一个主,挂n个sle从。如果主失效,redis cluster会根据选举算法从sle中选择一个上升为,整个集群继续对外提供服务。
twemproxy方案
twemproxy架构图:
Redis中间件twemproxy是一种利用中间件做分片的技术。twemproxy处于客户端和的中间,将客户端发来的请求,进行一定的处理后(sharding),再转发给后端真正的redis。也就是说,客户端不直接访问redis,而是通过twemproxy中间件间接访问。降低了客户端直连后端的连接数量,并且支持集群水平扩展。
twemproxy中间件的内部处理是无状态的,它本身可以很轻松地集群,这样可以at redis.clients.jedis.JedisFactory.makeObject(JedisFactory.ja:106)避免单点压力或故障。
twemproxy又称nutcracker,起源于推特系统中redis、memcached集群的轻量级。
Github源码地址(
从上面架构图看到twemproxy是一个单点,很容易对其造成很大的压力,所以通常会结合keepalived来实现twemproy的高可用。这时,通常只有一台twemproxy在工作,另外一台处于备机,当一台挂掉以后,vip自动漂移,备机接替工作。关于keepalived的用法可自行网上查阅资料。
哨兵模式
Sentinel哨兵
在1掉线后:
升级2为新的主:
每个Sentinel以每秒钟一次的频率向它所知的Master、Sle以及其他Sentinel实例发送一个PING命令。
当有足够数量的Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态,则Master会被标记为客观下线。
在一般情况下,每个Sentinel会以每10秒一次的频率向它所知的所有Master、Sle发送INFO命令。
当Master被Sentinel标记为客观下线时,Sentinel向下线的Master的所有Sle发送INFO命令的频率会从10秒一次改为每秒一次。
若没有足够数量的Sentinel同意Master已经下线,Master的客观下线状态就会被移除。若Master重新向Sentinel的PING命令返回有效值,Master的主观下线状态就会被移除。
codis
codis是一个分布式的Redis解决方案,由豌豆荚开源,对于上层的应用来说,连接codis proxy和连接原生的redis server没什么明显的区别,上层应用可以像使用单机的redis一样使用,codis底层会处理请求的转发,不停机的数据迁移等工作,所有后边的事情,对于前面的客户端来说是透明的,可以简单的认为后边连接的是一个内存无限大的redis服务。
客户端分片
分区的逻辑在客户端实现,由客户端自己选择请求到哪个。方案可参考一致性哈希,这种方案通常适用于用户对客户端的行为有完全控制能力的场景。
总结:没有的方案,只有最合适的方案。
更多Redis相关技术文章,请访问Redis教程栏目进行学习!
集群redis哨兵模式连接方式,解决database不生效问题(附源码)
注意事项:
1 引入pom依Z1仍然能够向主B中写入, 如果网络分区发生时间较短,那么集群将会继续正常运作,如果分区的时间足够让大部分的一方将B1选举为新的,那么Z1写入B中得数据便丢失了.赖
2 添加redis哨兵配置,database主动设置,才会生效
3 applicatio如果一个实例距离一次有效回复PING命令的时间超过down-after-milliseconds选项所指定的值,则这个实例会被Sentinel标记为主观下线。n.yml配置
5 启动测试连接
可以看到redis.clients.jedis.JedisSentinelPool : Created JedisSentinelPool to at 10.10.195.249:6379已经启动了
作为程序员第 140 篇文章,每次写一句歌词记录一下,看看人生有几首歌的时间,wahahaha ...
redis连不上咋整??
在redis-cli命令行使用: clients可以查看当前的redis连接数。如果 Redis 连不上,可能是以下原因之一:
4 项目目录Redis 服务未启动:请检查 Redis 服务是否已经启动。可以使用 `ps -ef | grep redis` 命令查看 Redis 进程是否在运行。
Redis 配置错误:请检查 Redis 配置文件是否正确。可以使用 `redis-cli config get bind` 命令查看 Redis 绑定的 IP 地址是否正确。
网络问题:请检查网络连接是否正常。可以使用 `ping` 命令测试 Redis 是否能够正常访问。
防火墙问题:请检查防火墙设置是否正确。如果 Redis 和客户端在不同的网络中,可能需要在防火墙中开放 Redis 端口。
如果您已经确认 Redis 服务已经启动,并且配置、网络和防火墙设置都正确,但仍然无法连接 Redis,可以尝试以下方法:
检查 Redis 日志:Redis 日志中可能会记录连接错误的详细信息。可以查看 Redis 日志文件,找到相关的错误信息。
检查 Redis 版本:请确保 Redis 客户端和使用的是相同的 Redis 版本。如果版本不一致,可能会导致连接错误。
检查 Redis 密码:如果 Redis 设置了密码,客户端需要提供正确的密码才能连接。请检查客户端是否提供了正确的密码。
检查 Redis 端口:请确保客户端使用的 Redis 端口与配置的端口一致。可以使用 `redis-cli -h ` 命令测试连接。 如果您仍然无法解决连接问题,请提供更多详细信息,我会尽力帮助您解决问题。 利用Docker 的swarm模式创建6个redis服务,在容器内可以相互ping通。利用容器名称创建redis集群里报 ERR Invalid node address specified: redis1:6379错误。 解决方法 把容器名称改在IP地址即可解决。 原因 所谓的高可用,也叫 HA(High Availability),是分布式系统架构设计中必须考虑的因素之一,它是保证系统SLA的重要指标。Redis 高可用的主要有三种模式: 主从模式 , 哨兵模式和集群模式 。 Redis 提供了 Redis 提供了(replication)功能,当一台 redis 数据库中的数据发生了变化,这个变化会被自动地同步到其他的 redis 机器上去。 Redis 多机器部署时,这些机器会被分成两类,一类是主( ),一类是从(sle )。一般 主可以进行读、写作 ,而 从只能进行读作 。一个主可以有多个从,但是一个从只会有一个主,也就是所谓的 一主多从结构 。 · 支持主从,主机会自动将数据同步到从机,可以进行读写分离; · Master 是以非阻塞的方式为主 Sles 提供服务。所以在 Master-Sle 同步期间,客户端仍然可以提交查询或修改请求; · Sle 同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis 则返回同步之前的数据。 · Redis 不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的 IP 才能恢复; · 主机宕机,宕机前有部分数据未能及时同步到从机,切换 IP 后面还会引入数据不一致的问题,降低了系统的可用性; · Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂; · Redis 的主和从中的数据是一样的,降低的内存的可用性 实际生产中,我们优先考虑哨兵模式。这种模式下, 宕机,哨兵会自动选举 并将其他的 sle 指向新的 。 在主从模式下,redis 同时提供了哨兵命令 redis-sentinel ,哨兵是一个的进程,作为进程,它会运行。其原理是哨兵进程向所有的 redis 机器人发送命令,等待 Redis 响应,从而运行的多个 Redis 实例。一般为了便于决策选举,使用 奇数个哨兵 。多个哨兵构成一个哨兵集群,哨兵直接也会相互通信,检查哨兵是否正常运行,同时发现 战机哨兵之间会进行决策选举新的 哨兵模式的作用: · 通过发送命令,让 Redis 返回其运行状态,包括主和从; · 然而一个哨兵进程对 Redis 进行,也可能会出现问题,为此,我们可以使用多个哨兵进行。各个哨兵之间还会进行,这样就形成了多种哨兵模式。 哨兵很像 kafka 集群中的 zookeeper 的功能。 · 哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有。 · 主从可以自动切换,系统更健壮,可用性更高。 · 具有主从模式的缺点,每台机器上的数据是一样的,内存的可用性较低。 · Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。 Redis 集群模式本身没有使用一致性 hash 算法,而是使用 slots 插槽 。 Redis 哨兵模式基本已经可以实现高可用,读写分离 ,但是在这种模式下每台 Redis 都存储相同的数据,很浪费内存,所以在 redis3.0 上加入了 Cluster 集群模式,实现了 Redis 的分布式存储,对数据进行分片,也就是说每台 Redis 上存储不同的内容;每个都会通过集群总线(cluster bus),与其他的进行通信。 通讯时使用特殊的端口号,即对外服务端口号加 10000。例如如果某个 node 的端口号是 6379,那么它与其它 nodes 通信的端口号是 16379。nodes 之间的通信采用特殊的二进制协议。 对客户端来说,整个 cluster 被看做是一个整体,客户端可以连接任意一个 node 进行作,就像作单一 Redis 实例一样, 当客户端作的时候 key 没有分配到该 node 上时,Redis 会返回转向指令,指向正确的 node,这有点儿像浏览器页面的 302 redirect 跳转。 根据,集群部署至少要 3 台以上的 ,使用 3 主 3 从六个的模式。 在 Redis 的每一个上,都有这么两个东西, 一个是插槽(slot),它的的取值范围是:0-16383, 可以从上面 redis-trib.rb 执行的结果看到这 16383 个 slot 在三个 上的分布。还有一个就是 cluster,可以理解为是一个集群管理的插件,类似的哨兵。 当我们的存取的 Key 到达的时候,Redis 会根据 crc16 的算法对计算后得出一个结果,然后把结果和 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的,然后直接自动跳转到这个对应的上进行存取作。 如果 1 和它的从 sle 1 都宕机了,整个集群就会进入 fail 状态,因为集群的 slot 映射不完整。 如果集群超过半数以上的 挂掉,无论是否有 sle,集群都会进入 fail 状态。 redis-cluster 采用去中心化的思想 ,没有中心的说法,客户端与 Redis 直连,不需要中间层,客户端不需要连接集群所有,连接集群中任何一个可用即可。 对 redis 集群的扩容就是向集群中添加机器,缩容就是从集群中删除机器,并重新将 16383 个 slots 分配到集群中的上(数据迁移)。 扩缩容也是使用集群管理工具 redis-tri.rb。 扩容时,先使用 redis-tri.rb add-node 将新的机器加到集群中,这是新机器虽然已经在集群中了,但是没有分配 slots,依然是不起做用的。在使用 redis-tri.rb reshard 进行分片重哈希(数据迁移),将旧上的 slots 分配到新上后,新才能起作用。 缩容时,先要使用 redis-tri.rb reshard 移除的机器上的 slots,然后使用 redis-tri.rb add-del 移除机器。 采用去中心化思想,数据按照 slot 存储分布在多个,间数据共享,可动态调整数据分布; 可扩展性:可线性扩展到 1000 多个,可动态添加或删除; 高注意:需要在 Redis 上正确配置连接数,否则 INFO 命令返回的信息中可能没有相应的连接池信息。可用性:部分不可用时,集群仍可用。通过增加 Sle 做 standby 数据副本,能够实现故障自动 failover,之间通过 gossip 协议交换状态信息,用投票机制完成 Sle 到 Master 的角色提升; 降低运维成本,提高系统的扩展性和可用性。 1.Redis Cluster 是无中心的集群架构,依靠 Goss 协议(谣言传播)协同自动化修复集群的状态。但 GosSIp 有消息延时和消息冗余的问题,在集群数量过多的时候,之间需要不断进行 PING/PANG 通讯,不必须要的流量占用了大量的网络资源。虽然 Reds4.0 对此进行了优化,但这个问题仍然存在。 2.数据迁移问题 Redis Cluster 可以进行的动态扩容缩容,这一过程,在目前实现中,还处于半自动状态,需要人工介入。在扩缩容的时候,需要进行数据迁移。 而 Redis 为了保证迁移的一致性,迁移所有作都是同步作 ,执行迁移时,两端的 Redis 均会进入时长不等的阻塞状态,对于小 Key,该时间可以忽略不计,但如果一旦 Key 的内存使用过大,的时候会接触发集群内的故障转移,造成不必要的切换。 主从模式: 挂掉后,需要手动指定新的 ,可用性不高,基本不用。 哨兵模式: 挂掉后,哨兵进程会主动选举新的 ,可用性高,但是每个存储的数据是一样的,浪费内存空间。数据量不是很多,集群规模不是很大,需要自动容错容灾的时候使用。 集群模式:数据量比较大,QPS 要求较高的时候使用。 Redis Cluster 是 Redis 3.0 以后才正式推出,时间较晚,目前能证明在大规模生产环境下成功的案例还不是很多,需要时间检验。 在 AIX 系统中查看 Redis 连接池连接数,可以通过连接 Redis 的客户端工具执行 INFO 命令,获取 Redis 的信息,其中包括连接池的相关信息。具体步骤如下: 在 AIX 系统为了保证高可用, redis-cluster 集群引入了主从模式 ,一个主对应一个或者多个从。当其它主 ping 主 1 时,如果半数以上的主与 1 通信超时,那么认为 1 宕机了,就会启用 1 的从 sle 1,将 sle 1 变成主继续提供服务。中安装 Redis 的客户端工具,比如 redis-cli。 通过 redis-cli 连接 Redis 。 执行 INFO 命令,获取 Redis 的信息。命令格式如下: 查看返回的信息中关于连接池的部分,其中包括连接数、当前连接数等相关信息。可以通过搜索 "maxclients" 来找到连接数的配置。 在阿里云Ubuntu新搭建的redis集群,始终无法连接,报Could not get a resource from the pool异常 所以将redis.conf中的protected-mode yes改为protected-mode no 重启redis实例,以为问Copy codeINFO题就解决了?发现还是报Could not get a resource from the pool异常 这个是什么情况,要逆天嘛? 查看redis node信息看一下,终于发现了问题 怎么会有172的IP,到这里终于找到问题根源了,修改node.conf配置,重启redis,问题终于解决。 如下图: config get maxclients 可以查询redis允许的连接数。 如下图: client list ——查看详细 clients ——查看连接数等信息 以Ja语言为例,简单说一下,除了一些公司自主开发的集群外。常用的解决高并发问题的集群一般有三种: 使用redis-trib.rb,这个是安装redis时就自带的一种集群,采用了服务端分片的方式,支持主备,此集群既解决了高并发的问题,也解决了高可用的问题。Jedis使用JedisCluster类来访问。 使用Jedis带的客户端分片ShardedJedisPool类。 使用进行分片twemproxy,连接可以使用Jedis类(单链接)和JedisPool类(多链接)。 通过Redis的sentinel机制还可以配置高可用集群,一主多从,主down掉后,sentinel负责选拔一个从机作为新的主机。 如果有什么疑问,可以留言。 Caused by: org.springframework.data.redis.RedisConnectionFailureException: Could not get a resource from the pool; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool at org.springframework.data.redis.connection.jedis.JedisExceptionConverter.convert(JedisExceptionConverter.ja:41) at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.ja:37) at org.springframework.data.redis.connection.jedis.JedisClusterConnection.convertJedisAccessException(JedisClusterConnection.ja:3999) at org.springframework.data.redis.connection.jedis.JedisClusterConnection.setEx(JedisClusterConnection.ja:717) at org.springframework.data.redis.core.DefaultValueOperations 11.doInRedis(DefaultValueOperations.ja:186) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.ja:207) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.ja:169) at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.ja:) at org.springframework.data.redis.core.DefaultValueOperations.set(DefaultValueOperations.ja:182) at io.renrenmon.utils.SuppleDataUtils.provideIcc(SuppleDataUtils.ja:107) at io.renren.modules.job.task.TaskIcc.taskFour(TaskIcc.ja:242) ... 10 common frames omitted Caused by: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool at redis.clients.util.Pool.getResource(Pool.ja:53) at redis.clients.jedis.JedisPool.getResource(JedisPool.ja:226) at redis.clients.jedis.JedisSlotBasedConnectionHandler.getConnectionFromSlot(JedisSlotBasedConnectionHandler.ja:66) at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.ja:116) at redis.clients.jedis.JedisClusterCommand.runBinary(JedisClusterCommand.ja:60) at redis.clients.jedis.BinaryJedisCluster.setex(BinaryJedisCluster.ja:268) at org.springframework.data.redis.connection.jedis.JedisClusterConnection.setEx(JedisClusterConnection.ja:715) ... 18 common frames omitted Caused by: redis.clients.jedis.exceptions.JedisConnectionException: ja.SocketTimeoutException: connect timed out at redis.clients.jedis.Connection.connect(Connection.ja:207) at redis.clients.jedis.Binary.connect(Binary.ja:93) at redis.clients.jedis.BinaryJedis.connect(BinaryJedis.ja:1767) at org.apachemons.pool2.impl.GenericObjectPool.create(GenericObjectPool.ja:868) at org.apachemons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.ja:435) at org.apachemons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.ja:363) at redis.clients.util.Pool.getResource(Pool.ja:49) ... 28 common frames omitted Caused by: ja.SocketTimeoutException: connect timed out at ja.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.ja:85) at ja.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.ja:350) at ja.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.ja:206) at ja.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.ja:188) at ja.PlainSocketImpl.connect(PlainSocketImpl.ja:172) at ja.SocksSocketImpl.connect(SocksSocketImpl.ja:392) at redis.clients.jedis.Connection.connect(Connection.ja:184) ... 35 common frames omitted 最近在本地测试通过springboot基础redis的方式连接redis集群,启动的时候没有报错。 到时当执行保存,查询到redis的作的时候,报上面的错误。 首先看到错误信息,先是connect timed out后,再出现的Could not get a resource from the pool错误。一开始排查这个错误,由于使用的是默认连接池,debug的时候,也看到有装载连接池,为啥报错呢。本地通过redis-manger工具,连接集群地址也可以连接访问。从日志也看不出还有其他的错误信息。 于是自己写了main方法直接作JedisCluster的方式来测试,出现的错误跟上面全文一样。用抓包工具wireshark过滤集群的地址,查看连接的消息也是正常的。 另外一个项目使用的reddison客户端,于是测试了deamo用reddison来连接集群地址,启动的时候,发现报如下错误 乖乖,恍然大悟;10.287.17.31地址是的内网地址,本机是连不上内网地址的,只有通过外网地址连接。而我配置的是外网地址。然而,客户端在集群同步和心跳检查的时候,是拉取的集群信息,redis集群信息里面的的信息 配置的是内网地址。客户端就通过这个内网地址来同步信息了。 再次同wireshark过滤集群10.287.17.31,发现有大量的超时重传的包,也没有响应。Docker环境下创建Redis集群出现ERR Invalid node address specified: redis1:6379错误
at org.springframework.data.redis.connection.jedis.JedisExceptionConverter.convert(JedisExceptionConverter.ja:67)玩转Redis的高可用(主从、哨兵、集群)
at ja.DualStackPlainSocketImpl.waitForConnect(Native Mod)AIX系统怎么查redis连接池连接数?
Sentinel(哨兵)是Redis的高可用性解决方案:由一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个主以及这些主下的所有从,并在被监视的主进入下线状态时,自动将下线主属下的某个从升级为新的主。连接远程的redis 集群报Could not get a resource from the pool异常
at ja.Socket.connect(Socket.ja:589)如何查看redis连接数
ZooKeeper 会一直保存当前有效的 主从实例 IP:Port 信息。至于主从自动切换过程,使用 redis 自带的 sentinel 实现,现设置为超过 30s 主 server 无响应,则由 sentinel 进行主从实例的切换,切换后就会触发以主、从实例通过以上提到的一系列动作,从而完成最终的切换。Redis集群方案应该怎么做
当某个 slot 从 online 变成 pre_migrate 后,客户端会删除 clients 下的 uid 临时,然后在M igrating s 创建 uid 临时。注意,因为需要保证数据不丢失,从 pre_migrate 到 migrating 期间,这个 slot 是被锁定的,即所有对这个 slot 的读写都会被阻塞。所以 mananger 会最多等待 10s ,确认所有客户端都已经切换到准备就绪状态,如果发现某个客户端一直未准备就绪,那么 mananger 会放弃此次迁移,把 slot 状态由 pre_migrate 改为 online 。如果客户端发现 slot 状态由 pre_migrate 变成 online 了,那么会删除 migrating_clients 下的 uid ,在 clients 下重新创建 uid 。还需要注意的一点是,有可能一个客户刚启动,并且正在往 clients 下创建 uid ,但是因为网络延迟还没创建完成,导致 mar 未确认到这个 client 是否准备就绪,所以 mananger 把 slot 改为 pre_migrate 后会等待 1s 再确认所有客户端是否准备就绪。jedis连接集群报Could not get a resource from the pool错误
Sentinel的工作方式