一:关于redis cluster
1:redis cluster的现状
reids-cluster计划在redis3.0中推出,可以看作者antirez的声明:http://antirez.com/news/49 (ps:跳票了好久,今年貌似加快速度了),目前的最新版本见:https://raw.githubusercontent.com/antirez/redis/3.0/00-RELEASENOTES
作者的目标:Redis Cluster will support up to ~1000 nodes. 赞...
目前redis支持的cluster特性(已测试):
1):节点自动发现
2):slave->master 选举,集群容错
3):Hot resharding:在线分片
4):集群管理:cluster xxx
5):基于配置(nodes-port.conf)的集群管理
6):ASK 转向/MOVED 转向机制.
2:redis cluster 架构
1)redis-cluster架构图
架构细节:
(1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
(2)节点的fail是通过集群中超过半数的master节点检测失效时才生效.
(3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
(4)redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->key
2) redis-cluster选举:容错
(1)领着选举过程是集群中所有master参与,如果半数以上master节点与故障节点通信超过(cluster-node-timeout),认为该节点故障,自动触发故障转移操作.
(2):什么时候整个集群不可用(cluster_state:fail)?
a:如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成集群的slot映射[0-16383]不完成时进入fail状态. ps : redis-3.0.0.rc1加入cluster-require-full-coverage参数,默认关闭,打开集群兼容部分失败.
b:如果集群超过半数以上master挂掉,无论是否有slave集群进入fail状态.
ps:当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误
二:redis cluster的使用
1:安装redis cluster
1):安装redis-cluster依赖:redis-cluster的依赖库在使用时有兼容问题,在reshard时会遇到各种错误,请按指定版本安装.
(1)确保系统安装zlib,否则gem install会报(no such file to load -- zlib)
- #download:zlib-1.2.6.tar
- ./configure
- make
- make install
(2)安装ruby:version(1.9.2)
- # ruby1.9.2
- cd /path/ruby
- ./configure -prefix=/usr/local/ruby
- make
- make install
- sudo cp ruby /usr/local/bin
(3)安装rubygem:version(1.8.16)
- # rubygems-1.8.16.tgz
- cd /path/gem
- sudo ruby setup.rb
- sudo cp bin/gem /usr/local/bin
(4)安装gem-redis:version(3.0.0)
- gem install redis --version 3.0.0
- #由于源的原因,可能下载失败,就手动下载下来安装
- #download地址:http://rubygems.org/gems/redis/versions/3.0.0
- gem install -l /data/soft/redis-3.0.0.gem
(5)安装redis-cluster
- cd /path/redis
- make
- sudo cp /opt/redis/src/redis-server /usr/local/bin
- sudo cp /opt/redis/src/redis-cli /usr/local/bin
- sudo cp /opt/redis/src/redis-trib.rb /usr/local/bin
2:配置redis cluster
1)redis配置文件结构:
使用包含(include)把通用配置和特殊配置分离,方便维护.
2)redis通用配置.
- #GENERAL
- daemonize no
- tcp-backlog 511
- timeout 0
- tcp-keepalive 0
- loglevel notice
- databases 16
- dir /opt/redis/data
- slave-serve-stale-data yes
- #slave只读
- slave-read-only yes
- #not use default
- repl-disable-tcp-nodelay yes
- slave-priority 100
- #打开aof持久化
- appendonly yes
- #每秒一次aof写
- appendfsync everysec
- #关闭在aof rewrite的时候对新的写操作进行fsync
- no-appendfsync-on-rewrite yes
- auto-aof-rewrite-min-size 64mb
- lua-time-limit 5000
- #打开redis集群
- cluster-enabled yes
- #节点互连超时的阀值
- cluster-node-timeout 15000
- cluster-migration-barrier 1
- slowlog-log-slower-than 10000
- slowlog-max-len 128
- notify-keyspace-events ""
- hash-max-ziplist-entries 512
- hash-max-ziplist-value 64
- list-max-ziplist-entries 512
- list-max-ziplist-value 64
- set-max-intset-entries 512
- zset-max-ziplist-entries 128
- zset-max-ziplist-value 64
- activerehashing yes
- client-output-buffer-limit normal 0 0 0
- client-output-buffer-limit slave 256mb 64mb 60
- client-output-buffer-limit pubsub 32mb 8mb 60
- hz 10
- aof-rewrite-incremental-fsync yes
3)redis特殊配置.
- #包含通用配置
- include /opt/redis/redis-common.conf
- #监听tcp端口
- port 6379
- #最大可用内存
- maxmemory 100m
- #内存耗尽时采用的淘汰策略:
- # volatile-lru -> remove the key with an expire set using an LRU algorithm
- # allkeys-lru -> remove any key accordingly to the LRU algorithm
- # volatile-random -> remove a random key with an expire set
- # allkeys-random -> remove a random key, any key
- # volatile-ttl -> remove the key with the nearest expire time (minor TTL)
- # noeviction -> don't expire at all, just return an error on write operations
- maxmemory-policy allkeys-lru
- #aof存储文件
- appendfilename "appendonly-6379.aof"
- #不开启rdb存储,只用于添加slave过程
- dbfilename dump-6379.rdb
- #cluster配置文件(启动自动生成)
- cluster-config-file nodes-6379.conf
- #部署在同一机器的redis实例,把auto-aof-rewrite搓开,因为cluster环境下内存占用基本一致.
- #防止同意机器下瞬间fork所有redis进程做aof rewrite,占用大量内存
- auto-aof-rewrite-percentage 80-100
3:cluster 操作
cluster集群相关命令,更多redis相关命令见文档:http://redis.readthedocs.org/en/latest/
- 集群
- CLUSTER INFO 打印集群的信息
- CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相关信息。
- 节点
- CLUSTER MEET <ip> <port> 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
- CLUSTER FORGET <node_id> 从集群中移除 node_id 指定的节点。
- CLUSTER REPLICATE <node_id> 将当前节点设置为 node_id 指定的节点的从节点。
- CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面。
- 槽(slot)
- CLUSTER ADDSLOTS <slot> [slot ...] 将一个或多个槽(slot)指派(assign)给当前节点。
- CLUSTER DELSLOTS <slot> [slot ...] 移除一个或多个槽对当前节点的指派。
- CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
- CLUSTER SETSLOT <slot> NODE <node_id> 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。
- CLUSTER SETSLOT <slot> MIGRATING <node_id> 将本节点的槽 slot 迁移到 node_id 指定的节点中。
- CLUSTER SETSLOT <slot> IMPORTING <node_id> 从 node_id 指定的节点中导入槽 slot 到本节点。
- CLUSTER SETSLOT <slot> STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。
- 键
- CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上。
- CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量。
- CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 个 slot 槽中的键。
4:redis cluster 运维操作
1)初始化并构建集群
(1)启动集群相关节点(必须是无数据的空节点),指定配置文件和输出日志
- redis-server /opt/redis/conf/redis-6380.conf > /opt/redis/logs/redis-6380.log 2>&1 &
- redis-server /opt/redis/conf/redis-6381.conf > /opt/redis/logs/redis-6381.log 2>&1 &
- redis-server /opt/redis/conf/redis-6382.conf > /opt/redis/logs/redis-6382.log 2>&1 &
- redis-server /opt/redis/conf/redis-7380.conf > /opt/redis/logs/redis-7380.log 2>&1 &
- redis-server /opt/redis/conf/redis-7381.conf > /opt/redis/logs/redis-7381.log 2>&1 &
- redis-server /opt/redis/conf/redis-7382.conf > /opt/redis/logs/redis-7382.log 2>&1 &
(2):使用自带的ruby工具(redis-trib.rb)构建集群
- #redis-trib.rb的create子命令构建
- #--replicas 则指定了为Redis Cluster中的每个Master节点配备几个Slave节点
- #节点角色由顺序决定,先master之后是slave(为方便辨认,slave的端口比master大1000)
- redis-trib.rb create --replicas 1 10.10.34.14:6380 10.10.34.14:6381 10.10.34.14:6382 10.10.34.14:7380 10.10.34.14:7381 10.10.34.14:7382
(3):检查集群状态
- #redis-trib.rb的check子命令构建
- #ip:port可以是集群的任意节点
- redis-trib.rb check 10.10.34.14:6380
- [OK] All nodes agree about slots configuration.
- >>> Check for open slots...
- >>> Check slots coverage...
- [OK] All 16384 slots covered.
2):添加新master节点
(1)添加一个master节点:创建一个空节点(empty node),然后将某些slot移动到这个空节点上,这个过程目前需要人工干预
a):根据端口生成配置文件(ps:establish_config.sh是我自己写的输出配置脚本)
- sh establish_config.sh 6386 > conf/redis-6386.conf
b):启动节点
- redis-server /opt/redis/conf/redis-6386.conf > /opt/redis/logs/redis-6386.log 2>&1 &
c):加入空节点到集群
add-node 将一个节点添加到集群里面, 第一个是新节点ip:port, 第二个是任意一个已存在节点ip:port
- redis-trib.rb add-node 10.10.34.14:6386 10.10.34.14:6381
node:新节点没有包含任何数据, 因为它没有包含任何slot。新加入的加点是一个主节点, 当集群需要将某个从节点升级为新的主节点时, 这个新节点不会被选中,同时新的主节点因为没有包含任何slot,不参加选举和failover。
d):为新节点分配slot
- redis-trib.rb reshard 10.10.34.14:6386
- #根据提示选择要迁移的slot数量(ps:这里选择500)
- How many slots do you want to move (from 1 to 16384)? 500
- #选择要接受这些slot的node-id
- What is the receiving node ID? f51e26b5d5ff74f85341f06f28f125b7254e61bf
- #选择slot来源:
- #all表示从所有的master重新分配,
- #或者数据要提取slot的master节点id,最后用done结束
- Please enter all the source node IDs.
- Type 'all' to use all the nodes as source nodes for the hash slots.
- Type 'done' once you entered all the source nodes IDs.
- Source node #1:all
- #打印被移动的slot后,输入yes开始移动slot以及对应的数据.
- #Do you want to proceed with the proposed reshard plan (yes/no)? yes
- #结束
3):添加新的slave节点
a):前三步操作同添加master一样
b)第四步:redis-cli连接上新节点shell,输入命令:cluster replicate 对应master的node-id
- cluster replicate 2b9ebcbd627ff0fd7a7bbcc5332fb09e72788835
注意:在线添加slave 时,需要bgsave整个master数据,并传递到slave,再由 slave加载rdb文件到内存,rdb生成和传输的过程中消耗Master大量内存和网络IO,以此不建议单实例内存过大,线上小心操作。
例如本次添加slave操作产生的rdb文件
- -rw-r--r-- 1 root root 34946 Apr 17 18:23 dump-6386.rdb
- -rw-r--r-- 1 root root 34946 Apr 17 18:23 dump-7386.rdb
4):在线reshard 数据:
对于负载/数据不均匀的情况,可以在线reshard slot来解决,方法与添加新master的reshard一样,只是需要reshard的master节点是已存在的老节点.
5):删除一个slave节点
- #redis-trib del-node ip:port '<node-id>'
- redis-trib.rb del-node 10.10.34.14:7386 'c7ee2fca17cb79fe3c9822ced1d4f6c5e169e378'
6):删除一个master节点
a):删除master节点之前首先要使用reshard移除master的全部slot,然后再删除当前节点
(redis-trib.rb一次只能把下线节点的slot迁移到一个节点上,如果需要均衡的迁移到其它节点需要执行多次reshard命令)
- #把10.10.34.14:6386节点slot和数据迁移到10.10.34.14:6380上
- redis-trib.rb reshard 10.10.34.14:6380
- #根据提示选择要迁移的slot数量(ps:这里选择500)
- How many slots do you want to move (from 1 to 16384)? 500(被删除master的所有slot数量)
- #选择要接受这些slot的node-id(10.10.34.14:6380)
- What is the receiving node ID? c4a31c852f81686f6ed8bcd6d1b13accdc947fd2 (ps:10.10.34.14:6380的node-id)
- Please enter all the source node IDs.
- Type 'all' to use all the nodes as source nodes for the hash slots.
- Type 'done' once you entered all the source nodes IDs.
- Source node #1:f51e26b5d5ff74f85341f06f28f125b7254e61bf(被删除master的node-id)
- Source node #2:done
- #打印被移动的slot后,输入yes开始移动slot以及对应的数据.
- #Do you want to proceed with the proposed reshard plan (yes/no)? yes
b):删除空master节点
- redis-trib.rb del-node 10.10.34.14:6386 'f51e26b5d5ff74f85341f06f28f125b7254e61bf'
1:客户端基本操作使用
- <span style="font-size: 16px;"> private static BinaryJedisCluster jc;
- static {
- //只给集群里一个实例就可以
- Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
- jedisClusterNodes.add(new HostAndPort("10.10.34.14", 6380));
- jedisClusterNodes.add(new HostAndPort("10.10.34.14", 6381));
- jedisClusterNodes.add(new HostAndPort("10.10.34.14", 6382));
- jedisClusterNodes.add(new HostAndPort("10.10.34.14", 6383));
- jedisClusterNodes.add(new HostAndPort("10.10.34.14", 6384));
- jedisClusterNodes.add(new HostAndPort("10.10.34.14", 7380));
- jedisClusterNodes.add(new HostAndPort("10.10.34.14", 7381));
- jedisClusterNodes.add(new HostAndPort("10.10.34.14", 7382));
- jedisClusterNodes.add(new HostAndPort("10.10.34.14", 7383));
- jedisClusterNodes.add(new HostAndPort("10.10.34.14", 7384));
- jc = new BinaryJedisCluster(jedisClusterNodes);
- }
- @Test
- public void testBenchRedisSet() throws Exception {
- final Stopwatch stopwatch = new Stopwatch();
- List list = buildBlogVideos();
- for (int i = 0; i < 1000; i++) {
- String key = "key:" + i;
- stopwatch.start();
- byte[] bytes1 = protostuffSerializer.serialize(list);
- jc.setex(key, 60 * 60, bytes1);
- stopwatch.stop();
- }
- System.out.println("time=" + stopwatch.toString());
- }</span>
2:redis-cluster客户端的一些坑.
1)cluster环境下slave默认不接受任何读写操作,在slave执行readonly命令后,可执行读操作
2)client端不支持多key操作(mget,mset等),但当keys集合对应的slot相同时支持mget操作见:hash_tag
3)不支持多数据库,只有一个db,select 0。
4)JedisCluster 没有针对byte[]的API,需要自己扩展(附件是我加的基于byte[]的BinaryJedisCluster api)
Jedis-2.8.0-SNAPSHOT 之后已支持BinaryJedisCluster和基于hash_tag的mget操作.
参考文档:
参考知识库
评论
这个和单机类似。 需要保证操作的key在同一个节点。
如果对多key的操作建议转成hash存储,方便lua脚本操作的数据落在同一个节点。
本地是用jedis 测试么。beanchmark测试没有网络延迟,而且value一般很小。
1:主送之间同步检测可以使用主节点和从节点的offset偏移量检测。
2:当节点存在大量key时,千万不要使用keys命令操作,由于redis单线程架构,keys命令是O(n)操作,导致你的执行keys命令时其他读写命令被阻塞(包括复制过来的写命令)。
3:redis采用异步复制,在没有大量慢查询下,复制非常快,毫秒级别延迟。
4:看下你主从的慢查询"slowlog get",应该能查到
5:redis监控一般都是基于info数据统计指标,千万不要用keys,monitor等命令做统计监控。
很谢谢博主的回复。不过依然有一些不懂的地方:(1)“主节点和从节点的offset偏移量检测”是什么意思?怎么检测?可以用来检测主节点的数据到从节点的数据同步时间是多少?(2)按您的意思是,虽然在主节点上set了1000w条数据,但从主到备的同步时间依旧是毫秒级别的,不应该是花费10分钟,主要还是我的程序的问题是吧。问题主要是在无限循环的使用keys(“key*”)直到找到匹配的一个键key100这段代码上,对主从之间的数据同步命令有影响是吧。
1:offset可以在主从节点上分别执行"info replication"获取到,表示master数据修改偏移量和slave已复制的偏移量。 具体原理看下《redis设计与实现》 复制章节
master:
- # Replication
- role:master
- connected_slaves:1
- slave0:ip=10.10.xx.xx,port=6379,state=online,offset=143472300141,lag=0
- master_repl_offset:143472300261
- repl_backlog_active:1
- repl_backlog_size:10000000
- repl_backlog_first_byte_offset:143462300262
- repl_backlog_histlen:10000000
slave:
- # Replication
- role:slave
- master_host:10.10.xx.xx
- master_port:6383
- master_link_status:up
- master_last_io_seconds_ago:0
- master_sync_in_progress:0
- slave_repl_offset:143472147072
- slave_priority:100
- slave_read_only:1
- connected_slaves:0
- master_repl_offset:0
- repl_backlog_active:0
- repl_backlog_size:10000000
- repl_backlog_first_byte_offset:139811639970
- repl_backlog_histlen:10000000
2:是的,同机房的主从复制在没有慢查询的情况下,毫秒级别延迟。但你的keys命令在大量key情况下就是慢查询。
1:主送之间同步检测可以使用主节点和从节点的offset偏移量检测。
2:当节点存在大量key时,千万不要使用keys命令操作,由于redis单线程架构,keys命令是O(n)操作,导致你的执行keys命令时其他读写命令被阻塞(包括复制过来的写命令)。
3:redis采用异步复制,在没有大量慢查询下,复制非常快,毫秒级别延迟。
4:看下你主从的慢查询"slowlog get",应该能查到
5:redis监控一般都是基于info数据统计指标,千万不要用keys,monitor等命令做统计监控。
很谢谢博主的回复。不过依然有一些不懂的地方:(1)“主节点和从节点的offset偏移量检测”是什么意思?怎么检测?可以用来检测主节点的数据到从节点的数据同步时间是多少?(2)按您的意思是,虽然在主节点上set了1000w条数据,但从主到备的同步时间依旧是毫秒级别的,不应该是花费10分钟,主要还是我的程序的问题是吧。问题主要是在无限循环的使用keys(“key*”)直到找到匹配的一个键key100这段代码上,对主从之间的数据同步命令有影响是吧。
1:主送之间同步检测可以使用主节点和从节点的offset偏移量检测。
2:当节点存在大量key时,千万不要使用keys命令操作,由于redis单线程架构,keys命令是O(n)操作,导致你的执行keys命令时其他读写命令被阻塞(包括复制过来的写命令)。
3:redis采用异步复制,在没有大量慢查询下,复制非常快,毫秒级别延迟。
4:看下你主从的慢查询"slowlog get",应该能查到
5:redis监控一般都是基于info数据统计指标,千万不要用keys,monitor等命令做统计监控。
第一个问题:“它成为某个节点的备后从节点无数据”
需要确认:
1):cluster info查看集群状态是否OK
2)确认被复制的主节点是否有覆盖的slots和是否有数据.
3)如果主节点有数据,从节点没数据,分别查看主从节点的复制状态:info Replication
4)查看主从节点的日志,"#"开头日志表示警告
第二个问题:在线添加slave 时,对IO冲击的问题
1)一般发生在master数据很大时,我们一般限制单个master最大内存量不超过5G.
2)IO的冲击指的是对master和slave网络流量消耗和master和slave本地写RDB文件的压力.
3) 对硬盘的写RBB可以启用无盘复制规避,但对网络的冲击无法避免。
这个问题和你的第一个应该没关系。
查看了日志是同步时被拒绝,问题应该出现在服务器端的网络传输问题,可能是某个配置配的不好或是服务器本身有些问题,换了个服务器可行。现在还有个问题要麻烦楼主哈。就是“cluster环境下slave默认不接受任何读写操作”,我试验了下确实slave节点已经无法用hget等命令查询值,但成为主节点后还是可以读的,不过我看了redis.conf那里有一项是slave-read-only yes,能否通过把yes写为no,来使节点既可读,又可写(用hset)呢?还是说这样改就变为“不可读也不可写”?
从节点一定不要参与写操作,默认cluster模式下从节点不接受任何读写,运行readonly命令后从节点可以做读操作。
第一个问题:“它成为某个节点的备后从节点无数据”
需要确认:
1):cluster info查看集群状态是否OK
2)确认被复制的主节点是否有覆盖的slots和是否有数据.
3)如果主节点有数据,从节点没数据,分别查看主从节点的复制状态:info Replication
4)查看主从节点的日志,"#"开头日志表示警告
第二个问题:在线添加slave 时,对IO冲击的问题
1)一般发生在master数据很大时,我们一般限制单个master最大内存量不超过5G.
2)IO的冲击指的是对master和slave网络流量消耗和master和slave本地写RDB文件的压力.
3) 对硬盘的写RBB可以启用无盘复制规避,但对网络的冲击无法避免。
这个问题和你的第一个应该没关系。
查看了日志是同步时被拒绝,问题应该出现在服务器端的网络传输问题,可能是某个配置配的不好或是服务器本身有些问题,换了个服务器可行。现在还有个问题要麻烦楼主哈。就是“cluster环境下slave默认不接受任何读写操作”,我试验了下确实slave节点已经无法用hget等命令查询值,但成为主节点后还是可以读的,不过我看了redis.conf那里有一项是slave-read-only yes,能否通过把yes写为no,来使节点既可读,又可写(用hset)呢?还是说这样改就变为“不可读也不可写”?
第一个问题:“它成为某个节点的备后从节点无数据”
需要确认:
1):cluster info查看集群状态是否OK
2)确认被复制的主节点是否有覆盖的slots和是否有数据.
3)如果主节点有数据,从节点没数据,分别查看主从节点的复制状态:info Replication
4)查看主从节点的日志,"#"开头日志表示警告
第二个问题:在线添加slave 时,对IO冲击的问题
1)一般发生在master数据很大时,我们一般限制单个master最大内存量不超过5G.
2)IO的冲击指的是对master和slave网络流量消耗和master和slave本地写RDB文件的压力.
3) 对硬盘的写RBB可以启用无盘复制规避,但对网络的冲击无法避免。
这个问题和你的第一个应该没关系。
原因如下:
最开始搭建的时候,是3主+3从,且每台主机都各自负责对应的槽
但是当时也无法完成自动迁移,究其原因,现在回想起来应该是当时是由于我设置的cluster-node-timeout节点值有误,导致无法完成投票
之后重新搭建的时候,我将其中一个主节点设置为负责所有槽(0-16383)
一来是为了方便,二来是想省区了在客户端操作的时候,还需要对槽点进行Hash处理
可是这就导致了我的最终问题:当有主节点无法服务时,对应的从节点会通知其他主节点这台主节点的状态为PFAIL,然后其他主节点也都通过gossip协议标识了这个主节点的状态,此时状态为FAIL,然后从节点应该等待其他主节点投票给自己,让自己提升为主节点即可;
没有负责任何槽的主节点没有投票权,就是这句话
导致从节点一直无法得到投票
终于解决了,2天了
再次多谢博主提醒啊~~~~~ 会一直关注博主好文的 赞一个~
分析的不错,祝好。
原因如下:
最开始搭建的时候,是3主+3从,且每台主机都各自负责对应的槽
但是当时也无法完成自动迁移,究其原因,现在回想起来应该是当时是由于我设置的cluster-node-timeout节点值有误,导致无法完成投票
之后重新搭建的时候,我将其中一个主节点设置为负责所有槽(0-16383)
一来是为了方便,二来是想省区了在客户端操作的时候,还需要对槽点进行Hash处理
可是这就导致了我的最终问题:当有主节点无法服务时,对应的从节点会通知其他主节点这台主节点的状态为PFAIL,然后其他主节点也都通过gossip协议标识了这个主节点的状态,此时状态为FAIL,然后从节点应该等待其他主节点投票给自己,让自己提升为主节点即可;
没有负责任何槽的主节点没有投票权,就是这句话
导致从节点一直无法得到投票
终于解决了,2天了
再次多谢博主提醒啊~~~~~ 会一直关注博主好文的 赞一个~
我这里目前Redis Cluster有六台(3主+3从)
M1 -- S1
M2 -- S2
M3 -- S3
为避免单点故障,实现故障自动迁移,我希望当主节点(M1、M2、M3)出现故障时,对于的从节点可以自动进行“接管”
然而目前并没有达到这个效果
当M1下线时,其他主节点投票,可以将M1标为FAIL状态
从节点S1也向M1发送了接管请求,但始终无法接管
请问博主,你所配置的集群支持故障自动迁移么? 需要注意哪些地方呢
需要你的cluster版本,集群相关配置,集群节点的日志信息才能方便定位问题.
一般影响cluster failover失败有:
(1)从节点超时过长,查看cluster-node-timeout和cluster-slave-validity-factor相关参数
(2)从节点的无法获取到集群中其他主节点的投票
(3)参与领导者选举的主节点不够一半以上
(3)从节点数达不到cluster-migration-barrier数量。
首先,非常感谢您的回复,而且这么效率
(1) cluster-node-timeout 15000
cluster-slave-validity-factor 10
cluster-migration-barrier 1
(2) 的确这个问题在日志里存在,其他主节点的投票始终无法到达
(3) 参与投票的主服务器的数量为2,满足3台服务器中的一半以上
(4) 从节点为1个,参数设置也为1,这里是满足的
还有一个问题是这样的,日志中会出现:Failover attempt expired
查看源码后我发现其实走到这句已经是从机标志主机为断开状态,并发动了投票
源码如下:
- mstime_t auth_age = mstime() - server.cluster->failover_auth_time;
- auth_timeout = server.cluster_node_timeout*2;
- if (auth_timeout < 2000) auth_timeout = 2000;
- /* Return ASAP if the election is too old to be valid. */
- if (auth_age > auth_timeout) {
- clusterLogCantFailover(REDIS_CLUSTER_CANT_FAILOVER_EXPIRED);
- return;
- }
配置文件代码如下:
port 8002
deamonize yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-slave-validity-factor 10
repl-ping-slave-period 1
cluster-migration-barrier 1
loglevel notice
logfile slave8002.log
appendonly yes
我这里目前Redis Cluster有六台(3主+3从)
M1 -- S1
M2 -- S2
M3 -- S3
为避免单点故障,实现故障自动迁移,我希望当主节点(M1、M2、M3)出现故障时,对于的从节点可以自动进行“接管”
然而目前并没有达到这个效果
当M1下线时,其他主节点投票,可以将M1标为FAIL状态
从节点S1也向M1发送了接管请求,但始终无法接管
请问博主,你所配置的集群支持故障自动迁移么? 需要注意哪些地方呢
需要你的cluster版本,集群相关配置,集群节点的日志信息才能方便定位问题.
一般影响cluster failover失败有:
(1)从节点超时过长,查看cluster-node-timeout和cluster-slave-validity-factor相关参数
(2)从节点的无法获取到集群中其他主节点的投票
(3)参与领导者选举的主节点不够一半以上
(3)从节点数达不到cluster-migration-barrier数量。
我这里目前Redis Cluster有六台(3主+3从)
M1 -- S1
M2 -- S2
M3 -- S3
为避免单点故障,实现故障自动迁移,我希望当主节点(M1、M2、M3)出现故障时,对于的从节点可以自动进行“接管”
然而目前并没有达到这个效果
当M1下线时,其他主节点投票,可以将M1标为FAIL状态
从节点S1也向M1发送了接管请求,但始终无法接管
请问博主,你所配置的集群支持故障自动迁移么? 需要注意哪些地方呢
BinaryJedisCluster提供了byte[]字节数组的操作。方便序列化后直接传对象
还补全了API,现在不需要了。目前Jedis https://github.com/xetorthio/jedis已经提供了BinaryJedisCluster和比较完毕的cluster协议支持。
BinaryJedisCluster和JedisCluster有什么区别呢?主要修改了哪些东西呢?麻烦楼主说下,多谢!
https://github.com/xetorthio/jedis/pull/966#issue-71806456
redis.clients.jedis.exceptions.JedisMovedDataException: MOVED xxx 127.0.0.1:xxxx
请问可能是哪儿的问题?
ShardedJedisPool是以前分片操作的API,不适用于cluster,
cluster环境用JedisCluster API, Jedis版本在2.7以上。
谢谢,我昨天刚搞明白。
顺便问下,你说的BinaryJedisCluster附件在哪儿呢?
没事,我以为单独的,原来是在你那个jar包里
jedis3.0已经支持BinaryJedisCluster,用Jedis官方的吧。
github: https://github.com/xetorthio/jedis/blob/a196d3e86e4dd686d4295e40233c42b2bb8d5cb0/src/main/java/redis/clients/jedis/BinaryJedisCluster.java
好的,谢谢提醒~
redis.clients.jedis.exceptions.JedisMovedDataException: MOVED xxx 127.0.0.1:xxxx
请问可能是哪儿的问题?
ShardedJedisPool是以前分片操作的API,不适用于cluster,
cluster环境用JedisCluster API, Jedis版本在2.7以上。
谢谢,我昨天刚搞明白。
顺便问下,你说的BinaryJedisCluster附件在哪儿呢?
没事,我以为单独的,原来是在你那个jar包里
jedis3.0已经支持BinaryJedisCluster,用Jedis官方的吧。
github: https://github.com/xetorthio/jedis/blob/a196d3e86e4dd686d4295e40233c42b2bb8d5cb0/src/main/java/redis/clients/jedis/BinaryJedisCluster.java
redis.clients.jedis.exceptions.JedisMovedDataException: MOVED xxx 127.0.0.1:xxxx
请问可能是哪儿的问题?
ShardedJedisPool是以前分片操作的API,不适用于cluster,
cluster环境用JedisCluster API, Jedis版本在2.7以上。
谢谢,我昨天刚搞明白。
顺便问下,你说的BinaryJedisCluster附件在哪儿呢?
没事,我以为单独的,原来是在你那个jar包里
redis.clients.jedis.exceptions.JedisMovedDataException: MOVED xxx 127.0.0.1:xxxx
请问可能是哪儿的问题?
ShardedJedisPool是以前分片操作的API,不适用于cluster,
cluster环境用JedisCluster API, Jedis版本在2.7以上。
谢谢,我昨天刚搞明白。
顺便问下,你说的BinaryJedisCluster附件在哪儿呢?
redis.clients.jedis.exceptions.JedisMovedDataException: MOVED xxx 127.0.0.1:xxxx
请问可能是哪儿的问题?
ShardedJedisPool是以前分片操作的API,不适用于cluster,
cluster环境用JedisCluster API, Jedis版本在2.7以上。
redis.clients.jedis.exceptions.JedisMovedDataException: MOVED xxx 127.0.0.1:xxxx
请问可能是哪儿的问题?
1)jedisCluster 维护整个集群节点的JedisPool列表,通过crc16计算key和slot的对应关系,在通过slot找到对应的jedisPool.
2:pipeline只能用于对应单个节点,不能对应集群操作。
3:“cli内如何检索更个集群的数据,而不是只检索一个port的数据”没看明白。
是包不对吗?
请问应该怎么处理?
/var/lib/gems/1.8/gems/redis-3.2.1/lib/redis/client.rb:113:in `call': ERR Slot 15495 is already busy (Redis::CommandError)
from /var/lib/gems/1.8/gems/redis-3.2.1/lib/redis.rb:2556:in `method_missing'
from /var/lib/gems/1.8/gems/redis-3.2.1/lib/redis.rb:37:in `synchronize'
from /usr/lib/ruby/1.8/monitor.rb:242:in `mon_synchronize'
from /var/lib/gems/1.8/gems/redis-3.2.1/lib/redis.rb:37:in `synchronize'
from /var/lib/gems/1.8/gems/redis-3.2.1/lib/redis.rb:2555:in `method_missing'
from ./redis-trib.rb:205:in `flush_node_config'
from ./redis-trib.rb:657:in `flush_nodes_config'
from ./redis-trib.rb:656:in `each'
from ./redis-trib.rb:656:in `flush_nodes_config'
from ./redis-trib.rb:997:in `create_cluster_cmd'
from ./redis-trib.rb:1373:in `send'
from ./redis-trib.rb:1373
用redis-trib.rb check ip:port检查下你的集群状态,
看错误应该是之前做过迁移失败了,
在slot=15495这个槽上正在分配中,尝试使用cluster setslot 15495 stable 取消对槽 slot 的导入或迁移
需要清理节点已配置的集群信息
是包不对吗?
请问应该怎么处理?
/var/lib/gems/1.8/gems/redis-3.2.1/lib/redis/client.rb:113:in `call': ERR Slot 15495 is already busy (Redis::CommandError)
from /var/lib/gems/1.8/gems/redis-3.2.1/lib/redis.rb:2556:in `method_missing'
from /var/lib/gems/1.8/gems/redis-3.2.1/lib/redis.rb:37:in `synchronize'
from /usr/lib/ruby/1.8/monitor.rb:242:in `mon_synchronize'
from /var/lib/gems/1.8/gems/redis-3.2.1/lib/redis.rb:37:in `synchronize'
from /var/lib/gems/1.8/gems/redis-3.2.1/lib/redis.rb:2555:in `method_missing'
from ./redis-trib.rb:205:in `flush_node_config'
from ./redis-trib.rb:657:in `flush_nodes_config'
from ./redis-trib.rb:656:in `each'
from ./redis-trib.rb:656:in `flush_nodes_config'
from ./redis-trib.rb:997:in `create_cluster_cmd'
from ./redis-trib.rb:1373:in `send'
from ./redis-trib.rb:1373
用redis-trib.rb check ip:port检查下你的集群状态,
看错误应该是之前做过迁移失败了,
在slot=15495这个槽上正在分配中,尝试使用cluster setslot 15495 stable 取消对槽 slot 的导入或迁移
是包不对吗?
请问应该怎么处理?
/var/lib/gems/1.8/gems/redis-3.2.1/lib/redis/client.rb:113:in `call': ERR Slot 15495 is already busy (Redis::CommandError)
from /var/lib/gems/1.8/gems/redis-3.2.1/lib/redis.rb:2556:in `method_missing'
from /var/lib/gems/1.8/gems/redis-3.2.1/lib/redis.rb:37:in `synchronize'
from /usr/lib/ruby/1.8/monitor.rb:242:in `mon_synchronize'
from /var/lib/gems/1.8/gems/redis-3.2.1/lib/redis.rb:37:in `synchronize'
from /var/lib/gems/1.8/gems/redis-3.2.1/lib/redis.rb:2555:in `method_missing'
from ./redis-trib.rb:205:in `flush_node_config'
from ./redis-trib.rb:657:in `flush_nodes_config'
from ./redis-trib.rb:656:in `each'
from ./redis-trib.rb:656:in `flush_nodes_config'
from ./redis-trib.rb:997:in `create_cluster_cmd'
from ./redis-trib.rb:1373:in `send'
from ./redis-trib.rb:1373
jedis-3.0还在SNAPSHOT,现在的2.7可以使用,有些命令没有支持需要改jedis来适配。
github: https://github.com/xetorthio/jedis/tree/jedis-2.7.0
谢谢博主回复,我遇到的问题是:
我们之前用的spring的api来操作redis,如果换为jedis,工作量及稳定性测试需要一定的时间,和 http://stackoverflow.com/questions/29602657/spring-data-redis-with-cluster-support 这个问题一样,不知道博主有何建议?
自己适配一个redisTemplate吧,开发量不是很大。
jc = new BinaryJedisCluster(jedisClusterNodes, 120 * 1000);
JedisCluster timeout 超时单位是秒。
我的集群部署在192.168.1.203上的 7000 7001 7002 7003 7004 7005这些端口上
重定向是指客户端报这个JedisClusterMaxRedirectionsException异常?
登录redis服务器,运行下 cluster info 命令线确认集群是否正常,slot是否完全覆盖。
public class Test2 {
private static BinaryJedisCluster jc;
static {
//只给集群里一个实例就可以
Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
jedisClusterNodes.add(new HostAndPort("192.168.1.203", 7000));
jedisClusterNodes.add(new HostAndPort("192.168.1.203", 7001));
jedisClusterNodes.add(new HostAndPort("192.168.1.203", 7002));
jedisClusterNodes.add(new HostAndPort("192.168.1.203", 7003));
jedisClusterNodes.add(new HostAndPort("192.168.1.203", 7004));
jedisClusterNodes.add(new HostAndPort("192.168.1.203", 7005));
jc = new BinaryJedisCluster(jedisClusterNodes, 120 * 1000);
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++) {
String res = jc.set("name" + i, "steven" + i);
System.out.println(res);
}
}
}
我的集群部署在192.168.1.203上的 7000 7001 7002 7003 7004 7005这些端口上
jedis-3.0还在SNAPSHOT,现在的2.7可以使用,有些命令没有支持需要改jedis来适配。
github: https://github.com/xetorthio/jedis/tree/jedis-2.7.0
谢谢博主回复,我遇到的问题是:
我们之前用的spring的api来操作redis,如果换为jedis,工作量及稳定性测试需要一定的时间,和 http://stackoverflow.com/questions/29602657/spring-data-redis-with-cluster-support 这个问题一样,不知道博主有何建议?
jedis-3.0还在SNAPSHOT,现在的2.7可以使用,有些命令没有支持需要改jedis来适配。
github: https://github.com/xetorthio/jedis/tree/jedis-2.7.0
这个是官方不支持:
Redis Cluster does not support multiple databases like the stand alone version of Redis, there is just database 0, and the SELECT command is not allowed.
停止集群目前redis cluster没有现成的命令,因为他是基于P2P的无中心化集群,没有master同意调度管理,我们一般采用直接停止进程的方式(shutdown)分别下线实例, 如果不停进程,采用cluster forget <node_id>直接让实例脱离进群也可以下线。
关于这点我想补充下:
redis3.0 我自己的测试是这样的:
1、同时或极短时间内超过半数以上master挂掉,整个集群进入fail不可用
2、如果一个master挂掉,集群中会有一个slave被转换为master,直到所有slave都变成master
3、当全部slave变为master,这时再有一个master挂掉,整个集群将进入fail状态
感谢补充.
b:如果集群超过半数以上master挂掉,无论是否有slave集群进入fail状态.现在不准确了,这个文档当时基于beta2
RC1加入cluster-require-full-coverage参数影响部分失败,开启后集群不完整也处于可用状态
RC3优化了gossip 协议,优化集群的状态传播速度,加快了节点失败判定的速度,之前测试10+的节点下故障判定达到30秒+。
关于这点我想补充下:
redis3.0 我自己的测试是这样的:
1、同时或极短时间内超过半数以上master挂掉,整个集群进入fail不可用
2、如果一个master挂掉,集群中会有一个slave被转换为master,直到所有slave都变成master
3、当全部slave变为master,这时再有一个master挂掉,整个集群将进入fail状态
4、如有其中一个对应的master和他的slave都挂了(同时或非同时),集群也会出故障
关于这点我想补充下:
redis3.0 我自己的测试是这样的:
1、同时或极短时间内超过半数以上master挂掉,整个集群进入fail不可用
2、如果一个master挂掉,集群中会有一个slave被转换为master,直到所有slave都变成master
3、当全部slave变为master,这时再有一个master挂掉,整个集群将进入fail状态
每对线有一个出去的一个进来的。
相关资源推荐