Redis Cluster 实践
一:关于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)
- .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)
- .tgz
- cd /path/gem
- sudo ruby setup.rb
- sudo cp bin/gem /usr/local/bin
(4)安装gem-redis:version(3.0.0)
- #由于源的原因,可能下载失败,就手动下载下来安装
- #download地址:http://rubygems.org/gems/redis/versions/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
- loglevel notice
- dir /opt/redis/data
- slave-serve-stale-data yes
- #slave只读
- slave-read-only yes
- #not use default
- repl-disable-tcp-nodelay yes
- #打开aof持久化
- appendonly yes
- #每秒一次aof写
- appendfsync everysec
- #关闭在aof rewrite的时候对新的写操作进行fsync
- no-appendfsync-on-rewrite yes
- auto-aof-rewrite-min-size 64mb
- #打开redis集群
- cluster-enabled yes
- #节点互连超时的阀值
- notify-keyspace-events ""
- activerehashing yes
- aof-rewrite-incremental-fsync yes
3)redis特殊配置.
- #包含通用配置
- include /opt/redis/redis-common.conf
- #监听tcp端口
- #最大可用内存
- 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过程
- .rdb
- #cluster配置文件(启动自动生成)
- .conf
- #部署在同一机器的redis实例,把auto-aof-rewrite搓开,因为cluster环境下内存占用基本一致.
- #防止同意机器下瞬间fork所有redis进程做aof rewrite,占用大量内存
- -
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)启动集群相关节点(必须是空节点,beta3后可以是有数据的节点),指定配置文件和输出日志
- .conf > /opt/redis/logs/redis-.log >& &
- .conf > /opt/redis/logs/redis-.log >& &
- .conf > /opt/redis/logs/redis-.log >& &
- .conf > /opt/redis/logs/redis-.log >& &
- .conf > /opt/redis/logs/redis-.log >& &
- .conf > /opt/redis/logs/redis-.log >& &
(2):使用自带的ruby工具(redis-trib.rb)构建集群
- #redis-trib.rb的create子命令构建
- #--replicas 则指定了为Redis Cluster中的每个Master节点配备几个Slave节点
- )
(3):检查集群状态
- #redis-trib.rb的check子命令构建
- #ip:port可以是集群的任意节点
最后输出如下信息,没有任何警告或错误,表示集群启动成功并处于ok状态
- [OK] All nodes agree about slots configuration.
- >>> Check for open slots...
- >>> Check slots coverage...
- slots covered.
2):添加新master节点
(1)添加一个master节点:创建一个空节点(empty node),然后将某些slot移动到这个空节点上,这个过程目前需要人工干预
a):根据端口生成配置文件(ps:establish_config.sh是我自己写的输出配置脚本)
- > conf/redis-.conf
b):启动节点
- .conf > /opt/redis/logs/redis-.log >& &
c):加入空节点到集群
add-node 将一个节点添加到集群里面, 第一个是新节点ip:port, 第二个是任意一个已存在节点ip:port
node:新节点没有包含任何数据, 因为它没有包含任何slot。新加入的加点是一个主节点, 当集群需要将某个从节点升级为新的主节点时, 这个新节点不会被选中,同时新的主节点因为没有包含任何slot,不参加选举和failover。
d):为新节点分配slot
- )
- to )?
- #选择要接受这些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.
- :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文件
- root root Apr : dump-.rdb
- root root Apr : dump-.rdb
4):在线reshard 数据:
对于负载/数据不均匀的情况,可以在线reshard slot来解决,方法与添加新master的reshard一样,只是需要reshard的master节点是已存在的老节点.
5):删除一个slave节点
- #redis-trib del-node ip:port '<node-id>'
- 'c7ee2fca17cb79fe3c9822ced1d4f6c5e169e378'
6):删除一个master节点
a):删除master节点之前首先要使用reshard移除master的全部slot,然后再删除当前节点
(redis-trib.rb一次只能把下线节点的slot迁移到一个节点上,如果需要均衡的迁移到其它节点需要执行多次reshard命令)
- 节点slot和数据迁移到上
- )
- to )? (被删除master的所有slot数量)
- )
- 的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.
- :f51e26b5d5ff74f85341f06f28f125b7254e61bf(被删除master的node-id)
- :done
- #打印被移动的slot后,输入yes开始移动slot以及对应的数据.
- #Do you want to proceed with the proposed reshard plan (yes/no)? yes
b):删除空master节点
- 'f51e26b5d5ff74f85341f06f28f125b7254e61bf'
1:客户端基本操作使用
- <span style="font-size: 16px;"> private static BinaryJedisCluster jc;
- static {
- //只给集群里一个实例就可以
- Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
- ));
- ));
- ));
- ));
- ));
- ));
- ));
- ));
- ));
- ));
- jc = new BinaryJedisCluster(jedisClusterNodes);
- }
- @Test
- public void testBenchRedisSet() throws Exception {
- final Stopwatch stopwatch = new Stopwatch();
- List list = buildBlogVideos();
- ; i < ; i++) {
- String key = "key:" + i;
- stopwatch.start();
- byte[] bytes1 = protostuffSerializer.serialize(list);
- * , 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-3.0.0-SNAPSHOT"已支持BinaryJedisCluster和基于hash_tag的mget操作.
Redis Cluster 实践的更多相关文章
- redis cluster 实践总结
最近项目接触到了redis cluster,现在趁着使用做一下总结,记录一下遇到过的问题,简单的概述一下常用到的命令和功能. 本篇文章主要是以运维的角度去讲述如何去更好的规划redis clust ...
- Redis Cluster 集群三主三从高可用环境搭建
前言 Redis 是我们目前大规模使用的缓存中间件,由于它强大高效而又便捷的功能,得到了广泛的使用. Window环境下载地址:https://github.com/tporadowski/redis ...
- redis集群与分片(2)-Redis Cluster集群的搭建与实践
Redis Cluster集群 一.redis-cluster设计 Redis集群搭建的方式有多种,例如使用zookeeper等,但从redis 3.0之后版本支持redis-cluster集群,Re ...
- Redis Cluster集群的搭建与实践
Redis Cluster集群 一.redis-cluster设计 Redis集群搭建的方式有多种,例如使用zookeeper等,但从redis 3.0之后版本支持redis-cluster集群,Re ...
- Redis进阶实践之十一 Redis的Cluster集群搭建
一.引言 本文档只对Redis的Cluster集群做简单的介绍,并没有对分布式系统的详细概念做深入的探讨.本文只是提供了有关如何设置集群.测试和操作集群的说明,而不涉及Redis集群规范中涵 ...
- Redis Cluster集群搭建后,客户端的连接研究(Spring/Jedis)(待实践)
说明:无论是否已经搭建好集群,还是使用什么样的客户端去连接,都是必须把全部IP列表集成进去,然后随机往其中一个IP写. 这样做的好处: 1.随机IP写入之后,Redis Cluster代理层会自动根据 ...
- Redis Cluster 理论知识
http://www.ttlsa.com/redis/redis-cluster-theoretical-knowledge/ Redis 集群的 TCP 端口(Redis Cluster TCP p ...
- codis集群和redis cluster的优劣对比
1.codis架构如下: (1)Codis是一整套缓存解决方案,包含高可用.数据分片.监控.动态扩态 etc..走的是 Apps->代理->redis cluster,一定规模后基本都采用 ...
- Redis进阶实践之十三 Redis的Redis-trib.rb文件详解
一.简介 事先说明一下,本篇文章不涉及对redis-trib.rb源代码的分析,只是从使用的角度来阐述一下,对第一次使用的人来说很重要.redis-trib.rb是redis官方推出的管理re ...
随机推荐
- python学习之路二(字符串,字典,序列和元组)
# -*- coding: utf-8 -* ''' Created on 2013-7-26 @author: lixingle ''' #!/usr/bin/python import math# ...
- IOS基础开发一(ios程序运行过程)
今天做了一个简单的仿QQ登陆UI晒一晒:
- jQuery Mobile (整合版)
jQuery Mobile (整合版) 前言 为了方便大家看的方便,我这里将这几天的东西整合一下发出. 里面的例子请使用手机浏览器查看. 什么是jQuery Mobile? jquery mobile ...
- 浅谈XSS
最近在做项目中的漏洞修复工作,在短时间内接触到很多关于web开发需要防范的漏洞,例如SQL injection , XSS, CSRF等等,这些漏洞对web开发的项目来说的破坏还是比较大的,其实在网上 ...
- spring得到实例和new一个实例,哪个快?
spring配置的bean是默认单例,那么在程序中,得到一个实例一定比创建一个实例的速度快,也更加省资源.今天实际测试的时候发现,new 一个对象比spring得到一个对象快多了.后面自己又加了个单例 ...
- Android 短信模块分析(四) MMS之短信的发送与接收
MMS之短信的发送与接收分析: 一.信息发送: com.android.mms.data.WorkingMessage.java 类 send()函数: public void send() { . ...
- vsftpd.conf 详解与实例配置
#################匿名权限控制############### anonymous_enable=YES #是否启用匿名用户 no_anon_password=YES #匿名用 ...
- 一张图让你快速学会UML(聚合、组合、依赖、继承、接口、类)
有朋友反映,一上来直接讲设计模式就算理解了,也不知道如何画出类图,那么我们就通过一张图,来图解如何应用UML正确表示类与类之间的关系. 这张图完整讲述了鸟类的生存. 首先是类:在UML中,我们用分成三 ...
- PYTHON黑帽编程 4.1 SNIFFER(嗅探器)之数据捕获(下)
上一节(<4.1 SNIFFER(嗅探器)之数据捕获(上)>)中, 我们讲解了通过Raw Socket的方式来编写Sniffer的基本方法. 本节我们继续来编写Sniffer,只不过使用现 ...
- [avalon]data-repeat-rendered循环渲染完毕后的回调函数
有些时候需要在渲染完毕后,引用其他类似JQ插件的初始化工作.这时候需要使用data-repeat-rendered的回调函数. 应用场景: 在metro-start界面下,需要给每个tile引用cli ...