关闭

Redis Cluster学习笔记

220人阅读 评论(0) 收藏 举报
分类:

Redis在3.0版正式引入了集群这个特性。Redis集群是一个分布式(distributed)、容错(fault-tolerant)的 Redis内存K/V服务, 集群可以使用的功能是普通单机 Redis 所能使用的功能的一个子集(subset),比如Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误。

Redis集群的几个重要特征:

(1).Redis 集群的分片特征在于将键空间分拆了16384个槽位,每一个节点负责其中一些槽位。

(2).Redis提供一定程度的可用性,可以在某个节点宕机或者不可达的情况下继续处理命令.

(3).Redis 集群中不存在中心(central)节点或者代理(proxy)节点, 集群的其中一个主要设计目标是达到线性可扩展性(linear scalability)。

1. Redis的数据分片(Sharding)

Redis 集群的键空间被分割为 16384 (2^14)个槽(slot), 集群的最大节点数量也是 16384 个(推荐的最大节点数量为 1000 个),同理每个主节点可以负责处理1到16384个槽位。

当16384个槽位都有主节点负责处理时,集群进入”稳定“上线状态,可以开始处理数据命令。当集群没有处理稳定状态时,可以通过执行重配置(reconfiguration)操作,使得每个哈希槽都只由一个节点进行处理。

重配置指的是将某个/某些槽从一个节点移动到另一个节点。一个主节点可以有任意多个从节点, 这些从节点用于在主节点发生网络断线或者节点失效时, 对主节点进行替换。

集群的使用公式CRC16(Key)&16383计算key属于哪个槽:

HASH_SLOT = CRC16(key) mod 16384

CRC16其结果长度为16位。

2. Redis集群节点

部分内容摘自附录2。Redis 集群中的节点不仅要记录键和值的映射,还需要记录集群的状态,包括键到正确节点的映射。它还具有自动发现其他节点,识别工作不正常的节点,并在有需要时,在从节点中选举出新的主节点的功能。

为了执行以上列出的任务, 集群中的每个节点都与其他节点建立起了“集群连接(cluster bus)”, 该连接是一个 TCP 连接, 使用二进制协议进行通讯。

节点之间使用 Gossip 协议 来进行以下工作:

a).传播(propagate)关于集群的信息,以此来发现新的节点。

b).向其他节点发送 PING 数据包,以此来检查目标节点是否正常运作。

c).在特定事件发生时,发送集群信息。

除此之外, 集群连接还用于在集群中发布或订阅信息。

集群节点不能前端代理命令请求, 所以客户端应该在节点返回 -MOVED或者 -ASK转向(redirection)错误时, 自行将命令请求转发至其他节点。

客户端可以自由地向集群中的任何一个节点发送命令请求, 并可以在有需要时, 根据转向错误所提供的信息, 将命令转发至正确的节点, 所以在理论上来说, 客户端是无须保存集群状态信息的。但如果客户端可以将键和节点之间的映射信息保存起来, 可以有效地减少可能出现的转向次数, 籍此提升命令执行的效率。

每个节点在集群中由一个独一无二的 ID标识, 该 ID 是一个十六进制表示的 160 位随机数,在节点第一次启动时由 /dev/urandom 生成。节点会将它的 ID 保存到配置文件, 只要这个配置文件不被删除, 节点就会一直沿用这个 ID 。一个节点可以改变它的 IP 和端口号, 而不改变节点 ID 。 集群可以自动识别出IP/端口号的变化, 并将这一信息通过 Gossip协议广播给其他节点知道。

下面是每个节点都有的关联信息, 并且节点会将这些信息发送给其他节点:

a).节点所使用的 IP 地址和 TCP 端口号。

b).节点的标志(flags)。

c).节点负责处理的哈希槽。

b).节点最近一次使用集群连接发送 PING 数据包(packet)的时间。

e).节点最近一次在回复中接收到 PONG 数据包的时间。

f).集群将该节点标记为下线的时间。

