畅购商城文章系列
畅购商城:分布式文件系统FastDFS
畅购商城:商品的SPU和SKU概念
畅购商城:Lua、OpenResty、Canal实现广告缓存
畅购商城:微服务网关和JWT令牌(上)
畅购商城:微服务网关和JWT令牌(下)
畅购商城:Spring Security Oauth2 JWT(上)
畅购商城:Spring Security Oauth2 JWT(下)
畅购商城:购物车
畅购商城:订单
畅购商城:微信支付
畅购商城:秒杀(上)
畅购商城:秒杀(下)
畅购商城:分布式事务
畅购商城:集群高可用
目录
学习目标
- 理解集群流程 - 服务
- 理解分布式概念 - 业务(对业务的拆分)
- 能实现Eureka集群
- 能实现Redis集群 【配置、烧饼策略、Redis击穿问题】
1.Redis集群的原理
2.Redis集群会用->在java代码中能链接集群服务
3.哨兵策略->监控集群的健康状态[作用]
4.Redis击穿->如何解决击穿问题
5.如何解决Redis雪崩问题->多级缓存
- RabbitMQ集群
1. 集群概述
1.1 什么是集群
1.1.1 集群概念 - 服务
集群是一种计算机系统, 它通过一组松散集成的计算机软件和/或硬件连接起来高度紧密地协作完成计算工作。在某种意义上,他们可以被看作是一台计算机。集群系统中的单个计算机通常称为节点,通常通过局域网连接,但也有其它的可能连接方式。集群计算机通常用来改进单个计算机的计算速度和/或可靠性。
1.1.2 集群的特点
- 可扩展性:集群的性能不限制于单一的服务实体,新的服务实体可以动态的添加到集群,从而增强集群的性能。
- 高可用性:集群当其中一个节点发生故障时,这台节点上面所运行的应用程序将在另一台节点被自动接管,消除单点故障对于增强数据可用性、可达性和可靠性是非常重要的。
1.1.3 集群的作用
- 负载均衡:负载均衡把任务比较均匀的分布到集群环境下的计算和网络资源,以提高数据吞吐量。
- 错误恢复:如果集群中的某一台服务器由于故障或者维护需要无法使用,资源和应用程序将转移到可用的集群节点上。这种由于某个节点的资源不能工作,另一个可用节点中的资源能够透明的接管并继续完成任务的过程,叫做错误恢复。
负载均衡和错误恢复要求各服务实体中有执行同一任务的资源存在,而且对于同一任务的各个资源来说,执行任务所需的信息视图必须是相同的。
1.2 集群与分布式的区别
相同点:
分布式和集群都是需要有很多节点服务器通过网络协同工作完成整体的任务目标。
不同点:
分布式是指将业务系统进行拆分,即分布式的每一个节点都是实现不同的功能。而集群每个节点做的是同一件事情。
【总结】:
将一套系统拆分成不同子系统部署在不同服务器上(这叫分布式), 然后部署多个相同的子系统在不同的服务器上(这叫集群),部署在不同服务器上的同一个子系统应做负载均衡。
分布式:一个业务拆分为多个子业务,部署在多个服务器上 。
集群:同一个业务,部署在多个服务器上 。
2. Eureka集群
2.1 Eureka简介
2.1.1 什么是Eureka
Eureka是一种基于REST(Representational State Transfer)的服务,主要用于AWS,用于定位服务,以实现中间层服务器的负载平衡和故障转移。我们将此服务称为Eureka Server。Eureka还附带了一个基于Java的客户端组件Eureka Client,它使与服务的交互变得更加容易。客户端还有一个内置的负载均衡器,可以进行基本的循环负载均衡。在Netflix,一个更复杂的负载均衡器包装Eureka,根据流量,资源使用,错误条件等多种因素提供加权负载平衡,以提供卓越的弹性。
理解:
Eureka是一个服务注册与发现的注册中心。类似于dubbo中的zookeeper.
application Service :相当于服务提供者
application Client :相当于服务消费者
make remote call :服务调用过程
us-east-1c d e 都是region:us-east-1 的可用区域。
简单可以理解为:
每一个Eureka都是一个节点,默认启动时就是以集群的方式。
区别:
Eureka:集群,各个节点的数据一致,各个节点都属于同等级别的注册中心,没有主从概念。
zookeeper:Zookeeper集群存在Leader节点,并且会进行Leader选举,Leader具有最高权限,选举过程中所有服务无法使用。
3. Redis Cluster
3.1 Redis Cluster 简介
3.1.1 什么是Redis Cluster
【重点】:
- 所有集群节点的数据合起来才是完整数据
- 集群节点的数量必须是奇数个(因为第3条)
- 判断集群是否可用:集群节点中主节点个数过半数以上宕机,则集群失败
- 程序每次链接集群中的任意一台节点
- Redis集群,会将16384个Hash槽分配给各个集群节点。
- 所有存入到Redis中的key的Hash值经过cr16算法之后得到的值在0-16383之间
- 每次往Redis中存/取数据的时候,会先计算出key经过cr16算法后的值,然后根据值到指定的Redis中获取数据
为何要搭建Redis集群。Redis是在内存中保存数据的,而我们的电脑一般内存都不大,这也就意味着Redis不适合存储大数据,适合存储大数据的是Hadoop生态系统的Hbase或者是MogoDB。Redis更适合处理高并发,一台设备的存储能力是很有限的,但是多台设备协同合作,就可以让内存增大很多倍,这就需要用到集群。
Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。其Redis-cluster架构图如下:
客户端与 redis 节点直连,不需要中间 proxy 层.客户端不需要连接集群所有节点连接集群中任何一个可用节点即可。
所有的 redis 节点彼此互联(PING-PONG 机制),内部使用二进制协议优化传输速度和带宽。
3.2 Redis单机版安装总结
- 解压Redis安装包
- 编译 -> make
- 安装 -> 指定安装路径 -> make install PREFIX = 安装路径
3.3 集群搭建
- 准备6个节点
- 每个节点需要开启集群
- 需要用ruby将每个开启集群的节点串联到一起
3.4 Redis的持久化
Redis的数据都放在内存中。如果机器挂掉,内存的数据就不存在,数据不能恢复,严重影响使用。那么Redis本身给我们提供了持久化机制。即使出现这样的问题,也能恢复数据。
Redis的两种持久化方式:RDB(快照形式)和AOF,建议集中持久化
- RDB:快照形式(定期数据保存磁盘中)会产生一个 dump.rdb文件,Redis默认开启了RDB的持久化方式。
- RDB特点:会存在数据丢失,性能较好,用于数据备份。
- AOF:append only file 。所有对Redis的操作命令记录在.aof文件中,如果想恢复数据,重新加载文件,执行文件中的命令即可。默认的情况下 Redis没有开启,要想开启,必须配置。
- AOF特点:每秒保存,数据完整性比较好,耗费性能。
RDB和AOF对比:
如果是秒杀或者数据文件很重要,一定要用AOF
命令 | RDB | AOF |
---|---|---|
启动优先级 | 低 | 高 |
体积 | 小 | 大 |
恢复速度 | 快 | 慢 |
数据安全性 | 丢数据 | 根据策略决定 |
RDB的最佳策略:
- 关闭
- 集中管理(用于备份数据)
- 主从模式,从开。
AOF的最佳策略:
- 建议 开 每秒刷盘->aof日志文件中
- AOF重写集中管理
最佳的策略:
- 小分片(max_memery 4G左右)
- 监控机器的负载
3.5 Redis哨兵模式(监控集群的健康状态)
Redis在使用过程中服务器毫无征兆的宕机,是一个麻烦的事情,如何保证备份的机器是原始服务器的完整备份呢?这时候就需要哨兵和复制。
- Sentinel(哨兵)可以管理多个Redis服务器,它提供了监控,提醒以及自动的故障转移的功能。
- Replication(复制)则是负责让一个Redis服务器可以配备多个备份的服务器。
- Redis也是利用这两个功能来保证Redis的高可用的。
Redis的主从复制实现高可用
- 它能自动进行故障转移。
- 客户端连接sentinel,不需要关系具体的master。
- 当master地址改变时由sentinel更新到客户端。
架构原理如图:
1.多个sentinel 发现并确认master有问题。
2.sentinel内部选举领导
3.选举出slave作为新的master
4.通知其余的slave成为新master的slave
5.通知客户端 主从变化
6.如果老的master重新复活,那么成为新的master的slave
要实现上边的功能的主要细节主要有以下三个定时任务:
- 每10秒,哨兵会向master和slave发送INFO命令(目的就是监控每一个节点信息)
- 每2秒,哨兵会向master库和slave的频道(sentinel:hello)发送自己的信息 (sentinel节点通过__sentinel__:hello频道进行信息交换,比如加入哨兵集群,分享自己节点数据)
- 每1秒,哨兵会向master和slave以及其他哨兵节点发送PING命令(目的就是 redis节点的状态监控,还有领导选举,主备切换选择等)
策略总结:
1.尽量为每一个节点部署一个哨兵
2.哨兵也要搭建集群(防止哨兵单点故障)
3.每一个节点都同时设置quorum的值超过半数(N/2)+1
面试常问:主从复制,以及哨兵和集群之间区别。
- 主从复制是Redis实现高可用的一个策略。将会有主节点和从节点,从节点的数据完整的从主节点中复制一份。
- 哨兵:当系统节点异常宕机的时候,开发者可以手动进行故障转移恢复,但是手动比较麻烦,所以通过哨兵机制自动进行监控和恢复。为了解决哨兵也会单点故障的问题,可以建立哨兵集群。
- 集群:即使使用哨兵,redis每个实例也是全量存储,每个redis存储的内容都是完整的数据,浪费内存且有木桶效应。为了最大化利用内存,可以采用集群,就是分布式存储。这个时候可以使用redis集群。将不同的数据分配到不同的节点中,这样就可以横向扩展,扩容。
3.6 Redis缓存击穿
- 当用户根据key 查询数据时,先查询缓存,如果缓存有命中,返回,
- 但是如果缓存没有命中直接穿过缓存层,访问数据层 如果有,则存储指缓存,
- 但是同样如果没有命中,(也就是数据库中也没有数据)直接返回用户,但是不缓存
这就是缓存的穿透。如果某一个key 请求量很大,但是存储层也没有数据,大量的请求都会达到存储层就会造成数据库压力巨大,有可能宕机的情况。
缓存击穿的解决方案
1.当缓存中没有命中的时候,从数据库中获取
2.当数据库中也没有数据的时候,我们直接将null 作为值设置redis中的key上边。
3.此时如果没有数据,一般情况下都需要设置一个过期时间,例如:5分钟失效。(为了避免过多的KEY 存储在redis中)
4.返回给用户,
5.用户再次访问时,已经有KEY了。此时KEY的值是null而已,这样就可以在缓存中命中,解决了缓存穿透的问题。
缓存空对象会有两个问题:
第一,空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间 ( 如果是攻击,问题更严重 ),比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除。
第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。例如过期时间设置为 5分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象。
3.7 缓存雪崩
如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。
缓存雪崩解决方案(尽量让失效时间点均匀分布):
- 限流 加锁排队
在缓存失效后,通过对某一个key加锁或者是队列 来控制key的线程访问的数量。例如:某一个key 只允许一个线程进行 操作。
- 限流
在缓存失效后,某一个key 做count统计限流,达到一定的阈值,直接丢弃,不再查询数据库。例如:令牌桶算法。
- 数据预热
在缓存失效应当尽量避免某一段时间,可以先进行数据预热,比如某些热门的商品。提前在上线之前,或者开放给用户使用之前,先进行loading
缓存中,这样用户使用的时候,直接从缓存中获取。要注意的是,要更加业务来进行过期时间的设置 ,尽量均匀。
- 做缓存降级(二级缓存策略)
当分布式缓存失效的时候,可以采用本地缓存,本地缓存没有再查询数据库。这种方式,可以避免很多数据分布式缓存没有,就直接打到数据库的情况。
4. RabbitMQ集群
在使用RabbitMQ的过程中,如果只有一个节点,但是一旦单机版宕机,服务不可用,影响比较严重,集群就能避免单点故障的问题。
RabbitMQ 集群分为两种 普通集群 和 镜像集群。
4.1 普通集群
以两个节点(rabbit01、rabbit02)为例来进行说明。
rabbit01和rabbit02两个节点仅有相同的元数据,即队列的结构,但消息实体只存在于其中一个节点rabbit01(或者rabbit02)中。
当消息进入rabbit01节点的Queue后,consumer从rabbit02节点消费时,RabbitMQ会临时在rabbit01、rabbit02间进行消息传输,把A中的消息实体取出并经过B发送给consumer。
所以consumer应尽量连接每一个节点,从中取消息,即对于同一个逻辑队列,要在多个节点建立物理Queue;否则无论consumer连rabbit01或rabbit02,出口总在rabbit01,会产生瓶颈。
当rabbit01节点故障后,rabbit02节点无法取到rabbit01节点中还未消费的消息实体。如果做了消息持久化,那么得等rabbit01节点恢复,然后才可被消费;如果没有持久化的话,就会产生消息丢失的现象。
4.2 镜像集群
在普通集群的基础上,把需要的队列做成镜像队列,消息实体会主动在镜像节点间同步,而不是在客户端取数据时临时拉取,也就是说多少节点消息就会备份多少份。该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉。所以在对可靠性要求较高的场合中适用
由于镜像队列之间消息自动同步,且内部有选举master机制,即使master节点宕机也不会影响整个集群的使用,达到去中心化的目的,从而有效的防止消息丢失及服务不可用等问题。