redis集群访问
① Django连接Redis集群问题排查思路和总结
直接就一个连接失败
确认账号密码和端口没问题后,问题同事配置有没验证过,他说直接从网上 cv 的,完全没经过验证。坑啊!!!
把生产的配置和测试配置比较好,修改了几个地方
信心满满,重启启动 django shell 测试,结果还是连接不上!这时候心情开始有点糟糕~
冷静, django shell 不行,那用 python shell 直连试试?
一点毛病都没有,直接连上了!
一脸懵逼,这到底是啥问题啊!
结果依然是连接不上。
不知不觉已经到了晚上九点,好累,不想卷了。下班回家吧
回家路上整个脑子都被这个问题困扰着。难道密码中含有 @ 符号的 redis 集群,Django 真的连接不上?反复的问自己。
问了其他同事,生产环境是否有其他的 redis 集群可以用来调试。很遗憾,并没有。
要不,我自己创建一个 redis 集群,把密码设置成含有 @ 符号?
可是,自己本地创建 redis 集群好麻烦啊。要本地安装虚拟机,想到一堆配置就直接劝退。
洗完澡,和老婆聊了 1h 左右的视频。已经到 11 点多,准备睡觉?
那是不可能的,带着问题是很难入睡!哎,这个是老毛病了。
突然想到了一个点,最小试错原则。自己搭建本地集群很麻烦,公司又没有多余的集群。
那直接买一个云版的 redis 集群?说干就干,直接从床上起来,打开电脑。
这时问题又来了,阿里云还是腾讯云?
鉴于双 11 买了腾讯云 2c 4g 8m 的服务器,只要 199 就能 3 年。
再对比之前买阿里云那个 1c 2g 1m 服务器,3 年也要 100 多。
瞬间对腾讯云好感倍增,决定先买腾讯云。
一顿操作,发现腾讯云是真的难用:
最最最重要,给把实例绑定了安全组后,外网还是无法访问???(不管了,反正我就是很生气)
对腾讯云太失望了,不得不把最后一根稻草压在阿里云身上。
所幸,阿里云没有让我失望!
咔咔咔,一顿操作:
密码中含有 @ 符号,但连接一点毛病都没有!!!
至此,问题终于解决了!!!
我已经迫不及待明天去公司验证,但回过头一看,已经是深夜一点半。
自言自语的说了一句:"睡吧,卷王"
经过对比,发现配置只需要生产的配置仅需要在测试的配置上加多一个 :
修复最磨人的 bug,往往仅需要一点小小的改动~
为什么测试环境没报错了呢???
因为测试环境的 redis 集群不需要密码
② 编写一个python程序实现redis集群的访问
用python-2.7.3\python是对的,但是你的hello.py放在那里?你需要先用“cd 目录名”转换当前目录到存放hello.py的地方,然后执行python-2.7.3\python hello.py。
③ Redis集群方案应该怎么做
以java语言为例,简单说一下,除了一些公司自主开发的集群外。常用的解决高并发问题的集群一般有三种:
使用redis-trib.rb,这个是安装redis时就自带的一种集群,采用了服务端分片的方式,支持主备,此集群既解决了高并发的问题,也解决了高可用的问题。Jedis使用JedisCluster类来访问。
使用Jedis带的客户端分片ShardedJedisPool类。
使用代理进行分片twemproxy,连接代理可以使用Jedis类(单链接)和JedisPool类(多链接)。
通过Redis的sentinel机制还可以配置高可用集群,一主多从,主down掉后,sentinel负责选拔一个从机作为新的主机。
如果有什么疑问,可以留言。
④ Redis怎么做集群
为什么集群?
通常,为了提高网站响应速度,总是把热点数据保存在内存中而不是直接从后端数据库中读取。Redis是一个很好的Cache工具。大型网站应用,热点数据量往往巨大,几十G上百G是很正常的事儿,在这种情况下,如何正确架构Redis呢?
首先,无论我们是使用自己的物理主机,还是使用云服务主机,内存资源往往是有限制的,scale up不是一个好办法,我们需要scale out横向可伸缩扩展,这需要由多台主机协同提供服务,即分布式多个Redis实例协同运行。
其次,目前硬件资源成本降低,多核CPU,几十G内存的主机很普遍,对于主进程是单线程工作的Redis,只运行一个实例就显得有些浪费。同时,管理一个巨大内存不如管理相对较小的内存高效。因此,实际使用中,通常一台机器上同时跑多个Redis实例。
方案
1.Redis官方集群方案 Redis Cluster
Redis Cluster是一种服务器Sharding技术,3.0版本开始正式提供。
Redis Cluster中,Sharding采用slot(槽)的概念,一共分成16384个槽,这有点儿类pre sharding思路。对于每个进入Redis的键值对,根据key进行散列,分配到这16384个slot中的某一个中。使用的hash算法也比较简单,就是CRC16后16384取模。
Redis集群中的每个node(节点)负责分摊这16384个slot中的一部分,也就是说,每个slot都对应一个node负责处理。当动态添加或减少node节点时,需要将16384个槽做个再分配,槽中的键值也要迁移。当然,这一过程,在目前实现中,还处于半自动状态,需要人工介入。
Redis集群,要保证16384个槽对应的node都正常工作,如果某个node发生故障,那它负责的slots也就失效,整个集群将不能工作。
为了增加集群的可访问性,官方推荐的方案是将node配置成主从结构,即一个master主节点,挂n个slave从节点。这时,如果主节点失效,Redis Cluster会根据选举算法从slave节点中选择一个上升为主节点,整个集群继续对外提供服务。这非常类似前篇文章提到的Redis Sharding场景下服务器节点通过Sentinel监控架构成主从结构,只是Redis Cluster本身提供了故障转移容错的能力。
Redis Cluster的新节点识别能力、故障判断及故障转移能力是通过集群中的每个node都在和其它nodes进行通信,这被称为集群总线(cluster bus)。它们使用特殊的端口号,即对外服务端口号加10000。例如如果某个node的端口号是6379,那么它与其它nodes通信的端口号是16379。nodes之间的通信采用特殊的二进制协议。
对客户端来说,整个cluster被看做是一个整体,客户端可以连接任意一个node进行操作,就像操作单一Redis实例一样,当客户端操作的key没有分配到该node上时,Redis会返回转向指令,指向正确的node,这有点儿像浏览器页面的302 redirect跳转。
Redis Cluster是Redis 3.0以后才正式推出,时间较晚,目前能证明在大规模生产环境下成功的案例还不是很多,需要时间检验。
2.Redis Sharding集群
Redis 3正式推出了官方集群技术,解决了多Redis实例协同服务问题。Redis Cluster可以说是服务端Sharding分片技术的体现,即将键值按照一定算法合理分配到各个实例分片上,同时各个实例节点协调沟通,共同对外承担一致服务。
多Redis实例服务,比单Redis实例要复杂的多,这涉及到定位、协同、容错、扩容等技术难题。这里,我们介绍一种轻量级的客户端Redis Sharding技术。
Redis Sharding可以说是Redis Cluster出来之前,业界普遍使用的多Redis实例集群方法。其主要思想是采用哈希算法将Redis数据的key进行散列,通过hash函数,特定的key会映射到特定的Redis节点上。这样,客户端就知道该向哪个Redis节点操作数据。
庆幸的是,java redis客户端驱动jedis,已支持Redis Sharding功能,即ShardedJedis以及结合缓存池的ShardedJedisPool。
Jedis的Redis Sharding实现具有如下特点:
1. 采用一致性哈希算法(consistent hashing),将key和节点name同时hashing,然后进行映射匹配,采用的算法是MURMUR_HASH。采用一致性哈希而不是采用简单类似哈希求模映射的主要原因是当增加或减少节点时,不会产生由于重新匹配造成的rehashing。一致性哈希只影响相邻节点key分配,影响量小。
2.为了避免一致性哈希只影响相邻节点造成节点分配压力,ShardedJedis会对每个Redis节点根据名字(没有,Jedis会赋予缺省名字)会虚拟化出160个虚拟节点进行散列。根据权重weight,也可虚拟化出160倍数的虚拟节点。用虚拟节点做映射匹配,可以在增加或减少Redis节点时,key在各Redis节点移动再分配更均匀,而不是只有相邻节点受影响。
3.ShardedJedis支持keyTagPattern模式,即抽取key的一部分keyTag做sharding,这样通过合理命名key,可以将一组相关联的key放入同一个Redis节点,这在避免跨节点访问相关数据时很重要。
⑤ 如何安装Redis集群
创建目录,配置文件
如何安装Redis集群
修改配置文件
按照此方式修改7001~7005的配置文件,注意修改端口号。
如何安装Redis集群
启动各个实例
如何安装Redis集群
创建集群
现在我们已经有了六个正在运行中的 Redis 实例, 接下来我们需要使用这些实例来创建集群, 并为每个节点编写配置文件。
通过使用 Redis 集群命令行工具redis-trib,编写节点配置文件的工作可以非常容易地完成redis-trib位于Redis 源码的src文件夹中,它是一个 Ruby 程序,这个程序通过向实例发送特殊命令来完成创建新集群,检查集群,或者对集群进行重新分片(reshared)等工作。
我们需要执行以下命令来创建集群:
[root@localhost src]# ./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
/usr/bin/env: ruby: No such file or directory
如何安装Redis集群
系统中没有安装ruby,所以报上面的错误。
先安装ruby
[root@localhost yum.repos.d]# yum install ruby
[root@localhost yum.repos.d]# yum install rubygems
[root@localhost yum.repos.d]# gem install redis
Successfully installed redis-3.2.2
1 gem installed
Installing ri documentation for redis-3.2.2...
Installing RDoc documentation for redis-3.2.2...
如何安装Redis集群
再次创建集群
[root@localhost src]# ./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
Redis自动选择主从
如何安装Redis集群
连接集群
redis-cli 也可以作为集群的客户端工具,要想访问集群,只需连接任意一个redis实例即可。使用-c参数
[root@localhost bin]# ./redis-cli -c -p 7000
总结
set 命令写数据,集群将数据写到7001实例上,当你使用get命令获取数据时,客户端即自动切换到7001端口。
redis-cli对集群的支持是非常基本的, 所以它总是依靠 Redis 集群节点来将它转向(redirect)至正确的节点。一个真正的(serious)集群客户端应该做得比这更好: 它应该用缓存记录起哈希槽与节点地址之间的映射(map), 从而直接将命令发送到正确的节点上面。
⑥ redis cluster集群部署
一.服务器设置准备
1. 将6379端口在防火墙看开启
[root@redis1 ~]#vi /etc/sysconfig/iptables
-A INPUT -m state --state NEW -m tcp -p tcp --dport 6379 -j ACCEPT
注:必须加在 REJECT 前面。
2.修改Selinux参数
[root@redis1 ~]#vi /etc/selinux/config
SELINUX=disabled
注:分别在其它几个节点上同样配置防火墙和 SELINUX。
二.安装Redis
1.安装系统组件
安装gcc、tcl
yum install –y gcc-c++
yum install –y tcl
2.安装redis
2.1.解压 Redis 到/usr/local目录下
[root@redis1 ~]# tar -zxvf /root/software/redis-3.2.6.tar.gz -C /usr/local/
2.2.在解压后的目录中进行 make 和 make test
[root@redis1 ~]# cd /usr/local/redis-3.2.6
[root@redis1 redis-3.2.6]# make
[root@redis1 redis-3.2.6]# make test
注:要检查 make 和 make test 的结果是否都正确,如果报错,针对性检查并安装系统缺少的组件。
2.3. 复制 redis-server 和 redis-cli 到/usr/local/bin 目录下:
[root@redis1 redis-3.2.6]# cd src
[root@redis1 src]# cp redis-server /usr/local/bin/
[root@redis1 src]# cp redis-cli /usr/local/bin/
2.4验证 Redis 安装是否成功:
[root@redis1 ~]# redis-server
[root@redis1 ~]# redis-cli
注:安装其它 5 台服务器
三.配置集群模式
1.配置 redis.conf
1.1 配置 redis.conf
[root@redis1 ~]# mkdir /etc/redis
[root@redis1 ~]# cd /etc/redis
[root@redis ~]# vi redis.conf
port 6379
daemonize yes
cluster-enabled yes
cluster-config-file /etc/redis/nodes.conf
cluster-node-timeout 5000
appendonly yes
requirepass Ab123456
注 1:cluster-node-timeout 是集群中各节点相互通讯时,允许“失联”的最大毫秒数,本演示
中配置的为 5 秒,如果超过 5 秒某个节点没有向其它节点汇报成功,认为该节点挂了。
注 2:requirepass 是 Redis 访问密码,为了安全起见,该参数建议必须配置,从但客户端
Jedis 版本必须使用 2.8.x 以上的版本,否则需要通过扩展 JedisCluster 来实现对密码访问的
支持。此外几个 Redis 节点的密码应该设置为相同的。
注 3:分别在其它几个节点上创建与上面相同的 redis.conf 文件,内容也相同。
注 4:重启/重建 Redis 集群时,必须删除去/etc/redis/nodes.conf 文件。
1.2以次启动所有节点
[root@redis1 ~]# redis-server /etc/redis/redis.conf
[root@redis2 ~]# redis-server /etc/redis/redis.conf
[root@redis3 ~]# redis-server /etc/redis/redis.conf
[root@redis4 ~]# redis-server /etc/redis/redis.conf
[root@redis5 ~]# redis-server /etc/redis/redis.conf
[root@redis6 ~]# redis-server /etc/redis/redis.conf
2.安装 Redis 集群所需的 Ruby 工具
2.1安装 Ruby 工具:
Redis 集群需要借助其它工具将相关节点加入到 Cluster 中,而这个工具是由 Redis 提供
一个名为 redis-trib.rb 的 ruby 脚本,否则接下来创建 cluster 会失败。
[root@redis1 ~]# cd /usr/local/redis-3.2.6/src
[root@redis1 src]# yum install –y ruby
[root@redis1 src]# yum install -y rubygems
[root@redis1 src]# gem install redis --version 3.0.0
[root@redis1 src]# gem list
2.2 设置 Ruby 连接 Redis 的密码:
[root@redis1 ~]# vi /usr/lib/ruby/gems/1.8/gems/redis-3.0.0/lib/redis/client.rb
:password => "Ab123456"
注:分别在其它几个节点上用同样的方式安装好 Ruby 工具
3 利用redis-trib.rb 创建 Redis集群
3. 1. 在 src 目录下运行以下脚本:
[root@redis1 ~]# cd /usr/local/redis-3.2.6/src
[root@redis1 src]# ./redis-trib.rb create --replicas 1 10.50.130.101:6379 10.50.130.102:6379
10.50.130.103:6379 10.50.130.104:6379 10.50.130.105:6379 10.50.130.106:6379
注 1:只需在其中某个个节点执行以上脚本(本例在第一个节点执行)。
注 2:利用 redis-trib 创建 Cluster,只需要操作一次即可,假设系统关机、重启,把所有的
节点全部关闭之后,下次重启后,即自动进入 Cluster 模式,不用现次执行 redis-trib.rb cteate
命令。
3.2查看 Cluster 进程:
[root@redis1 ~]# ps -ef|grep redis
[root@redis2 ~]# ps -ef|grep redis
[root@redis3 ~]# ps -ef|grep redis
[root@redis4 ~]# ps -ef|grep redis
[root@redis5 ~]# ps -ef|grep redis
[root@redis6 ~]# ps -ef|grep redis
3.3 查看节点属性(Master/Slave)
[root@redis1 ~]# cd /usr/local/redis-3.2.6/src
[root@redis1 src]# ./redis-trib.rb check 10.50.130.101:6379
[root@redis1 src]# ./redis-trib.rb check 10.50.130.102:6379
[root@redis1 src]# ./redis-trib.rb check 10.50.130.103:6379
[root@redis1 src]# ./redis-trib.rb check 10.50.130.104:6379
[root@redis1 src]# ./redis-trib.rb check 10.50.130.105:6379
[root@redis1 src]# ./redis-trib.rb check 10.50.130.106:6379
3.4查看节点/集群信息
redis-cli 客户端登录到任一个节点,查看:
4.Jedis 测试 Redis 集群
⑦ 使用 redis-cli 搭建 Redis 集群
参考: Redis 集群教程
redis.conf 文件中包含很多信息,如:端口号、持久化方式、持久化的文件等等。
使用写入了不同端口号的配置文件就可以启动多个 Redis 实例。
下面是一个最少选项的集群的配置文件:
文件中的 cluster-enabled 选项用于开实例的集群模式, 而 cluster-conf-file 选项则设定了保存节点配置文件的路径, 默认值为 nodes.conf 。节点配置文件无须人为修改, 它由 Redis 集群在启动时创建, 并在有需要时自动进行更新。
要让集群正常运作至少需要三个主节点,不过在刚开始试用集群功能时, 强烈建议使用六个节点: 其中三个为主节点, 而其余三个则是各个主节点的从节点。
首先, 让我们进入一个新目录, 并创建六个以端口号为名字的子目录, 稍后我们在将每个目录中运行一个 Redis 实例: 命令如下:
在文件夹 7000 至 7005 中, 各创建一个 redis.conf 文件, 文件的内容可以使用上面的示例配置文件, 但记得将配置中的 port 和 cluster-conf-file 中的端口号数字 从 7000 改为与文件夹名字相同的号码。不同的集群节点要使用不同的 cluster-conf-file 。
配置文件的路径是可以自定义的。创建完毕后分别启动一个实例。
网上看到的教程,包括参考的官方文档里的文章,大多是使用以下方式创建集群。
这个命令在这里用于创建一个新的集群, 选项–replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。
之后跟着的其他参数则是这个集群实例的地址列表,3 个 master 3 个 slave redis-trib 会打印出一份预想中的配置给你看,如果你觉得没问题的话,就可以输入 yes,redis-trib 就会将这份配置应用到集群当中,让各个节点开始互相通讯,最后可以得到如下信息:
这表示集群中的 16384 个槽都有至少一个主节点在处理,集群运作正常。
但是在 Redis 的 github 仓库 中看到,该文件已经不建议使用。
我在 手把手教你实现 Docker 部署 Redis 集群 的评论中看到, 现在 redis-cli --cluster 命令已经可以创建集群,分配槽,分配主从服务器了 ,于是使用以下命令了解到相关的命令。
可以看到,命令的组成形式和旧方式是一致的。
可以看到执行命令后,redis 客户端做了以下工作:
输入 yes 后,redis 客户端做了以下工作:
集群搭建完毕。
因为 Redis Cluster 默认要求所有的槽位被覆盖,可以通过修改 cluster-require-full-coverage yes 配置来改变该行为。
CLUSTERDOWN The cluster is down in redis 这里的回答中提到:我们可以使用 N 个Master 和 N+1 个 Slave,正常情况下多余的一个实例作为随机一个 Master 的 Slave,一旦有实例宕机,可以迅速顶替,以保证每个主节点总是有至少一个从节点保持数据同步。
ps:搜索命令行的输出时,才看到 深入理解Redis系列之集群环境搭建 这篇文章,有时候搜索的关键词不合适容易走弯路啊……
⑧ 玩转Redis的高可用(主从、哨兵、集群)
所谓的高可用,也叫 HA(High Availability),是分布式系统架构设计中必须考虑的因素之一,它是保证系统SLA的重要指标。Redis 高可用的主要有三种模式: 主从模式 , 哨兵模式和集群模式 。
Redis 提供了 Redis 提供了复制(replication)功能,当一台 redis 数据库中的数据发生了变化,这个变化会被自动地同步到其他的 redis 机器上去。
Redis 多机器部署时,这些机器节点会被分成两类,一类是主节点(master 节点),一类是从节点(slave 节点)。一般 主节点可以进行读、写操作 ,而 从节点只能进行读操作 。一个主节点可以有多个从节点,但是一个从节点只会有一个主节点,也就是所谓的 一主多从结构 。
· 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离;
· Master 是以非阻塞的方式为主 Slaves 提供服务。所以在 Master-Slave 同步期间,客户端仍然可以提交查询或修改请求;
· Slave 同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis 则返回同步之前的数据。
· Redis 不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的 IP 才能恢复;
· 主机宕机,宕机前有部分数据未能及时同步到从机,切换 IP 后面还会引入数据不一致的问题,降低了系统的可用性;
· Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂;
· Redis 的主节点和从节点中的数据是一样的,降低的内存的可用性
实际生产中,我们优先考虑哨兵模式。这种模式下,master 宕机,哨兵会自动选举 master 并将其他的 slave 指向新的 master。
在主从模式下,redis 同时提供了哨兵命令 redis-sentinel ,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵进程向所有的 redis 机器人发送命令,等待 Redis 服务器响应,从而监控运行的多个 Redis 实例。一般为了便于决策选举,使用 奇数个哨兵 。多个哨兵构成一个哨兵集群,哨兵直接也会相互通信,检查哨兵是否正常运行,同时发现 master 战机哨兵之间会进行决策选举新的 master
哨兵模式的作用:
· 通过发送命令,让 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 台以上的 master 节点,最好使用 3 主 3 从六个节点的模式。
在 Redis 的每一个节点上,都有这么两个东西, 一个是插槽(slot),它的的取值范围是:0-16383, 可以从上面 redis-trib.rb 执行的结果看到这 16383 个 slot 在三个 master 上的分布。还有一个就是 cluster,可以理解为是一个集群管理的插件,类似的哨兵。
当我们的存取的 Key 到达的时候,Redis 会根据 crc16 的算法对计算后得出一个结果,然后把结果和 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
为了保证高可用, redis-cluster 集群引入了主从模式 ,一个主节点对应一个或者多个从节点。当其它主节点 ping 主节点 master 1 时,如果半数以上的主节点与 master 1 通信超时,那么认为 master 1 宕机了,就会启用 master 1 的从节点 slave 1,将 slave 1 变成主节点继续提供服务。
如果 master 1 和它的从节点 slave 1 都宕机了,整个集群就会进入 fail 状态,因为集群的 slot 映射不完整。 如果集群超过半数以上的 master 挂掉,无论是否有 slave,集群都会进入 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 多个节点,节点可动态添加或删除;
高可用性:部分节点不可用时,集群仍可用。通过增加 Slave 做 standby 数据副本,能够实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成 Slave 到 Master 的角色提升;
降低运维成本,提高系统的扩展性和可用性。
1.Redis Cluster 是无中心节点的集群架构,依靠 Goss 协议(谣言传播)协同自动化修复集群的状态。但 GosSIp 有消息延时和消息冗余的问题,在集群节点数量过多的时候,节点之间需要不断进行 PING/PANG 通讯,不必须要的流量占用了大量的网络资源。虽然 Reds4.0 对此进行了优化,但这个问题仍然存在。
2.数据迁移问题
Redis Cluster 可以进行节点的动态扩容缩容,这一过程,在目前实现中,还处于半自动状态,需要人工介入。在扩缩容的时候,需要进行数据迁移。
而 Redis 为了保证迁移的一致性,迁移所有操作都是同步操作 ,执行迁移时,两端的 Redis 均会进入时长不等的阻塞状态,对于小 Key,该时间可以忽略不计,但如果一旦 Key 的内存使用过大,严重的时候会接触发集群内的故障转移,造成不必要的切换。
主从模式:master 节点挂掉后,需要手动指定新的 master,可用性不高,基本不用。
哨兵模式:master 节点挂掉后,哨兵进程会主动选举新的 master,可用性高,但是每个节点存储的数据是一样的,浪费内存空间。数据量不是很多,集群规模不是很大,需要自动容错容灾的时候使用。
集群模式:数据量比较大,QPS 要求较高的时候使用。 Redis Cluster 是 Redis 3.0 以后才正式推出,时间较晚,目前能证明在大规模生产环境下成功的案例还不是很多,需要时间检验。
⑨ Redis的哨兵模式和集群模式
原文地址: https://www.cnblogs.com/itplay/p/11098990.html
哨兵模式 #
哨兵模式是redis高可用的实现方式之一
使用一个或者多个哨兵(Sentinel)实例组成的系统,对redis节点进行监控,在主节点出现故障的情况下,能将从节点中的一个升级为主节点,进行故障转义,保证系统的可用性。
哨兵们是怎么感知整个系统中的所有节点(主节点/从节点/哨兵节点)的 #
首先主节点的信息是配置在哨兵(Sentinel)的配置文件中
哨兵节点会和配置的主节点建立起两条连接命令连接和订阅连接
哨兵会通过命令连接每10s发送一次INFO命令,通过INFO命令,主节点会返回自己的run_id和自己的从节点信息
哨兵会对这些从节点也建立两条连接命令连接和订阅连接
哨兵通过命令连接向从节点发送INFO命令,获取到他的一些信息
a. run_id
b. role
c. 从服务器的复制偏移量 offset
d. 等
因为哨兵对与集群中的其他节点(主从节点)当前都有两条连接,命令连接和订阅连接
a. 通过命令连接向服务器的_sentinel:hello频道发送一条消息,内容包括自己的ip端口、run_id、配置纪元(后续投票的时候会用到)等
b. 通过订阅连接对服务器的_sentinel:hello频道做了监听,所以所有的向该频道发送的哨兵的消息都能被接受到
c. 解析监听到的消息,进行分析提取,就可以知道还有那些别的哨兵服务节点也在监听这些主从节点了,更新结构体将这些哨兵节点记录下来
d. 向观察到的其他的哨兵节点建立命令连接----没有订阅连接
哨兵模式下的故障迁移 #
主观下线
哨兵(Sentinel)节点会每秒一次的频率向建立了命令连接的实例发送PING命令,如果在down-after-milliseconds毫秒内没有做出有效响应包括(PONG/LOADING/MASTERDOWN)以外的响应,哨兵就会将该实例在本结构体中的状态标记为SRI_S_DOWN主观下线
客观下线
当一个哨兵节点发现主节点处于主观下线状态是,会向其他的哨兵节点发出询问,该节点是不是已经主观下线了。如果超过配置参数quorum个节点认为是主观下线时,该哨兵节点就会将自己维护的结构体中该主节点标记为SRI_O_DOWN客观下线
询问命令SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> <run_id>
参数意义
ip/port当前认为下线的主节点的ip和端口
current_epoch配置纪元
run_id*标识仅用于询问是否下线
有值标识该哨兵节点希望对方将自己设置为leader
询问时用*,选举时用run_id
leader选举
在认为主节点客观下线的情况下,哨兵节点节点间会发起一次选举,命令还是上面的命令SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> <run_id>,只是run_id这次会将自己的run_id带进去,希望接受者将自己设置为主节点。如果超过半数以上的节点返回将该节点标记为leader的情况下,会有该leader对故障进行迁移
故障迁移
在从节点中挑选出新的主节点
a. 通讯正常
b. 优先级排序
c. 优先级相同是选择offset最大的
将该节点设置成新的主节点 SLAVEOF no one,并确保在后续的INGO命令时,该节点返回状态为master
将其他的从节点设置成从新的主节点复制, SLAVEOF命令
将旧的主节点变成新的主节点的从节点
优缺点 #
优点
高可用,在主节点故障时能实现故障的转移
缺点:好像没办法做到水平拓展,如果内容很大的情况下
集群模式 #
官方提供的分布式方案(槽指派/重新分片/故障转移)
集群内的节点,都会有个数据结构存储整个集群内的节点信息
//整体structclusterState{clusterNode *mySelf; .... dict *nodes;//集群内的所有节点}// 单个节点structclusterNode{charname[];charip[];intport; clusterLink *link;//保存节点间,连接的信息intflags;//状态标记}//节点间连接的信息structclusterLink{mstime_tctime;//创建时间intfd;//tcp套接字描述符sds sndbuf;// 输出缓存区sds rcvbuf;//输入缓存区structclusterNode*node;}
槽指派 #
redis集群可以被分为16384个槽,只有这些槽全被指派了处理的节点的情况下,集群的状态才能是上线状态(ok)
操作redis集群的时候,将key作为参数,就可以计算出对应的处理槽上,所以存储等操作都应该在该槽对应的节点上。通过这种方式,可以完美的实现集群存储的水平拓展。
defslot_number(key):returnCRC16(key) &16383//得到的结果就是槽的序号
槽指派的信息是怎么存储的
structclusterState{clusterNode *slots[16384] }structclusterNode{unsignedcharslots[16384/8]}
通过上面两个结构体中的定义可以看出,槽指派的信息是分了两种方式,保存在结构体里面。
分两种存储的好处
1. 如果需要判断某一个节点负责的槽,只需要获取方式二中的数组做判断就可以
2.如果找某个槽是哪个节点负责,只需要获取方式一的列表,一查就知道
重新分片 #
将已经指派给节点的槽,重新执行新的节点。
故障转移 #
发现故障节点
集群内的节点会向其他节点发送PING命令,检查是否在线
如果未能在规定时间内做出PONG响应,则会把对应的节点标记为疑似下线
集群中一半以上负责处理槽的主节点都将主节点X标记为疑似下线的话,那么这个主节点X就会被认为是已下线
向集群广播主节点X已下线,大家收到消息后都会把自己维护的结构体里的主节点X标记为已下线
从节点选举
当从节点发现自己复制的主节点已下线了,会向集群里面广播一条消息,要求所有有投票权的节点给自己投票(所有负责处理槽的主节点都有投票权)
主节点会向第一个给他发选举消息的从节点回复支持
当支持数量超过N/2+1的情况下,该从节点当选新的主节点
故障的迁移
新当选的从节点执行 SLAVEOF no one,修改成主节点
新的主节点会撤销所有已下线的老的主节点的槽指派,指派给自己
新的主节点向集群发送命令,通知其他节点自己已经变成主节点了,负责哪些槽指派
新的主节点开始处理自己负责的槽的命令
集群模式和哨兵模式的区别 #
哨兵模式监控权交给了哨兵系统,集群模式中是工作节点自己做监控
哨兵模式发起选举是选举一个leader哨兵节点来处理故障转移,集群模式是在从节点中选举一个新的主节点,来处理故障的转移
转自:https://www.jianshu.com/p/d6d2325a5ec7
⑩ 怎么连接redis集群 使用jedis连接单机和集群redis的两种方式
第一:非集群状态下
非集群状态下用Jedis获取Redis连接,得到Jedis对象即可,一共有两种:
1.利用Jedis构造器,仅限用于测试,在实际项目中肯定是用JedisPool。
Jedis(String host);
Jedis(String host , int port);
2.利用JedisPool
主要是利用Jedis jedis=jedisPool.getResource();
JedisPool有N多个构造器,常用的构造器参数有GenericObjectPoolConfig poolConfig,String host,int port,int timeout,String password,创建GenericObjectPoolConfig对象时我们一般用其子类JedisPoolConfig (redis.clients.jedis.JedisPoolConfig),timeout是连接redis服务器的超时时间,以毫秒为单位,一般设置为0,如果不设为0,则不可设置太小,如果设成1、2,那么可能因为网络原因在1毫秒、2毫秒之内没有连上服务器而报错。见下例:
[java] view plain
public static void main(String[] args) {
JedisPoolConfig poolConfig = new JedisPoolConfig();
// 最大连接数
poolConfig.setMaxTotal(2);
// 最大空闲数
poolConfig.setMaxIdle(2);
// 最大允许等待时间,如果超过这个时间还未获取到连接,则会报JedisException异常:
// Could not get a resource from the pool
poolConfig.setMaxWaitMillis(1000);
JedisPool pool = new JedisPool(poolConfig, "192.168.83.128", 6379, 0, "123");
Jedis jedis = null;
try {
for (int i = 0; i < 5; i++) {
jedis = pool.getResource();
jedis.set("foo" + i, "bar" + i);
System.out.println("第" + (i + 1) + "个连接, 得到的值为" + jedis.get("foo" + i));
// 用完一定要释放连接
jedis.close();
}
} finally {
pool.close();
}
}
如上,创建出一个JedisPool对象,然后调用其getResource()方法获取redis连接即可,之后就可以调用Jedis API操作redis了。jedis连接用完要释放即close,如果不close,则产生的连接会越来越多,当达到了最大连接数,再想获得连接,就会等待,当超过了最大等待时间后就会报异常。
第二:集群状态下
集群状态下用Jedis获取redis连接,是得到JedisCluster对象,之后对redis进行操作都是用此对象的方法进行的:
[java] view plain
public static void main(String[] args) {
JedisPoolConfig poolConfig = new JedisPoolConfig();
// 最大连接数
poolConfig.setMaxTotal(1);
// 最大空闲数
poolConfig.setMaxIdle(1);
// 最大允许等待时间,如果超过这个时间还未获取到连接,则会报JedisException异常:
// Could not get a resource from the pool
poolConfig.setMaxWaitMillis(1000);
Set<HostAndPort> nodes = new LinkedHashSet<HostAndPort>();
nodes.add(new HostAndPort("192.168.83.128", 6379));
nodes.add(new HostAndPort("192.168.83.128", 6380));
nodes.add(new HostAndPort("192.168.83.128", 6381));
nodes.add(new HostAndPort("192.168.83.128", 6382));
nodes.add(new HostAndPort("192.168.83.128", 6383));
nodes.add(new HostAndPort("192.168.83.128", 6384));
JedisCluster cluster = new JedisCluster(nodes, poolConfig);
String name = cluster.get("name");
System.out.println(name);
cluster.set("age", "18");
System.out.println(cluster.get("age"));
try {
cluster.close();
} catch (IOException e) {
e.printStackTrace();
}
}
用集群时,好像没有办法设置集群的参数,比如最大连接数,虽然在创建JedisCluster 对象时传了JedisPoolConfig对象进去,但是JedisPoolConfig对象中的设置是不生效的。