1 Redis集群
1.1 什么是集群
集群就是很多服务器组成的一个网络。指的是将多台服务器集中在一起,实现同一业务。
1.2 为什么要集群
一台服务器不能满足开发需要的时候,需要多台服务器来支持。这个时候就需要做集群,但是集群往往伴随
着分布式。
1.3 集群的特性及能力
1、集群的两大关键特性:
可扩展性----集群的性能不限于单一的服务实体,新的服务实体可以动态地加入到集群,从而增强集群的性能。动态添加服务器
高可用性----集群通过服务实体冗余使客户端免于轻易遇到out of service的警告。在集群中,同样的服务可以由多个服务实体提供。如果一个服务实体失败了,另一个服务实体会接管失败的服务实体。集群提供的从一个出错的服务实体恢复到另一个服务实体的功能增强了应用的可用性
2、集群的两大能力:
负载均衡----负载均衡能把任务比较均衡地分布到集群环境下的计算和网络资源。
错误恢复----由于某种原因,执行某个任务的资源出现故障,另一服务实体中执行同一任务的资源接着完成任务。这种由于一个实体中的资源不能工作,另一个实体中的资源透明的继续完成任务的过程叫错误恢复。
2 分布式
分布式是将不同的业务分布在不同的地方,web应用和数据库服务分开,将不同业务分不到不同的集群。
分布式的特点:
1. 防止单点故障
2. 处理高并发(太多请求,一台服务器搞不定)
3. 处理大量数据(太多内存数据,一台服务器处理不过来)
3 Redis集群的方案
3.1 主从复制
主从同步,读写分离,主备切换。
原理:
- 从服务器连接主服务器,发送SYNC命令;
- 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
- 主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
- 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
- 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
- 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;(从服务器初始化完成)
- 主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令(从服务器初始化完成后的操作)
优点:
- 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离
缺点:
- Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。
- Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
- 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
3.2 哨兵模式
自动化的系统监控和故障恢复功能。
优点:哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有。主从可以自动切换,系统更健壮,可用性更高。
缺点:比较难扩容,服务占用空间比较多
3.3 Redis-Cluster集群
3.3.1 什么是Redis-Cluster
Redis的哨兵模式基本已经可以实现高可用,读写分离 ,但是在这种模式下每台redis服务器都存储相同的数据,很浪费内存,所以在redis3.0上加入了cluster模式,实现的redis的分布式存储,也就是说每台redis节点上存储不同的内容。
为何要搭建Redis集群。Redis是在内存中保存数据的,而我们的电脑一般内存都不大,这也就意味着Redis不适合存储大数据,适合存储大数据的是Hadoop生态系统的Hbase或者是MogoDB。Redis更适合处理高并发,一台设备的存储能力是很有限的,但是多台设备协同合作,就可以让内存增大很多倍,这就需要用到集群。
Redis集群搭建的方式有多种,例如使用客户端分片、Twemproxy、Codis等,但从redis 3.0之后版本支持redis-cluster集群,它是Redis官方提出的解决方案,Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。其redis-cluster架构图如下:
客户端与 redis 节点直连,不需要中间 proxy 层.客户端不需要连接集群所有节点连接集群中任何一个可用节点即可。
所有的 redis 节点彼此互联(PING-PONG 机制),内部使用二进制协议优化传输速度和带宽。
3.3.2 分布存储机制—槽
redis-cluster 把所有的物理节点映射到[0-16383]slot 上,cluster 负责维护。
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。
例如三个节点:槽分布的值如下:
SERVER1: 0-5460
SERVER2: 5461-10922
SERVER3: 10923-16383
3.3.3 容错机制—投票
1)选举过程是集群中所有master参与,如果半数以上master节点与故障节点通信超过(cluster-node-timeout),认为该节点故障,自动触发故障转移操作. 故障节点对应的从节点自动升级为主节点
(2)什么时候整个集群不可用(cluster_state:fail)?
如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成集群的slot映射[0-16383]不完成时进入fail状态。
4 集成环境搭建
4.1 准备工作
(1)Redis 3.2
需要 6 台 redis 服务器。搭建伪集群。
需要 6 个 redis 实例。
需要运行在不同的端口 6379-6384
(2)Ruby语言运行环境 我们需要使用ruby脚本来实现集群搭建
Ruby,一种简单快捷的面向对象(面向对象程序设计)脚本语言,在20世纪90年代由日本人松本行弘(Yukihiro Matsumoto)开发,遵守GPL协议和Ruby License。它的灵感与特性来自于 Perl、Smalltalk、Eiffel、Ada以及 Lisp 语言。由 Ruby 语言本身还发展出了JRuby(Java平台)、IronRuby(.NET平台)等其他平台的 Ruby 语言替代品。Ruby的作者于1993年2月24日开始编写Ruby,直至1995年12月才正式公开发布于fj(新闻组)。因为Perl发音与6月诞生石pearl(珍珠)相同,因此Ruby以7月诞生石ruby(红宝石)命名。
(3)RubyGems简称gems,是一个用于对 Ruby组件进行打包的 Ruby 打包系统
(4)Redis的Ruby驱动redis-xxxx.gem
(5)创建Redis集群的工具redis-trib.rb
4.2 开始搭建
(1)拷贝6个服务器,并将其端口号依次改为6379、6380、6381、6382、6383、6384.
(2)在redis.windows.conf配置文件中设置以下属性:
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000
appendonly yes
(3)编写启动脚本startup.bat,内容为:
title redis-6379
redis-server.exe redis.windows.conf
(4)安装Ruby,redis的集群需要使用。
(5)安装Redis的Rudy驱动redis-xxxx.gem
下载地址:Rubygems官方下载地址
下载zip文件,下载后解压。当前目录切换到解压目录中,如 D: edis-cluster ubygems-3.0.6 ubygems-3.0.6然后命令行执行 ruby setup.rb
再用 GEM 安装 Redis :切换到redis安装目录,需要在命令行中,执行 gem install redis
(6)启动每个节点并执行集群构建脚本,点击每个节点start.bat进行启动,拷贝redis-trib.rb到6379的redis节点。
执行命令:
redis-trib.rb create --replicas 1 127.0.0.1:6379 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
在出现 Can I set the above configuration? (type ‘yes’ to accept): 请确定并输入 yes 。
4.3 集群环境测试
4.3.1 命令测试
- redis-cli –c –h ”地址” –p “端口号” ; c 表示集群
- cluster info 查看集群的信息
- info replication 查看当前服务器的信息
- cluster nodes 查看各个节点分配slot
4.3.2 java代码测试
@Test public void testCluster() throws IOException, InterruptedException { Set<HostAndPort> nodes = new HashSet<>(); //添加服务器 nodes.add(new HostAndPort("127.0.0.1", 6379)); 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)); JedisCluster cluster = new JedisCluster(nodes); try { String res = cluster.get("name"); System.out.println(res); // cluster.quit(); } catch (Exception e) { e.printStackTrace(); // cluster.quit(); } } }
1.1.1. 分布存储机制-槽