1.集群与分布式的概述
1.1 分布式
分布式是指将不同的业务分布在不同的地方. web应用和数据库服务分开
1.2. 集群
集群指的是将多台服务器集中在一起,实现同一业务。 数据库集群和应用集群和功能集群
- 两大关键特性
- ①可扩展性--集群的性能不限于单一的服务实体,新的服务实体可以动态地加入到集群,从而增强集群的性能。动态添加服务器
- ②高可用性--集群通过服务实体冗余使客户端免于轻易遇到out of service的警告。在集群中,同样的服务可以由多个服务实体提供。如果一个服务实体失败了,另一个服务实体会接管失败的服务实体。集群提供的从一个出错的服务实体恢复到另一个服务实体的功能增强了应用的可用性
当访问的服务器挂了时,集群要有能力找可以正常使用额服务器继续提供服务器。
- 两大能力
为了具有可扩展性和高可用性特点,集群的必须具备以下两大能力- ①负载均衡--负载均衡能把任务比较均衡地分布到集群环境下的计算和网络资源。
- ②错误恢复--由于某种原因,执行某个任务的资源出现故障,另一服务实体中执行同一任务的资源接着完成任务。这种由于一个实体中的资源不能工作,另一个实体中的资源透明的继续完成任务的过程叫错误恢复。
当访问的服务器挂了时,集群要有能力找可以正常使用额服务器继续提供服务器。
负载均衡和错误恢复都要求各服务实体中有执行同一任务的资源存在,而且对于同一任务的各个资源来说,执行任务所需的信息视图(信息上下文)必须是一样的
-
分布式和集群相同点和不同点
- 相同点:都是处理高并发,而且都需要多台服务器协同.一把在一个系统中同时存在分布式和集群.
- 不同点:分布式中不同服务器处理是不同业务.而集群处理时同一业务.
2.Redis集群方案选择
2.1为什么redis要做集群?
- 防止单点故障
- 处理高并发-太多请求一台服务器搞不定
- 处理大量数据-太多内存数据一台服务器搞不定
2.2方案一:主从复制
- 原理
- 从服务器连接主服务器,发送SYNC命令;
- 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
- 主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
- 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
- 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
- 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;(从服务器初始化完成)
- 主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令(从服务器初始化完成后的操作)
简单总结:主从同步,读写分离,主备切换.
- 优点
- 为了分载Master(主)的读操作压力,Slave(从)服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成
- Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。
- Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。
- Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据
简单总结:支持主从复制,主机会自动将数据同步到从机,可以进行读写分离
- 缺点
- Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
- 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
- Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。
- 简单总结:只解决了高并发
2.3方案二:哨兵模式
- 简单介绍
当主服务器中断服务后,可以将一个从服务器升级为主服务器,以便继续提供服务,但是这个过程需要人工手动来操作。 为此,Redis2.8中提供了哨兵工具来实现自动化的系统监控和故障恢复功能。 - 作用
哨兵的作用就是监控Redis系统的运行状况。它的功能包括以下两个。- (1)监控主服务器和从服务器是否正常运行。
- (2)主服务器出现故障时自动将从服务器转换为主服务器。
- 哨兵的工作方式
- 每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。
- 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN)
- 如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态
- 当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)
- 在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。
- 当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
- 若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。
- 哨兵模式的优缺点
- 优点:哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有。主从可以自动切换,系统更健壮,可用性更高。
- 缺点:Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂
- 简单总结:只解决了单点故障和高并发!
2.4方案三:Redis-Cluster集群(采纳)
- 简单引入
- redis的哨兵模式基本已经可以实现高可用,读写分离 ,但是在这种模式下每台redis服务器都存储相同的数据,很浪费内存,所以在redis3.0上加入了cluster模式,实现的redis的分布式存储,也就是说每台redis节点上存储不同的内容。
- Redis-Cluster采用无中心结构,它的特点如下:
- a.所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
- b.节点的fail是通过集群中超过半数的节点检测失效时才生效。
- c.客户端与redis节点直连,不需要中间代理层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
- d.在redis的每一个节点上,都有这么两个东西,一个是插槽(slot),它的的取值范围是:0-16383。还有一个就是cluster,可以理解为是一个集群管理的插件。当我们的存取的key到达的时候,redis会根据crc16的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
- e.为了保证高可用,redis-cluster集群引入了主从模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。当其它主节点ping一个主节点A时,如果半数以上的主节点与A通信超时,那么认为主节点A宕机了。如果主节点A和它的从节点A1都宕机了,那么该集群就无法再提供服务了。
- Redis-Cluster介绍
- 1)为何要搭建Redis集群?
- Redis是在内存中保存数据的,而我们的电脑一般内存都不大,这也就意味着Redis不适合存储大数据,适合存储大数据的是Hadoop生态系统的Hbase或者是MogoDB。Redis更适合处理高并发,一台设备的存储能力是很有限的,但是多台设备协同合作,就可以让内存增大很多倍,这就需要用到集群。
- Redis集群搭建的方式有多种,例如使用客户端分片、Twemproxy、Codis等,但从redis 3.0之后版本支持redis-cluster集群,它是Redis官方提出的解决方案,Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。
- 所有的 redis 节点彼此互联(PING-PONG 机制),内部使用二进制协议优化传输速度和带宽.
- 2)分布存储机制-槽
- redis-cluster 把所有的物理节点映射到[0-16383]slot上,cluster 负责维护。node<->slot<->value
- Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。
- 3)容错机制-投票
- 选举过程是集群中所有master参与,如果半数以上master节点与故障节点通信超过(cluster-node-timeout),认为该节点故障,自动触发故障转移操。故障节点对应的从节点自动升级为主节
- 什么时候整个集群不可用(cluster_state:fail)?。如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成集群的slot映射[0-16383]不完成时进入fail状态.
- 1)为何要搭建Redis集群?
3.集群环境搭建
3.1准备
- redis3.2
需要 6 台 redis 服务器。搭建伪集群。
需要 6 个 redis 实例。
需要运行在不同的端口 6379-6384 - Ruby语言运行环境
需要使用ruby脚本来实现集群搭建 - RubyGems简称gems,是一个用于对 Ruby组件进行打包的 Ruby 打包系统
- Redis的Ruby驱动redis-xxxx.gem
- 创建Redis集群的工具redis-trib.rb
3.2安装和配置redis
- redis下载地址:https://github.com/MicrosoftArchive/redis/releases
- 要让集群正常运作至少需要3个主节点,建议配置3个主节点,其余3个作为各个主节点的从节点(也是官网推荐的模式)。 同一台电脑,不同端口模拟
所以需要6台虚拟机。主节点崩溃,从节点的Redis就会提升为主节点,代替原来的主节点工作,崩溃的主Redis恢复工作后,会再成为从节点。
3.3创建Redis集群目录
把下载的redis压缩包解压后,再复制出5份,配置 三主三从集群。由于redis默认端口号为6379,那么其它5份的端口可以为6380,6381,6382,6383,6384。并且把目录使用端口号命名
3.4修改配置文件
打开每个Redis目录下的文件redis.windows.conf,修改里面的配置
- 端口号分别对应相对应的文件夹名:6379、6380、6381、6382、6383、6384
- cluster-config-file nodes-6379.conf
- cluster-enabled yes
- cluster-node-timeout 15000
- appendonly yes
cluster-config-file nodes-6379.conf 是为该节点的配置信息,这里使用 nodes-端口.conf命名方法。服务启动后会在目录生成该文件。
3.5编写启动脚本,或者进入每个端口命名的文件夹下启动服务,方便启动
编写一个 bat 来启动 redis,在每个节点目录下建立 startup.bat,内容如下:
title redis-6379
redis-server.exe redis.windows.conf
title命名规则 redis-相对应的端口。
3.6安装Ruby
- redis的集群使用 ruby脚本编写,所以系统需要有 Ruby 环境。
- 下载地址:https://rubyinstaller.org/downloads/
- 安装时3个选项都勾选。
3.7安装Redis的Ruby驱动redis-xxxx.gem
下载地址:https://rubygems.org/pages/download
- 下载后解压,当前目录切换到解压目录中,进入到setup.rb所在的目录,打开黑窗口,然后命令行执行 ruby setup.rb
- 再用 GEM 安装Redis:切换到redis安装目录,需要在命令行中,执行 gem install redis
3.8启动每个节点并且执行集群构建脚本
- 点击每个节点start.bat进行启动
- 拷贝redis-trib.rb到redis节点
- 执行命令
redis-trib.rb create --replicas 1 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 127.0.0.1:6385 - 在出现 Can I set the above configuration? (type 'yes' to accept): 请确定并输入 yes 。
- 注意事项:
- 1)现在是windows搭建的,以后再linux.只是redis安装与启动不一样其他都是一样的.
- 2)5.0以上版本兼容
如果出现 redis-trib.rb is not longer available! 如果redis版本是5.0以上,则使用如下命令: - 3)redis-cli --cluster create 127.0.0.1:6380 127.0.0.1:6381 12 1:6382 127.0.0.1:6383 127.0.0.1:6384 127.0.0.1:6385 --cluster-replicas 1
- 4)原因是redis5.0以上不再需要redis-trib.rb了,而是使用自带的redis-cli作为创建集群的命令了。
4.集群环境测试
4.1 命令测试
- 使用Redis客户端Redis-cli.exe来查看数据记录数,以及集群相关信息
- 命令:redis-cli.exe –c –h ip地址 –p 端口号
- 注意:c 表示集群
- 查看集群的信息,命令:cluster info
- 命令:info replication
- 主:命令那里会显示role:master
- 从:命令那里会显示role:slave
- 查看各个节点分配slot,命令 cluster nodes
- 存值测试
- set test 123
- 存值工作原理解析
- 以6380节点为例,管理的slots为5461-10922,key为test的slot为6918,显然命中6380管理的卡槽6918,所以客户端也跳转到了6380。key为test1的slot为4768,在6379的卡槽范围0-5460,所以客户端又跳转到了6379。
- Redis集群数据分配策略:采用一种叫做哈希槽 (hash slot)的方式来分配数据,redis cluster 默认分配了 16384 个slot,当我们set一个key 时,会用CRC16算法来取模得到所属的slot,然后将这个key分到哈希槽区间的节点上,具体算法就是:CRC16(key) % 16384
- 注意:必须要3个以上的主节点,否则在创建集群时会失败,三个节点分别承担的slot 区间是:
- 节点A覆盖0-5460;
- 节点B覆盖5461-10922;
- 节点C覆盖10923-16383.
4.2 jedis代码测试
package cn.wangningbo.redis.client.jedis;
import org.junit.Test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
public class JedisClusterTest {
@Test
public void testCluster() throws IOException, InterruptedException {
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("127.0.0.1", 6380));
nodes.add(new HostAndPort("127.0.0.1", 6381));
nodes.add(new HostAndPort("127.0.0.1", 6382));
nodes.add(new HostAndPort("127.0.0.1", 6383));
nodes.add(new HostAndPort("127.0.0.1", 6384));
nodes.add(new HostAndPort("127.0.0.1", 6385));
JedisCluster cluster = new JedisCluster(nodes);
try {
String res = cluster.get("test");
System.out.println(res);
} catch (Exception e) {
e.printStackTrace();
}
}
}
5.面试题
- 简单说一下你对分布式理解?
分布式是指将不同的业务分布在不同的地方 - 简单说一下你对集群理解?
集群指的是将多台服务器集中在一起,实现同一业务。 - 说一下分布式和集群联系和区别。
- 相同点:都是处理高并发,而且都需要多台服务器协同.一把在一个系统中同时存在分布式和集群.
- 不同点:分布式中不同服务器处理是不同业务.而集群处理时同一业务.
- redis集群方式有哪些?
- 1)主从复制
- 2)哨兵模式
- 3)Redis-Cluster集群(采纳)
- 简单说一下redis-cluster里面槽?
槽是存放数据,存放是要通过key计算槽位,选择对应的服务器来存储,获取也是同样的算法.
默认16384个槽位要均匀分布到主节点上面
为了槽里面数据安全要对主节点进行1-N从节点备份 - 简单说一下redis-cluster里面选举投票机制
所有主节点都参与投票,默认半数以上挂点,启动容错机制,提升从节点为主节点. - 怎么通过命令连接redis集群?
-c是关键!c表示集群。例如:redis-cli.exe –c –h ip地址 –p 端口号 - 怎么通过jedis连接集群
使用Set,如下代码
@Test
public void testCluster() throws IOException, InterruptedException {
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("127.0.0.1", 6380));
nodes.add(new HostAndPort("127.0.0.1", 6381));
nodes.add(new HostAndPort("127.0.0.1", 6382));
nodes.add(new HostAndPort("127.0.0.1", 6383));
nodes.add(new HostAndPort("127.0.0.1", 6384));
nodes.add(new HostAndPort("127.0.0.1", 6385));
JedisCluster cluster = new JedisCluster(nodes);
try {
String res = cluster.get("test");
System.out.println(res);
} catch (Exception e) {
e.printStackTrace();
}
}