g).该节点的从节点数量。

如果该节点是从节点的话,那么它会记录主节点的节点 ID 。 如果这是一个主节点的话,那么主节点 ID 这一栏的值为 0000000。

在了解Redis Cluster的集群基本特征后,我们首先搭建出这个Redis Cluster集群。

3. 安装Redis 3.0.x

当前最新版为3.0.1

wget http://download.redis.io/releases/redis-3.0.1.tar.gz
tar xvzf redis-3.0.1.tar.gz
cd redis-3.0.1/
make -j
#apt-get install tcl
make test
###将redis安装到/usr/local/redis3上
#cd src && make PREFIX=/usr/local/redis3 install
###创建符号链接
 #ls /usr/local/redis3/bin/redis-*
/usr/local/redis3/bin/redis-benchmark  /usr/local/redis3/bin/redis-check-dump  /usr/local/redis3/bin/redis-sentinel
/usr/local/redis3/bin/redis-check-aof  /usr/local/redis3/bin/redis-cli         /usr/local/redis3/bin/redis-server
#for i in `cd /usr/local/redis3/bin; ls redis-*`
do
ln -s /usr/local/redis3/bin/$i /usr/local/bin/$i
done;
#mkdir -p /usr/local/redis3/conf
#ln -sf /usr/local/redis3/conf /etc/redis3
###检查版本信息
redis-cli -v
redis-cli 3.0.1

4. Redis Cluster配置

运行在集群模式的Redis实例与普通的Redis实例有所不同,集群模式需要通过配置启用cluster特性,开启集群模式后的Redis实例便可以使用集群特有的命令和特性了.下面是一个最少选项的集群的配置文件 : 注意如果使用的是单机测试,最好把cluster-config-file nodes.conf设置为对应的 端口 nodes-xxx.conf,还有就是 pid 设置为当前 目录下 pidfile ./redis.pid

port 7001
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

文件中的 cluster-enabled 选项用于开实例的集群模式, 而 cluster-conf-file 选项则设定了保存节点配置文件的路径, 默认值为 nodes.conf。该节点配置文件无须人为修改,它由Redis集群在启动时自动创建, 并在有需要时自动进行更新。

若要让集群正常运作至少需要三个主节点,我们的环境中,每个主节点附带一个从节点,所以一共六个节点。端口为7001-7006。

在/app/redis3, 并创建六个以端口号为名字的子目录, 稍后我们在将每个目录中运行一个 Redis 实例:

cd /app/redis3
mkdir 7001 7002 7003 7004 7005 7006
 cp /etc/redis3/conf/redis.conf  /app/redis3/7001/
......
cp /etc/redis3/conf/redis.conf  /app/redis3/7006/

将redis.conf里的端口号修改为对应的端口。下面我们打开对应的目录,启动redis实例即可,启动的时候要进入到对应的目录然后启动。

cd /app/redis3/7001;nohup redis-server redis.conf &
cd /app/redis3/7002;nohup redis-server redis.conf &
......

实例打印的日志显示, 因为 nodes.conf 文件不存在, 所以每个节点都为它自身指定了一个新的 ID ,

/app/redis3/7006# tail -f nohup.out
27040:M 09 May 22:53:50.197 * No cluster configuration found, I'm 1984c27297c6ef50bbfcbd35c11b93cc40ba17e4
/app/redis3/7006# cat nodes.conf 
d2b437ca8b9007dcdb63ac16210f6540860361e3 :0 myself,master - 0 0 0 connected
vars currentEpoch 0 lastVoteEpoch 0

现在我们已经有了六个正在运行中的 Redis 实例, 接下来我们需要使用这些实例来创建集群。通过使用 Redis 集群命令行工具 redis-trib , 编写节点配置文件的工作可以非常容易地完成: redis-trib 位于 Redis 源码的 src 文件夹中, 它是一个 Ruby 程序, 这个程序通过向实例发送特殊命令来完成创建新集群, 检查集群, 或者对集群进行重新分片(reshared)等工作。这里通过create命令来创建集群,指定replicas=1,即每一个主实例有一个从实例。redis-trib 会打印出一份预想中的配置给你看, 如果你觉得没问题的话, 就可以输入 yes , redis-trib 就会将这份配置应用到集群当中,让各个节点开始互相通讯,最后可以得到如下信息

