SpringCloudAlibaba
1.简介
集群/分布式/微服务
集群:同一个业务,部署在多个服务器上(不同的服务器运行同样的代码,干同一件事)。集群系统中的单个计算机通常称为节点,通常通过局域网连接,但也有其它的可能连接方式。
分布式:一个业务分拆多个子业务,每个子业务为一个节点,部署在不同的服务器上(不同的服务器,运行不同的代码,为了同一个目的)
微服务:是系统架构上的一种设计风格, 它的主旨是将一个原本独立的系统 拆分成多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间通过基于HTTP 的RESTful API进行通信协作。 被拆分成的每一个小型服务都围绕着系统中的某一项或一 些耦合度较高的业务功能进行构建, 并且每个服务都维护着自身的数据存储、 业务开发、 自动化测试案例以及独立部署机制。 由于有了轻量级的通信协作基础, 所以这些微服务可 以使用不同的语言来编写。微服务强调独每个服务都是单独数据库,保证每个服务于服务之间互不影响。非常重要的概念:独立部署、可配置、动态化
CAP理论
C:数据一致性(consistency)
所有节点拥有数据的最新版本,强一致性, 或是时序一致性, 或是滞后的最终一致性
A:可用性(availability)
数据具备高可用性,尽量保证服务不会失去响应
P:分区容错性(partition-tolerance)
一个分布式系统里面,节点组成的网络本来应该是连通的。然而可能因为一些故障,使得有些节点之间不连通了,整个网络就分成了几块区域。数据就散布在了这些不连通的区域中。这就叫分区。
当你一个数据项只在一个节点中保存,那么分区出现后,和这个节点不连通的部分就访问不到这个数据了。这时分区就是无法容忍的。
提高分区容忍性的办法就是一个数据项复制到多个节点上,那么出现分区之后,这一数据项就可能分布到各个区里。容忍性就提高了。
然而,要把数据复制到多个节点,就会带来一致性的问题,就是多个节点上面的数据可能是不一致的。要保证一致,每次写操作就都要等待全部节点写成功,而这等待又会带来可用性的问题。
总的来说就是,数据存在的节点越多,分区容忍性越高,但要复制更新的数据就越多,一致性就越难保证。为了保证一致性,更新所有节点数据所需要的时间就越长,可用性就会降低。
大致拆分简图:
拆分出多个模块以后,就会出现各种各样的问题,而SpringCloud提供了一整套的解决方案!
- 注:这些模块是独立成一个子系统的(不同主机)。
问题:
- 什么是脑裂: 集群(M-S的情况)通常是发生在节点通信不可达(分区)的情况下,集群会分裂成不同的小集群,小集群各自选举出多个master节点的情况。
- nacos和zookeeper是如何避免脑裂的? leader选举,要求节点的投票数量>总节点数量/2,即过半数,有这个选举原则保证了集群出现分区,无论如何最多只能有一个小集群选出leader。
2.SpringCloudAlibaba的基础功能
- 服务治理&配置中心: Spring Cloud Nacos
- 客户端负载均衡: Spring Cloud Loadbalancer
- 服务容错保护: Spring Cloud Sentinel
- 声明式服务调用: Spring Cloud OpenFeign
- API网关服务:Spring Cloud Gateway
3.Nacos
服务(Service)是 Nacos 世界的一等公民。
主要特性:
- 服务发现和服务健康监测:支持基于 DNS 和基于 RPC 的服务发现。提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求。
- 动态配置服务:以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。
- 动态 DNS 服务:动态 DNS 服务支持权重路由。
- 服务及其元数据管理:管理数据中心的所有服务及元数据。
Nacos分为:Nacos控制台-服务注册中心(Service Registry),服务提供方 (Service Provider),服务消费方 (Service Consumer)
Nacos启动方式:https://nacos.io/zh-cn/docs/quick-start.html
Nacos注册中心分为server与client,server采用Java编写,为client提供注册发现服务与配置服务。而client可以用多语言实现,client与微服务嵌套在一起,nacos提供sdk和openApi,如果没有sdk也可以根据openApi手动写服务注册与发现和配置拉取的逻辑
Nacos Server(服务注册中心)
- 失效剔除:默认每隔一段时间(默认为5秒)如果客户端实例超过15秒还没有发送心跳过来,则将实例健康状态改成false;如果客户端实例超过30秒还没有发送心跳过来,则剔除该实例。
- 自我保护:Nacos Server 在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%(通常由于网络不稳定导致)。 Nacos Server会将当前的实例注册信息保护起来, 让这些实例不会过期,尽可能保护这些注册信息。
服务提供者
- 服务注册:Nacos-client启动时,会去注册中心进行服务注册,其实是通过HTTP请求调用Nacos-server,当nacos-server端接收到客户端的注册请求时,会将客户端的实例数据(包括ip、端口、微服务名等)保存到server端的注册表中
- 服务续约:在注册完服务之后,服务提供者会维护一个心跳(默认周期为5秒)用来持续告诉Nacos Server: "我还活着 ” 、
- 服务下线:当服务实例进行正常的关闭操作时,它会触发一个服务下线的DELETE 请求给Nacos Server, 告诉服务注册中心:“我要下线了 ”。
服务消费者
- 获取服务:当我们启动服务消费者的时候,它会发送一个REST请求给服务注册中心,来获取上面注册的服务清单
- 服务调用:服务消费者在获取服务清单后,得到具体提供服务的实例名和该实例的元数据信息。通过本地负载均衡(loadbalence)获取相应的地址进行访问。
健康检查
以指定方式检查服务下挂载的实例 (Instance) 的健康度,从而确认该实例 (Instance) 是否能提供服务。根据检查结果,实例 (Instance) 会被判断为健康或不健康。对服务发起解析请求时,不健康的实例 (Instance) 不会返回给客户端。
健康保护阈值
为了防止因过多实例 (Instance) 不健康导致流量全部流向健康实例 (Instance) ,继而造成流量压力把健康实例 (Instance) 压垮并形成雪崩效应,应将健康保护阈值定义为一个 0 到 1 之间的浮点数。当域名健康实例数 (Instance) 占总服务实例数 (Instance) 的比例小于该值时,无论实例 (Instance) 是否健康,都会将这个实例 (Instance) 返回给客户端。这样做虽然损失了一部分流量,但是保证了集群中剩余健康实例 (Instance) 能正常工作。
Nacos代码配置
https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html
Nacos配置中心
基础概念
命名空间(Namespace)
粗粒度配置隔离,允许相同Group 或 Data ID 的配置。主要区分正式和测试环境
配置集ID(Data ID )
相同分组内保证全局唯一性。
分组(Group)
不同的应用或组件使用了相同的配置类型,如 database_url 配置和 MQ_topic 配置。
DataID + Group 唯一
首先,Nacos Config针对配置的管理提供了4种操作: 获取配置,从Nacos Config Server中读取配置。 监听配置:订阅感兴趣的配置,当配置发生变化的时候可以收到一个事件。 发布配置:将配置保存到Nacos Config Server中。 删除配置:删除配置中心的指定配置。 而从原理层面来看,可以归类为两种类型:配置的CRUD和配置的动态监听。
1. 配置的CRUD操作
对于Nacos Config来说,主要是提供了配置的集中式管理功能,然后对外提供CRUD的访问接口使得应用系统可以完成配置的基本操作。
对于服务端来说:需要考虑的是配置如何存储,是否需要持久化。 对于客户端来说:需要考虑的是通过接口从服务器查询得到相应的数据然后返回。 关系如下:
注意:
Nacos服务端的数据存储默认采用的是Derby数据库(也支持Mysql)。
2. 配置的动态监听
Nacos的客户端和服务端之间存在着数据交互的一种行为(不然怎么做到实时的更新和数据的查询呢),而对于这种交互行为共有两种方式:
Pull模式:表示客户端从服务端主动拉取数据。 Pull模式下,客户端需要定时从服务端拉取一次数据,由于定时带来的时间间隔,因此不能保证数据的实时性,并且在服务端配置长时间不更新的情况下,客户端的定时任务会做一些无效的Pull操作。
Push模式:服务端主动把数据推送到客户端。 Push模式下,服务端需要维持与客户端的长连接,如果客户端的数量比较多,那么服务端需要耗费大量的内存资源来保存每个资源,并且为了检测连接的有效性,还需要心跳机制来维持每个连接的状态。
Nacos采用的是Pull模式(Kafka也是如此),并且采用了一种长轮询机制。客户端采用长轮询的方式定时的发起Pull请求,去检查服务端配置信息是否发生了变更,如果发生了变更,那么客户端会根据变更的数据获得最新的配置。
长轮询:客户端发起轮询请求后,服务端如果有配置发生变更,就直接返回。
如下图:
详细地来说:
如果客户端发起Pull请求后,发现服务端的配置和客户端的配置是保持一致的,那么服务端会“Hold”住这个请求。(服务端拿到这个连接后在指定的时间段内不会返回结果,直到这段时间内的配置发生变化) 一旦配置发生了变化,服务端会把原来“Hold”住的请求进行返回。 工作流程图如下:
对于流程图解释如下:
Nacos服务端收到请求后,会检查配置是否发生了变更,如果没有,那么设置一个定时任务,延期29.5秒执行。同时并且把当前的客户端长轮询连接加入到allSubs队列。 这时候有两种方式触发该连接结果的返回:
第一种:等待29.5秒(长连接保持的时间)后触发自动检查机制,这时候不管配置有无发生变化,都会把结果返回给客户端。 第二种:在29.5秒内的任意一个时刻,通过Nacos控制台或者API的方式对配置进行了修改,那么触发一个事件机制,监听到该事件的任务会遍历allSubs队列,找到发生变更的配置项对应的ClientLongPolling任务,将变更的数据通过该任务中的连接进行返回,即完成了一次推送操作。
项目配置
引入pom文件
配置文件:
spring:
cloud:
nacos:
config:
# nacos服务地址
server-addr:
# 配置文件后缀
file-extension: yaml
# 命名空间id
namespace:
config:
import:
- nacos:${spring.application.name}-${spring.profiles.active}.yaml
数据交互模式
Push(推模式)和 Pull(拉模式)。
推模式
指的是客户端与服务端建立好网络长连接,服务方有相关数据,直接通过长连接通道推送到客户端。
优点是及时,一旦有数据变更,客户端立马能感知到;另外对客户端来说逻辑简单,不需要关心有无数据这些逻辑处理
缺点是如果客户端的数量比较多,那么服务端需要耗费大量的内存资源来保存每个资源,并且为了检测连接的有效性,还需要心跳机制来维持每个连接的状态
拉模式
指的是客户端主动向服务端发出请求,拉取相关数据
优点是此过程由客户端发起请求,故不存在推模式中数据积压的问题
缺点是可能不够及时,如果服务端配置长时间不更新的情况下,客户端的定时任务会做一些无效的Pull操作
轮询与长轮询
两者都是拉模式的实现
轮询是指不管服务端数据有无更新,客户端每隔定长时间请求拉取一次数据,可能有更新数据返回,也可能什么都没有。配置中心如果使用「轮询」实现动态推送,会有以下问题:
推送延迟。客户端每隔 5s 拉取一次配置,若配置变更发生在第 6s,则配置推送的延迟会达到 4s。
服务端压力。配置一般不会发生变化,频繁的轮询会给服务端造成很大的压力。
推送延迟和服务端压力无法中和。降低轮询的间隔,延迟降低,压力增加;增加轮询的间隔,压力降低,延迟增高。
长轮询则不存在上述的问题。
客户端发起长轮询,如果服务端的数据没有发生变更,会 hold 住请求,直到服务端的数据发生变化,或者等待一定时间超时才会返回。返回后,客户端又会立即再次发起下一次长轮询。配置中心使用「长轮询」如何解决「轮询」遇到的问题也就显而易见了
- 推送延迟。服务端数据发生变更后,长轮询结束,立刻返回响应给客户端。
- 服务端压力。长轮询的间隔期一般很长,例如 30s、60s,并且服务端 hold 住连接不会消耗太多服务端资源。