集群
- 集群指的就是一组计算机作为一个整体向用户提供一组网络资源
- 我就举一个简单的例子,比如百度,在北京和你在上海访问的百度是同一个服务器吗?
- 答案肯定是不是的,每一个应用可以部署在不同的地方,但是我们提供的服务是相同的
- 也就是说我每一个节点上跑的都是相同的业务,但是我对用户而言是透明的
- 我要保证我这个服务不出故障高可用,现在我全球分布了很多台机器
- 每一台机器上跑的都是百度的业务,对用户而言,你在北京
- 我就给你分发到离北京最近的一个服务器上,在上海就分发到离上海最近的一个服务器上
- 这其中的每一个计算服务器就是集群中的节点
- 集群还提供了以下关键的一些特性
- 1 )可扩展性
- 集群的性能,不限于单一的服务实体
- 新的服务实体可以动态的加入到集群,从而增强了集群的性能
- 2 )高可用性
- 把这些节点服务器发生故障的时候,这台服务器上所运行的应用程序
- 可以在另一台服务器上被自动接管,消除单点故障,增强了数据的可用性可达性可靠性
- 3 )负载均衡
- 负载均衡,能把这些任务比较均匀的分散到集群环境下的这些服务器上
- 在全球有很多服务器,但是我请求的时候,把这些请求全部都集中的分发到一个机器上
- 那我搭集群的意义何在呢?所以说它还有负载均衡的特性
- 4 )错误恢复
- 就是我们集群中的某一台服务器,由于故障或者说无法使用了
- 我们要把它的资源对应的这些应用程序要转移到一个可用的节点上
- 这个转移的过程,让它继续可用,就把它叫做错误恢复
- 1 )可扩展性
- 分布式和集群又有什么区别和联系呢?
- 1 )分布式指的就是把不同的业务分布在不同的地方去做,就是分开部署
- 2 )我们的集群,它是将几台服务器集中在一起,实现同一业务
- 这个集中在一起,不是说就部署在一个地方
- 比如说,我在北京,我在上海,无所谓的我布在哪都行
- 但是我们实现的是同一业务,这就是集群
- 3 )分布式的每一个节点都可以做集群,而集群并不一定就是分布式
- 比如我们有一个商城业务的网站,如果我把其中的每一个服务,因为用到微服务开发
- 其中的每一个服务都是可以单独部署,单独开发的
- 我把每一个服务分别部署在不同的服务器上,这就叫分布式
- 我们每一个服务都有自己的责任和职责
- 不同的服务部署在不同的服务器上,一起完成了一个大的功能
- 就是我们对外提供的是一个完整的功能,但是我们是要分开独立开发独立部署的
- 其实这个就是分布式
- 再比如,我们拿到其中的一个服务,比如说授权认证,它可以做集群
- 因为一开始它是单一的节点,如果你想要它高可用,那就来3,5, 7台
- 所以说,分布式的每一个节点都是可以做集群的,但集群不一定就是分布式
- 即使不用这种微服务的架构,我就用传统的单体应用都写在一个服务里面没有拆分
- 这样的单体应用想让其高可用,就来上多个机器,这个只能是集群,而非分布式
- 集群主要分为三大类
- HA: 高可用集群(High Availability Cluster),Redis Cluster 用的就是这种模式
- 高可用集群,其实指的是以减少服务中断时间为目的的服务器集群技术
- 通过保护用户的业务程序,对外不间断的提供服务
- 把因为一些软件、硬件人为造成的故障,对业务影响降到最低,这就是高可用性集群
- LBC:负载均衡集群/负载均衡系统 (Load Balance Cluster)
- 这种集群它所有的节点都是处于活动状态的, 它们分摊系统的工作负载
- 一般像我们的web服务器集群, 数据库集群和我们的应用服务器集群都属于这种LBC
- HPC: 科学计算集群 (High Performance computing Cluster) / 高性能计算集群 (High Performance Computing)
- 高性能计算集群, 它采用的是将计算任务分配到集群不同的计算节点上提高计算能力
- 主要应用在科学计算领域
- HA: 高可用集群(High Availability Cluster),Redis Cluster 用的就是这种模式
- 一般开发应用就是HA 和 LBC用的比较多。
- HA 就是提高它的一个高可用
- LBC 就是像我们的应用服务器, 我们倾向于 Nginx结合一些硬件来实现这种负载均算集群
Redis 集群架构
- 我们先来看下不同问题的应对策略
- 并发量大了:通过主从复制解决
- 主从稳定性:通过哨兵解决
- 单节点存储能力:通过集群Cluster解决
1 ) 并发量大了:通过主从复制解决
- 现在假设上千万,上亿的用户同时在访问 Redis, 其 QPS 达到了10w+
- 这些请求过来,单机 Redis 很快就会挂掉,现在系统的瓶颈出现在 Redis 单机的问题上
- 此时,通过主从复制解决这个问题,实现系统的高并发
- 这就是并发量大了,主从复制解决
- 主从模式中主节点宕机之后,从节点是可以作为主节点顶上来继续提供服务的
- 但是我们需要修改应用方的主节点地址,还需要命令所有的从节点去复制新的主节点
- 这一系列的过程都是需要要人工完成,比较复杂,于是在Redis@2.8版本开始引入了哨兵
2 ) 主从稳定性:通过哨兵解决
- 在主从复制的基础上,哨兵实现了自动化故障恢复
- 哨兵模式中单个节点的写能力,存储能力还是受到单机的限制的
- 而且动态扩容是相对而言,困难复杂,于是 Redis@3.0 版本推出 Redis Cluster 集群模式
3 ) 单节点存储能力:通过集群Cluster解决
- 集群有效解决 Redis 分布式方面的需求,
- Redis Cluster 模式还具有高可用高扩展性分布式容错等特性
- 通过上图,可以看到,Redis Cluster集群的架构采用的是无中心结构
- 就是我们经常所说的去中心化,每个节点都可以保存数据和整个集群的状态
- 而且每个节点都和其他的节连连接,这些虚线和其他的节点连接起来了
- 数据保存在主节点中,从节点只是主节点的一个复制,就是容灾备份使用的
- 集群一般是由多个节点组成,官方建议至少六个才能保证组成完整的高可用集群
- 其中三个是主节点,三个是从节点
- 三个主节点会分配插槽,它们分配插槽之后,每一个key,比如说 set username
- 这个key会经过哈希运算,之后,会对应到一个插槽的索引上,然后插到这个插槽里边
- 比如说,M1(0-3000), M2(3000-6000), M3(6000-9000),而实际上它的插槽是16384个
- 使用上面假设的例子,set username 运算完成后,他是 5000多,它会被插入到 M2
- 你的一个key的运算会对应到一个索引的插槽上
- 所如说,三个主节点会分配槽来存储数据处理客户端的命令请求
- 而从节点是主节点的一个复制,就是在主节点故障之后,顶替主节点的一个作用
- 如果按照一主两从的要求,最终是 9个节点(3主6从)
- 总结一下
- 读请求可以分配给所有节点写请求,可以分配给 master
- 数据同步再从master到slave节点
集群和主从模式
- 主从模式其实就是为了保证数据高可用性而存在的
- 而集群其实准确的讲,它没有上图的右边Slave节点,M1~M3 才是集群分片
- 但是我们要保证它的高可用性,就需要主从容灾备份
- Redis Cluster 为了保证数据的高可用性,加入了主从模式
- 一个主节点对应一个或多个从节点,主节点提供数据的存取,从节点复制主节点数据备份
- 当这个主节点挂掉后,就会通过主节点的从节点选取一个来充当新的主节点保证集群的高可用
- 在上图例子中,有3个主节点,若其中一个挂掉了,如果它还没有从节点,那整个环境就没法用了
- 因为每个主节点都提供这个中间槽的功能,比如上面的 username,对应主节点挂掉了,怎么去获取这个槽对应的值
- 所以说我们在创建集群的时候,一定要为每个主节点都添加对应的从节点
集群架构的优缺点
1 )优点
- 去中心化
- 可扩展性
- 是数据是按照槽存储分配在多个节点上的
- 节点间的数据共享,节点可以动态的添加或删除,可以动态的调整
- 高可用性
- 部分节点不能用的时候,集群仍然是可用的
- 因为我们可以通过增加slave从节点做备份来充当数据的副本
- 自动故障转移
- 然后它出了故障之后,从节点可以顶上来,就是自动故障转移
- 节点之间通过留言协议交换状态信息
- 再采用投票机制完成 slave从节点到master的角色的升级
2 )缺点
- 任何事物都是一把双刃剑
- 数据通过异步复制,没有办法保证数据强一致性,但保证最终一致性
- 集群环境的搭建复杂
- 在之前的版本要用ruby脚本去创建集群
- 目前最新的模式去创建集群就简单了很多
数据分区
- Redis 集群模式是把数据分别存储在多个节点上的
- 因为随着请求量和数据量的增加,一台机器满足不了我们的需求了
- 主从模式主节点仍然有写的压力问题和存储压力的问题,所以我们需要把数据和请求分散到多台机器
- 这时候需要引入分布式存储,那分布式存储有哪些特性
- 1 )增强可用性
- 如果数据库的某个节点出现了故障。
- 在其他节点的数据仍然是可用的,增强了可用性
- 不会说一个节点出了问题,可能就是其他节点全部都用不了
- 只是说当前这个节点数据可能暂时性的不可用了,其他节点的数据仍然可用
- 2 )维护方便
- 这个节点出现故障了,我们需要修复,那也只修复该节点即可
- 3 )均衡IO
- 可以把不同的请求映射到各节点以平衡IO
- 改善整个系统的性能
- 4 )改善了查询性能
- 对分区对象的查询,可以仅搜索自己关心的节点,提高检索速度
- 1 )增强可用性
- 分布式存储首先要解决的就是数据集是如何按照什么样的分区规则映射到多个节点上的
- 即把数据集划分到多个节点上,每个节点负责整体数据的一个子集
常见数据分区算法
1 )范围分区
- 范围分区在关系型数据库,用的比较多
- 它指的就是把数据基于范围映射到每一个分区
- 这个范围是你自己在创建分区时候指定的这个分区键决定的
- 分区键也经常会采用以日期的方式来做分区
- 它的优点就是同一范围内的范围查询,不需要跨节点提升了查询速度
- 应用场景就是 mysql oracle 关系数据库居多
2 )哈希分区
2.1 节点取余分区
- 根据 hash(object) % N
- object是 key, % 是取余,N是节点数
- 就是对一个key取余,比如说现在我们有三台机器,那么对这个key做一个哈希处理运算
- 然后对3取于取余的余数是多少?我们就放到一二三对应的那个节点上去
- 优点是实现起来非常简单:
- 你有几个节点,哈希运算完就对这个节点取余就行了。
- 然后把这个值就分配到这个节点上去了
- 缺点
- 如果扩容/收缩节点的时候,你做的这个数据迁移量会很大
- 大概得有百分之七八十这样子, 举一个最简单的例子
- 比如说, 这个key, 哈希运算完之后,它是10; 10取余三, 余数是1
- 我这里有三个节点,它就放到1那个节点上去了
- 现在我增加了一个节点,现在4个节点了,刚才10对3取余,余数是1
- 现在你增加一个节点之后,就相当于分配这个key
- 那 10 再对4 取余,它就变成2了, 这个key就要从第一个节点上转移到第二个节点上
- 类似这种,需要做的这个数据迁移量会非常的大
- 建议就是翻倍扩容相对减少迁移量,但仍旧很大,基本上在百分之四五十的迁移量
- 这种算法现在用的比较少了,它的出现就是因为一致性哈希、虚拟槽这种概念还没有提出来
- 就像我们的 Redis 一样,它随着发展它刚开始肯定是单节点嘛
2.2 一致性哈希分区
- 它的实现思路就是为系统中的每个节点分配一个token
- 这个 token 的范围是在就是 0 ~ 2 32 2^{32} 232 区间
- 这些token会构成一个哈希环,数据读写执行节点查询操作的时候
- 就是先根据key的计算,计算到一个哈希值,然后顺时针找到第一个大于等于该哈希的token节点
- 优点
- 这种方式相比我们刚才节点取余最大的好处,就是
- 在加入和删除节点的时候,它只会影响相邻的节点
- 缺点
- 你使用少量节点的时候,节点的变化还是大范围的影响
- 所以说它是不适合少量数据节点的分布式方案
- 它更多的是那种规模比较大的这种数据节点的一种分布式的缓存方案
- 应用场景就是 Memcached 居多,基本上就是用这个一致性哈希来分区的
2.3 虚拟槽分区
- 虚拟槽分区,你可以理解为就是在一致性哈希分区的基础上加入了虚拟槽的概念
- 它把这个分割的力度变得更小了,让每一个节点持有固定的槽
- 当你去添加一个节点的时候,它不会对这里边的每一个重新去分配
- 你只需要给它的分配指定的槽,这里边的这些槽,我们可以选择自动的分配,或者说手动的去分配
- 你可以自己去进行分配管理,影响可以说是非常非常的小,这就是Redis Cluster 用的虚拟槽分区
- 现在我们的一个key经过哈希运算之后,对 16384取余
- CRC16 这是它内部的一个执行的一个对key处理的一个源码里边的函数
- 取余以后,这里就会有我们的槽的范围,这里大概有5个节点如上图
- 我对这个key, 比如说username做完处理之后,它映射到这个区间了,比如节点2
- 上面是节点2的一个详细图,我现在,新增一个节点,我新增一个节点之后
- 可以把原先一个节点的部分范围取出来重新分配给另一个节点,它的影响极小
- 这是关于虚拟槽分区的一个方式,它也是 Redis Cluster 用的方式
- 它的缺点就是
- 我们的每一个节点都要去存储nodes和槽对应的信息
- 因为我们知道客户端来访问的时候,肯定是不是说指定访问到某一个节点上
- 假如说, 我访问到一号节点上,而访问的 key 实际上是在三号节点里边
- 它内部会给我们去做一些转向的处理, 它会存储节点和槽对应的信息