~/redis-3.0.1/src# apt-get install ruby gem
~/redis-3.0.1/src# gem sources -a http://ruby.taobao.org/
~/redis-3.0.1/src# gem install redis
~/redis-3.0.1/src# cp redis-trib.rb /usr/local/redis3/bin/
~/redis-3.0.1/src# ln -sf /usr/local/redis3/bin/redis-trib.rb /usr/bin/redis-trib.rb
~/redis-3.0.1/src# redis-trib.rb create --replicas 1  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 127.0.0.1:7006
M: 1984c27297c6ef50bbfcbd35c11b93cc40ba17e4 127.0.0.1:7001
   slots:0-5460 (5461 slots) master
M: 481e256be4c724f5a2c64a761e52b4be61ca45b4 127.0.0.1:7002
   slots:5461-10922 (5462 slots) master
M: b5b652fa02d9999861e66c843b01fd2700c02adf 127.0.0.1:7003
   slots:10923-16383 (5461 slots) master
S: 821ec823dc0c2d4f65319e84fe74157fb1014155 127.0.0.1:7004
   replicates 1984c27297c6ef50bbfcbd35c11b93cc40ba17e4
S: b3b8541b9520d707180d56a2fb3cf3ee6895ed10 127.0.0.1:7005
   replicates 481e256be4c724f5a2c64a761e52b4be61ca45b4
S: d2b437ca8b9007dcdb63ac16210f6540860361e3 127.0.0.1:7006
   replicates b5b652fa02d9999861e66c843b01fd2700c02adf
Can I set the above configuration? (type 'yes' to accept):
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

以上信息的其中一部分可以通过向集群中的任意节点(主节点或者从节点都可以)发送 CLUSTER NODES 命令来获得。该命令还可以获得节点 ID , IP 地址和端口号, 标志(flag), 最后发送 PING 的时间, 最后接收 PONG 的时间, 连接状态, 节点负责处理的槽。

redis-cli -p 7001 cluster nodes
481e256be4c724f5a2c64a761e52b4be61ca45b4 127.0.0.1:7002 master - 0 1431186119174 2 connected 5461-10922
b3b8541b9520d707180d56a2fb3cf3ee6895ed10 127.0.0.1:7005 slave 481e256be4c724f5a2c64a761e52b4be61ca45b4 0 1431186120677 5 connected
d2b437ca8b9007dcdb63ac16210f6540860361e3 127.0.0.1:7006 slave b5b652fa02d9999861e66c843b01fd2700c02adf 0 1431186119174 6 connected
b5b652fa02d9999861e66c843b01fd2700c02adf 127.0.0.1:7003 master - 0 1431186118673 3 connected 10923-16383
821ec823dc0c2d4f65319e84fe74157fb1014155 127.0.0.1:7004 slave 1984c27297c6ef50bbfcbd35c11b93cc40ba17e4 0 1431186120176 4 connected
1984c27297c6ef50bbfcbd35c11b93cc40ba17e4 127.0.0.1:7001 myself,master - 0 0 1 connected 0-5460

5. 连接Redis集群

通过上面的输出,我们可以看出Redis三个主节点的slot范围。一个 Redis 客户端可以向集群中的任意节点(包括从节点)发送命令请求。我们首先连接第一个节点:

redis-cli -p 7001
127.0.0.1:7001> set a 1 
(error) MOVED 15495 127.0.0.1:7003
127.0.0.1:7001> get a
(error) MOVED 15495 127.0.0.1:7003
127.0.0.1:7001> set b 1
OK

