Spring Cloud Alibaba从入门到精通,史上最全面的讲解(下篇)
- 跳转连接:上篇地址
九. 消息驱动的微服务-Spring Cloud Alibaba
9.1 Spring实现异步的方法
9.2 引入MQ后的架构演进
- 引入MQ后,一些同步耗时的地方可以用异步处理,MQ作为一个中间件连接两个地方
9.3 MQ适用场景
- 异步处理
- 流量削峰填谷
- 解耦微服务
9.4 MQ的选择
9.5 搭建RocketMQ
9.6 搭建RocketMQ控制台
9.7 RocketMQ的术语与概念
-
术语/概念:
9.8 RocketMQ进阶
- 如果要完整的去理解RocketMQ,我们需要阅读开发者指南
9.9 Spring消息编程模型01
- 在项目中使用RocketMQ:
-
引入依赖:
-
写注解: 无注解
-
写配置:
-
引入RocketTemplate:
-
发送消息:
不指定group会报异常,后期不知是否会处理这种;
-
- 工具类的使用:
- RocketMQ: RocketMQTemplate
- ActiveMQ/Artemis:JmsTemplate
- RabbitMQ:AmqpTemplate
- Kafka: KafkaTemplate
9.10 Spring消息编程模型02
- 我们已经编写好了消息的生产者,接下来我们来编写消息的消费者:
- 步骤如下:
- 引入依赖:
<dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-spring-boot-starter</artifactId> <version>2.0.3</version> </dependency>
- 写配置,在application.yml中编写:
rocketmq: name-server:127.0.0.1:9876
name-server的值根据每个人自身实际的ip及端口来填写,以我们安装的rocketmq地址来决定
- 创建接收消息的对象:
@Data @NoArgsConstructor @AllArgsConstructor @Builder public class UserAddBOnusMsgDTO{ /** * 为谁加积分 */ private Integer userId; /** * 加多少积分 */ private Integer bonus; }
- 创建消息监听类:
@Service @RocketMQMessageListener(consumerGroup= "consumer-group",topic= "add-bonus") public class AddBonusListener implements RocketMQListener<UserAddBonusMsgDTO>{ @Override public void onMessage(UserAddBonusMsgDTO message){ System.out.println(message.getUserId()) System.out.println(message.getBonus()) } }
注意:consumerGroup在生产者中是写到配置文件中的,在消费者中是在此处进行指定的。topic在生产者中是发送消息的时候添加,在此处是接收监听类的时候指定,这两个都必须带上;
- 引入依赖:
- 官方文档中对各类MQ的使用方法总结
- 消费者各个MQ的注解简单总结:
- RocketMQ: RocketMQMessageListener
- ActiveMQ/Artemis:JmsListener
- RabbitMQ: RabbitListener
- Kafka: KafkaListener
9.11 分布式事务01
- 以前解决事务的办法: @Transactional(rollbackFor= Exception.class) 当发现了Exception异常,就进行回滚
- 存在的问题:
- 图示:
- 问题概述:当我们的逻辑代码中,不仅仅对数据库做了处理,一些场景下我们需要同时进行消息发送和与MySQL进行交互的功能;此图中,我们首先进行了消息发送,然后再把消息写入缓存,那么就会导致: 如果写入缓存的时候,代码执行失败,回滚操作只能回滚数据库,消息已经被消费者监听到了并做了处理了。
- 图示:
- RocketMQ实现事务的流程:
简单来说RocketMQ实现分布式事务的原理是: 执行到应该发送消息的时候,它并未发送,而是处于“准备发送”阶段,当所有的代码都已执行完毕且无异常时,则进行完全发送,此刻消息消费者才能监听到消息;
- 概念术语解答:
- 半消息(Half(Prepare) Message)
- 暂时无法消费的消息。生产者将消息发送到了MQ server,但这个消息会被标记为“暂不能投递”状态,先存储起来;消费者不会去消费这条消息
- 消息回查(Message Status Check)
- 网络断开或生产者重启可能会导致丢失事务消息的第二次确认。当MQ Server发现消息长时间处于半消息状态时,将向消息生产者发送请求,询问该消息的最终状态(提交或回滚)
- 消息三态:
- Commit:提交事务消息,消费者可以消费此消息
- Rollback: 回滚事务消息,broker会删除该消息,消费者不能消费
- UNKNOWN: broker需要回查确认该消息的状态
- 半消息(Half(Prepare) Message)
9.12 分布式事务02- 编码
-
到数据库中新增一张表,用来记录 RocketMQ的事务日志:
- 执行代码:
create table rocketmq_transaction_log( id int auto_increment comment 'id' primary key, transaction_Id varchar(45) not null comment '事务id', log varchar(45) not null comment '日志')
- 执行代码:
-
消息生产者编写:发送半消息:
// 首先可以判断,当前面代码执行成功后再执行此代码,此处略 // 发送半消息 String transactionId=UUID.randomUUID().toString() this.rocketMQTemplate.sendMessageInTransaction( "tx-add-bonus-group","add-bonus",MessageBuilder.withPayload( UserAddBonusMsgDTO.builder().userId(share.getUserId) .bonus(50) .build() ).setHeader(RocketMQHeaders.TRANSACTION_ID,transactionId) .setHeader("share_id",id) .build(), auditDTO )
此处 "tx-add-bonus-group","add-bonus" 组名及topic是由自己指定的,可根据实际改变。auditDTO、share_id是根据业务需要所传入的数据,auditDTO在消息监听类中可以直接强转使用,share_id的数据可以直接从请求头中获取;
-
消息消费者编写:
@RocketMQTransactionListener(txProducerGroup = "tx-add-bonus-group") @RequiredArgsConstructor(onConstructor = @_(@Autowired)) public class AddBonusTransactionListener implements RocketMQLocalTransactionListener{ @Override public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) String transactionId(String)headers.get(RocketMQHeaders.TRANSACTION_ID); Integer shareId= Integer.valueOf((String)headers.get("share_id")) try{ this.shareService.auditByIdInDB(shareId,(ShareAuditDTO) arg) return RocketMQLocalTransactionState.COMMIT; }catch(Exception e){ return RocketMQLocalTransactionState.ROLLBACK; } } // 编写回查代码,当我们 @Override public RocketMQLocalTransactionState checkLocalTransaction(Message msg){ return null; } }
当我们执行成功,则执行RocketMQLocalTransactionState.COMMIT,失败则ROLLBACK。但是有这样一种情况,比如我们已经执行完逻辑代码,正准备COMMIT提交,此时突然停电了,导致数据已经存入,但是却没有提交成功。所以我们需要一个回查方法,checkLocalTransaction()是一个回查方法,它会去里面进行判断是否执行成功。结合我们已经建立的RocketMQ事务表,我们可以进行回查操作,代码看下方: // auditByInDB具体方法内容如图所示:
-
新建一个存入方法,我们之前的存入方法,没有将事务数据加入日志表,我们可以这样改造: 当数据存入的时候,将数据存入日志表;回查方法就进行回查,如果没有存入则表示执行失败:
@Autowired private RocketmqTransactionLogMapepr rocketmqTransactionLogMapepr; @Transactional(rollbackFor= Exception.class) public void auditByIdWithRocketMqLog(Integer id, ShareAuditDTO auditDTO, String transactionId){ this.auditByIdInDB(id,auditDTO); this.rocketmqTransactionLogMapper.insertSelective( RocketmqTransactionLog.builder().transactionId(transactionId) .log("审核分享") .build() ); }
-
消息消费者重写:
@Autowired private ShareService shareService; @Autowired priavte RocketmqTransactionLogMapper rocketmqTransactionLogMapper; @RocketMQTransactionListener(txProducerGroup = "tx-add-bonus-group") @RequiredArgsConstructor(onConstructor = @_(@Autowired)) public class AddBonusTransactionListener implements RocketMQLocalTransactionListener{ @Override public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) String transactionId(String)headers.get(RocketMQHeaders.TRANSACTION_ID); Integer shareId= Integer.valueOf((String)headers.get("share_id")) try{ this.shareService.auditByIdWIthRocketMqLog(shareId,(ShareAuditDTO) arg,transactionId) return RocketMQLocalTransactionState.COMMIT; }catch(Exception e){ return RocketMQLocalTransactionState.ROLLBACK; } } // 编写回查代码,当我们 @Override public RocketMQLocalTransactionState checkLocalTransaction(Message msg){ MessageHeaders headers= msg.getHeaders(); String transactionId= (String) headers.get(RocketMQHeaders.TRANSACTION_ID); // 查询是否存了事务数据 this.rocketmqTransactionLogMapper.selectOne(RocketmqTransactionLog.builder().transactionId(transactionId).build()); // 判断是否提交 if(transactionLog != null){ return RocketMQLocalTransactionState.COMMIT; } return RocketMQLocalTransactionState.ROLLBACK; } }
使用header和arg可以传参
9.13 Spring Cloud Stream 是什么?
- 是一个用于构建消息驱动的微服务的框架
- 架构:
9.14 Spring Cloud Stream 编程模型
- 概念:
- Destination Binder(目标绑定器)
- 与消息中间件通信的组件
- Destination Bindings(目标绑定)
- Binding是连接应用程序跟消息中间件的桥梁,用于消息的消费和生产,由binder创建
- Message(消息)
- Destination Binder(目标绑定器)
- 编程模型图:
当消息生产者使用Kafka发送消息,那只能用Kafka来接收消息。当使用SpringCloudStream来处理消息的话,我们接收Kafka的消息,可以使用其他的消息中间件来进行接收。SpringCloudStream对消息进行了一层封装,所以我们不需要去关心生产者用的是什么消息中间件。
9.15 Spring Cloud Stream 代码-消息生产者
- 编写生产者:
- 添加依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-stream-rocketmq</artifactId> </dependency>
- 添加注解(在启动类上添加注解):
- 添加@ EnableBing(Source.class) 注解,如图所示:
- 添加@ EnableBing(Source.class) 注解,如图所示:
- 写配置(application.yml):
spring: cloud: stream: rocketmq: binder: name-server: 127.0.0.1:9876 bindings: output: # 用来指定topic destination: stream-test-topic
- 生产者发送消息:
@GetMapping("test-stream") public String testStream(){ this.source.output() .send( MessageBuilder .withPayload("消息体") .build() ); return "success"; }
- 检查是否成功发送。
- 在控制台中我们可以查看此组下是否有已发送过的消息:
- 如果控制台在一直打印日志的话,我们可以降低日志级别:
- 在控制台中我们可以查看此组下是否有已发送过的消息:
- 添加依赖:
9.16 Spring Cloud Stream 消息消费者
- 编写消费者:
- 添加依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-stream-rocketmq</artifactId> </dependency>
- 添加注解(在启动类上添加注解):@EnableBinding(Sink.class)
- 写配置(application.yml):
spring: cloud: stream: rocketmq: binder: name-server: 127.0.0.1:9876 bindings: input: destination: stream-test-topic group: binder-group # 这里的group 一定要设置; 如果使用的不是rocketmq的话,这里可以不用设置,可以留空
- 监听消费类:
@Service @Slf4j public class TestStreamConsumer{ @StreamListener(Sink.INPUT) public void receive(String messageBody){ log.info("通过stream收到了消息: messageBody = {}"); } }
- 添加依赖:
9.17 Spring Cloud Stream 接口自定义:消息生产者
- 接口:
public interface MySource{ String MY_OUTPUT= "my-output"; @Output(MY_OUTPUT) MessageChannel output(); }
- 启动类上,**@EnableBinding注解上引入 MySource.class,如图所示:
- 加配置:
- 定义接口,发送消息:
使用自定义的接口我们可以进行消息的收发;
9.18 Spring Cloud Stream 接口自定义:消息消费者
- 创建方法:
- 启动类中引入:
- 配置类修改:
- 使用自定义接口:消息消费监听,如图所示:
9.19 消息过滤
9.20 Spring Cloud Stream 的监控
- Spring Cloud Actuator为我们提供了三个端点来监控Stream:
- /actuator/bindings
- /actuator/channels
- /actuator/health
9.21 Spring Cloud Stream 异常处理
- 错误处理手记
- 定义全局异常处理的办法如下:
@StreamListener("errorChannel") public void error(Message<?> message){ ErrorMessage errorMessage= (ErrorMessage) message; log.warn("发生异常,errorMessage = {}",errorMessage); }
9.22 Spring Cloud Stream + RocketMQ实现分布式事务
- SpringCloud Stream 本身没有实现分布式事务,它与RocketMQ结合则是使用RocketMQ的分布式事务。它若与其他结合,则使用其他消息中间件的分布式事务。
- Spring Cloud Stream 的分布式事务改造如图:
-
发送者从rocketRestTemplate改为source:
-
在配置文件中定义组合事务:
-
消息的监听定义组名称时,一定要与配置文件中的保持一致,如图所示:
-
十. Spring Cloud Gateway
10.1 为什么要使用网关
- 在不使用Gateway的情况下,当我们直接与微服务通信的情况下,需要每个服务都进行网关登录验证,同时需要解决各个服务的登录状态的同步等功能;
- 使用Gateway可以对外暴露一个域名,微服务无论增加多少,都只需要指向一个网关即可,它可以统一对外进行登录、校验、授权、以及一些拦截操作;
10.2 Spring Cloud Gateway 是什么?
- 它是SpringCloud的网关(第二代),未来会取代Zuul(第一代)
- 基于Netty、Reactor以及WebFlux构建(所以它启动会比其他微服务一般要快)
- 它的优点:
- 性能强劲: 它的性能是第一代网关Zuul 1.x的1.6倍! 性能PK
- 功能强大:内置了很多实用功能,比如转发、监控、限流等
- 设计优雅、易扩展
- 它的缺点:
- 依赖Netty与Webflux,不是Servlet编程模型,有一定适应成本
- 不能在Servlet容器下工作,也不能构建成WAR包
- 不支持Spring Boot 1.x
10.3 编写Spring Cloud Gateway
- 创建项目 gateway,此处省略
-
pom.xml:
-
父工程依赖:
-
定义SpringCloud版本、gateway依赖:
-
SpringCloudAlibaba等引入:
-
加入Nacos、Actuator依赖:
-
-
application.yml配置:
-
配置端口及nacos、gateway配置:
-
配置Actuator相关配置:
-
-
启动gateway
-
gateway是基于Netty,所以启动速度非常快。从上面就已经可以进行服务转发了,因为gateway:discovery:locator:enabled:true 可以自动让服务转发到对应的路径去;
- 转发规律:访问${GATEWAY_URL}/{微服务X}/路径 会转发到微服务X的/路径
10.4 核心概念
- Route(路由):
- Spring Cloud Gateway 的基础元素,可简单理解成一条转发的规则。包含:ID、目标URL、Predicate集合以及Filter集合。
- Predicate(谓词):即 java.util.function.Predicate,Spring Cloud Gateway 使用Predicate实现路由的匹配条件
- Filter(过滤器): 修改请求以及响应
- 路由配置示例:
10.5 架构剖析
- 架构图:
- 源码:
10.6 内置路由谓词工厂详解(Route Predicate Factories)
- 工厂图示:
- 谓词工厂手记
10.7 自定义路由谓词工厂
- 自定义路由谓词工厂类必须以PredicateFactory结尾命名
- 大致步骤:
- 继承 AbstractRoutePredicateFactory<自定义配置对象>
- 添加构造方法
- 重写抽象方法
- 配置中添加配置规则
10.8 内置过滤器工厂详解
10.9 自定义过滤器工厂
- 内容介绍:
- 过滤器生命周期
- 自定义过滤器工厂的方式
- 核心API
- 编写一个过滤器工厂
- 过滤器生命周期:
- pre: Gateway 转发请求之前
- post: Gateway 转发请求之后
- 自定义过滤器工厂- 方式1:
- 继承和参考示例:
- 配置形式:
- 继承和参考示例:
- 自定义过滤器工厂-方式2:
- 自定义过滤器工厂-核心API
这些过滤器工厂的核心Api比较简单,从名称就可以看出其含义;
- 编写一个过滤器工程:
-
创建一个类: PreLogGatewayFilterFactory:
最后在过滤器工厂上面加上 @Component 注解
-
在配置中新增内容,并修改工厂类,打印配置中新增的数据:
配置文件中,传入了ab两个配置值,在我们工厂类中可以通过config.getName,config.getValue获取到;当有请求访问经过此过滤器工厂时,日志就会打印出来了;
-
10.10 全局过滤器
- 会作用在所有的路由,有执行顺序的概念,order越小越靠前执行;
- 手记笔记
10.11 悬念:如何为Spring Cloud Gateway 整合Sentinel?
sentinel要在1.6 版本以后才支持gateway
10.12 监控SpringCloud gateway
10.13 排错、调试技巧总结
10.14 进阶:再谈过滤器执行顺序
- 结论:
- order越小越靠前执行
- 过滤器工厂的Order按配置顺序从1开始递增
- 如果配置了默认过滤器,则线执行相同Order的默认过滤器
相同顺序的,以default-filter中的优先
- 如需自行控制Order,可返回OrderedGatewayFilter
- 源码:
10.15 Spring Cloud Gateway限流
10.16 本章总结
- 路由、路由谓词工厂、过滤器工厂、全局过滤器
- 网关集大成:
- 注册到Nacos
- 集成Ribbon
- 容错(默认Hystrix,也可用Sentinel)
十一. 微服务的用户认证与授权
11.1 认证授权-必然会面临的话题
- 每个应用基本上都需要进行登录,校验用户权限
11.2 有状态vs 无状态
- 有状态:
- 图示:
- 优点:服务端控制力强
- 缺点:存在中心点,鸡蛋放在一个篮子里,迁移麻烦,服务器端存储数据,加大了服务器端压力
- 图示:
- 无状态:
- 图示:
- 优点:去中心话,无存储,简单,任意扩容、缩容
- 缺点:服务器端控制力相对弱(不能随时强制让人下线,修改登录时长等)
- 图示:
11.3 微服务认证方案 01 “处处安全”
- 关于处处安全的博客
- 常用的协议为: OAuth2.0,系列文章
- 代表实现:
看好Keyclock,但是它不支持CLoud,它是Servlet模型的,无法与Gateway配合使用;
- 优点: 安全性高 缺点: 实现成本高,性能要低一些
11.4 微服务认证方案 02 - 外部无状态,内部有状态方案
- 图示:
- 它能够与老架构项目相兼容。就是老项目可能没有Token,但是可以从Session中获取信息。
它安全性和性能都不占优势,但它的优点是能够与老项目服务相兼容
11.5 微服务认证方案 03 - 网关认证授权、内部裸奔方案
- 图示:
安全性低,性能高
11.6 微服务认证方案 04 内部裸奔改进方案
- 图示:
- 每个服务都能够对Token进行解析,每个服务就不会裸奔了,但是每个服务都知道Token解密方式,容易暴露;
11.7 微服务认证方案 05 方案对比
- 对比图示:
11.8 访问控制模型
- 模型如图:
- RBAC:
11.9 JWT是什么?【是什么、组成】
- JWT全称Json web token,是一个开放标准(RFC 7519),用来在各方之间安全地传输信息。JWT可被验证和信任,因为它是数字签名的。
- JWT组成图示:
- 公式:
- JWT的手记
11.10 AOP实现登录状态检查
- 实现登录状态检查的方式:
建议使用SpringAop 来实现,这样解耦且灵活
- 手动实现切面:
- 定义注解:
- 定义切面:
- 定义异常捕获类:
- 定义注解:
11.11 Feign实现Token传递
-
Controller层可以接收Token:
-
Feign中可以携带Token:
-
上面的这种方式携带Token,需要每个都进行配置,比较麻烦。当我们Feign调用的接口比较多的时候,我们可以使用拦截器统一携带Token:
-
使用全局配置的时候,需要在配置中添加如图配置:
11.12 RestTemplate实现Token传递
- 两种方式,分别是
exchange()
和ClientHttpRequestInterceptor
- exchange()代码示例:
- 使用RestTemplate拦截器示例:
- 拦截器配置:
- RestTemplate配置:
- 拦截器配置:
11.13 Java 自定义注解
11.15 本章总结
十二. 配置管理
12.1 为什么要实现配置管理?
- 不同环境存在不同的配置
- 配置属性要求动态刷新,不重启
使用Nacos就可以作为一个配置服务器,实现上面两个功能;
12.2 使用Nacos管理配置
-
添加依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
-
写配置:- 配置内的内容与Nacos中的配置必须保持一致,一定要记住这张图:
-
建立bootstrap.yml:
spirngconfig与Nacos的配置是分开来的。config的配置建议放在bootstrap.yml中,否则可能不生效,应用无法读取配置;
-
代码中写入配置:
-
在Nacos中建立配置:
配置好内容后点击发布即可。
-
重启应用,调用接口,发现参数能获取到,完成!
12.3 配置属性动态刷新与回滚
-
在需要属性动态刷新的类上写上注解
@RefreshScope
,即可动态刷新配置,如图所示: -
当我们将itmuch改为itmuch.com,调用接口时,会自动刷新:
-
回滚:
12.4 应用的配置共享
-
配置共享:
-
shared-dataids:
-
方式2: ext-config:
-
方式3: 自动的方式:
这个自动方式就是里面的内容是所有环境的公共配置数据,profiles.active指向的环境可以放置其存在变化的配置;
-
优先级:
12.5 引导上下文
- 默认远程配置优先级更高,我们可以使用下方代码进行配置优先级:
- 远程配置优先级必须要在Nacos下配置才生效,如图所示:
12.6 数据持久化
服务发现组件是放在文件夹内。配置数据是放在嵌入式数据库中(生产环境建议更换为mysql);
12.7 搭建生产可用的Nacos集群
12.8 配置最佳实践总结
- 能放本地的情况下,就不要放在远程
- 尽量规避优先级,简化配置
- 定规范,例如所有配置属性都要加上注释
- 配置管理人员尽量少(Nacos的安全权限功能还未齐全,为了安全高效管理着想,人员尽量少)
十三. 调用链监控-Sleuth
13.1 调用链监控
- 使用调用链监控,我们能够清晰的看出来这个接口调用了哪些方法,哪些方法消耗了多少时间,同时如果出现了问题,是哪个方法出现了问题,我们也能够快速定位
- 业界主流的调用链监控工具
- Spring Cloud Sleuth+Zipkin
- Skywalking、Pinpoint
13.2 整合Sleuth
- 什么是Sleuth?
- Sleuth是一个Spring Cloud的分布式跟踪解决方案
- Sleuth术语?
- Span(跨度): Sleuth的基本工作单元,它用一个64位的id唯一标识。除ID外,span还包含其他数据,例如描述、时间戳事件、键值对的注解(标签)、span ID、span 父ID等
里面每一行数据,可以理解为一个span
- trace(跟踪): 一组span组成的树状结构成为trace
- Annotation(标注):
- CS(Client Sent 客户端发送):客户端发起一个请求,该annotation描述了span的开始
- SR(Serverr Received 服务器端的接收): 服务器端获得请求并准备处理它
- SS(Server Sent服务器端发送): 该annotation表明完成请求处理(当响应发回客户端时)
- CR(Client Received客户端接收):span结束的标识。客户端成功接收到服务器端的响应
- Span(跨度): Sleuth的基本工作单元,它用一个64位的id唯一标识。除ID外,span还包含其他数据,例如描述、时间戳事件、键值对的注解(标签)、span ID、span 父ID等
- 为用户中心整合Sleuth:
-
加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency>
-
修改日志级别(可打印更多的日志,可选项)
-
13.3 Zipkin搭建与整合
- Zipkin是什么?
- Zipkin是Twitter开源的分布式跟踪系统,主要用来收集系统的时序数据,从而追踪系统的调用问题
- Zipkin通俗来讲,它就是将sleuth收集来的数据进行存储、展示的,它的可视化界面能够更友好的,更清晰的为我们提供决策;
- 搭建Zipkin Server (本文章版本为:2.12.9)
- 方式一:使用Zipkin官方的Shell下载,如下命令可下载最新版本:
curl -sSL https://zipkin.io/quickstart.sh | bash -s
- 方式二: 到Maven中央仓库下载,访问如下地址即可:
https://search.maven.org/remote_content?g=io.zipkin.java&a=zipkin-server&v=1
下载下来的文件名为: zipkin-server-2.12.9-exec.jar
- 方式三:使用百度盘地址下载,提供2.12.9版本:
https://pan.baidu.com/s/1HXjzNDpzin6fXGrZPyQeWQ
密码:aon2
- 方式一:使用Zipkin官方的Shell下载,如下命令可下载最新版本:
- 启动Zipkin,执行如图所示命令:
java -jar zipkin-server-2.12.9-exec.jar
- 为用户中心整合Sleuth+Zipkin:
- 加依赖:去掉Sleuth,加上zipkin依赖(去掉sleuth是因为zipkin中有sleuth的依赖)
- Gradle:
compile group: 'org.springframework.cloud', name: 'spring-cloud-sleuth-zipkin', version: '2.2.3.RELEASE'
- Maven:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-zipkin</artifactId> <version>2.2.3.RELEASE</version> </dependency>
- Gradle:
- 加配置:设置zipkin服务器地址以及抽样率,如图所示:
抽样率不是越高越好,也不是越低越好。抽样率高的话,分析的更加准确,但是它的性能消耗会更严重;
- 加依赖:去掉Sleuth,加上zipkin依赖(去掉sleuth是因为zipkin中有sleuth的依赖)
13.4 整合Zipkin之后Nacos报错的解决
- SpringCloud 把http://localhost:9411/当做了服务发现组件里面的服务名称;于是,Nacos Client尝试从Nacos Server寻找一个名为:
localhost:9411
的服务...这个服务根本不存在,所以会一直报异常; - 解决方案:
- 方案一: 让Spring Cloud 正确识别 http://localhost:9411/当成一个URL,而不要当做服务名(选择此项目)
- 方案二: 把Zipkin Server注册到Nacos(官方不支持)
- 以方案一的方式解决,需要将
discoveryClientEnabled: false
,如图所示:这里的小驼峰命名是因为有一个小bug,后面会修复就以 - 隔开
13.5 为所有微服务整合Zipkin
- 参照13.5的引入方式;
13.6 Zipkin数据持久化
-
持久化方式:
- MySQL(不建议,有性能问题)
- Elasticsearch
- Cassandra
- 相关文档: (github.com/openzipkin/…]
-
下载ElasticSearch:( 建议使用5,6,7版本)
- 点击地址进行下载:(官网地址)[elastic.co/cn/downloads/past-releases#elasticsearch]
- 解压并进入目录:
- 切换到bin目录,并执行:
./elasticsearch
或后台执行./elasticsearch -d
- 查看Zipkin的环境变量,配置
STORAGE_TYPE
和ES_HOSTS
,然后执行zipkin server服务:
Zipkin其他环境变量:github.com/openzipkin/…
- 点击地址进行下载:(官网地址)[elastic.co/cn/downloads/past-releases#elasticsearch]
13.7 依赖关系图
- 使用ElasticSearch的话,需要使用
spark job
才能分析出依赖关系图,使用方式如下:它是zipkin的子项目,第一步下载,第二步启动
- Zipkin Dependencies使用ElasticSearch的环境变量:
- 启动Zipkin Dependencies:
- Zipkin Denpendencies其他的环境变量:(github.com/openzipkin/…]
- Zipkin Dependencies指定分析日期:
可以编写脚本每日执行;
十四. 既有代码优化与改善
14.1 简单指标: Statistic
- 注释原则:
- 每一步主要业务流程
- 核心方法
- 条件、分支、判断前
- 使用Statistic插件:
建议服务上线,注释率要求达到35%
14.3 Alibaba Java代码规约(P3c)
- github
- IDEA插件支持,搜索
Alibaba Java Coding Guidelines
14.4 SonarQube
- 教程
- 下载:jdk8只支持6.x~7.8.x 的版本
- 安装:
- 查看日志命令:
tail -f ../../logs/sonar.log
- 访问首页:localhost:9000/about
- 账号密码都是admin
- 根据手记我们与项目融合,建议使用Token,命令行的方式去融合。融合后我们可以很方便的看到程序有多少个bug,哪里的代码不够优雅等信息:
- 它还有很多插件,比如汉化插件、其他监控插件等:
内嵌数据库不方便伸缩,所以不适用于生产环境,所以建议更换为MySql之类的数据库
十五. 进阶:多维度微服务监控
1.51 本章概要
- Spring Boot Actutator: 监控微服务实例的情况
- Sentinel Dashboard: 监控实例的QPS、限流等
- Spring Cloud Sleuth+Zipkin: 监控服务的调用情况
15.2 Spring Boot Actuator监控数据库
-
SpringBoot Admin:
- 它是为Spring Boot 量身打造的一个简单易用的监控数据管理工具
- (GitHub地址)[github.com/codecentric…]
- (官方文档)[codecentric.github.io/spring-boot…]
-
搭建SpringBoot admin 步骤:
- 加依赖:
- 整合版本,如图所示:
- 加入SpringBootAdmin以及Nacos,将Admin注册到Nacos上,如图所示:
- 整合版本,如图所示:
- 写注解:
- 在启动类上添加
@EnableAdminServer
注解,如图所示:
- 在启动类上添加
- 加配置:
- 在application.yml中进行配置:
- 在application.yml中进行配置:
- 加依赖:
-
被监控的服务的步骤:
- 加依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
- 加配置:
- 加依赖:
15.3 JVM监控
- Spring Boot Actuator: metrics、heapdump、threaddump
- Java自带的JVM监控工具: jconsole、jvisualvm
- 自带工具打开方式:
- jconsole: 在IDEA或者CMD中输入 jconsole,如图所示:
- jvisualvm: 与jconsole类似,输入
jvisualvm
即可,如图所示:jvisualvm与jconsole类似,但是它的功能更强大一点,但是它们都是客户端形式,希望能出一款强大的web浏览形式的监控工具;
- jconsole: 在IDEA或者CMD中输入 jconsole,如图所示:
15.4 GC日志、线程Dump日志、堆Dump可视化分析
- 第一步,启动参数中设置打印GC详情日志:
- 第二步,选择项目,右击选择
Synchronize 'xxxx'
,生成出gc.log,如图所示: - 找到输出的日志文件,右键后选择
Reveal in Finder
,将文件导出: - 将生成的文件在
gceasy.io
中,点击选择文件打开,然后会生成统计图表 - 生成统计图表如图:
- 虽然这款工具很强大,但是它不是开源产品,我们可以使用如图产品替代,但是可能相比来说要功能缺失一些:
15.5 日志监控
- ELK架构如图所示:
对日志监控的工具可以不做强制要求,只要合适就行,不一定得必须要ELK
15.6 其他监控
- 监控的时候,应该要全面一点,比如用到了docker,我们应该就要监控docker。用到了Linux服务器,我们就应该要监控服务器的运行情况。用到了RabbitMQ,我们也应该去监控rabbitmq。
- 只有当监控完善的时候,我们分析问题就能更加的全面。
十六. 进阶:完美融合异构微服务
17.1 如何完美整合异构微服务
- 非SpringCloud的服务,就叫做异构微服务
- 完美整合:
- SpringCloud 微服务完美调用异构微服务
- 异构微服务完美嗲用SpringCloud微服务
- 完美调用:互相之间需要满足如下:
- 服务发现
- 负载均衡
- 容错处理
17.2 Spring Cloud Wii实现完美整合
- 使用SpringCloud Wii完美整合Github地址
- 部分配置如图所示,参照上方的教程配置即可
它未来是SpringCloudAlibaba的一个子项目
十八.课程总结:
- SpringCloud是一系列的工具集,SpringCloudAlibaba是一站式解决方案
- 知其然而不知其所以然是不可取的,我们更要知道去知道核心原理,这样就算是Eureka、Nacos、或者别的服务发现或者其他组件,我们都能很快的上手;