Redis4.0 单节点集群到三主三从节点集群实验
Redis4.0 单节点集群到三主三从节点集群实验
环境相关:
OS:CentOS release 7.4.1708
IP:192.168.77.101/102/103
MEM:16G
DISK:50G
简单说明
参照《Redis4.0 三主三备集群安装配置》配置三节点主机6个redis实例并启动
第五步配置集群使用本博文操作进行
集群创建
1,在节点一上创建单实例集群:
cp -av /usr/local/redis/src/redis-trib.rb /usr/local/bin
redis-trib.rb create --replicas 0 192.168.77.101:7000
# 创建一个单实例集群会报错,因为redis的集群需要至少3个master实例
# 该报错可以忽略掉,使用fix命令进行修复
redis-trib.rb fix 192.168.77.101:7000
# 使用fix命令修复集群,需要交互式输入yes进行确认
redis-cli -c -h 192.168.77.101 -p 7000 cluster nodes
redis-trib.rb check 192.168.77.101:7000
# 查看集群状态,目前集群只有一个master实例,所有的数据槽都在该实例上
# 单实例集群创建就完成了
2,添加两个主节点:
redis-trib.rb add-node 192.168.77.102:7002 192.168.77.101:7000
redis-trib.rb add-node 192.168.77.103:7004 192.168.77.101:7000
# 使用add-node命令,将102的7002和103的7004添加到集群里
redis-trib.rb check 192.168.77.101:7000
# 查看集群状态,发现目前集群中有三个master实例,但是所有的slot都在第一个master之上
# 此时,新加入的两个master实例没有任何的slot,是可以直接删掉的
redis-trib.rb reshard 192.168.77.101:7000
# 使用reshard命令重新分配slot,需要交互输入重新分配的slot数量和接收实例以及来源实例
# 两次使用该命令,将新添加的两个实例都分配一定数量的slot
输入需要重新分配的slot数量
输入接收这些slot的实例ID
输入这些slot的来源实例ID
确认移动
如果是真实的生产环境,在移动数据槽的时候,有可能会超时失败,如移动1000个数据槽到另外一个主实例
原因是某个或某些数据槽占用内存较大,移动操作超时,就需要使用fix命令进行修复
超时失败不会对集群造成影响,已经移动成功的数据槽状态也是没问题的
可以修复后再次重新分布数据槽,减少数据槽的数量,防止再次超时失败
redis-trib.rb fix 192.168.77.101:7000
redis-trib.rb check 192.168.77.101:7000
# 检查集群节点状态,发现三个master实例都有slot存在,此时就不能直接删除master实例
3,添加三个从实例:
redis-trib.rb add-node --slave 192.168.77.101:7001 192.168.77.101:7000
redis-trib.rb add-node --slave 192.168.77.102:7003 192.168.77.101:7000
redis-trib.rb add-node --slave 192.168.77.103:7005 192.168.77.101:7000
# 添加三个slave实例,每个slave实例会自动分配到一个master实例之下
redis-cli -c -h 192.168.77.101 -p 7000 cluster nodes|sort -k2
redis-trib.rb check 192.168.77.101:7000
# 查看集群节点状态
4,生成集群状态报表:
此时的信息输出太多了,可以对cluster nodes命令的输出结果做一下转换,生成状态报表
redis-cli -c -h 192.168.77.101 -p 7000 cluster nodes|\
awk 'BEGIN{print"节点 角色 自身ID 挂接的主实例ID"}
{if($4=="-") {print $2,$3,$1,$1}
else {print $2,$3,$1,$4}}'|\
sort -rk4|column -t
# 查看集群状态,主备关系
# 当自身ID和挂接的主实例ID相同时,代表本实例是一个master实例
# 否则代表本实例是一个slave实例
5,手动调整master实例和slave实例之间的关系
当一个节点上存在两个以上的实例的时候,如果运行期间发生了宕机实例切换
会产生一个节点上运行多个master实例或者一个节点全部都是slave的情况
或者出现一个节点上的两个实例正好是一对master实例和slave实例
此时就需要手动调整master实例和slvae实例之间的对应关系,以免在节点故障时产生不可用的情况
redis-cli -c -h 192.168.77.101 -p 7001 cluster replicate 45c239f2a6637cb8c5209c7ccd5754acfbaeb6b4
redis-cli -c -h 192.168.77.102 -p 7003 cluster replicate 8af251aab2566469e8742abc80737acc9f7b60a2
redis-cli -c -h 192.168.77.103 -p 7005 cluster replicate 48c93c36580fc7314307ed4eeae6363b15b1be50
# 根据 生成集群状态报表 命令查看集群状态,验证切换操作
6,手动宕机master实例,查看集群热切:
redis-cli -c -h 192.168.77.102 -p 7002 debug segfault
# 将102的7002实例停机
# 根据 生成集群状态报表 命令查看集群状态,验证集群热切
# 发现角色一栏102的7002实例 出现 master,fail 信息
# 该实例原本的slave实例现在变成的master实例,集群热切成功
节点2将停掉的实例启动
/usr/local/bin/redis-server /usr/local/redis/redis_cluster/redis_7002.conf
# 根据 生成集群状态报表 命令查看集群状态,查看集群状态
# 发现停掉的实例启动后变成了slave状态的实例
集群删除
1,删除slave实例:
redis-trib.rb del-node 192.168.77.101:7000 45c239f2a6637cb8c5209c7ccd5754acfbaeb6b4
redis-trib.rb del-node 192.168.77.101:7000 d65247f83fbe5f3c9bc0b25c8ffbd3aace203bea
redis-trib.rb del-node 192.168.77.101:7000 a1c5ede35007ba6c1bf6d9fad907dbe09f7c6f62
# slave角色的实例可以直接删除
# 实例从集群删除后,实例会关闭
2,删除master实例:
redis-trib.rb reshard 192.168.77.101:7000
# 需要将即将删除的master实例上的slot移动到其他master实例上
# 当master实例上有slot存在时,是无法删除的
redis-trib.rb check 192.168.77.101:7000
# 查看待删除的实例上已经没有slot了
redis-trib.rb del-node 192.168.77.101:7000 f2b7cb07b0f3a16c7c650df205ef269933d5badc
redis-trib.rb del-node 192.168.77.101:7000 8af251aab2566469e8742abc80737acc9f7b60a2
# 根据 生成集群状态报表 命令查看集群状态 只剩下一个master实例了
redis-cli -c -h 192.168.77.101 -p 7000 debug segfault
# 将最后一个master实例关闭
3,残余信息删除:
实例删除后,存在残余信息,需要删除才可以做集群的再次创建添加等操作
这些残余信息是实例运行产生的,因此三个节点主机都要删除缓存信息
cd /usr/local/redis/run/data
rm -rf nodes*.conf
# 删除集群配置信息
rm -rf dump*.rdb
# 删除内存快照
rm -rf appendonly*.aof
# 删除aof日志文件
cd ..
rm -rf log/redis*.log
# 删除实例运行日志
tree
简单总结
从本次实验可以看出,redis集群其实没有对master数量和slave数量做限制
两种实例的添加和删除比较灵活,可以根据内存的使用情况增加master,然后迁移数据槽
当然被添加的master的内存限额也是没有限制的,可以根据实际生产负载添加翻倍内存限额的master
slave一般要和master内存限额一样大,因为slave在master宕机后会自动切换成master
为了集群安全,一般一个master至少有一个slave,而且要保证slave不会先于master宕机
如果一个master的所有slave都已经宕机,此时master再宕机的话就会对服务产生影响了
原文地址http://www.bieryun.com/3290.html
Redis4.0 单节点集群到三主三从节点集群实验
Redis4.0 单节点集群到三主三从节点集群实验http://www.bieryun.com/3290.html
环境相关:
OS:CentOS release 7.4.1708
IP:192.168.77.101/102/103
MEM:16G
DISK:50G
简单说明
参照《Redis4.0 三主三备集群安装配置》配置三节点主机6个redis实例并启动
第五步配置集群使用本博文操作进行
集群创建
1,在节点一上创建单实例集群:
cp -av /usr/local/redis/src/redis-trib.rb /usr/local/bin
redis-trib.rb create --replicas 0 192.168.77.101:7000
# 创建一个单实例集群会报错,因为redis的集群需要至少3个master实例
# 该报错可以忽略掉,使用fix命令进行修复
redis-trib.rb fix 192.168.77.101:7000
# 使用fix命令修复集群,需要交互式输入yes进行确认
redis-cli -c -h 192.168.77.101 -p 7000 cluster nodes
redis-trib.rb check 192.168.77.101:7000
# 查看集群状态,目前集群只有一个master实例,所有的数据槽都在该实例上
# 单实例集群创建就完成了
2,添加两个主节点:
redis-trib.rb add-node 192.168.77.102:7002 192.168.77.101:7000
redis-trib.rb add-node 192.168.77.103:7004 192.168.77.101:7000
# 使用add-node命令,将102的7002和103的7004添加到集群里
redis-trib.rb check 192.168.77.101:7000
# 查看集群状态,发现目前集群中有三个master实例,但是所有的slot都在第一个master之上
# 此时,新加入的两个master实例没有任何的slot,是可以直接删掉的
redis-trib.rb reshard 192.168.77.101:7000
# 使用reshard命令重新分配slot,需要交互输入重新分配的slot数量和接收实例以及来源实例
# 两次使用该命令,将新添加的两个实例都分配一定数量的slot
输入需要重新分配的slot数量
输入接收这些slot的实例ID
输入这些slot的来源实例ID
确认移动
如果是真实的生产环境,在移动数据槽的时候,有可能会超时失败,如移动1000个数据槽到另外一个主实例
原因是某个或某些数据槽占用内存较大,移动操作超时,就需要使用fix命令进行修复
超时失败不会对集群造成影响,已经移动成功的数据槽状态也是没问题的
可以修复后再次重新分布数据槽,减少数据槽的数量,防止再次超时失败
redis-trib.rb fix 192.168.77.101:7000
redis-trib.rb check 192.168.77.101:7000
# 检查集群节点状态,发现三个master实例都有slot存在,此时就不能直接删除master实例
3,添加三个从实例:
redis-trib.rb add-node --slave 192.168.77.101:7001 192.168.77.101:7000
redis-trib.rb add-node --slave 192.168.77.102:7003 192.168.77.101:7000
redis-trib.rb add-node --slave 192.168.77.103:7005 192.168.77.101:7000
# 添加三个slave实例,每个slave实例会自动分配到一个master实例之下
redis-cli -c -h 192.168.77.101 -p 7000 cluster nodes|sort -k2
redis-trib.rb check 192.168.77.101:7000
# 查看集群节点状态
4,生成集群状态报表:
此时的信息输出太多了,可以对cluster nodes命令的输出结果做一下转换,生成状态报表
redis-cli -c -h 192.168.77.101 -p 7000 cluster nodes|\
awk 'BEGIN{print"节点 角色 自身ID 挂接的主实例ID"}
{if($4=="-") {print $2,$3,$1,$1}
else {print $2,$3,$1,$4}}'|\
sort -rk4|column -t
# 查看集群状态,主备关系
# 当自身ID和挂接的主实例ID相同时,代表本实例是一个master实例
# 否则代表本实例是一个slave实例
5,手动调整master实例和slave实例之间的关系
当一个节点上存在两个以上的实例的时候,如果运行期间发生了宕机实例切换
会产生一个节点上运行多个master实例或者一个节点全部都是slave的情况
或者出现一个节点上的两个实例正好是一对master实例和slave实例
此时就需要手动调整master实例和slvae实例之间的对应关系,以免在节点故障时产生不可用的情况
redis-cli -c -h 192.168.77.101 -p 7001 cluster replicate 45c239f2a6637cb8c5209c7ccd5754acfbaeb6b4
redis-cli -c -h 192.168.77.102 -p 7003 cluster replicate 8af251aab2566469e8742abc80737acc9f7b60a2
redis-cli -c -h 192.168.77.103 -p 7005 cluster replicate 48c93c36580fc7314307ed4eeae6363b15b1be50
# 根据 生成集群状态报表 命令查看集群状态,验证切换操作
6,手动宕机master实例,查看集群热切:
redis-cli -c -h 192.168.77.102 -p 7002 debug segfault
# 将102的7002实例停机
# 根据 生成集群状态报表 命令查看集群状态,验证集群热切
# 发现角色一栏102的7002实例 出现 master,fail 信息
# 该实例原本的slave实例现在变成的master实例,集群热切成功
节点2将停掉的实例启动
/usr/local/bin/redis-server /usr/local/redis/redis_cluster/redis_7002.conf
# 根据 生成集群状态报表 命令查看集群状态,查看集群状态
# 发现停掉的实例启动后变成了slave状态的实例
集群删除
1,删除slave实例:
redis-trib.rb del-node 192.168.77.101:7000 45c239f2a6637cb8c5209c7ccd5754acfbaeb6b4
redis-trib.rb del-node 192.168.77.101:7000 d65247f83fbe5f3c9bc0b25c8ffbd3aace203bea
redis-trib.rb del-node 192.168.77.101:7000 a1c5ede35007ba6c1bf6d9fad907dbe09f7c6f62
# slave角色的实例可以直接删除
# 实例从集群删除后,实例会关闭
2,删除master实例:
redis-trib.rb reshard 192.168.77.101:7000
# 需要将即将删除的master实例上的slot移动到其他master实例上
# 当master实例上有slot存在时,是无法删除的
redis-trib.rb check 192.168.77.101:7000
# 查看待删除的实例上已经没有slot了
redis-trib.rb del-node 192.168.77.101:7000 f2b7cb07b0f3a16c7c650df205ef269933d5badc
redis-trib.rb del-node 192.168.77.101:7000 8af251aab2566469e8742abc80737acc9f7b60a2
# 根据 生成集群状态报表 命令查看集群状态 只剩下一个master实例了
redis-cli -c -h 192.168.77.101 -p 7000 debug segfault
# 将最后一个master实例关闭
3,残余信息删除:
实例删除后,存在残余信息,需要删除才可以做集群的再次创建添加等操作
这些残余信息是实例运行产生的,因此三个节点主机都要删除缓存信息
cd /usr/local/redis/run/data
rm -rf nodes*.conf
# 删除集群配置信息
rm -rf dump*.rdb
# 删除内存快照
rm -rf appendonly*.aof
# 删除aof日志文件
cd ..
rm -rf log/redis*.log
# 删除实例运行日志
tree
简单总结
从本次实验可以看出,redis集群其实没有对master数量和slave数量做限制
两种实例的添加和删除比较灵活,可以根据内存的使用情况增加master,然后迁移数据槽
当然被添加的master的内存限额也是没有限制的,可以根据实际生产负载添加翻倍内存限额的master
slave一般要和master内存限额一样大,因为slave在master宕机后会自动切换成master
为了集群安全,一般一个master至少有一个slave,而且要保证slave不会先于master宕机
如果一个master的所有slave都已经宕机,此时master再宕机的话就会对服务产生影响了
redis误同步恢复
redis主备同步非常方便,通过slaveof命令即可同步。上周应用切换了redis,想让新的redis和旧的redis进行数据同步,结果把新redis中其他应用已经写入的所有数据都删除了。。。这里记录下恢复方法。
首先先恢复redis的dump文件。还好现在阿里云弹性计算集群给每个镜像每天都进行了备份,通过操作前一天的备份镜像,快照制作当时的整个redis目录复制了出来,作为恢复的基础。
然后将恢复回来的文件再复制一份备份,原先那份修改redis的配置文件,修改启动端口(我从默认的6379改成了6479),然后启动旧的redis,成功将当时的dump文件载入到新的redis实例中。
查询到redis有migrate命令,能够将key迁移到另外一个redis实例中(具体参考这里)。通过bash命令,循环的将备份的实例所有key,都试图通过migrate命令迁移到新的redis中。
迁移过程中,迁移成功的key,在旧的实例中会被删除,失败的key,可以看见失败原因都是key is busy。也就是说,要迁移的key在新的实例中已经存在了。
和使用方确定了所有已经存在的key,是hash类型的,都是要保留的数据。因此,通过一个简单的shell脚本,读取备份实例中hash类型key,并添加到新的redis中。bash脚本为:
[cce lang=”bash”]
#!/bin/bash
OLD_REDIS="./redis-cli -p 6479"
NEW_REDIS="./redis-cli"
KEYS=`$OLD_REDIS keys '*'`
for k in $KEYS
do
key_type=`$OLD_REDIS type $k`
if [ $key_type = "hash" ]; then
hash_keys=`$OLD_REDIS HKEYS $k`
for hash_key in $hash_keys
do
hash_value=`$OLD_REDIS HGET $k $hash_key`
$NEW_REDIS HSET $k $hash_key $hash_value
echo "merge $k $hash_key to new redis"
done
#eval "$OLD_REDIS DEL $k"
fi
done
[/cce]
逻辑非常简单,就是先通过keys命令获取到所有迁移失败的key,然后通过type命令获取类型。如果是hash类型的key,遍历所有的hash key,然后读取出一个key下所有的键值对,并通过hset命令放到新的redis实例中。最后将合并完成的key从备份实例中删除。这里由于业务上只需要合并hash类型的,其他容器类型(list, set等)也可以通过类似的方式做新老合并。
转载自:https://coolex.info/blog/427.html
一文揭秘阿里云Redis全球多活产品
简介
Redis全球多活产品是阿里云自研、基于云数据库Redis版(ApsaraDB for Redis)、100%兼容 Redis 协议的多活数据库系统。通过数据同步通道,把多个Redis实例组网成1个逻辑上的 Redis 多活实例,多活实例内的所有实例均可读写并保持实时数据同步。数据同步通道通过内网打通,具有高可靠、高安全,低延迟的特性。子实例间通过CRDT(Conflict-free Replicated Data Type)机制检测并解决数据冲突,保障数据最终一致性。Redis全球多活产品轻松支持异地多个站点同时对外提供服务的业务场景,助力企业快速复制阿里巴巴异地多活架构。
目前阿里云Redis全球多活产品已开放售卖,相关产品介绍详见https://promotion.aliyun.com/ntms/act/redis-geo-replication.html。
产品架构
Redis多活实例由三部分构成:
云数据库 Redis 版实例
同步通道
通道管理器
云数据库 Redis 版实例
原生内核的日志机制比较简单,不足以支撑多活相互复制数据,我们对aof日志改造为binlog,把每一条aof日志扩展为oplog:
每条oplog包含一个全局唯一id(类似mysql的GTID),id包含两部分, 一部分是Redis实例id,用于解决循环同步的问题,第二部分是递增数字,保证有序和唯一。
oplog包含逻辑时钟信息,在目标端Redis 执行merge时,使用CRDT策略解决数据一致性问题。
通道
每两个redis实例间有负责同步oplog的双向通道,同步过程根据oplog gtid保证exactly once语义,并且能处理 上下游Redis实例异常(主备切换、备库重搭)。
通道管理器
负责通道生命周期管理
产品优势
高可用
同步支持断点续传,最高可以容忍天级别的隔断。
自适应处理上下游 Redis 子实例发生HA(主备切换)的情况。
高性能
多活同步的过程是异步的,对正常的Redis读写没有性能影响。高吞吐:标准版单向同步通道10万tps,集群版随 Redis 节点数线性扩展。低延迟:1个洲际内地域间数据同步延迟在百毫秒级,跨洲际地域间延迟在1秒级。
数据最终一致
在多活场景中, 由于存在多个实例且每个实例都可读写,则在同步过程中,一定会遇到数据一致性问题。如下图,同时在redis实例A上写入key value_A,在redis实例B上写入key value_B,互相同步之后很可能实例A上key的值为value_B,而实例B上key的值为value_A,这种不一致可能是业务上是不能接受的。
我们基于CRDT(Conflict-free Replicated Data Type)的方案,对redis内核进行针对性改造,实现了string、counter、hash、set、zset、hyperloglog、geo几种数据类型的最终一致性.
功能丰富
多活支持Redis标准版,集群版和读写分离版。
在多活同步过程中支持 Redis 子实例规格变配。
支持新增和删除redis子实例。
应用场景
Redis 多活产品主要应用于异地多活业务架构的存储层,业务层设计可以参考文档《数据库异地多活解决方案》。
Redis数据闪回: 任意时间点秒级恢复数据-1
Redis数据闪回: 任意时间点秒级恢复数据本步骤在DMS数据管理平台上操作,通过DMS登录Redis实例,在Redis数据库中增加和删除数据。登录Redis数据库:进入Redis控制台,选择实例所在区域,单击实例ID-选择实例信息-登录数据库,输入数据库账号和密码,单击登录。 2.在数据库中,执行以下命令,插入数据。模拟误删除操作,删除 a5 a6 a7,并记录操作时间点。说明:本案例中,删除a5、a6、a7的时间为11:04。本步骤在Redis控制台操作。1、在实例信息页,单击备份与恢复-数据闪回-马上闪回。2、闪回数据:选择指定key,填写key名称(a5),恢复模式选择为原实例,设置闪回时间点,单击确定。说明:本案例中,闪回时间点为2021年7月20日11:04:00。选择全量数据闪回,恢复模式只支持新建实例(新实例包含全量数据),按照界面提示克隆实例。恢复过程约10分钟。执行如下命令可查看数据已恢复。
《Redis官方文档》分区
原文链接 译者:Alexandar Mahone
分区:如何把数据存储到多个Redis实例中
分区就是把你的数据分割到多个Redis实例中的一个过程,因此每个实例仅仅包含部分键。这篇文章第一部分介绍分区概念,第二部分将介绍Redis分区的用法。
(译者注:Redis集群是分区事实上标准)
为什么分区是非常有用的
分区在Redis中主要有两个目的:
分区利用多台机器的内存构建一个更大数据库。如果不使用分区,数据库大小受限于单个计算机内存。
分区可以在多核和多计算机之间弹性扩展计算能力,并且分区可以在多计算机和网络适配器之间弹性扩展网络带宽。
分区基础:
有多种的分区标准。假设我们有4个Redis实例 R0,R1,R2,R3,很多表示用户的键例如 user:1,user:2等等,我们可以找到不同方式选择实例存储指定的键。换句话说有不同的系统映射一个指定的键到一个给定的Redis服务器。
一个最简单的方法是使用范围分区,并且通过映射某一范围的对象到特定的Redis实例。例如,我可以指定ID 0到10000的用户存储到实例R0,而ID 10001到20000的用户存储到实例R2等等。
该方案实际上是可以应用在实践中的,尽管他的缺点是需要一张映射对象范围与实例的表。这张表需要进行维护,并且我们需要为每种类型对象建立一张表,所以范围分区在Redis中常常是不受欢迎的,因为比其他分区方法更低效。
一个范围分区替代方法是哈希分区。此方案适用于任何形式键,无需键格式形如object_name:<id>,就是这么简单:
使用哈希方法(例如crc32哈希方法)将键名转换成数字。例如一个键名是foobar,crc32(foobar)输出结果形如93024922。
我是使用取模操作将该数字转换成0到3的数字,以便映射到四个Redis实例中的一个。93024922对4取余数等于2,这样我知道foobar键应该存储到R2实例中。注意:模操作返回除法运算的余数,大部分编程语言使用%(取余)就可以了。
通过这两个例子,你应该可以想到还有很多其他方法进行分区。一个更先进的哈希分区是一致性哈希,并且是由几个Redis客户端和代理实现的。
分区不同实现方式
分区可以由一个软件栈的不同部分完成。
客户端分区:客户端直接选择正确节点读写指定键。很多Redis客户实现了这种分区方式。
代理辅助分区:是指我们的客户端通过Redis协议把请求发送给代理,而不是直接发送给真正的Redis实例服务器。这个代理会确保我们的请求根据配置分区策略发送到正确的Redis实例上,并返回给客户端。Redis和Memcached的代理都是用Twemproxy (译者注:这是twitter开源的一个代理框架)来实现代理服务分区的。
查询路由:是指你可以把一个请求发送给一个随机的实例,这时实例会把该查询转发给正确的节点。通过客户端重定向(客户端的请求不用直接从一个实例转发到另一个实例,而是被重定向到正确的节点),Redis集群实现了一种混合查询路由。
Redis分区缺点:
Redis分区在有些方面做的并不好:
不支持多个键的操作。比如你不能操作映射在两个Redis实例上的两个集合的交叉集。(其实可以做到这一点,但是需要间接的解决).
Redis不支持多个键的事务。
Redis是以键来分区,因此不能使用单个大键对数据集进行分片,例如一个非常大的有序集。
如果使用分区,数据的处理会变得复杂,比如你必须处理多个RDB和AOF文件,在多个实例和主机之间持久化你的数据。
添加和删除节点也会变得复杂。例如通过在运行时添加和删除节点,Redis集群通常支持透明地再均衡数据,但是其他系统像客户端分区或者代理分区的特性就不支持该特性。不过Pre-sharding(预分片)可以在这方面提供帮助。
作为数据存储还是作为缓存使用?
使用Redis存储数据或者缓存数据在概念上是相同的,但是Redis被当作数据存储使用时有一个显著限制。当Redis被当作数据存储服务器使用的时候意味着对于相同的键值必须被映射到相同的实例上面,但是如果把Redis当作数据缓存器,使用多个不同节点,一个给定节点挂掉并不是个大问题,改变键值和实例映射表可以提升系统的可用性(也就是系统处理查询请求的能力)。
如果一个指定键的首选节点不可用,一致性哈希可以为指定键切换到其他的节点上。同样的,你添加一个新的节点,部分新的键值开始存储到新添加的节点上面。
主要的概念如下:
如果Redis只作为可伸缩缓存服务器来使用,那么用一致性哈希是非常容易的。
若果Redis被作为数据持久化服务器,需要提供节点和键值的固定映射,还有节点数目必须是固定的,不能改变。否则当增加或删除节点时,我们需要一个系统来为键重新分配节点,从2015年4月1日开始,Redis集群提供该特性。
预分片
从分区的概念中,我们知道分区有一个缺点:除非只把Redis当作缓存服务器来使用,否则添加和删除Redis节点都会非常复杂。相反使用固定的键值和实例映射更加简单。
然而数据存储会经常需要变化。今天我只需要10个Redis节点(实例),但是明天我可能会需要50个节点。
因为Redis足够轻量和小巧(一个备用实例使用1M的内存),解决这个问题的简单方法就是一开始就使用大量的实例节点。即使你开始只有一个服务器,你可以换成分布式的结构,通过分区分方式在单个服务器上来运行多个Redis实例。
你一开始可以选择的实例可数可以非常大。例如,32或者64个实例能够满足绝大多数的用户,并且可以为其提供足够的增长空间。
通过这样的方法,当摸得数据存储需求增加时,你只需要更多的Redis服务器,然后把一个节点移动到另外的服务器上面。一旦你添加了额外的服务器,你需要将一半的Redis的实例移动到第二个服务器,以此类推。
你可以使用Redis 的主从复制来减少服务的停止时间:
在新服务器上开启新的redis空实例。
将节点的数据配置移动到新的从服务器上
停止你的redis客户端。
在新的服务器上更新IP地址到移动过来的节点配置文件中。
发送SLAVEOF NO ONE 命令到新服务器的从节点。
使用新的配置重启客户端。
最后关闭老服务器上不再使用的节点。
分区实践
到目前为止,我们讲了分区的原理。但是该如何实战?你应该使用什么样的系统?
Redis集群
推荐使用Redis集群获得自动分片和高可用性。Redis集群是2015年4月1日版本发布的可用和生成就绪特性。可以从集群教程中获取更多信息。
一旦Redis集群是可用的,并且一个Redis集群兼容客户端支持您的编程语言,Redis集群就是Redis分区事实上标准。
Redis集群混合使用了查询路由和客户端分区。
Twemproxy 框架
Twemproxy是一个由Twitter开发的适合Memached ASCII和Redis协议的代理。它是单线程工作,使用C语言实现的,速度非常快。并且是基于Apache 2.0 协议的开源软件。
Twemproxy支持自动在多个redis节点分区,如果某个节点不可用,将会被自动屏蔽(这将改变键值和节点映射表,所以如果你把Redis当作缓存服务器使用,你应该使用这个功能)。
你可以启用多个代理,让你的客户端得到可用的连接,这样不会发生单点故障。
Twemproxy基本上是Redis和客户端的一个中间层,通过简化使用让我们使用可靠的分区。
你可以在antirez的博客获取有关Twemproxy的更多知识。
客户端一致性哈希实现。
替代Twemproxy的一种方案是使用客户端一致性哈西或者其他类似的算法。有很多Redis客户端支持一致性哈希,比如Redis-rb和Predis。
请检查Redis客户端全量列表,以确定是否有适合于你的编程语言、成熟的一致性哈希实现的客户端。
《Redis官方文档》分区
分区:如何把数据存储到多个Redis实例中
分区就是把你的数据分割到多个Redis实例中的一个过程,因此每个实例仅仅包含部分键。这篇文章第一部分介绍分区概念,第二部分将介绍Redis分区的用法。
(译者注:Redis集群是分区事实上标准)
为什么分区是非常有用的
分区在Redis中主要有两个目的:
分区利用多台机器的内存构建一个更大数据库。如果不使用分区,数据库大小受限于单个计算机内存。
分区可以在多核和多计算机之间弹性扩展计算能力,并且分区可以在多计算机和网络适配器之间弹性扩展网络带宽。
分区基础:
有多种的分区标准。假设我们有4个Redis实例 R0,R1,R2,R3,很多表示用户的键例如 user:1,user:2等等,我们可以找到不同方式选择实例存储指定的键。换句话说有不同的系统映射一个指定的键到一个给定的Redis服务器。
一个最简单的方法是使用范围分区,并且通过映射某一范围的对象到特定的Redis实例。例如,我可以指定ID 0到10000的用户存储到实例R0,而ID 10001到20000的用户存储到实例R2等等。
该方案实际上是可以应用在实践中的,尽管他的缺点是需要一张映射对象范围与实例的表。这张表需要进行维护,并且我们需要为每种类型对象建立一张表,所以范围分区在Redis中常常是不受欢迎的,因为比其他分区方法更低效。
一个范围分区替代方法是哈希分区。此方案适用于任何形式键,无需键格式形如object_name:<id>,就是这么简单:
使用哈希方法(例如crc32哈希方法)将键名转换成数字。例如一个键名是foobar,crc32(foobar)输出结果形如93024922。
我是使用取模操作将该数字转换成0到3的数字,以便映射到四个Redis实例中的一个。93024922对4取余数等于2,这样我知道foobar键应该存储到R2实例中。注意:模操作返回除法运算的余数,大部分编程语言使用%(取余)就可以了。
通过这两个例子,你应该可以想到还有很多其他方法进行分区。一个更先进的哈希分区是一致性哈希,并且是由几个Redis客户端和代理实现的。
分区不同实现方式
分区可以由一个软件栈的不同部分完成。
客户端分区:客户端直接选择正确节点读写指定键。很多Redis客户实现了这种分区方式。
代理辅助分区:是指我们的客户端通过Redis协议把请求发送给代理,而不是直接发送给真正的Redis实例服务器。这个代理会确保我们的请求根据配置分区策略发送到正确的Redis实例上,并返回给客户端。Redis和Memcached的代理都是用Twemproxy (译者注:这是twitter开源的一个代理框架)来实现代理服务分区的。
查询路由:是指你可以把一个请求发送给一个随机的实例,这时实例会把该查询转发给正确的节点。通过客户端重定向(客户端的请求不用直接从一个实例转发到另一个实例,而是被重定向到正确的节点),Redis集群实现了一种混合查询路由。
Redis分区缺点:
Redis分区在有些方面做的并不好:
不支持多个键的操作。比如你不能操作映射在两个Redis实例上的两个集合的交叉集。(其实可以做到这一点,但是需要间接的解决).
Redis不支持多个键的事务。
Redis是以键来分区,因此不能使用单个大键对数据集进行分片,例如一个非常大的有序集。
如果使用分区,数据的处理会变得复杂,比如你必须处理多个RDB和AOF文件,在多个实例和主机之间持久化你的数据。
添加和删除节点也会变得复杂。例如通过在运行时添加和删除节点,Redis集群通常支持透明地再均衡数据,但是其他系统像客户端分区或者代理分区的特性就不支持该特性。不过Pre-sharding(预分片)可以在这方面提供帮助。
作为数据存储还是作为缓存使用?
使用Redis存储数据或者缓存数据在概念上是相同的,但是Redis被当作数据存储使用时有一个显著限制。当Redis被当作数据存储服务器使用的时候意味着对于相同的键值必须被映射到相同的实例上面,但是如果把Redis当作数据缓存器,使用多个不同节点,一个给定节点挂掉并不是个大问题,改变键值和实例映射表可以提升系统的可用性(也就是系统处理查询请求的能力)。
如果一个指定键的首选节点不可用,一致性哈希可以为指定键切换到其他的节点上。同样的,你添加一个新的节点,部分新的键值开始存储到新添加的节点上面。
主要的概念如下:
如果Redis只作为可伸缩缓存服务器来使用,那么用一致性哈希是非常容易的。
若果Redis被作为数据持久化服务器,需要提供节点和键值的固定映射,还有节点数目必须是固定的,不能改变。否则当增加或删除节点时,我们需要一个系统来为键重新分配节点,从2015年4月1日开始,Redis集群提供该特性。
预分片
从分区的概念中,我们知道分区有一个缺点:除非只把Redis当作缓存服务器来使用,否则添加和删除Redis节点都会非常复杂。相反使用固定的键值和实例映射更加简单。
然而数据存储会经常需要变化。今天我只需要10个Redis节点(实例),但是明天我可能会需要50个节点。
因为Redis足够轻量和小巧(一个备用实例使用1M的内存),解决这个问题的简单方法就是一开始就使用大量的实例节点。即使你开始只有一个服务器,你可以换成分布式的结构,通过分区分方式在单个服务器上来运行多个Redis实例。
你一开始可以选择的实例可数可以非常大。例如,32或者64个实例能够满足绝大多数的用户,并且可以为其提供足够的增长空间。
通过这样的方法,当摸得数据存储需求增加时,你只需要更多的Redis服务器,然后把一个节点移动到另外的服务器上面。一旦你添加了额外的服务器,你需要将一半的Redis的实例移动到第二个服务器,以此类推。
你可以使用Redis 的主从复制来减少服务的停止时间:
在新服务器上开启新的redis空实例。
将节点的数据配置移动到新的从服务器上
停止你的redis客户端。
在新的服务器上更新IP地址到移动过来的节点配置文件中。
发送SLAVEOF NO ONE 命令到新服务器的从节点。
使用新的配置重启客户端。
最后关闭老服务器上不再使用的节点。
分区实践
到目前为止,我们讲了分区的原理。但是该如何实战?你应该使用什么样的系统?
Redis集群
推荐使用Redis集群获得自动分片和高可用性。Redis集群是2015年4月1日版本发布的可用和生成就绪特性。可以从集群教程中获取更多信息。
一旦Redis集群是可用的,并且一个Redis集群兼容客户端支持您的编程语言,Redis集群就是Redis分区事实上标准。
Redis集群混合使用了查询路由和客户端分区。
Twemproxy 框架
Twemproxy是一个由Twitter开发的适合Memached ASCII和Redis协议的代理。它是单线程工作,使用C语言实现的,速度非常快。并且是基于Apache 2.0 协议的开源软件。
Twemproxy支持自动在多个redis节点分区,如果某个节点不可用,将会被自动屏蔽(这将改变键值和节点映射表,所以如果你把Redis当作缓存服务器使用,你应该使用这个功能)。
你可以启用多个代理,让你的客户端得到可用的连接,这样不会发生单点故障。
Twemproxy基本上是Redis和客户端的一个中间层,通过简化使用让我们使用可靠的分区。
你可以在antirez的博客获取有关Twemproxy的更多知识。
客户端一致性哈希实现。
替代Twemproxy的一种方案是使用客户端一致性哈西或者其他类似的算法。有很多Redis客户端支持一致性哈希,比如Redis-rb和Predis。
请检查Redis客户端全量列表,以确定是否有适合于你的编程语言、成熟的一致性哈希实现的客户端。
转载自 并发编程网 - ifeve.com
分区:怎样将数据分布到多个redis实例
分区是将你的数据分发到不同redis实例上的一个过程,每个redis实例只是你所有key的一个子集。文档第一部分将介绍分区概念,第二部分介绍分区的另外一种可选方案。
为什么分区非常有用
Redis分区主要有两个目的:
分区可以让Redis管理更大的内存,Redis将可以使用所有机器的内存。如果没有分区,你最多只能使用一台机器的内存。
分区使Redis的计算能力通过简单地增加计算机得到成倍提升,Redis的网络带宽也会随着计算机和网卡的增加而成倍增长。
分区基本概念
有许多分区标准。假如我们有4个Redis实例R0, R1, R2, R3,有一批用户数据user:1, user:2, … ,那么有很多存储方案可以选择。从另一方面说,有很多different systems to map方案可以决定用户映射到哪个Redis实例。
一种最简单的方法就是范围分区,就是将不同范围的对象映射到不同Redis实例。比如说,用户ID从0到10000的都被存储到R0,用户ID从10001到20000被存储到R1,依此类推。
这是一种可行方案并且很多人已经在使用。但是这种方案也有缺点,你需要建一张表存储数据到redis实例的映射关系。这张表需要非常谨慎地维护并且需要为每一类对象建立映射关系,所以redis范围分区通常并不像你想象的那样运行,比另外一种分区方案效率要低很多。
另一种可选的范围分区方案是散列分区,这种方案要求更低,不需要key必须是object_name:<id>的形式,如此简单:
使用散列函数 (如 crc32 )将键名称转换为一个数字。例:键foobar, 使用crc32(foobar)函数将产生散列值93024922。
对转换后的散列值进行取模,以产生一个0到3的数字,以便可以使这个key映射到4个Redis实例当中的一个。93024922 % 4 等于 2, 所以 foobar 会被存储到第2个Redis实例。 R2 注意: 对一个数字进行取模,在大多数编程语言中是使用运算符%
还有很多分区方法,上面只是给出了两个简单示例。有一种比较高级的散列分区方法叫一致性哈希,并且有一些客户端和代理(proxies)已经实现。
不同的分区实现方案
分区可以在程序的不同层次实现。
客户端分区就是在客户端就已经决定数据会被存储到哪个redis节点或者从哪个redis节点读取。大多数客户端已经实现了客户端分区。
代理分区 意味着客户端将请求发送给代理,然后代理决定去哪个节点写数据或者读数据。代理根据分区规则决定请求哪些Redis实例,然后根据Redis的响应结果返回给客户端。redis和memcached的一种代理实现就是Twemproxy
查询路由(Query routing) 的意思是客户端随机地请求任意一个redis实例,然后由Redis将请求转发给正确的Redis节点。Redis Cluster实现了一种混合形式的查询路由,但并不是直接将请求从一个redis节点转发到另一个redis节点,而是在客户端的帮助下直接redirected到正确的redis节点。
分区的缺点
有些特性在分区的情况下将受到限制:
涉及多个key的操作通常不会被支持。例如你不能对两个集合求交集,因为他们可能被存储到不同的Redis实例(实际上这种情况也有办法,但是不能直接使用交集指令)。
同时操作多个key,则不能使用Redis事务.
分区使用的粒度是key,不能使用一个非常长的排序key存储一个数据集(The partitioning granularity is the key, so it is not possible to shard a dataset with a single huge key like a very big sorted set).
当使用分区的时候,数据处理会非常复杂,例如为了备份你必须从不同的Redis实例和主机同时收集RDB / AOF文件。
分区时动态扩容或缩容可能非常复杂。Redis集群在运行时增加或者删除Redis节点,能做到最大程度对用户透明地数据再平衡,但其他一些客户端分区或者代理分区方法则不支持这种特性。然而,有一种预分片的技术也可以较好的解决这个问题。
持久化数据还是缓存?
无论是把Redis当做持久化的数据存储还是当作一个缓存,从分区的角度来看是没有区别的。当把Redis当做一个持久化的存储(服务)时,一个key必须严格地每次被映射到同一个Redis实例。当把Redis当做一个缓存(服务)时,即使Redis的其中一个节点不可用而把请求转给另外一个Redis实例,也不对我们的系统产生什么影响,我们可用任意的规则更改映射,进而提高系统的高可用(即系统的响应能力)。
一致性哈希能够实现当一个key的首选的节点不可用时切换至其他节点。同样地,如果你增加了一个新节点,立刻就会有新的key被分配至这个新节点。
重要结论如下:
如果Redis被当做缓存使用,使用一致性哈希实现动态扩容缩容。
如果Redis被当做一个持久化存储使用,必须使用固定的keys-to-nodes映射关系,节点的数量一旦确定不能变化。否则的话(即Redis节点需要动态变化的情况),必须使用可以在运行时进行数据再平衡的一套系统,而当前只有Redis集群可以做到这样 - Redis 集群已经可用 2015.4.1.
预分片
从上面获知,除非我们把Redis当做缓存使用,否则(在生产环境动态)增加和删除节点将非常麻烦,但是使用固定的keys-instances则比较简单。
一般情况下随着时间的推移,数据存储需求总会发生变化。今天可能10个Redis节点就够了,但是明天可能就需要增加到50个节点。
既然Redis是如此的轻量(单实例只使用1M内存),为防止以后的扩容,最好的办法就是一开始就启动较多实例。即便你只有一台服务器,你也可以一开始就让Redis以分布式的方式运行,使用分区,在同一台服务器上启动多个实例。
一开始就多设置几个Redis实例,例如32或者64个实例,对大多数用户来说这操作起来可能比较麻烦,但是从长久来看做这点牺牲是值得的。
这样的话,当你的数据不断增长,需要更多的Redis服务器时,你需要做的就是仅仅将Redis实例从一台服务迁移到另外一台服务器而已(而不用考虑重新分区的问题)。一旦你添加了另一台服务器,你需要将你一半的Redis实例从第一台机器迁移到第二台机器。
使用Redis复制技术,你可以做到极短或者不停机地对用户提供服务:
在你新服务器启动一个空Redis实例。
把新Redis实例配置为原实例的slave节点
停止你的客户端
更新你客户端配置,以便启用新的redis实例(更新IP)。
在新Redis实例中执行SLAVEOF NO ONE命令
(更新配置后)重启你的客户端
停止你原服务器的Redis实例
Redis分区实现
截止到目前,我们从理论上讨论了Redis分区,但是实际上是怎样的呢?你应该采用哪种实现方案呢?
Redis 集群
Redis集群是自动分片和高可用的首选方案。新的集群方案2015年4月1日就已经可用。2015.4.1 Google论文. 你可以从这里Cluster tutorial了解更多。
当Redis集群可用,并且有兼容Redis 集群客户端可用于你的编程语言,Redis 集群将成为Redis分区的实际标准.
Redis集群是 query routing 和 client side partitioning的一种混合实现。
Twemproxy
Twemproxy是Twitter维护的(缓存)代理系统,代理Memcached的ASCII协议和Redis协议。它是单线程程序,使用c语言编写,运行起来非常快。它是采用Apache 2.0 license的开源软件。
Twemproxy支持自动分区,如果其代理的其中一个Redis节点不可用时,会自动将该节点排除(这将改变原来的keys-instances的映射关系,所以你应该仅在把Redis当缓存时使用Twemproxy)。
Twemproxy本身不存在单点问题,因为你可以启动多个Twemproxy实例,然后让你的客户端去连接任意一个Twemproxy实例。
Twemproxy是Redis客户端和服务器端的一个中间层,由它来处理分区功能应该不算复杂,并且应该算比较可靠的。
更多关于Twemproxy in this antirez blog post.
支持一致性哈希的客户端
相对于Twemproxy,另一种可选的分区方案是在客户端实现一致性哈希或者其他类似算法。有很多客户端已经支持一致性哈希,如 Redis-rb 和 Predis.
请检查 Redis客户端完整列表 以确认在你想要使用的编程语言,有成熟的一致性哈希客户端实现。
本文作者:陈群
本文来自云栖社区合作伙伴rediscn,了解相关信息可以关注redis.cn网站。
Redis分片(分布式缓存)
分片(partitioning)就是将你的数据拆分到多个 Redis 实例的过程,这样每个实例将只包含所有键的子集.
1 分片何用
Redis 的分片承担着两个主要目标:
允许使用很多电脑的内存总和来支持更大的数据库。没有分片,你就被局限于单机能支持的内存容量。
允许伸缩计算能力到多核或多服务器,伸缩网络带宽到多服务器或多网络适配器。
2 分片基础
有很多不同的分片标准(criteria).假想我们有 4 个 Redis 实例 R0,R1,R2,R3,还有很多表示用户的键,像 user:1,user:2,… 等等,我们能找到不同的方式来选择一个指定的键存储在哪个实例中。换句话说,有许多不同的办法来映射一个键到一个指定的 Redis 服务器。
最简单的执行分片的方式之一是范围分片(range partitioning),通过映射对象的范围到指定的 Redis 实例来完成分片。例如,我可以假设用户从 ID 0 到 ID 10000 进入实例 R0,用户从 ID 10001 到 ID 20000 进入实例 R1.
这套办法行得通,并且事实上在实践中被采用,然而,这有一个缺点,就是需要一个映射范围到实例的表格.这张表需要管理,不同类型的对象都需要一个表,所以范围分片在 Redis 中常常并不可取,因为这要比其他分片可选方案低效得多。
一种范围分片的替代方案是哈希分片(hash partitioning).这种模式适用于任何键,不需要键像 object_name: 这样的饿形式,就像这样简单
使用一个哈希函数(例如,crc32 哈希函数) 将键名转换为一个数字。例如,如果键是 foobar,crc32(foobar)将会输出类似于 93024922 的东西。
对这个数据进行取模运算,以将其转换为一个 0 到 3 之间的数字,这样这个数字就可以映射到我的 4 台 Redis 实例之一。93024922 模 4 等于 2,所以我知道我的键 foobar 应当存储到 R2 实例。注意:取模操作返回除法操作的余数,在许多编程语言总实现为%操作符。
有许多其他的方式可以分片,从这两个例子中你就可以知道了。一种哈希分片的高级形式称为一致性哈希(consistent hashing),被一些 Redis 客户端和代理实现。
3 分片实现(理论)
分片可由软件栈中的不同部分来承担。
客户端分片(Client side partitioning)客户端直接选择正确的节点来写入和读取指定键,许多 Redis 客户端实现了客户端分片.
代理协助分片(Proxy assisted partitioning)我们的客户端发送请求到一个可以理解 Redis 协议的代理上.而不是直接发送请求到 Redis 实例上.
代理会根据配置好的分片模式,来保证转发我们的请求到正确的 Redis 实例,并返回响应给客户端.Redis 和 Memcached 的代理 Twemproxy 实现了代理协助的分片.
查询路由(Query routing)你可以发送你的查询到一个随机实例,这个实例会保证转发你的查询到正确的节点.
Redis 集群在客户端的帮助下,实现了查询路由的一种混合形式 (请求不是直接从 Redis 实例转发到另一个,而是客户端收到重定向到正确的节点).
4 分片缺点
Redis 的一些特性与分片在一起时玩的不是很好
涉及多个键的操作通常不支持。例如,你不能对映射在两个不同 Redis 实例上的键执行交集(事实上有办法做到,但不是直接这么干).
涉及多个键的事务不能使用
分片的粒度(granularity)是键,所以不能使用一个很大的键来分片数据集,例如一个很大的有序集合
当使用了分片,数据处理变得更复杂,例如,你需要处理多个 RDB/AOF 文件,备份数据时你需要聚合多个实例和主机的持久化文件
添加和删除容量也很复杂。例如,Redis 集群具有运行时动态添加和删除节点的能力来支持透明地再均衡数据,但是其他方式,像客户端分片和代理都不支持这个特性。但是,有一种称为预分片(Presharding)的技术在这一点上能帮上忙。
5 存储 OR 缓存
尽管无论是将 Redis 作为数据存储还是缓存,Redis 的分片概念上都是一样的,但是作为数据存储时有一个重要的局限。当 Redis 作为数据存储时,一个给定的键总是映射到相同的 Redis 实例。当 Redis 作为缓存时,如果一个节点不可用而使用另一个节点,这并不是一个什么大问题,按照我们的愿望来改变键和实例的映射来改进系统的可用性(就是系统回复我们查询的能力)。
一致性哈希实现常常能够在指定键的首选节点不可用时切换到其他节点。类似的,如果你添加一个新节点,部分数据就会开始被存储到这个新节点上。
这里的主要概念如下:
如果 Redis 用作缓存,使用一致性哈希来来实现伸缩扩展(scaling up and down)是很容易的。
如果 Redis 用作存储,使用固定的键到节点的映射,所以节点的数量必须固定不能改变。否则,当增删节点时,就需要一个支持再平衡节点间键的系统,当前只有 Redis 集群可以做到这一点.
6 预分片
我们已经知道分片存在的一个问题,除非我们使用 Redis 作为缓存,增加和删除节点是一件很棘手的事情,使用固定的键和实例映射要简单得多。
然而,数据存储的需求可能一直在变化。今天我可以接受 10 个 Redis 节点(实例),但是明天我可能就需要 50 个节点。
因为 Redis 只有相当少的内存占用且轻量级(一个空闲的实例只是用 1MB 内存),一个简单的解决办法是一开始就开启很多的实例。即使你一开始只有一台服务器,你也可以在第一天就决定生活在分布式的世界里,使用分片来运行多个 Redis 实例在一台服务器上。
你一开始就可以选择很多数量的实例。例如,32 或者 64 个实例能满足大多数的用户,并且为未来的增长提供足够的空间。
这样,当你的数据存储需要增长,你需要更多的 Redis 服务器,你要做的就是简单地将实例从一台服务器移动到另外一台。当你新添加了第一台服务器,你就需要把一半的 Redis 实例从第一台服务器搬到第二台,如此等等。
使用 Redis 复制,你就可以在很小或者根本不需要停机时间内完成移动数据:
在你的新服务器上启动一个空实例。
移动数据,配置新实例为源实例的从服务。
停止你的客户端。
更新被移动实例的服务器 IP 地址配置。
向新服务器上的从节点发送 SLAVEOF NO ONE 命令。
以新的更新配置启动你的客户端。
最后关闭掉旧服务器上不再使用的实例。
7 分片实现(实践)
到目前为止,我们从理论上讨论了 Redis 分片,但是实践情况如何呢?你应该使用什么系统呢?
7.1 Redis 集群
Redis 集群是自动分片和高可用的首选方式.
一旦 Redis 集群可用,以及支持 Redis 集群的客户端可用,Redis 集群将会成为 Redis 分片的事实标准。
Redis 集群是查询路由和客户端分片的混合模式。
7.2 Twemproxy
Twemproxy 是 Twitter 开发的一个支持 Memcached ASCII 和 Redis 协议的代理。它是单线程的,由 C 语言编写,运行非常的快。基于 Apache 2.0 许可的开源项目。
Twemproxy 支持自动在多个 Redis 实例间分片,如果节点不可用时,还有可选的节点排除支持(这会改变键和实例的映射,所以你应该只在将 Redis 作为缓存是才使用这个特性)。
这并不是单点故障(single point of failure),因为你可以启动多个代理,并且让你的客户端连接到第一个接受连接的代理。
从根本上说,Twemproxy 是介于客户端和 Redis 实例之间的中间层,这就可以在最下的额外复杂性下可靠地处理我们的分片。这是当前建议的处理 Redis 分片的方式.
7.3 支持一致性哈希的客户端
Twemproxy 之外的可选方案,是使用实现了客户端分片的客户端,通过一致性哈希或者别的类似算法。有多个支持一致性哈希的 Redis 客户端,例如 Redis-rb 和 Predis。
请查看完整的 Redis 客户端列表,看看是不是有支持你的编程语言的,并实现了一致性哈希的成熟客户端。
联系我
gayhub
Redis管道技术/分区
Redis管道技术Redis是一种基于客户机-服务器模型和请求/响应协议的TCP服务。这意味着请求通常将遵循以下步骤:客户端向服务器发送查询请求,并侦听套接字返回,通常处于阻塞模式,等待服务器响应。服务器处理该命令并将结果返回给客户端。Redis管道技术允许客户端在服务器没有响应时继续向服务器发送请求,最后一次读取所有服务器的响应。实例要查看redis管道,只需启动redis实例并输入以下命令:$(echo -en "PING\r\n SET runoobkey redis\r\nGET runoobkey\r\nINCR visitor\r\nINCR visitor\r\nINCR visitor\r\n"; sleep 10) | nc localhost 6379
+PONG
+OK
redis
:1
:2
:3在上面的示例中,我们使用ping命令检查redis服务是否可用。然后我们将runoobkey的值设置为redis,然后我们得到runoobkey的值,并使访问者自动增加三倍。在返回的结果中,我们可以看到这些命令一次提交到redis服务,最后一次读取所有服务器的响应管道技术最显著的优势是提高redis服务的性能。一些测试数据require 'rubygems'
require 'redis'
def bench(descr)
start = Time.now
yield
puts "#{descr} #{Time.now-start} seconds"
end
def without_pipelining
r = Redis.new
10000.times {
r.ping
}
end
def with_pipelining
r = Redis.new
r.pipelined {
10000.times {
r.ping
}
}
end
bench("without pipelining") {
without_pipelining
}
bench("with pipelining") {
with_pipelining
}在接下来的测试中,我们将使用redis的Ruby客户端来支持流水线技术的特性,并测试流水线技术的提速效果。在局域网中的Mac OS X系统上执行的上述简单脚本的数据表明,在开启管道操作后,往返延迟已显著改善。Redis分区是将数据划分为多个redis实例的过程,因此每个实例只保存密钥的子集。分区的优势通过使用多台计算机的内存总和,我们可以构建一个更大的数据库。通过多核和多台计算机,我们可以扩展我们的计算能力;通过多台计算机和网络适配器,我们可以扩展网络带宽。分区不足redis的一些功能在分区方面表现不佳:通常不支持涉及多个键的操作。例如,当两个集合映射到不同的redis实例时,您无法对这两个集合执行交集操作。不能使用涉及多个密钥的Redis事务。使用分区时,数据处理更加复杂。例如,您需要处理多个rdb/aof文件,并备份来自多个实例和主机的持久文件。添加或删除容量也很复杂。大多数redis集群支持在运行时添加和删除节点的透明数据平衡,但其他系统(如客户端分区和代理)不支持此功能。然而,一种叫做预硬化的技术是有帮助的。分区类型Redis有两种类型的分区。假设有四个redis实例R0、R1、R2、R3和多个键代表用户,例如user:1和user:2。对于给定的键,有许多不同的方法来选择该键存储在哪个实例中。换句话说,有不同的系统将密钥映射到redis服务。范围分区最简单的分区方法是按范围,即将特定范围内的对象映射到特定的redis实例。例如,ID为0到10000的用户将保存到实例R0,ID为10001到20000的用户将保存到R1,依此类推。该方法是可行的,可以在实践中使用。缺点是有一个从区间范围到实例的映射表。此表需要管理。同时,它还需要各种对象的映射表,这通常不是redis的好方法。哈希分区另一种分区方法是哈希分区。这适用于任何键,并且不需要是对象名称:该形式与以下描述一样简单:使用哈希函数将密钥转换为数字,例如,使用CRC32哈希函数。在键foobar上执行CRC32(foobar)将输出一个类似于93024922的整数。取这个整数的模并将其转换为0到3之间的数字,然后这个整数可以映射到四个redis实例之一。93024922%4=2,这意味着键foobar应该保存在R2实例中。注:模运算是除法的余数,在许多编程语言中通常由%运算符实现。