节点会对命令请求进行分析和key的slot计算,并且会查找这个命令所要处理的键所在的槽。如果要查找的哈希槽正好就由接收到命令的节点负责处理, 那么节点就直接执行这个命令。

另一方面, 如果所查找的槽不是由该节点处理的话, 节点将查看自身内部所保存的哈希槽到节点 ID 的映射记录, 并向客户端回复一个 MOVED 错误。上面的错误信息包含键 x 所属的哈希槽15495, 以及负责处理这个槽的节点的 IP 和端口号 127.0.0.1:7003 。

虽然我们用Node ID来标识集群中的节点, 但是为了让客户端的转向操作尽可能地简单, 节点在 MOVED 错误中直接返回目标节点的 IP 和端口号, 而不是目标节点的 ID 。客户端应该记录槽15495由节点127.0.0.1:7003负责处理“这一信息, 这样当再次有命令需要对槽15495执行时, 客户端就可以加快寻找正确节点的速度。这样,当集群处于稳定状态时,所有客户端最终都会保存有一个哈希槽至节点的映射记录,使得集群非常高效: 客户端可以直接向正确的节点发送命令请求, 无须转向、代理或者其他任何可能发生单点故障(single point failure)的实体(entiy)。


6.java 连接Redis集群

使用 jedis-2.7.2.jar jar 包

import java.util.HashSet;
import java.util.Set;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;

public class JedisClusterTest {

	public static void main(String[] args) {

		JedisPoolConfig config = new JedisPoolConfig();
		config.setMaxTotal(20);
		config.setMaxIdle(2);

		HostAndPort hp0 = new HostAndPort("localhost", 7000);
		HostAndPort hp1 = new HostAndPort("localhost", 7001);
		HostAndPort hp2 = new HostAndPort("localhost", 7002);
		HostAndPort hp3 = new HostAndPort("localhost", 7003);
		HostAndPort hp4 = new HostAndPort("localhost", 7004);
		HostAndPort hp5 = new HostAndPort("localhost", 7005);

		Set<HostAndPort> hps = new HashSet<HostAndPort>();
		hps.add(hp0);
		hps.add(hp1);
		hps.add(hp2);
		hps.add(hp3);
		hps.add(hp4);
		hps.add(hp5);

		// 超时,最大的转发数,最大链接数,最小链接数都会影响到集群
		JedisCluster jedisCluster = new JedisCluster(hps, 5000, 10, config);

		long start = System.currentTimeMillis();
		for (int i = 0; i < 100; i++) {
			jedisCluster.set("sn" + i, "n" + i);
		}
		long end = System.currentTimeMillis();

		System.out.println("Simple  @ Sharding Set : " + (end - start) / 10000);

		for (int i = 0; i < 1000; i++) {
			System.out.println(jedisCluster.get("sn" + i));
		}

		jedisCluster.close();

	}

}

7.java 连接Redis集群常见错误


7.1.Too many Cluster redirections
这种情况一般情况下都是 redis 绑定ip问题,默认情况下 redis 绑定的 ip 是本机的 127.0.0.1 如果redis 部署在其他机器上,而本地测试程序想要通过网络链接到 redis 集群,那么就需要注意,在 redis.conf 文件中配置 bind xxx.xxx.xxx.xxx 注意这个地方要配置成客户端链接的 ip

注意:如果 redis 绑定了指定的 ip 地址了,这时候在启动集群的时候也需要注意,需要指定ip地址了,本来启动集群的方式是这样的:
./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-trib.rb create --replicas 1 xxx.xxx.xxx.xxx:7000  xxx.xxx.xxx.xxx:7001 xxx.xxx.xxx.xxx:7002 xxx.xxx.xxx.xxx:7003 xxx.xxx.xxx.xxx:7004 xxx.xxx.xxx.xxx:7005./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


原文地址:http://blog.csdn.net/tengdazhang770960436/article/details/49925031

0
0
查看评论

Redis Essentials 读书笔记 - 第九章: Redis Cluster and Redis Sentinel (Collective Intelligence)

