redis主从:可以一主多从,redis主服务器负责读写,从服务器只负责读。master写入完成后会将指令发给slave服务器,这个过程是异步的,slave服务器根据指令写入,所以存在读取数据延迟的问题。
哨兵 :redis主从配置好后,主节点挂掉后,哨兵模式会自动将从节点升级为主节点,它主要实现的是主从切换的功能
集群:集群+主从适用大规模的数据场景。哨兵+主从适用小规模数据场景。集群主要是高并发,哨兵是高可用,集群不会用到哨兵,集群的主从切换有自己的方式。
redis单机与集群的客户端区别:
以代码区分
单机
public void testJedisPool() throws Exception {
// 第一步:创建一个JedisPool对象。需要指定服务端的ip及端口。
JedisPool jedisPool = new JedisPool("192.168.25.153", 6379);
// 第二步:从JedisPool中获得Jedis对象。
Jedis jedis = jedisPool.getResource();
// 第三步:使用Jedis操作redis服务器。
jedis.set("a", "1");
String result = jedis.get("a");
System.out.println(result);
// 第四步:操作完毕后关闭jedis对象,连接池回收资源。
jedis.close();
// 第五步:关闭JedisPool对象。
jedisPool.close();
}
集群
public void testJedisCluster() throws Exception {
// 第一步:使用JedisCluster对象。需要一个Set参数。Redis节点的列表。
Set nodes = new HashSet<>();
nodes.add(new HostAndPort("192.168.00.000", 7001));
nodes.add(new HostAndPort("192.168.00.000", 7002));
nodes.add(new HostAndPort("192.168.00.000", 7003));
nodes.add(new HostAndPort("192.168.00.000", 7004));
nodes.add(new HostAndPort("192.168.00.000", 7005));
nodes.add(new HostAndPort("192.168.00.000", 7006));
JedisCluster jedisCluster = new JedisCluster(nodes);
// 第二步:直接使用JedisCluster对象操作redis。在系统中单例存在。
jedisCluster.set("a", "1");
String result = jedisCluster.get("a");
// 第三步:打印结果
System.out.println(result);
// 第四步:系统关闭前,关闭JedisCluster对象。
jedisCluster.close();
}
哨兵客户端连接更为复杂,请查看其他专业资料。
redis为何用到线程池?
redis为了防止网络链接造成的开销,维护了一个线程池,客户端与redis保持长链接,避免频繁创建断开链接
下面讲解,主从+哨兵的搭建配置,笔者以一台win7电脑为例,搭建一主二从三哨兵
首先 下载window版的redis,解压缩
复制6份这样的文件
先搭建主从:
修改 redis_master/redis.windows.conf
bind 10.112.11.186
port 6380
#如果不配置哨兵,并且没有设置连接密码,那么这个属性一定要设置no,这是redis的安全模式,默认是yes,即开启状态,如果你没有设置密码,那么你用redis的客户端(如jedis)是无法访问redis的)。报错信息如下:
Cannot get master address from sentinel running @ 10.112.11.186:26381
protected-mode no
从服务器只需要修改自己的地址和端口,在增加一个配置
slaveof 10.112.11.186
#(设置master 的连接ip和port)
启动三个节点
redis-server.exe redis.window.conf
下面搭建哨兵,新建配置文件sentinel.conf,内容如下
port 26381
daemonize yes
protected-mode no
sentinel monitor master 192.168.9.103 6380 2
sentinel down-after-milliseconds master 3000
sentinel failover-timeout master 10000
着重修改两个地方
port:哨兵监听的端口号
sentinel monitor master :哨兵监听的主节点,最后数字2代表几个哨兵同意才能切换主从
启动三个哨兵
redis-server.exe sentinel.conf --Sentinel
哨兵最好有三个,如果只有一个哨兵会出现主观下线,就是主节点与哨兵可能因为短暂的网路波动,哨兵误判主节点down掉。
自此搭建完成。
下面我们来杂谈一些额外的东西
linux下配置主从复制的方式有以下三种:
1)在配置文件中加入slaveof{masterHost}{masterPort}随Redis启动生效。
2)在redis-server启动命令后加入--slaveof{masterHost}{masterPort}生效。
3)直接使用命令:slaveof{masterHost}{masterPort}生效。
在从节点执行slaveof命令后,复制过程便开始运作,下面详细介绍建立
大致分为6个过程:
1.保存主节点(master)信息。
2.从节点(slave)内部通过每秒运行的定时任务维护复制相关逻辑,当定时任务发现存在新的主节点后,会尝试与该节点建立网络连接
3.发送ping命令。
连接建立成功后从节点发送ping请求进行首次通信,ping请求主要目的
·检测主从之间网络套接字是否可用。
·检测主节点当前是否可接受处理命令。
如果发送ping命令后,从节点没有收到主节点的pong回复或者超时,比如网络超时或者主节点正在阻塞无法响应命令,从节点会断开复制连接,下次定时任务会发起重连
4.权限验证。如果主节点设置了requirepass参数,则需要密码验证,从节点必须配置masterauth参数保证与主节点相同的密码才能通过验证;如果验证失败复制将终止,从节点重新发起复制流程。
5.同步数据集。主从复制连接正常通信后,对于首次建立复制的场景,主节点会把持有的数据全部发送给从节点,这部分操作是耗时最长的步骤。Redis在2.8版本以后采用新复制命令psync进行数据同步,原来的sync命令依然支持,保证新旧版本的兼容性。新版同步划分两种情况:全量同步和部分同步。
6.命令持续复制。当主节点把当前的数据同步给从节点后,便完成了复制的建立流程。接下来主节点会持续地把写命令发送给从节点,保证主从数据一致性。
主从复制的原理,先明确两个概念:
1.复制偏移量:节点在处理完写入命令后,会把命令的字节长度做累加记录。一个字节的总的长度叫做复制偏移量。主节点会保存自己的和从节点上报的偏移量。从节点也会保存自己的偏移量。通过对比主从节点的复制偏移量,可以判断主从节点数据是否一致
2.复制积压缓冲区:由于缓冲区本质上是先进先出的定长队列,所以能实现保存最近已复制数据的功能,用于部分复制和复制命令丢失的数据补救,复制积压缓冲区的功能如下
从节点使用psync命令完成部分复制和全量复制功能,命令格式:
psync{runId}{offset},参数含义如下:
runId:从节点所复制主节点的运行id。
offset:当前从节点已复制的数据偏移量。
流程说明:
1)从节点(slave)发送psync命令给主节点,参数runId是当前从节点保存的主节点运行ID,如果没有则默认值为,参数offset是当前从节点保存的复制偏移量,如果是第一次参与复制则默认值为-1。
2)主节点(master)根据psync参数和自身数据情况决定响应结果:
·如果回复+FULLRESYNC{runId}{offset},那么从节点将触发全量复制流程。
·如果回复+CONTINUE,从节点将触发部分复制流程。
·如果回复+ERR,说明主节点版本低于Redis2.8,无法识别psync命令,从节点将发送旧版的sync命令触发全量复制流程。
部分复制的流程:
复制积压缓冲区
复制积压缓冲区是由主服务器维护的一个固定长度(fixed-size)先进先出(FIFO)队列,默认大小为1MB。
和普通先进先出队列随着元素的增加和减少而动态调整长度不同,固定长度先进先出队列的长度是固定的,当入队元素的数量大于队列长度时,最先入队的元素会被弹出,而新元素会被放入队列。
当主服务器进行命令传播时,它不仅会将写命令发送给所有从服务器,还会将写命令入队到复制积压缓冲区里面
因此,主服务器的复制积压缓冲区里面会保存着一部分最近传播的写命令,并且复制积压缓冲区会为队列中的每个字节记录相应的复制偏移量,就像下表所示的那样。
当从服务器重新连上主服务器时,从服务器会通过PSYNC命令将自己的复制偏移量offset发送给主服务器,主服务器会根据这个复制偏移量来决定对从服务器执行何种同步操作:
如果offset偏移量之后的数据(也即是偏移量offset+1开始的数据)仍然存在于复制积压缓冲区里面,那么主服务器将对从服务器执行部分重同步操作;
相反,如果offset偏移量之后的数据已经不存在于复制积压缓冲区,那么主服务器将对从服务器执行完整重同步操作(也就是全量复制)。
根据需要调整复制积压缓冲区的大小
Redis为复制积压缓冲区设置的默认大小为1MB,如果主服务器需要执行大量写命令,又或者主从服务器断线后重连接所需的时间比较长,那么这个大小也许并不合适。如果复制积压缓冲区的大小设置得不恰当,那么PSYNC命令的复制重同步模式就不能正常发挥作用,因此,正确估算和设置复制积压缓冲区的大小非常重要。
复制积压缓冲区的最小大小可以根据公式secondwrite_size_per_second来估算:
其中second为从服务器断线后重新连接上主服务器所需的平均时间(以秒计算);
而write_size_per_second则是主服务器平均每秒产生的写命令数据量(协议格式的写命令的长度总和);
例如,如果主服务器平均每秒产生1 MB的写数据,而从服务器断线之后平均要5秒才能重新连接上主服务器,那么复制积压缓冲区的大小就不能低于5MB。
为了安全起见,可以将复制积压缓冲区的大小设为2second*write_size_per_second,这样可以保证绝大部分断线情况都能用部分重同步来处理。