Spring Cloud 高级进阶
微服务监控之 Turbine 聚合监控
参考上⽂Hystrix部分
微服务监控之分布式链路追踪技术 Sleuth Zipkin
分布式链路追踪技术适⽤场景(问题场景)
场景描述
为了⽀撑⽇益增⻓的庞⼤业务量,我们会使⽤微服务架构设计我们的系统,使得 我们的系统不仅能够通过集群部署抵挡流量的冲击,⼜能根据业务进⾏灵活的扩展。那么,在微服务架构下,⼀次请求少则经过三四次服务调⽤完成,多则跨越⼏⼗ 个甚⾄是上百个服务节点。那么问题接踵⽽来:
1)如何动态展示服务的调⽤链路?(⽐如A服务调⽤了哪些其他的服务---依赖 关系) 2)如何分析服务调⽤链路中的瓶颈节点并对其进⾏调优?(⽐如A—>B—>C,C 服务处理时间特别⻓) 3)如何快速进⾏服务链路的故障发现?
这就是分布式链路追踪技术存在的⽬的和意义
分布式链路追踪技术
如果我们在⼀个请求的调⽤处理过程中,在各个链路节点都能够记录下⽇志,并 最终将⽇志进⾏集中可视化展示,那么我们想监控调⽤链路中的⼀些指标就有希 望了~~~⽐如,请求到达哪个服务实例?请求被处理的状态怎样?处理耗时怎 样?这些都能够分析出来了...
分布式环境下基于这种想法实现的监控技术就是就是分布式链路追踪(全链路追 踪)。
市场上的分布式链路追踪⽅案
分布式链路追踪技术已然成熟,产品也不少,国内外都有,⽐如
Spring Cloud Sleuth Twitter Zipkin 阿⾥巴巴的“鹰眼” ⼤众点评的“CAT” 美团的“Mtrace” 京东的“Hydra” 新浪的“Watchman” 另外还有最近也被提到很多的Apache Skywalking。
分布式链路追踪技术核⼼思想
本质:记录⽇志,作为⼀个完整的技术,分布式链路追踪也有⾃⼰的理论和概念
微服务架构中,针对请求处理的调⽤链可以展现为⼀棵树,示意如下
上图标识⼀个请求链路,⼀条链路通过TraceId唯⼀标识,span标识发起的请求信 息,各span通过parrentId关联起来
注意:我们往往把Spring Cloud Sleuth 和 Zipkin ⼀起使⽤,把 Sleuth 的数据信 息发送给 Zipkin 进⾏聚合,利⽤ Zipkin 存储并展示数据。
微服务统⼀认证⽅案 Spring Cloud OAuth2 JWT
第⼆代 Spring Cloud 核⼼组件 (SCA)
第⼀代 Spring Cloud (主要是 SCN)很多组件已经进⼊停更维护模式。
Spring Cloud:Netflix,Spring官⽅,SCA(被Spring官⽅认可) 注意:市场上主要使⽤的还是SCN,SCA⼀套框架的集合
Alibaba 更进⼀步,搞出了Spring Cloud Alibaba(SCA),SCA 是由⼀些阿⾥巴巴 的开源组件和云产品组成的,2018年,Spring Cloud Alibaba 正式⼊住了 Spring Cloud 官⽅孵化器。
- Nacos(服务注册中⼼、配置中⼼)
- Sentinel哨兵(服务的熔断、限流等)
- Dubbo RPC/LB
- Seata分布式事务解决⽅案
nacos
下载 nacos 编译后压缩包 nacos-server-$version.zip
包。
启动服务器 Linux/Unix/Mac 启动命令(standalone代表着单机模式运行,非集群模式):
代码语言:javascript复制sh startup.sh -m standalone
Windows 启动命令(standalone代表着单机模式运行,非集群模式):
代码语言:javascript复制cmd startup.cmd -m standalone
保护阈值:可以设置为0-1之间的浮点数,它其实是⼀个⽐例值(当前服务健康实例数/当前服务总实例数)。
保护阈值的意义在于当服务A健康实例数/总实例数 < 保护阈值 的时候,nacos将会把该服务所有的实例信息全部提供给消费者,消费者可能访问到不健康的实例,保证了整个系统的⼀个可⽤。
Nacos 数据模型(领域模型)
Namespace 命名空间、Group 分组、集群这些都是为了进⾏归类管理,把服务和配置⽂件进⾏归类,归类之后就可以实现⼀定的效果,⽐如隔离 ⽐如,对于服务来说,不同命名空间中的服务不能够互相访问调⽤
Namespace:命名空间,对不同的环境进⾏隔离,⽐如隔离开发环境、测试环境和⽣产环境 Group:分组,将若⼲个服务或者若⼲个配置集归为⼀组,通常习惯⼀个系统归为⼀个组 Service:某⼀个服务,⽐如简历微服务 DataId:配置集或者可以认为是⼀个配置⽂件
Namespace Group Service 如同 Maven 中的GAV坐标,GAV坐标是为了锁定Jar,⼆这⾥是为了锁定服务 Namespace Group DataId 如同 Maven 中的GAV坐标,GAV坐标是为了锁定Jar,⼆这⾥是为了锁定配置⽂件
SCA Nacos 服务注册和配置中⼼
Nacos (Dynamic Naming and Configuration Service)是阿⾥巴巴开源的⼀个针对微服务架构中服务发现、配置管理和服务管理平台。 Nacos就是注册中⼼ 配置中⼼的组合(Nacos=Eureka Config Bus)
官⽹:https://nacos.io 下载地址:https://github.com/alibaba/Nacos
Nacos功能特性
- 服务发现与健康检查
- 动态配置管理
- 动态DNS服务
- 服务和元数据管理(管理平台的⻆度,nacos也有⼀个ui⻚⾯,可以看到注册的服务及其实例信息(元数据信息)等),动态的服务权重调整、动态服务优雅下线,都可以去做
SCA Sentinel 分布式系统的流量防卫兵
Sentinel是⼀个⾯向云原⽣微服务的流量控制、熔断降级组件。替代Hystrix,针对问题:服务雪崩、服务降级、服务熔断、服务限流。
Sentinel 分为两个部分: 核⼼库:(Java 客户端)不依赖任何框架/库,能够运⾏于所有 Java 运⾏时环 境,同时对 Dubbo / Spring Cloud 等框架也有较好的⽀持。 控制台:(Dashboard)基于 Spring Boot 开发,打包后可以直接运⾏,不需 要额外的 Tomcat 等应⽤容器。
Nacos Sentinel Dubbo 三剑合璧
删除OpenFeign 和 Ribbon,使⽤Dubbo RPC 和 Dubbo LB。
SCA ⼩结
1)因为内容重叠,SCA 中的分布式事务解决⽅案 Seata 会在紧接着的Mysql课程中 讲解。 2)SCA实际上发展了三条线
第⼀条线:开源出来⼀些组件 第⼆条线:阿⾥内部维护了⼀个分⽀,⾃⼰业务线使⽤ 第三条线:阿⾥云平台部署⼀套,付费使⽤ 从战略上来说,SCA更是为了贴合阿⾥云。 ⽬前来看,开源出来的这些组件,推⼴及普及率不⾼,社区活跃度不⾼,稳定性 和体验度上仍需进⼀步提升,根据实际使⽤来看Sentinel的稳定性和体验度要好 于Nacos。
作业
编程题:根据如下描述,改造 Spring Cloud(上)的作业,完成以下要求: 1、Eureka 注册中心替换为 Nacos 注册中心 2、Config Bus 配置中心替换为 Nacos 配置中心 3、Feign 调用 替换为 Dubbo RPC 调用 4、使用 Sentinel 对 GateWay 网关的入口资源进行限流(限流参数自定义并完成测试即可)
注意:所有替换组件使用单节点即可
作业资料说明: 1、提供资料:代码工程、验证及讲解视频。 2、讲解内容包含:题目分析、实现思路、代码讲解。 3、效果展示
这个作业可以根据之前的图进行下列的改造:
首先,保证基本配置不变。比如 nginx 配置依旧得到保留。
第一步: 启用 Nacos 服务端
使用单机模式进行启动 sh startup.sh -m standalone
。Nacos 将默认使用 8848 端口.
访问地址为:http://localhost:8848/nacos/
第二步: 集成 Nacos 客户端发现服务配置
lagou-parent 的 pom 文件中引入依赖
代码语言:javascript复制 <dependencyManagement/>
</dependencies/>
...
<!--SCA -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--SCA -->
</dependencies>
</dependencyManagement>
在⼯程中注释掉 eureka 客户端相关依赖, 引⼊ nacos客户端依赖
代码语言:javascript复制<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
bootstrap.yml 新增以下配置
代码语言:javascript复制spring:
cloud:
nacos:
discovery:
# 配置 nacos server地址
server-addr: 192.168.3.29:8848
然后根据此种方式依次改造 code, email, gateway 和 user 微服务。
【可选操作】这里顺便对 Nacos Server 数据持久化改造, 方便 nacos 服务端每次重启后还得重新进行配置.
- 执行项目中的
${nacoshome}/conf/nacos-mysql.sql
SQL 语句。 - 修改
${nacoshome}/conf/application.properties
,增加 Mysql 数据源配置
spring.datasource.platform=mysql
### Count of DB:
db.num=1
### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?
characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=123456
第三步: Nacos Nacos 客户端配置集成
- 微服务中如何锁定 Nacos Server 中的配置⽂件(dataId) 通过 Namespace Group dataId 来锁定配置⽂件.
目前已知 Namespace 不指定就默认public Group不指定就默认 DEFAULT_GROUP dataId 的完整格式如下 {prefix}-{spring.profile.active}.
先在网页中进行新建配置 lagou-cloud-config.yaml
spring:
# 1. 数据库配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: YOUR-URL
username: YOUR-USER-NAME
password: YOUR-PASSWORD
# 2. 邮箱配置
mail:
## 发送邮件服务器
host: YOUR-HOST
## 发送邮件的邮箱地址
username: YOUR-USER-NAME
## 客户端授权码,不是邮箱密码,这个在qq邮箱设置里面自动生成的
password: YOUR-PASSWORD
# 3. 防暴刷配置:限制单个客户端ip最新 X 分钟的请求注册接口不能超过 Y 次
myconfig:
x: 2
y: 2
- 客户端添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos�config</artifactId>
</dependency
和 bootstap.yml 配置
代码语言:javascript复制spring:
cloud:
nacos:
config:
server-addr: ${myServerIp}:8848
namespace: public
group: DEFAULT_GROUP
# 前缀
prefix: lagou-cloud-config
# 拓展名,默认为 properties
file-extension: yaml
- 通过@Value读取属性, 通过 @RefreshScope 注解使支持自动刷新.
举例改造 email 服务
代码语言:javascript复制package com.lagou.edu.service.impl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
...
...
@Service
@RefreshScope
public class EmailServiceImpl implements EmailService {
@Value("${spring.mail.username}")
private String fromEmailAddress;
/**
* @param toEmailAddress 收件人邮箱
* @param code 几位数的验证码
*/
@Override
public void sendSimpleMail(String toEmailAddress, String code) {
...
...
}
}
测试验证: email 服务是否可以读取配置. http://edu.lagou.com:8082/email/acc8226@vip.qq.com/123456
第四步: Sentinel 集成
服务端依旧是通过 java -jar 的方式启动: java -jar ./sentinel-dashboard-1.7.2.jar
- 客户端 pom.xml 引用依赖
<!--Sentinel 核⼼环境 依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
- 客户端配置 yml
spring:
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8080 # sentinel dashboard/console
port: 8719 # sentinel会在该端⼝启动http server,那么这样 的话,控制台定义的⼀些限流等规则才能发送传递过来, #如果8719端⼝被占⽤,那么会依次 1
- 简单配置流控规则
这里顺便对 Sentinel 进行数据持久化改造【可选操作】
lagou-service-email-degrade-rules
代码语言:javascript复制[
{
"resource":"/email/acc8226@vip.qq.com/123456",
"grade":2,
"count":1,
"timeWindow":5
}
]
lagou-service-email-flow-rules
代码语言:javascript复制[
{"resource":"/email/acc8226@vip.qq.com/123456",
"limitApp":"default",
"grade":1,
"count":1,
"strategy":0,
"controlBehavior":0,
"clusterMode":false}
]
代码语言:javascript复制<!-- Sentinel⽀持采⽤ Nacos 作为规则配置数据源,引⼊该适配依赖 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
代码语言:javascript复制spring:
cloud:
sentinel:
datasource:
# 此处的flow为⾃定义数据源名
flow: # 流控规则
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
data-id: ${spring.application.name}-flow-rules
groupId: DEFAULT_GROUP
data-type: json
# 类型来⾃RuleType类 流控规则
rule-type: flow
degrade: # 流控规则
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
data-id: ${spring.application.name}-degrade-rules
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
第五步: feign 换成 dubbo
- 注释掉父工程的 spring-boot-devtools 依赖
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
- 客户端配置
1.创建 lagou-service-dubbo-api 工程. 这里包含了共用的接口.
2.添加dubbo 相关依赖
代码语言:javascript复制 <!--spring cloud alibaba dubbo 依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
</dependency>
3.实现类使用 org.apache.dubbo.config.annotation.Service 注解. 而非spring的注解.
4.yaml 进行配置
代码语言:javascript复制dubbo:
scan:
# dubbo 服务扫描基准包
base-packages: com.lagou.edu.service.impl
protocol:
# dubbo 协议
name: dubbo
# dubbo 协议端⼝( -1 表示⾃增端⼝,从 20880 开始)
port: -1
registry:
# 挂载到 Spring Cloud 的注册中⼼
address: spring-cloud://192.168.3.29
spring:
main:
allow-bean-definition-overriding: true
具体实现: 改造 email 微服务
- 删除 feigen 和 robbion 配置. 转用 dubbo 相关配置. 同样需要配置下spring.main.allow-bean-definition-overriding=true 2.将 EmailService 接口移动至 lagou-sercie-dobbo-api 服务 3.service 添加 dubbo 的 @Service 注解 4.配置 bootstrap.yml, 添加以下内容。
# 只提供服务
dubbo:
scan:
# 服务扫描基准包
base-packages: com.lagou.edu.service.impl
protocol:
# dubbo 协议
name: dubbo
# dubbo 协议端⼝( -1 表示⾃增端⼝,从 20880 开始)
port: -1
registry:
# 挂载到 Spring Cloud 的注册中⼼
address: spring-cloud://192.168.3.29
改造 code 微服务
- 删除 feigen 和 robbion 配置. 转用 dubbo 相关配置. 同样需要配置下spring.main.allow-bean-definition-overriding=true 2.将 CodeService 接口移动至 lagou-sercie-dobbo-api 服务 3.service 添加 dubbo 的 @Service 注解 4.配置 bootstrap.yml, 添加以下内容。
# 只提供服务
dubbo:
scan:
# dubbo 服务扫描基准包
base-packages: com.lagou.edu.service.impl
protocol:
# dubbo 协议
name: dubbo
# dubbo 协议端⼝( -1 表示⾃增端⼝,从 20880 开始)
port: 20881
host: 192.168.3.29
registry:
# 挂载到 Spring Cloud 的注册中⼼
address: spring-cloud://192.168.3.29
# 还使用服务
cloud:
# 订阅服务提供⽅的应⽤列表,订阅多个服务提供者使⽤ "," 连接
subscribed-services: lagou-service-email,lagou-service-user
验证: 发送验证码的服务是否正常 http://localhost:8081/code/create/acc8226@qq.com
改造 user 微服务
- 删除 feigen 和 robbion 配置. 转用 dubbo 相关配置. 同样需要配置下spring.main.allow-bean-definition-overriding=true 2.将 UserService 接口移动至 lagou-sercie-dobbo-api 服务
- service 添加 dubbo 的 @Service 注解
- 配置 bootstrap.yml, 添加以下内容。
# 只提供服务
dubbo:
scan:
# dubbo 服务扫描基准包
base-packages: com.lagou.edu.service.impl
protocol:
# dubbo 协议
name: dubbo
# dubbo 协议端⼝( -1 表示⾃增端⼝,从 20880 开始)
port: 20882
host: 192.168.3.29
registry:
# 挂载到 Spring Cloud 的注册中⼼
address: spring-cloud://192.168.3.29
# 还使用服务
cloud:
# 订阅服务提供⽅的应⽤列表,订阅多个服务提供者使⽤ "," 连接
subscribed-services: lagou-service-code
验证: 注册功能是否好使 http://localhost:8077/user/register/acc8226@qq.com/123456/989410
第六步网关改造
详见第四步提到的 Sentinel 集成方案.
pom 导入 Sentinel 核心依赖
代码语言:javascript复制 <!--Sentinel 核⼼环境 依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
bootstrap.yml 需要新增以下配置
代码语言:javascript复制spring:
cloud:
sentinel:
transport:
# sentinel服务端地址
dashboard: 127.0.0.1:8080
# sentinel dashboard/console
port: 8719 # sentinel会在该端⼝启动 http server,那么这样的话,控制台定义的⼀些限流等规则才能发送传递过来,
# 如果8719端⼝被占⽤,那么会依次 1
# 如果发现监听的地址不对的话,可以在sentinel客户端配置中加入客户端ip配置
# client-ip: 192.168.0.7
测试验证:添加每秒只能访问1次的限制 测试地址:http://edu.lagou.com/api/user/info/5d1ad7d9-53ba-4566-8a39-6a96078545da
参考
nacos 中文官网 https://nacos.io/zh-cn/
SpringCloud、dubbo 和 druid 问题总结 - 星火燎原智勇 - 博客园 https://www.cnblogs.com/liang1101/p/12702631.html