SpringCloud笔记
Posted ThinkStu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud笔记相关的知识,希望对你有一定的参考价值。
2023年最新笔记,全文约 3 万字,蕴含 Spring Cloud 常用组件 Nacos、OpenFeign、Seata、Sentinel 等
〇、简介
-
什么是Spring Cloud?
Spring Cloud是一系列框架的有序集合,是一种基于微服务的分布式架构技术。它利用 Spring Boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 Spring Boot 的开发风格做到一键启动和部署,从而提供了良好的开箱即用体验。
-
主流的架构方式:
- 单体架构:架构简单、部署成本低,耦合度高。
- 分布式架构:架构复杂、部署成本高,耦合度低。
-
微服务架构特征:
总体方向:高内聚、低耦合
- 单一职责:微服务拆分粒度小,每个服务对应单一业务功能。
- 面向服务:对外暴露业务接口。
- 自治:团队独立、技术独立、数据独立、部署独立。
- 隔离性强:提升容错性、避免出现级联故障。
-
常见微服务技术对比:
- 阿里 Dubbo
- Spring Cloud(第一代)
- Spring Cloud Alibaba(第二代)
-
Spring Cloud 版本说明
大版本说明:
- 2020 年之前:按照“伦敦地铁”命名,从 A 到 H。
- 2020 年之后:按年份命名。
小版本说明:
其余版本信息说明
- snapshot: 快照
- pre:预览版本
- alpha : 内测
- beta : 公测
- release : 稳定版本
- GA: General Availability,发行版,即最稳定的版本
- Final : 正式版
- Pro(professional) : 专业版
- Plus: 加强版
- Retail : 零售版
- DEMO : 演示版
- Build : 内部标号
- Corporation或Enterpraise 企业版
- M1 M2 M3 : M是milestone的简写 里程碑的意思
- RC 版本RC:(Release Candidate),几乎就不会加入新的功能了,而主要着重于除错
- SR : 修正版
- Trial : 试用版
- Shareware : 共享版
- Full : 完全版
- Spring Cloud 与 Spring Boot 的选型必须严格按照官方给出的建议去对应,我们可以通过官网或者详情链接https://start.spring.io/actuator/info查看最新推荐的版本对应关系:
-
【其他注意点】:
- 微服务之间的联系通过暴露接口实现,比如HTTP协议或者Dubbo协议。
- 每个微服务都应该有专属的独立数据库,并且每个微服务只能访问自己的数据库,严禁访问别人的微服务数据库(避免重复开发原则)。
-
构建 Spring Cloud 父工程
创建 Maven 项目,选择一个较为简单的架构模式(方便后面删除)
将父工程中除了.pom
文件的其余文件全部删除
在父工程的pom 文件中修改或新增<packaging>pom</packaging>
,代表这是父工程,其他工程项目可继承于它。
<packaging>pom</packaging>
粘贴下列pom配置:
<dependencyManagement>
:只声明依赖,不实现引入,子项目需要显示声明使用的依赖- 作用:子项目在声明时可以不用带上版本号,如果子版本中也配置了版本号,则以子版本标明的为主。
- 注意 Spring Boot 与 Spring Cloud 之间的版本对应关系
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.9.RELEASE</version>
<relativePath/>
</parent>
<!-- 广泛使用的 lombok -->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<!-- 定义版本号 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
<mysql.version>5.1.47</mysql.version>
<mybatis.version>2.1.1</mybatis.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- springCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>$spring-cloud.version</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--nacos的管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>$mysql.version</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>$mybatis.version</version>
</dependency>
</dependencies>
</dependencyManagement>
-
构建 Spring Cloud 子工程
- 方式一:构建初始 Maven 项目(module),后面内容缓慢补充(改 pom、写 yml、编写主启动类、编写业务类)
- 方式二:构建 Spring Initializr 项目(module),后面改写 pom 文件使形成 Maven 继承关系即可。个人偏向于这种方式。
-
父类显式声明子类,子类标明继承自父类
<modules>
<module>子类1</module>
<module>子类2</module>
</modules>
<!--标明继承自父类-->
<parent>
<artifactId>springcloud_test</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
-
【强制性】凡是微服务,一般都需要有端口号与名称(程序名称将作为
服务Id
,用于与其他服务分辨)server: port: 8001 spring: application: name: payment8001
-
返回结果定义(通常结构)
- 数值类型code码,表示状态
- 消息类型message:例如 success,error 等
- 消息实体 data,即数据
@Data @AllArgsConstructor @NoArgsConstructor public class CommonResult<T> private Integer code; private String message; private T data;
-
RestTemplate
类简介:RestTemplate 是 Spring 提供的用于访问 Restful 风格服务的客户端模版工具集,其提供了多种便捷访问远程 Http 服务的方法,作用类似 Java 原生的
HttpClient
。 -
Spring Cloud 初体验:
服务之间通过暴露接口、HTTP 请求实现沟通。
自行配置Spring对象
RestTemplate
并注入,发送 GET 与 POST 请求使用.getForObject()
、.postForObject()
@Configuration public class CommonConfig @Bean RestTemplate getRsetTemplate() return new RestTemplate();
一、Eureka
NetFlix Eureka,注册中心
-
简介:
- Spring Cloud 使用 Eureka 来充当第一代注册中心,其类似于【发布者】-【订阅者】模型。
-
Eureka 拥有 3 个角色
- Eureka Server:服务端。注册中心,提供记录服务信息(业务功能、健康状况等)、心跳监控等。
- Eureka Client:客户端。用于简化与 Eureka Server 的交互
- Provider:服务提供者,会将自己的信息注册到 Eureka Server 并每隔 30s 发送一次心跳包。
- consumer:服务消费者,根据所需从 Eureka Server 中拉取服务列表,并根据负载均衡策略对其中一个微服务发起远程调用。
-
Eureka 实现原理
- 微服务启动时,会通过 Eureka Client 向 Eureka Server 进行注册自己的信息,而 Eureka Server 会存储该服务的信息。
- 微服务启动后,会周期性地向 Eureka Server 发送心跳(即自身信息,默认周期为30秒),如果Eureka Server在一定时间内没有接收到某个微服务节点的心跳,则会注销该微服务节点(默认90秒)。
- 每个 Eureka Server 同时也是 Eureka Client ,多个Eureka Server之间通过复制的方式完成服务注册表的同步。
- Eureka Client 会缓存 Eureka Server 中的信息。即使所有的 Eureka Server 节点宕机,服务消费者依然可以使用缓存中的信息找到服务提供者。
-
简单实现(单机版)
- pom 导包(分为 server 与 client 包,部分Spring版本 parent 中无 Eureka 信息,需手动指定版本)
- 服务端主配置上开启
@EnableEurekaServer
。 - yaml 配置 Eureka 信息(注意也要配置 Spring 程序名称)
【服务端】:服务端一般不需要将自己注册成微服务
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
@EnableEurekaServer
server: port: 10086 spring: application: name: MyServer eureka: client: service-url: defaultZone: http://127.0.0.1:10086/eureka # 不向 eureka server 注册自己与获取服务列表 register-with-eureka: false fetch-registry: false
【客户端】
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
spring: application: name: user_service eureka: client: service-url: defaultZone: http://127.0.0.1:10086/eureka
利用
RestTemplate
向其他微服务发送请求。在编写 URL 路径时,通过指定其他微服务的应用名即spring.application.name
来调用其服务(如http://userservice/
),注册中心将充当 DNS 为各微服务提供解析服务,从而使我们不用像之前一样编写 IP 或域名硬编码的形式(如http://127.0.0.1:8080/
)。// 子微服务使用其他微服务,并实现负载均衡 @Bean @LoadBalanced public RestTemplate rest() return new RestTemplate();
String url="http://userservice/user/"+order.getUserId();
二、Ribbon
NetFlix Ribbon,负载均衡
-
简介:
- Ribbon 实现了客户端负载均衡,主要结合 Eureka 用于服务注册及发现。
- 传统的服务端负载均衡诸如 nginx 需要单独部署额外的服务(成本增加),而 Ribbon 结合 Eureka 可以直接在客户端实现负载均衡。
- Ribbon拥有多种负载均衡模式,与 nginx 类似。
-
Ribbon 默认使用【轮询算法】
下面是 Ribbon 中实现的各种算法简介,
IRule
是顶层接口,下面是具体的实现类。 -
简单实现:
由于 Ribbon 与 Eureka 都是由 NetFlix 公司开发,且 Ribbon 常用于与 Eureka 组合实现负载均衡,所以当我们引入
spring-cloud-starter-eureka
依赖时也会默认引入 Ribbon 依赖,无需重复引入。<!-- 下面是 spring-cloud-starter-eureka 的依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
我们要做的只是通过简单配置更改 Ribbon 的【负载均衡】模式,有 2 种办法:
-
全局生效:因为 Ribbon 的所有模式都基于
IRule
接口,所以可以通过改变其注入的 Bean 实现。@Bean public IRule randomRule() // 随机模式 return new RandomRule();
-
局部生效:仅对所调用的某微服务生效
某微服务名称: ribbon: NFLoadBalancerRuLeClassName: com.netfLix.Loadbalancer.RandomRule
微服务名称即:所要调用的微服务名称
另外,由于 Ribbon 默认采用**【懒汉模式】,即第一次请求链接时才会获取“可用的微服务列表”,这将造成一定的体验损耗,我们可以将其更改成【饿汉模式】**。
ribbon:
eager-load:
enable: true
# 客户端在启动时,就会去请求这些名称的“微服务表”
clients:
- userservice
- vipservice
三、Nacos
阿里 Nacos,Eureka的替代品
注册中心(服务发现中心)、配置管理。
0、简介
-
Nacos /nɑ:kəʊs/ ,
Dynamic Naming and Configuration Service(动态域名命名和配置服务)
首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台,Nacos 致力于发现、配置和管理微服务。 -
Nacos 使用 Java 编写,如果本地 JDK 环境配置不对,会出现一系列不明所以的报错。
-
Nacos是一个内部微服务组件,需要在可信的内部网络中运行,并非面向公网环境的产品,不可暴露在公网环境,强烈不建议部署在公共网络环境。Nacos提供了简单的鉴权实现,是为防止业务错用的弱鉴权体系,而不是防止恶意攻击的强鉴权体系。
-
Nacos 架构
- Namespace:命名空间,默认
空串
代表公共命名空间public
。 - Group:分组,默认为
DEFAULT_GROUP
,作项目区分,用来区分相同开发环境下的不同项目(如测试环境下的电商项目、测试环境下的培训机构项目) - Service:服务,提供具体服务(如登录服务、验证码服务等)。
- Cluster:集群,如上海集群,杭州集群。
例如在某命名空间下(如测试环境的命名空间),有众多分组(项目),每个项目又有一些服务(服务可以说是最小可用单位),服务又会归属于不同集群(提升可用性与性能)。
- Namespace:命名空间,默认
-
整合 Spring Cloud 配置说明:
discovery
:服务发现中心config
:配置中心
-
当 Nacos 没有整合 OpenFeign 时,默认使用的是 RestTemplate ,此时如果需要实现“负载均衡”策略,则:
@LoadBalanced @Bean public RestTemplate restTemplate() return new RestTemplate();
负载均衡方式默认为轮询
1、安装
-
简介:
- Nacos 已经被封装成 jar 包,我们配置好基本要求,直接运行 jar 包即可。
- 在程序运行之后,其余配置只能在网页端的控制面板修改,不能在代码中修改。
-
手动模式:
-
解压并启动(此处为单机模式)
-
单机模式
-
集群模式
-
# 单击模式启动 ./startup.sh -m standalone # 关闭 ./shutdown.sh
-
Docker模式
未挂载配置目录与日志目录
docker run \\ --name myNacos \\ -e MODE=standalone \\ --env NACOS_AUTH_ENABLE=true \\ -p 8848:8848 \\ -d \\ nacos/nacos-server
挂载已有的配置目录与日志目录:提前将 Nacos
/conf/
目录文件拷贝至/tmp/nacos/conf/
docker run \\ --name myNacos \\ -e MODE=standalone \\ --env NACOS_AUTH_ENABLE=true \\ -v /tmp/nacos/conf/:/home/nacos/conf/ \\ -v /tmp/nacos/logs/:/home/nacos/logs/ \\ -p 8848:8848 \\ -d \\ nacos/nacos-server
挂载新的的配置目录与日志目录:
docker run \\ --name myNacos \\ -e MODE=standalone \\ --env NACOS_AUTH_ENABLE=true \\ -v nacosConf:/home/nacos/conf/ \\ -v nacosLogs:/home/nacos/logs/ \\ -p 8848:8848 \\ -d \\ nacos/nacos-server
docker inspect mq | grep volume
-
开启服务器鉴权
按照官方文档配置启动,默认是不需要登录的,这样会导致配置中心对外直接暴露。而启用鉴权之后,需要在使用用户名和密码登录之后,才能正常使用nacos。(所以 Nacos 才推荐不要把自身放在“外网”中)
配置
/conf/application.properties
文件nacos.core.auth.enabled=true
如此一来,Client 端便需要配置 nacos 的账号密码才能登录。
**注意:**鉴权开关是修改之后立马生效的,不需要重启服务端。
-
安装之后
- 可以通过查看
/logs/start.out
日志来查看启动详情。 - 访问
http://127.0.0.1:8848/nacos
登录 Nacos,默认账号密码均为 nacos。
- 可以通过查看
-
Spring项目引入 Nacos 依赖
父工程(这是必备的)
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.5.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency>
子工程
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
-
配置 Nacos 地址
在未开启“鉴权模式”时,可以不配置
username
与password
spring: cloud: nacos: server-addr: localhost:8848 username: nacos password: nacos
-
**注意:**Nacos 包不可与 Eureka 包同时导入同一工程,否则产生冲突
Bean multiple
。
2、命名空间
命名空间使实例之间【相互隔离】,看不到彼此,这可以用作正式环境与测试环境的区分。当 Nacos 启动时会默认使用全局唯一命名空间public
。
步骤:
- 新建命名空间(此处自动使用 UUID 当作“主键id”)
- 实例 yml 文件配置命名空间(使用生成的主键 id )
spring:
cloud:
nacos:
server-addr: http://localhost:8848
discovery:
cluster-name: HZ
namespace: 53a68426-7e6c-4e09-83e3-57a87f116980 # 声明命名空间
3、服务分级模型
服务分级模型在相同“命名空间”的前提下,Nacos 利用服务分级存储模型来提高【容灾率】,例如:
- 总体服务
- 集群(如上海、杭州)
- 实例
- 集群(如上海、杭州)
集群默认为DEFAULT_GROUP
,更改如下:
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
cluster-name: HZ # 例如:HZ代表杭州、SH表示上海
- 一个集群就相当于一个小型完善的“生态系统”。
- 在开启集群设置后,我们应该将**【负载均衡策略】修改为【优先使用本地集群】(如果本地集群全部失效,程序会自动转向其他集群发起请求),随后 Nacos 就会再在本地集群选择【随机选取】**的方式进行实例的选择(注意这里不是轮询)。
某微服务名称:
ribbon:
NFLoadBalancerRuLeClassName: com.alibaba.cloud.ribbon.NacosRule
4、服务权重
Nacos可以通过【网页控制台】为实例设置权重,范围从0~1
,值越大越容易被访问,设置为0
则完全不会被访问,这可以用作“灰度升级”。
注意:必须是相同集群下拥有多个相同实例时,才可配置权重。
5、服务监测
监测实例的健康状态
Nacos拥有临时监测(被动)、非临时监测(主动)
Eureka只有临时监测
-
临时监测(默认、被动检测):
- 发送心跳包。
- 客户端心跳上报Nacos实例健康状态,默认间隔5秒,Nacos在15秒内未收到该实例的心跳,则会设置为不健康状态,超过30秒则将实例移除。在被移除后如果又开始上报心跳,则会重新注册实例。
- 运维只能通过检查实例数量来监测实例状态,但临时实例的设置本就是应对“流量突增”情况的。
-
非临时监测(主动检测)
- Nacos会定期 主动 发起请求询问实例的健康状态(不发送心跳包)
- 在实例失效时也会主动 push 推送信息给服务消费者,及时更新数据。此时实例并不会被移除,依旧保留在服务列表,只是状态为
false
。 - 主动询问的方式对服务器压力较大,它的好处是运维可以实时看到实例的健康状态,便于后续的警告、扩容等一些列措施。
-
配置非临时检测:
spriing: cloud: nacos: server-addr: http://localhost:8848 discovery: cluster-name: HZ namespace: 53a68426-7e6c-4e09-83e3-57a87f116980 # ephemeral,短暂的 ephemeral: fasle
-
【非临时监测】的另外一个作用:设置保护阈值,防止产生服务雪崩效应
Nacos中可以针对具体的实例设置一个保护阈值,值为0-1之间的浮点类型。本质上,保护阈值是⼀个⽐例值(当前服务健康实例数/当前服务总实例数)。
⼀般情况下(临时监测),服务消费者要从Nacos获取可用实例有健康/不健康状态之分。Nacos在返回实例时,只会返回健康实例。
但在高并发、大流量场景会存在⼀定的问题。比如,服务A有100个实例,98个实例都处于不健康状态,如果Nacos只返回这两个健康实例的话,流量洪峰的到来可能会直接打垮这两个服务,进一步产生雪崩效应。保护阈值存在的意义在于当服务A健康实例数/总实例数 < 保护阈值时,说明健康的实例不多了,保护阈值会被触发(状态true)。
Nacos会把该服务所有的实例信息(健康的+不健康的)全部提供给消费者,消费者可能访问到不健康的实例,请求失败,但这样也⽐造成雪崩要好。牺牲了⼀些请求(将请求分流到不健康的实例),保证了整个系统的可⽤。
6、配置管理
实现“统一配置”与“热更新”
-
简介:
使用 Nacos 可以实现实例的统一配置与配置热更新(即当配置被修改时,主动推送并实现热更新、不重启)
应该将固定不变配置写入服务本身的
application.yml
,易于变化的配置则写入 Nacos 配置文件。 -
应用 Nacos 统一配置流程图
声明:一个服务如果以 nacos 作为配置中心,应该先拉取 nacos 中管理的配置,然后与本地的配置文件比如 application.yml 中的配置合并,最后作为项目的完整配置,启动项目。
实现原理:Spring 中
bootstrap.yml
文件的启动优先级高于application.yml
,我们可以将 Nacos 配置写入其中(注意单词有两个t
)。 -
【共同配置】
在Nacos情境下,微服务在启动时会从 Nacos 读取2个配置文件,按优先级为:
配置名称-环境.yaml
:userservice-dev.yaml
配置环境.yaml
:userservice.yaml
而且无论如何都会读取到第二个配置环境,所以我们可以将微服务相同的配置再放入第二种配置环境中。
-
【统一配置】:
- Nacos 中新建配置文件,命名规则:
服务名称-环境.yaml
,在其中编写易于变化的配置。 - 微服务程序中引入
nacos-config
依赖。 - 编写
bootstrap.yml
文件,这些配置决定了微程序会去读取哪一个Nacos配置文件。- Nacos地址
- 服务名称
- 当前环境
- 文件后缀名
- Nacos 中新建配置文件,命名规则:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configSpringCloud入门概述