Chapter 9. Redis Cluster and Redis Sentinel (Collective Intelligence)上一章介绍了复制,一个master可以对应一个或多个slave(replica), 在以下的情况下是够用的: 1. master有足够内存容纳所有key 2....
  • stevensxiao
  • stevensxiao
  • 2016-05-09 14:12
  • 1961

redis sentinel & cluster 原理分析

1. Redis集群实现分析 1.1  sentinel 1.   功能 Sentinel实现如下功能: (1)monitoring——redis实例是否正常运行。 (2)notification——通知application错误信息。 (3)f...
  • bubayimao
  • bubayimao
  • 2015-09-29 11:10
  • 3014

唯品会大规模 Redis Cluster 的生产实践

分享大纲 本次分享内容如下: 1、生产应用场景 2、存储架构演变 3、应用最佳实践 4、运维经验总结 关于这4部分的内容介绍: 第1、2部分:介绍redis cluster在唯品会的生产应用场景,以及存储架构的演变。第3部分:redis cluster的稳定性,应用成熟度,踩到过那...
  • yubinpll9110
  • yubinpll9110
  • 2016-06-07 14:58
  • 1237

Redis 学习笔记(十四)Redis Cluster介绍与搭建

Redis Cluster 介绍与搭建1. Redis Cluster介绍Redis Cluster是Redis的分布式解决方案,在Redis 3.0版本正式推出的,有效解决了Redis分布式方面的需求。当遇到单机内存、并发、流量等瓶颈时,可以采用Cluster架构达到负载均衡的目的。1.1 数据分...
  • men_wen
  • men_wen
  • 2017-06-03 16:58
  • 3686

解决spring4连接redis集群报错:CLUSTERDOWN The cluster is down

原因是redis出错了。解决方法如下: 1、使用命令检查REDIS状态: /java/redis/redis7000/src/redis-trib.rb check 192.168.249.230:7000 [ERR] Nodes don't agree about confi...
  • yong472727322
  • yong472727322
  • 2017-08-08 14:27
  • 3727

redis cluster--简介

redis3.0是redis cluster版本。
  • whycold
  • whycold
  • 2015-01-10 20:53
  • 2421

Redis原理(Replication、Sentinel、Twemproxy、RedisCluster)

主要分析Redis的主从复制原理、Sentinel实现主从切换原理、Twemproxy数据分片原理、RedisCluster负载均衡与主从切换原理。
  • xmj_csdn
  • xmj_csdn
  • 2017-07-10 09:54
  • 298

Redis高可用-Cluster-测试

I.高可用测试 II.关闭所有节点 ps -ef|grep redis  kill -9 888   II.删除 cd /usr/local/redis3/cluster/7111/ -rw-r--r--. 1 root root 352415 3月 ...
  • dingsai88
  • dingsai88
  • 2016-03-29 15:46
  • 1757

Redis Cluster架构优化

Redis Cluster架构优化在《全面剖析Redis Cluster原理和应用》中,我们已经详细剖析了现阶段Redis Cluster的缺点: 无中心化架构 Gossip消息的开销 不停机升级困难 无法根据统计区分冷热数据 客户端的挑战 Cluster协议支持 连接和路由表的维护开销 Mul...
  • dc_726
  • dc_726
  • 2015-09-25 15:01
  • 18403

Redis Cluster 实现细节

Redis Cluster 实现 本文将从设计思路,功能实现,源码几个方面介绍Redis Cluster。假设读者已经了解Redis Cluster的使用方式。 简介 Redis Cluster作为Redis的分布式实现,主要做了两个方面的事情: 1,数据分片 Redi...
  • lambert310
  • lambert310
  • 2016-05-13 18:06
  • 2549
    个人资料
    • 访问:382684次
    • 积分:5267
    • 等级:
    • 排名:第6172名
    • 原创:42篇
    • 转载:723篇
    • 译文:0篇
    • 评论:14条
    最新评论