第一章 微服务介绍
1.1 系统架构演变
1.1.1 SpringCloud
Spring Cloud是一系列框架的集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。
Spring Cloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
1.1.2 SpringCloud Alibaba
Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
1.2 SpringCloud Alibaba介绍
Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。
1.2.1 主要功能
服务限流降级:默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
服务注册与发现:适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。
分布式配置管理:支持分布式系统中的外部化配置,配置更改时自动刷新。
消息驱动能力:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。
分布式事务:使用 @GlobalTransactional 注解, 高效并且对业务零侵入地解决分布式事务问题。
阿里云对象存储:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任 何时间、任何地点存储和访问任意类型的数据。
分布式任务调度:提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有Worker(schedulerx-client)上执行。
阿里云短信服务:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建 客户触达通道。
1.2.2 组件
Sentinel:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳 定性。
Nacos:一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
RocketMQ:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠 的消息发布与订阅服务。
Dubbo:Apache Dubbo 是一款高性能 Java RPC 框架。
Seata:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
Alibaba Cloud ACM:一款在分布式架构环境中对应用配置进行集中管理和推送的应用配置中心产品。
OSS: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和 访问任意类型的数据。
Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。
Alibaba Cloud SMS: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
1.3 版本对应关系
第二章 微服务环境搭建
2.1 商品、订单、用户
2.1.1 技术选型
maven:3.6.1
数据库:MySQL 5
持久层: SpingData Jpa
SpringCloud Alibaba 技术栈
2.1.2 模块设计
springcloud-alibaba 父工程
shop-common 公共模块【实体类】
shop-user 用户微服务 【端口: 807x】
shop-product 商品微服务 【端口: 808x】
shop-order 订单微服务 【端口: 809x】
2.1.3 微服务调用
在微服务架构中,最常见的场景就是微服务之间的相互调用。我们以电商系统中常见的用户下单为 例来演示微服务的调用:客户向订单微服务发起一个下单的请求,在进行保存订单之前需要调用商品微 服务查询商品的信息。
我们一般把服务的主动调用方称为服务消费者,把服务的被调用方称为服务提供者。
在这种场景下,订单微服务就是一个服务消费者, 商品微服务就是一个服务提供者。
2.2 创建springcloud-alibaba父工程
创建一个maven工程,然后在pom.xml文件中添加下面内容
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF- 8</project.reporting.outputEncoding>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
<spring-cloud-alibaba.version>2.1.0.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2.3 创建shop-common模块
创建shop-common 模块,在pom.xml中添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>
构建实体类
//用户
@Entity(name = "shop_user")
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer uid;//主键
private String username;//用户名
private String password;//密码
private String telephone;//手机号
}
//商品
@Entity(name = "shop_product")
@Data public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer pid;//主键
private String pname;//商品名称
private Double pprice;//商品价格
private Integer stock;//库存
}
//订单
@Entity(name = "shop_order")
@Data public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long oid;//订单id
private Integer uid;//用户id
private String username;//用户名
private Integer pid;//商品id
private String pname;//商品名称
private Double pprice;//商品单价
private Integer number;//购买数量
}
2.4 创建用户shop-user微服务
1 创建pom.xml
<dependencies>
<dependency>
<groupId>com.itheima</groupId>
<artifactId>shop-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
2.修改yml
server:
port: 8071
spring:
application:
name: service-user
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql:///shop?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
username: root
password: 123456
jpa:
properties:
hibernate:
hbm2ddl:
auto: update
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
2.5 创建商品shop-product微服务
1.修改pom
<dependencies>
<dependency>
<groupId>com.itheima</groupId>
<artifactId>shop-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
2.修改yml
server:
port: 8081
spring:
application:
name: service-product
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql:///shop?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
username: root
password: 123456
jpa:
properties:
hibernate:
hbm2ddl:
auto: update
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
2.5 创建订单shop-order微服务
1.pom
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.itheima</groupId>
<artifactId>shop-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
2.yml
server:
port: 8091
spring:
application:
name: service-order
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql:///shop?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
username: root
password: 123456
jpa:
properties:
hibernate:
hbm2ddl:
auto: update
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
第三章 RestTemplate基础服务调用
3.1shop-product 服务
@RestController
public class ProductController {
@Autowired
private ProductService productService;
@RequestMapping("/product/{pid}")
public Product product(@PathVariable("pid") Integer pid){
Product product = productService.findByPid(pid);
String s = JSON.toJSONString(product);
System.out.println(s);
return product;
}
}
3.2 shop-order 服务
3.2.1 RestTemplate注册组件
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
3.2.2 order 调用product
@RestController
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private OrderService orderService;
@RequestMapping("/order/prod/{pid}")
public Order order(@PathVariable("pid") Integer pid){
// 1.查询商品服务
Product product = restTemplate.getForObject("http://localhost:8081/product/"+pid,Product.class);
String s = JSON.toJSONString(product);
// 2.模拟下单
Order order = new Order();
order.setUid(1);
order.setUsername("测试用户");
order.setPid(pid);
order.setPname(product.getPname());
order.setPprice(product.getPprice());
order.setNumber(1);
orderService.createOrder(order);
return order;
}
}
测试调用:http://localhost:8091/order/prod/2
返回值:{“oid”:1,“uid”:1,“username”:“测试用户”,“pid”:2,“pname”:“华为”,“pprice”:2000.0,“number”:1}
第四章 Nacos注册中心
4.1 安装
略,启动bin下的nacos服务器。
web: http://localhost:8848/nacos
用户名密码都是 nacos
4.2 shop-product注册到nacos
1.pom依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2.主类添加注解
3.yml配置文件添加服务器地址
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
- 启动测试,观看nacos控制台
4.3 shop-product注册到nacos
如同以上步骤
4.4 nacos进行服务调用
1.修改order服务
@RestController
public class OrderController {
@Autowired
private DiscoveryClient discoveryClient;
List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
ServiceInstance instance = instances.get(0);
// 修改如下
Product product = restTemplate.getForObject("http://"+instance.getHost()+":"+instance.getPort()+"/product/"+pid,Product.class);
测试服务调用:http://localhost:8091/order/prod/1
调用结果:{“oid”:2,“uid”:1,“username”:“测试用户”,“pid”:1,“pname”:“小米”,“pprice”:1000.0,“number”:1}
第五章 Ribbon负载均衡
5.1 复制一个shop-product应用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DXbznADj-1597822416381)(C:\Users\15067\AppData\Local\Temp\1597802059837.png)]
5.2 自定义负载均衡
@RestController
public class OrderController {
@Autowired
private DiscoveryClient discoveryClient;
@RequestMapping("/order/prod/{pid}")
public Order order(@PathVariable("pid") Integer pid){
// 1.查询商品服务
List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
// 2.自定义到随机一台机器
int index = new Random().nextInt(instances.size()); // 0 1
ServiceInstance instance = instances.get(index);
Product product = restTemplate.getForObject("http://"+instance.getHost()+":"+instance.getPort()+"/product/"+pid,Product.class);
5.3 Ribbon负载均衡
1.在RestTemplate的方法中添加 @LoadBalanced注解
@SpringBootApplication
@EnableDiscoveryClient
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
2.OrderController 修改服务调用
@RestController
public class OrderController {
@Autowired
private DiscoveryClient discoveryClient;
@RequestMapping("/order/prod/{pid}")
public Order order(@PathVariable("pid") Integer pid){
// 1.查询商品服务
Product product = restTemplate.getForObject("http://service-product/product/"+pid,Product.class);
默认是轮询的算法策略。
测试服务调用:http://localhost:8091/order/prod/1
3.在yml中调整负载均衡策略为随机试试看
service-product:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
第六章 Feign 实现服务调用
RestTemplate服务调用问题:
1.代码可读性不好
2.代码风格不一样
3.使用fegin就像调用本地的服务一样,注入服务即可。
4.feign很好的兼容了nacos
5.feign默认继承了ribbon负载均衡
6.1集成Feign
1.pom引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.启动类开启注解支持
@EnableFeignClients
6.2 修改order服务调用
1.创建ProductService接口
//用于指定 调用nacos的哪一个微服务
@FeignClient(value = "service-product")
public interface ProductService {
@RequestMapping("/product/{pid}")
public Product findByPid(@PathVariable("pid") Integer pid);
}
2.OrderController服务进行feign调用
@RestController
public class OrderController {
@Autowired
private ProductService productService;
@RequestMapping("/order/prod/{pid}")
public Order order(@PathVariable("pid") Integer pid){
// 1.查询商品服务
Product product = productService.findByPid(pid);
3.重启order服务进行测试
http://localhost:8091/order/prod/1
返回结果:{“oid”:7,“uid”:1,“username”:“测试用户”,“pid”:1,“pname”:“小米”,“pprice”:1000.0,“number”:1}
第七章 Sentinel 服务容错
7.1 简介
Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于服务容错的综合性解决方案。它以流量为切入点, 从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。
Sentinel 分为两个部分
核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。
7.2 集成Sentinel
1.order上游服务引入pom依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2.编写一个Controller测试使用
@RestController
public class OrderController3 {
@RequestMapping("/order/message1")
public String message1() {
return "message1";
}
@RequestMapping("/order/message2")
public String message2() {
return "message2";
}
}
3.修改shop-order配置文件
spring:
cloud:
sentinel:
transport:
port: 9999 #跟控制台交流的端口,随意指定一个未使用的端口即可
dashboard: localhost:8080 # 指定控制台服务的地址
7.3 安装Sentinel控制台
Sentinel 提供一个轻量级的控制台, 它提供机器发现、单机资源实时监控以及规则管理等功能。
Sentinel的控制台其实就是一个SpringBoot编写的程序。我们需要将我们的微服务程序注册到控制台上, 即在微服务中指定控制台的地址, 并且还要开启一个跟控制台传递数据的端口, 控制台也可以通过此端口调用微服务中的监控程序获取微服务的各种信息。
1 下载jar包,解压到文件夹https://github.com/alibaba/Sentinel/releases
2 启动项目
# 直接使用jar命令启动项目(控制台本身是一个SpringBoot项目)
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.0.jar
3.访问控制台
通过浏览器访问 localhost:8080 进入控制台
( 默认用户名密码是 sentinel/sentinel )
7.4 Sentinel规则配置
7.4.1 流控规则
流量控制在网络传输中是一个常用的概念,它用于调整网络包的数据。任意时间到来的请求往往是 随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状。
流量控制,其原理是监控应用流量的QPS(每秒查询率) 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
第1步: 点击簇点链路,我们就可以看到访问过的接口地址,然后点击对应的流控按钮,进入流控规则配置页面。
资源名:唯一名称,默认是请求路径,可自定义
针对来源:指定对哪个微服务进行限流,默认指default,意思是不区分来源,全部限制 阈
sentinel共有三种流控模式,分别是:
直接(默认):接口达到限流条件时,开启限流
关联:当关联的资源达到限流条件时,开启限流 [适合做应用让步]
链路:当从某个接口过来的资源达到限流条件时,开启限流下面呢分别演示三种模式:
直接流控模式
直接流控模式是最简单的模式,当指定的接口达到限流条件时开启限流。上面案例使用的就是直接流控 模式。
关联流控模式
关联流控模式指的是,当指定接口关联的接口达到限流条件时,开启对指定接口开启限流。
链路流控模式
链路流控模式指的是,当从某个接口过来的资源达到限流条件时,开启限流。它的功能有点类似于针对 来源配置项,区别在于:针对来源是针对上级微服务,而链路流控是针对上级接口,也就是说它的粒度更细。
7.4.2 降级规则
降级规则就是设置当满足什么条件的时候,对服务进行降级。Sentinel提供了三个衡量条件:
平均响应时间 :当资源的平均响应时间超过阈值(以 ms 为单位)之后,资源进入准降级状态。如果接下来 1s 内持续进入 5 个请求,它们的 RT都持续超过这个阈值,那么在接下的时间窗口(以 s 为单位)之内,就会对这个方法进行服务降级。
异常比例:当资源的每秒异常总数占通过量的比值超过阈值之后,资源进入降级状态,即在接下的 时间窗口(以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0]。
异常数 :当资源近 1 分钟的异常数目超过阈值之后会进行服务降级。注意由于统计时间窗口是分钟级别的,若时间窗口小于 60s,则结束熔断状态后仍可能再进入熔断状态
7.4.3 热点规则
热点参数流控规则是一种更细粒度的流控规则, 它允许将规则具体到参数上。
7.5 统一异常
@Component
public class ExceptionHandlerPage implements UrlBlockHandler {
@Override
public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException e) throws IOException {
response.setContentType("application/json;charset=utf-8");
ResponseData data = null;
if (e instanceof FlowException) {
data = new ResponseData(-1, "接口被限流了...");
} else if (e instanceof DegradeException) {
data = new ResponseData(-2, "接口被降级了...");
}
response.getWriter().write(JSON.toJSONString(data));
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class ResponseData {
private int code;
private String message;
}
7.6 Feign整合Sentinel实现容错
7.6.1 配置文件开启feign对sentinel的支持
feign:
sentinel:
enabled: true
7.6.2 创建容错类
@Service
public class ProductServiceFallback implements ProductService {
@Override
public Product findByPid(Integer pid) {
Product product = new Product();
product.setPid(-1);
product.setPname("出现异常,进入容错模式");
return product;
}
}
7.6.3 服务中心指定容错类
@FeignClient(value = "service-product", fallback = ProductServiceFallback.class)
public interface ProductService {
@RequestMapping("/product/{pid}")//指定请求的URI部分
Product findByPid(@PathVariable Integer pid);
}
如下测试Controller即可
if (product.getPid() == -1) {
Order order = new Order();
order.setPname("下单失败");
return order;
}
第八章 Gateway 服务网关
所谓的API网关,就是指系统的统一入口,它封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、路由转发等等。 它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。它的目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控和限流。
要求:只能打成jar包,springboot2.0以上的版本
8.1 创建api-gateway网关服务模块
1.pom依赖
<dependencies>
<!--不能引入web相关的-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
2.启动类开启服务发现
@EnableDiscoveryClient
3.配置文件yml参数
server:
port: 7000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true # 在nacos中注册
routes:
- id: product_route
uri: lb://service-product
order: 1
predicates:
- Path=/product-serv/**
filters:
- StripPrefix=1
4.测试访问
http://localhost:7000/product-serv/product/2
5.默认路由---->如果路由规则 routes全部注释掉
默认路由名称为nacos中服务节点的名称
测试访问
http://localhost:7000/service-product/product/2
8.2 网关限流
网关是所有请求的公共入口,所以可以在网关进行限流,而且限流的方式也很多,我们本次采用前 面学过的Sentinel组件来实现网关的限流。Sentinel支持对SpringCloud Gateway、Zuul等主流网关进行限流。
实现:略
1.pom
2.配置类
3.测试
第九章 Sleuth 链路追踪
SpringCloud Sleuth主要功能就是在分布式系统中提供追踪解决方案。它大量借用了Google Dapper的设计, 先来了解一下Sleuth中的术语和相关概念。
9.1 集成Sleuth
1.父工程的pom依赖
<!--链路追踪 Sleuth-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
重新启动微服务,调用之后,我们可以在控制台观察到sleuth的日志输出。
查看日志文件并不是一个很好的方法,当微服务越来越多日志文件也会越来越多,通过Zipkin可以 将日志聚合,并进行可视化展示和全文检索。
Zipkin 是 Twitter 的一个开源项目,它基于Google Dapper实现,它致力于收集服务的定时数据, 以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。
我们可以使用它来收集各个服务器上请求链路的跟踪数据,并通过它提供的REST API接口来辅助我们查询跟踪数据以实现对分布式系统的监控程序,从而及时地发现系统中出现的延迟升高问题并找出系 统性能瓶颈的根源。
9.2 集成Zipkin
9.2.1 Zipkin服务端安装
1.下载jar包
https://search.maven.org/remote_content?g=io.zipkin.java&a=zipkin- server&v=LATEST&c=exec
2.执行jar包
java -jar zipkin-server-2.12.9-exec.jar
3.访问
http://localhost:9411
9.2.2 Zipkin客户端安装
1.每个微服务的pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
2.配置文件
spring:
zipkin:
base-url: http://127.0.0.1:9411/ #zipkin server的请求地址
discoveryClientEnabled: false #让nacos把它当成一个URL,而不要当做服务名
sleuth:
sampler:
probability: 1.0 #采样的百分比
3.测试访问
http://localhost:7000/order-serv/order/prod/1
4.登录zipkin的界面观看变化
http://localhost:9411
9.3 持久化
mysql elasticsearch 略
第十章 RocketMQ 消息队列
RocketMQ是阿里巴巴开源的分布式消息中间件,现在是Apache的一个顶级项目。在阿里内部使用 非常广泛,已经经过了"双11"这种万亿级的消息流转。
安装略,请见安装策略。注意安装配置JVM参数调小即可。
接下来我们模拟一种场景: 下单成功之后,向下单用户发送短信。设计图如下:
10.1 订单微服务发送消息
1.shop-order中添加依赖
<!--rocketmq-->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.4.0</version>
</dependency>
2.yml配置
rocketmq:
name-server: 47.94.39.202:9876 #rocketMQ服务的地址
producer:
group: shop-order # 生产者组
3.controller
@RestController
@Slf4j
public class OrderController2 {
@Autowired
private OrderService orderService;
@Autowired
private ProductService productService;
@Autowired
private RocketMQTemplate rocketMQTemplate;
//准备买1件商品@GetMapping("/order/prod/{pid}")
public Order order(@PathVariable("pid") Integer pid) {
log.info(">>客户下单,这时候要调用商品微服务查询商品信息");
//通过fegin调用商品微服务
Product product = productService.findByPid(pid);
if (product == null){
Order order = new Order(); order.setPname("下单失败");
return order;
}
log.info(">>商品信息,查询结果:" + JSON.toJSONString(product));
Order order = new Order(); order.setUid(1);
order.setUsername(" 测 试 用 户 ");
order.setPid(product.getPid());
order.setPname(product.getPname());
order.setPprice(product.getPprice());
order.setNumber(1);
orderService.save(order);
//下单成功之后,将消息放到mq中
rocketMQTemplate.convertAndSend("order-topic", order);
return order;
}
}
10.2 用户微服务订阅消息
1.shop-user pom依赖
<dependencies>
<dependency>
<groupId>com.itheima</groupId>
<artifactId>shop-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos- discovery</artifactId>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.4.0</version>
</dependency>
</dependencies>
2.主启动类添加注解
@EnableDiscoveryClient
3.配置文件
server:
port: 8071
spring:
application:
name: service-user
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql:///shop?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
username: root
password: root jpa:
properties:
hibernate:
hbm2ddl:
auto: update
dialect: org.hibernate.dialect.MySQL5InnoDBDialect cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
rocketmq:
name-server: 192.168.109.131:9876
4.编写消息接收服务
//发送短信的服务
@Slf4j
@Service
@RocketMQMessageListener(consumerGroup = "shop-user", topic = "order-topic")
public class SmsService implements RocketMQListener<Order> {
@Override
public void onMessage(Order order) {
log.info("收到一个订单信息{},接下来发送短信", JSON.toJSONString(order));
}
}
5.执行下单操作,观看shop-user服务的控制台输出。
第十一章 Seata 分布式事务控制