SpringCloud Alibaba系统框架搭建 - 图1

一、官网集合:

Springboot 官网

https://spring.io/projects/spring-boot

https://github.com/spring-projects/spring-boot

中文文档

http://www.spring-boot.org/doc/

Mybatis 官网

https://mybatis.org/mybatis-3/

SpringCloud Alibaba 官网

https://spring.io/projects/spring-cloud-alibaba#overview

github 中文官网

https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md

英文官网

https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html

https://github.com/alibaba/spring-cloud-alibaba

Nacos 官网

https://github.com/alibaba/Nacos

https://nacos.io/zh-cn/index.html

https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_nacos_discovery

Sentinel 官网

https://github.com/alibaba/Sentinel

https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D

OpenFeign 官网

https://github.com/spring-cloud/spring-cloud-openfeign

Gateway 官网

https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/

Seata 官网

http://seata.io/zh-cn/

https://github.com/seata/seata

Sleuth 官网

https://github.com/spring-cloud/spring-cloud-sleuth

二、微服务架构编码构建

2.1 idea 新建 project 工作空间

步骤:

1.New Project

SpringCloud Alibaba系统框架搭建 - 图2

2.聚合总工程名字

SpringCloud Alibaba系统框架搭建 - 图3

3.Maven 选版本

SpringCloud Alibaba系统框架搭建 - 图4

4.工程名字

SpringCloud Alibaba系统框架搭建 - 图5 5.字符编码

SpringCloud Alibaba系统框架搭建 - 图6

6.注解生效激活

SpringCloud Alibaba系统框架搭建 - 图7 7.java 编译版本选 8

SpringCloud Alibaba系统框架搭建 - 图8

8.File Type 过滤

SpringCloud Alibaba系统框架搭建 - 图9

2.2 父工程 POM

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <packaging>pom</packaging>
  5. <name>csii_dataservice_bus</name>
  6. <modules>
  7. <module>csii_service_regist5001</module>
  8. <module>csii_service_subscription6001</module>
  9. <module>csii_service_monitoring7001</module>
  10. <module>csii_gateway_gateway4001</module>
  11. <module>csii_data_assets9001</module>
  12. <module>csii_auth_management8001</module>
  13. <module>csii_api_commons</module>
  14. </modules>
  15. <groupId>com.csii.dbus</groupId>
  16. <artifactId>csii_dataservice_bus</artifactId>
  17. <version>1.0-SNAPSHOT</version>
  18. <!--统一管理jar包版本-->
  19. <properties>
  20. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  21. <maven.compiler.source>1.8</maven.compiler.source>
  22. <maven.compiler.target>1.8</maven.compiler.target>
  23. <junit.version>4.12</junit.version>
  24. <log4j.version>1.2.17</log4j.version>
  25. <lombok.version>1.16.18</lombok.version>
  26. <mysql.version>5.1.47</mysql.version>
  27. <druid.version>1.1.16</druid.version>
  28. <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
  29. </properties>
  30. <!--子模块继承之后,提供作用:锁定版本+子module不用groupId和version-->
  31. <dependencyManagement>
  32. <dependencies>
  33. <!--spring boot 2.2.2-->
  34. <dependency>
  35. <groupId>org.springframework.boot</groupId>
  36. <artifactId>spring-boot-dependencies</artifactId>
  37. <version>2.2.2.RELEASE</version>
  38. <type>pom</type>
  39. <scope>import</scope>
  40. </dependency>
  41. <!--spring cloud Hoxton.SR1-->
  42. <dependency>
  43. <groupId>org.springframework.cloud</groupId>
  44. <artifactId>spring-cloud-dependencies</artifactId>
  45. <version>Hoxton.SR1</version>
  46. <type>pom</type>
  47. <scope>import</scope>
  48. </dependency>
  49. <!--spring cloud alibaba 2.1.0.RELEASE-->
  50. <dependency>
  51. <groupId>com.alibaba.cloud</groupId>
  52. <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  53. <version>2.1.0.RELEASE</version>
  54. <type>pom</type>
  55. <scope>import</scope>
  56. </dependency>
  57. <dependency>
  58. <groupId>mysql</groupId>
  59. <artifactId>mysql-connector-java</artifactId>
  60. <version>${mysql.version}</version>
  61. </dependency>
  62. <dependency>
  63. <groupId>com.alibaba</groupId>
  64. <artifactId>druid</artifactId>
  65. <version>${druid.version}</version>
  66. </dependency>
  67. <dependency>
  68. <groupId>org.mybatis.spring.boot</groupId>
  69. <artifactId>mybatis-spring-boot-starter</artifactId>
  70. <version>${mybatis.spring.boot.version}</version>
  71. </dependency>
  72. <dependency>
  73. <groupId>junit</groupId>
  74. <artifactId>junit</artifactId>
  75. <version>${junit.version}</version>
  76. </dependency>
  77. <dependency>
  78. <groupId>org.projectlombok</groupId>
  79. <artifactId>lombok</artifactId>
  80. <version>${lombok.version}</version>
  81. <optional>true</optional>
  82. </dependency>
  83. </dependencies>
  84. </dependencyManagement>
  85. <build>
  86. <plugins>
  87. <plugin>
  88. <groupId>org.springframework.boot</groupId>
  89. <artifactId>spring-boot-maven-plugin</artifactId>
  90. <configuration>
  91. <fork>true</fork>
  92. <addResources>true</addResources>
  93. </configuration>
  94. </plugin>
  95. </plugins>
  96. </build>
  97. </project>

Maven 工程落地细节复习

SpringCloud Alibaba系统框架搭建 - 图10 父工程创建完成执行 mvn:install 将父工程发布到仓库方便子工程继承

2.2Rest 微服务工程构建

2.2.1 Module 模块搭建与工程样图

SpringCloud Alibaba系统框架搭建 - 图11

下边案例用以上 Module。

三、SpringBoot 集成构建

3.1 什么是 SpringBoot

Spring Boot 是由 Pivotal 团队提供的全新框架。Spring Boot 是所有基于 Spring Framework 5.0 开发的项目的起点。Spring Boot 的设计是为了让你尽可能快的跑起来 Spring 应用程序并且尽可能减少你的配置文件。

设计目的: 用来简化新 Spring 应用的初始搭建以及开发过程。

从最根本上来讲,Spring Boot 就是一些库的集合,它能够被任意项目的构建系统所使用。它使用 “习惯优于配置” (项目中存在大量的配置,此外还内置一个习惯性的配置)的理念让你的项目快速运行起来。用大佬的话来理解,就是 spring boot 其实不是什么新的框架,它默认配置了很多框架的使用方式,就像 maven 整合了所有的 jar 包,spring boot 整合了所有的框架,总结一下及几点:

(1)为所有 Spring 开发提供一个更快更广泛的入门体验。

(2)零配置。无冗余代码生成和 XML 强制配置,遵循“约定大于配置” 。

(3)集成了大量常用的第三方库的配置, Spring Boot 应用为这些第三方库提供了几乎可以零配置的开箱即用的能力。

(4)提供一系列大型项目常用的非功能性特征,如嵌入式服务器、安全性、度量、运行状况检查、外部化配置等。

(5)Spring Boot 不是 Spring 的替代者,Spring 框架是通过 IOC 机制来管理 Bean 的。Spring Boot 依赖 Spring 框架来管理对 象的依赖。Spring Boot 并不是 Spring 的精简版本,而是为使用 Spring 做好各种产品级准备。

#

3.2 csii_service_regist5001 Moudle 中搭建

3.2.1 导入 POM

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-actuator</artifactId>
  8. </dependency>
  9. <dependency>
  10. <groupId>org.springframework.boot</groupId>
  11. <artifactId>spring-boot-starter-test</artifactId>
  12. <scope>test</scope>
  13. </dependency>
  14. <dependency>
  15. <groupId>org.springframework.boot</groupId>
  16. <artifactId>spring-boot-devtools</artifactId>
  17. <scope>runtime</scope>
  18. <optional>true</optional>
  19. </dependency>

3.2.2 写 yml

  1. server:
  2. port: 5000
  3. spring:
  4. application:
  5. name: nocas-csii-provider

3.2.3 加主启动类

  1. package com.csii.regist;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  5. @SpringBootApplication
  6. public class RegistMain5001 {
  7. public static void main(String[] args) {
  8. SpringApplication.run(RegistMain5001.class,args);
  9. }
  10. }

3.2.4 业务类(省略 service 层+mapper 层+entities 层)

  1. @RestController
  2. @Slf4j
  3. public class RegistController {
  4. @Value("${server.port}")
  5. private String serverPort;
  6. @GetMapping(value = "/getregist/nacos/{id}")
  7. public String getRegist(@PathVariable("id") Integer id) {
  8. return "nacos registry, serverPort: " + serverPort + "\t id" + id;
  9. }
  10. }

3.2.5 测试

启动 csii_service_regist5001

SpringCloud Alibaba系统框架搭建 - 图12

访问: http://localhost:5000/getregist/nacos/1

SpringCloud Alibaba系统框架搭建 - 图13

测试成功

四、Mybatis 持久层框架构建

4.1 什么是 MyBatis ?

MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生 Map 使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录。

MyBatis 的功能架构:

我们把 Mybatis 的功能架构分为三层:

  1. API 接口层:提供给外部使用的接口 API,开发人员通过这些本地 API 来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
  2. 数据处理层:负责具体的 SQL 查找、SQL 解析、SQL 执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
  3. 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。

MyBatis 的优缺点

优点:

  • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个 jar 文件+配置几个 sql 映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
  • 灵活:mybatis 不会对应用程序或者数据库的现有设计强加任何影响。 sql 写在 xml 里,便于统一管理和优化。通过 sql 基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。
  • 解除 sql 与程序代码的耦合:通过提供 DAL 层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql 和代码的分离,提高了可维护性。
  • 提供映射标签,支持对象与数据库的 orm 字段关系映射
  • 提供对象关系映射标签,支持对象关系组建维护
  • 提供 xml 标签,支持编写动态 sql。

缺点:

  • 编写 SQL 语句时工作量很大,尤其是字段多、关联表多时,更是如此。
  • SQL 语句依赖于数据库,导致数据库移植性差,不能更换数据库。
  • 框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。
  • 二级缓存机制不佳

4.2 Mybatis 在 csii_service_regist5001 中的使用

4.2.1 导入 POM

  1. <!--mysql-connector-java-->
  2. <dependency>
  3. <groupId>mysql</groupId>
  4. <artifactId>mysql-connector-java</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-jdbc</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.mybatis.spring.boot</groupId>
  12. <artifactId>mybatis-spring-boot-starter</artifactId>
  13. </dependency>

4.2.2 写 yml

  1. server:
  2. port: 5000
  3. spring:
  4. application:
  5. name: nocas-csii-provider
  6. datasource:
  7. type: com.alibaba.druid.pool.DruidDataSource
  8. driver-class-name: org.gjt.mm.mysql.Driver
  9. url: jdbc:mysql://xxx.xxx.xx.xxx:3306/csii_dbus?useUnicode=true&characterEncoding=utf-8&useSSL=false
  10. username: root
  11. password: root

4.2.3 加 mapper 文件+entities 层+dao 层+service 层+controller 层

1.resources 下加+mapper 文件+PaymentMapper.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.csii.regist.dao.PaymentDao">
  6. <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
  7. insert into payment(serial) values(#{serial})
  8. </insert>
  9. <resultMap id="BaseResultMap" type="com.csii.dbus.entities.Payment">
  10. <id column="id" property="id" jdbcType="BIGINT"/>
  11. <result column="serial" property="serial" jdbcType="VARCHAR"/>
  12. </resultMap>
  13. <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
  14. select * from payment where id=#{id};
  15. </select>
  16. </mapper>

2.entities

  1. package com.csii.dbus.entities;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. @Data
  6. public class Payment {
  7. private Long id;
  8. private String serial;
  9. public Payment() {
  10. }
  11. public Payment(Long id, String serial) {
  12. this.id = id;
  13. this.serial = serial;
  14. }
  15. }

2.dao 层

  1. package com.csii.regist.dao;
  2. import com.csii.dbus.entities.Payment;
  3. import org.apache.ibatis.annotations.Mapper;
  4. import org.apache.ibatis.annotations.Param;
  5. @Mapper
  6. public interface PaymentDao {
  7. int create(Payment payment);
  8. Payment getPaymentById(@Param("id") Long id);
  9. }

3.service 层

  1. package com.csii.regist.service;
  2. import com.csii.dbus.entities.Payment;
  3. import org.apache.ibatis.annotations.Param;
  4. public interface PaymentService {
  5. public int create(Payment payment);
  6. public Payment getPaymentById(@Param("id") Long id);
  7. }
  1. package com.csii.regist.service.impl;
  2. import com.csii.dbus.entities.Payment;
  3. import com.csii.regist.dao.PaymentDao;
  4. import com.csii.regist.service.PaymentService;
  5. import org.springframework.stereotype.Service;
  6. import javax.annotation.Resource;
  7. @Service
  8. public class PaymentServiceImpl implements PaymentService {
  9. @Resource
  10. private PaymentDao paymentDao;
  11. public int create(Payment payment){
  12. return paymentDao.create(payment);
  13. }
  14. public Payment getPaymentById(Long id){
  15. return paymentDao.getPaymentById(id);
  16. }
  17. }

4.controller 层

  1. package com.csii.regist.controller;
  2. import com.csii.dbus.entities.CommonResult;
  3. import com.csii.dbus.entities.Payment;
  4. import com.csii.regist.service.PaymentService;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.beans.factory.annotation.Value;
  7. import org.springframework.cloud.context.config.annotation.RefreshScope;
  8. import org.springframework.web.bind.annotation.GetMapping;
  9. import org.springframework.web.bind.annotation.PathVariable;
  10. import org.springframework.web.bind.annotation.PostMapping;
  11. import org.springframework.web.bind.annotation.RestController;
  12. import javax.annotation.Resource;
  13. import java.util.HashMap;
  14. import java.util.concurrent.TimeUnit;
  15. @RestController
  16. @Slf4j
  17. @RefreshScope//实现配置自动更新
  18. public class RegistController {
  19. @Value("${server.port}")
  20. private String serverPort;
  21. @Resource
  22. private PaymentService paymentService;
  23. //只传给前端CommonResult,不需要前端了解其他的组件
  24. @PostMapping(value = "/getregist/create")
  25. public CommonResult create(Payment payment) {
  26. int result = paymentService.create(payment);
  27. //log.info("*****插入结果:"+result);
  28. if (result > 0) {
  29. return new CommonResult(200, "插入数据成功,serverPort:" + serverPort, result);
  30. } else {
  31. return new CommonResult(444, "插入数据失败", null);
  32. }
  33. }
  34. @GetMapping(value = "/getregist/get/{id}")
  35. public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
  36. Payment payment = paymentService.getPaymentById(id);
  37. //log.info("*****插入结果:"+payment);
  38. if (payment != null) {
  39. return new CommonResult(200, "查询成功,serverPort:" + serverPort, payment);
  40. } else {
  41. return new CommonResult(444, "没有对应记录,查询ID:" + id, null);
  42. }
  43. }
  44. }

启动+测试成功(步骤省略)

五、 Nacos 服务注册与配置

5.1 什么是 Nacos?

Nacos 是用于构建云本机应用程序的易于使用的动态服务发现,配置和服务管理平台。

5.2 安装并运行 Nacos

5.2.1 环境

本地 Java8+Maven 环境已经 OK

5.2.2 官网下载 Nacos

https://github.com/alibaba/nacos/releases/tag/1.1.4

5.2.3 解压安装包,直接运行 bin 目录下的 startup.cmd

SpringCloud Alibaba系统框架搭建 - 图14

5.2.4 命令运行成功后直接访问 http://localhost:8848/nacos;默认账户密码都是:nacos

SpringCloud Alibaba系统框架搭建 - 图15

5.3 Nacos 作为服务注册中心演示

1.父 POM 加

  1. <!--spring cloud alibaba 2.1.0.RELEASE-->
  2. <dependency>
  3. <groupId>com.alibaba.cloud</groupId>
  4. <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  5. <version>2.1.0.RELEASE</version>
  6. <type>pom</type>
  7. <scope>import</scope>
  8. </dependency>

2.本地模块 POM 加

  1. <dependency>
  2. <groupId>com.alibaba.cloud</groupId>
  3. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  4. </dependency>

3.写 yml

  1. server:
  2. port: 5000
  3. spring:
  4. application:
  5. name: nocas-csii-provider
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: xxx.xxx.xx.xxx:8090 #Nacos服务注册中心地址

4.主启动类加注解:@EnableDiscoveryClient 开启服务注册发现功能

  1. package com.csii.regist;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  5. @SpringBootApplication
  6. @EnableDiscoveryClient//开启服务注册发现功能
  7. public class RegistMain5001 {
  8. public static void main(String[] args) {
  9. SpringApplication.run(RegistMain5001.class,args);
  10. }
  11. }

5.启动+访问测试

SpringCloud Alibaba系统框架搭建 - 图16

6.nacos 控制台证明服务注册成功

SpringCloud Alibaba系统框架搭建 - 图17

5.4Nacos 作为配置中心(基础配置+分类配置)

1.POM 依赖添加

  1. <dependency>
  2. <groupId>com.alibaba.cloud</groupId>
  3. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  4. </dependency>

2.写 yml

SpringCloud Alibaba系统框架搭建 - 图18 bootstrap.yml 编写

  1. server:
  2. port: 5000
  3. spring:
  4. application:
  5. name: nocas-csii-provider
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: 192.168.xxx.xxx:8090 #Nacos服务注册中心地址
  10. config:
  11. server-addr: 192.168.xxx.xxx:8090 #Nacos作为配置中心地址
  12. file-extension: yaml #指定yaml格式的配置
  13. group: DEFAULT_GROUP
  14. #group: DEV_GROUP
  15. namespace: bd677bce-c69e-473e-8f71-da92c6987215

application.yml 编写

  1. server:
  2. port: 5000
  3. spring:
  4. application:
  5. name: nocas-csii-provider
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: xxx.xxx.xx.xxx:8090 #Nacos服务注册中心地址
  10. config:
  11. server-addr: xxx.xxx.xx.xxx:8090 #Nacos作为配置中心地址
  12. file-extension: yaml #指定yaml格式的配置
  13. group: DEFAULT_GROUP
  14. #group: DEV_GROUP
  15. namespace: bd677bce-c69e-473e-8f71-da92c6987215

3.controller 添加注解:@RefreshScope//实现配置自动更新

  1. package com.csii.regist.controller;
  2. import com.csii.dbus.entities.CommonResult;
  3. import com.csii.dbus.entities.Payment;
  4. import com.csii.regist.service.PaymentService;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.beans.factory.annotation.Value;
  7. import org.springframework.cloud.context.config.annotation.RefreshScope;
  8. import org.springframework.web.bind.annotation.GetMapping;
  9. import org.springframework.web.bind.annotation.PathVariable;
  10. import org.springframework.web.bind.annotation.PostMapping;
  11. import org.springframework.web.bind.annotation.RestController;
  12. import javax.annotation.Resource;
  13. import java.util.HashMap;
  14. import java.util.concurrent.TimeUnit;
  15. @RestController
  16. @Slf4j
  17. @RefreshScope//实现配置自动更新
  18. public class RegistController {
  19. @Value("${server.port}")
  20. private String serverPort;
  21. @Resource
  22. private PaymentService paymentService;
  23. //只传给前端CommonResult,不需要前端了解其他的组件
  24. @PostMapping(value = "/getregist/create")
  25. public CommonResult create(Payment payment) {
  26. int result = paymentService.create(payment);
  27. //log.info("*****插入结果:"+result);
  28. if (result > 0) {
  29. return new CommonResult(200, "插入数据成功,serverPort:" + serverPort, result);
  30. } else {
  31. return new CommonResult(444, "插入数据失败", null);
  32. }
  33. }
  34. @GetMapping(value = "/getregist/get/{id}")
  35. public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
  36. Payment payment = paymentService.getPaymentById(id);
  37. //log.info("*****插入结果:"+payment);
  38. if (payment != null) {
  39. return new CommonResult(200, "查询成功,serverPort:" + serverPort, payment);
  40. } else {
  41. return new CommonResult(444, "没有对应记录,查询ID:" + id, null);
  42. }
  43. }
  44. }

5.4.1 Nacos 的图形化管理界面

配置管理

SpringCloud Alibaba系统框架搭建 - 图19

命名空间

SpringCloud Alibaba系统框架搭建 - 图20

Namespace+Group+Data ID 三者关系?为什么这么设计?

SpringCloud Alibaba系统框架搭建 - 图21

新建 csii_dbus/test 的 Namespace

SpringCloud Alibaba系统框架搭建 - 图22

SpringCloud Alibaba系统框架搭建 - 图23

配置规则+nacos 配置

SpringCloud Alibaba系统框架搭建 - 图24

SpringCloud Alibaba系统框架搭建 - 图25

SpringCloud Alibaba系统框架搭建 - 图26 SpringCloud Alibaba系统框架搭建 - 图27

配置内容

  1. spring:
  2. datasource:
  3. type: com.alibaba.druid.pool.DruidDataSource
  4. driver-class-name: org.gjt.mm.mysql.Driver
  5. url: jdbc:mysql://xxx.xxx.xx.xxx:3306/csii_dbus?useUnicode=true&characterEncoding=utf-8&useSSL=false
  6. username: root
  7. password: root
  8. # 开启所有端点允许HTTP查看
  9. management:
  10. endpoints:
  11. web:
  12. exposure:
  13. include: '*'
  14. mybatis:
  15. mapperLocations: classpath:mapper/*.xml
  16. type-aliases-package: com.csii.dbus.entities #所有Entity别名类所在包

启动+测试访问+访问成功+测试成功

六、OpenFeign 服务接口调用

6.1 OpenFeign 是什么?

Feign 是一个声明式的 web 服务客户端,让编写 web 服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可。

6.2 OpenFeign 能干什么?

SpringCloud Alibaba系统框架搭建 - 图28

6.3Feign 和 OpenFeign 两者区别

SpringCloud Alibaba系统框架搭建 - 图29

6.4 OpenFeign 使用步骤

接口+注解:微服务调用接口+@FeignClient

1.新建 cloud-consumer-feign-order80

2.写 POM

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-openfeign</artifactId>
  4. </dependency>
  5. <!--nacos-config-->
  6. <dependency>
  7. <groupId>com.alibaba.cloud</groupId>
  8. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  9. </dependency>
  10. <!--nacos-discovery-->
  11. <dependency>
  12. <groupId>com.alibaba.cloud</groupId>
  13. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  14. </dependency>
  15. <!-- sentinel-datasource-nacos 后续持久化用 -->
  16. <dependency>
  17. <groupId>com.alibaba.csp</groupId>
  18. <artifactId>sentinel-datasource-nacos</artifactId>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-web</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-starter-actuator</artifactId>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.projectlombok</groupId>
  30. <artifactId>lombok</artifactId>
  31. <optional>true</optional>
  32. </dependency>
  33. <dependency>
  34. <groupId>org.springframework.boot</groupId>
  35. <artifactId>spring-boot-starter-test</artifactId>
  36. <scope>test</scope>
  37. </dependency>
  38. <dependency>
  39. <groupId>org.springframework.boot</groupId>
  40. <artifactId>spring-boot-devtools</artifactId>
  41. <scope>runtime</scope>
  42. <optional>true</optional>
  43. </dependency>

3.写 yml

  1. server:
  2. port: 6001
  3. spring:
  4. application:
  5. name: nocas-csii-subscription
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: 192.168.xxx.xxx:8090 #Nacos服务注册中心地址

4.主启动类加注解 :@EnableFeignClients//启动 Feign 功能

  1. package com.csii.subscription;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  5. import org.springframework.cloud.openfeign.EnableFeignClients;
  6. @SpringBootApplication
  7. @EnableDiscoveryClient//开启服务注册发现功能
  8. @EnableFeignClients//启动Feign功能
  9. public class SubscriptionMain6001 {
  10. public static void main(String[] args) {
  11. SpringApplication.run(SubscriptionMain6001.class,args);
  12. }
  13. }

5.业务类

业务逻辑接口+@FeignClient 配置调用 provider 服务

  1. package com.csii.subscription.service;
  2. import com.csii.dbus.entities.CommonResult;
  3. import com.csii.dbus.entities.Payment;
  4. import org.springframework.cloud.openfeign.FeignClient;
  5. import org.springframework.stereotype.Component;
  6. import org.springframework.web.bind.annotation.GetMapping;
  7. import org.springframework.web.bind.annotation.PathVariable;
  8. @Component
  9. @FeignClient(value = "nocas-csii-provider")
  10. public interface PaymentFeignService {
  11. @GetMapping(value = "/getregist/nacos/{id}")
  12. public String getRegist(@PathVariable("id") Integer id);
  13. }

控制层 Controller

  1. package com.csii.subscription.controller;
  2. import com.csii.dbus.entities.CommonResult;
  3. import com.csii.dbus.entities.Payment;
  4. import com.csii.subscription.service.PaymentFeignService;
  5. import org.springframework.beans.factory.annotation.Value;
  6. import org.springframework.cloud.context.config.annotation.RefreshScope;
  7. import org.springframework.web.bind.annotation.GetMapping;
  8. import org.springframework.web.bind.annotation.PathVariable;
  9. import org.springframework.web.bind.annotation.RestController;
  10. import javax.annotation.Resource;
  11. @RestController
  12. public class OrderFeignController {
  13. @Resource
  14. private PaymentFeignService paymentFeignService;
  15. @Value("${server.port}")
  16. private String serverPort;
  17. @GetMapping(value = "/sub/getregist/nacos/{id}")
  18. public String getRegist(@PathVariable("id") Integer id){
  19. return paymentFeignService.getRegist(id);
  20. }
  21. }

启动测试成功

SpringCloud Alibaba系统框架搭建 - 图30

6.5 OpenFeign 超时控制

SpringCloud Alibaba系统框架搭建 - 图31

OpenFeign 默认支持 Ribbon

1.YML 文件里需要开启 OpenFeign 客户端超时控制

  1. ribbon:
  2. ReadTimeout: 5000
  3. ConnectTimeout: 5000

测试:1.先去掉 yml 配置并关闭 5001 服务访问直接报错,

2.加上 yml 配置并开启 5001 服务,效果明显。

6.6 OpenFeign 日志打印功能

SpringCloud Alibaba系统框架搭建 - 图32

1.日志级别

SpringCloud Alibaba系统框架搭建 - 图33

2.配置日志 bean

  1. package com.atguigu.springcloud.config;
  2. import feign.Logger;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. @Configuration
  6. public class FeignConfig {
  7. @Bean
  8. Logger.Level feignLoggerLevel(){
  9. return Logger.Level.FULL;
  10. }
  11. }

3.YML 文件里需要开启日志的 Feign 客户端

  1. logging:
  2. level:
  3. com.atguigu.springcloud.service.PaymentFeignService: debug

idea 后台日志查看

七、Sentinel 实现熔断与限流

7.1 什么是 Sentinel

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

SpringCloud Alibaba系统框架搭建 - 图34

Sentinel 具有以下特征:

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
  • 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
  • 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

7.2 安装与使用

SpringCloud Alibaba系统框架搭建 - 图35

Sentinel 分为两个部分:

  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

7.2.1 启动 Nacos 成功

7.2.2 5001 服务模块编辑

1.写 POM

  1. <dependency>
  2. <groupId>com.alibaba.cloud</groupId>
  3. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  4. </dependency>

2.写 yml

  1. server:
  2. port: 5001
  3. spring:
  4. application:
  5. name: nocas-csii-provider
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: localhost:8848
  10. sentinel:
  11. transport:
  12. dashboard: localhost:8080
  13. port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
  14. management:
  15. endpoints:
  16. web:
  17. exposure:
  18. include: '*'
  1. 启动 Sentinel8080

java -jar sentinel-dashboard-1.7.0

4.启动 5001 微服务后查看 sentienl 控制台

SpringCloud Alibaba系统框架搭建 - 图36

7.3 流控规则

7.3.1 基本介绍

其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

SpringCloud Alibaba系统框架搭建 - 图37

限流的直接表现是在执行 Entry nodeA = SphU.entry(resourceName) 的时候抛出 FlowException 异常。FlowExceptionBlockException 的子类,您可以捕捉 BlockException 来自定义被限流之后的处理逻辑。

一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果:

SpringCloud Alibaba系统框架搭建 - 图38

7.3.2 流控模式

1.系统默认直接快速失败>>>配置及说明

SpringCloud Alibaba系统框架搭建 - 图39

测试访问>>快速点:http://192.168.xxx.xxx:5001/getregist/get/1

结果:

SpringCloud Alibaba系统框架搭建 - 图40

思考:直接调用默认报错技术上 ok,但是太粗暴了,体验很不好。所以需要类似有一个 fallback 的兜底方法。

2.关联

当关联的资源达到阈值时,就限流自己;当与 A 关联的资源 B 达到阈值后,就限流自己;B 惹事,A 挂了。

配置:

SpringCloud Alibaba系统框架搭建 - 图41

postman 模拟并发密集访问/sub/getregist/nacos/1

postman 里新建多线程集合组:

SpringCloud Alibaba系统框架搭建 - 图42

大批量线程高并发访问 B,导致 A 失效了:

SpringCloud Alibaba系统框架搭建 - 图43

快速在浏览器访问:/getregist/get/1

结果:

SpringCloud Alibaba系统框架搭建 - 图44

3.链路

NodeSelectorSlot 中记录了资源之间的调用链路,这些资源通过调用关系,相互之间构成一棵调用树。这棵树的根节点是一个名字为 machine-root 的虚拟节点,调用链的入口都是这个虚节点的子节点。

一棵典型的调用树如下图所示:

  1. machine-root
  2. / \
  3. / \
  4. Entrance1 Entrance2
  5. / \
  6. / \
  7. DefaultNode(nodeA) DefaultNode(nodeA)

上图中来自入口 Entrance1Entrance2 的请求都调用到了资源 NodeA,Sentinel 允许只根据某个入口的统计信息对资源限流。比如我们可以设置 FlowRule.strategyRuleConstant.CHAIN,同时设置 FlowRule.ref_identityEntrance1 来表示只有从入口 Entrance1 的调用才会记录到 NodeA 的限流统计当中,而不关心经 Entrance2 到来的调用。

注意:为了方便理解上边这一段话大家自行与下两图匹配,不理解可以评论留言。

  1. public static final int FLOW_GRADE_THREAD = 0;
  2. public static final int FLOW_GRADE_QPS = 1;
  3. public static final int DEGRADE_GRADE_RT = 0;
  4. /**
  5. * Degrade by biz exception ratio in the current {@link IntervalProperty#INTERVAL} second(s).
  6. */
  7. public static final int DEGRADE_GRADE_EXCEPTION_RATIO = 1;
  8. /**
  9. * Degrade by biz exception count in the last 60 seconds.
  10. */
  11. public static final int DEGRADE_GRADE_EXCEPTION_COUNT = 2;
  12. public static final int AUTHORITY_WHITE = 0;
  13. public static final int AUTHORITY_BLACK = 1;
  14. public static final int STRATEGY_DIRECT = 0;
  15. public static final int STRATEGY_RELATE = 1;
  16. public static final int STRATEGY_CHAIN = 2;
  17. public static final int CONTROL_BEHAVIOR_DEFAULT = 0;
  18. public static final int CONTROL_BEHAVIOR_WARM_UP = 1;
  19. public static final int CONTROL_BEHAVIOR_RATE_LIMITER = 2;
  20. public static final int CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER = 3;
  21. public static final String LIMIT_APP_DEFAULT = "default";
  22. public static final String LIMIT_APP_OTHER = "other";
  23. public static final int DEFAULT_SAMPLE_COUNT = 2;
  24. public static final int DEFAULT_WINDOW_INTERVAL_MS = 1000;

SpringCloud Alibaba系统框架搭建 - 图45

配置:

SpringCloud Alibaba系统框架搭建 - 图46

测试访问:http://192.168.xxx.xxx:4001/getregist/get/1

当 1 秒流量(qps)>3 时,报错:

SpringCloud Alibaba系统框架搭建 - 图47

7.3.3 流控效果

1、快速失败:直接失败

方式是默认的流量控制方式,当 QPS 超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。

直接抛错:(演示略)

  1. Blocked by Sentinel (flow limiting)

2、Warm Up 方式:即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值(预热/冷启动方式)

即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过”冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。

默认 coldFactor 为 3,即请求 QPS 从 threshold/3 开始,经预热时长逐渐升至设定的 QPS 阈值。

源码:com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController

  1. public WarmUpController(double count, int warmUpPeriodInSec) {
  2. construct(count, warmUpPeriodInSec, 3);
  3. }
  4. private void construct(double count, int warmUpPeriodInSec, int coldFactor) {
  5. if (coldFactor <= 1) {
  6. throw new IllegalArgumentException("Cold factor should be larger than 1");
  7. }
  8. this.count = count;
  9. this.coldFactor = coldFactor;
  10. // thresholdPermits = 0.5 * warmupPeriod / stableInterval.
  11. // warningToken = 100;
  12. warningToken = (int)(warmUpPeriodInSec * count) / (coldFactor - 1);
  13. // / maxPermits = thresholdPermits + 2 * warmupPeriod /
  14. // (stableInterval + coldInterval)
  15. // maxToken = 200
  16. maxToken = warningToken + (int)(2 * warmUpPeriodInSec * count / (1.0 + coldFactor));
  17. // slope
  18. // slope = (coldIntervalMicros - stableIntervalMicros) / (maxPermits
  19. // - thresholdPermits);
  20. slope = (coldFactor - 1.0) / count / (maxToken - warningToken);
  21. }

SpringCloud Alibaba系统框架搭建 - 图48

Warmup 配置:

SpringCloud Alibaba系统框架搭建 - 图49

测试访问:http://xxx:4001/getregist/get/1

一直狂点刚开始不行,基本 5 秒后就可以正常访问了。

3、排队等待

会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。详细文档可以参考 流量控制 - 匀速器模式,具体的例子可以参见 PaceFlowDemo

SpringCloud Alibaba系统框架搭建 - 图50

这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

源码:com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController

配置:匀速排队,阈值必须设置为 QPS

SpringCloud Alibaba系统框架搭建 - 图51

SpringCloud Alibaba系统框架搭建 - 图52

测试访问 1s 通过一个,所以多线程 1000ms 访问 10 次是不行的,已受到限制只能排队。

7.4 降级规则

7.4.1 官网溜一圈

概述

除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。

SpringCloud Alibaba系统框架搭建 - 图53

降级策略

我们通常用以下几种方式来衡量资源是否处于稳定的状态:

  • 平均响应时间 (DEGRADE_GRADE_RT):当 1s 内持续进入 N 个请求,对应时刻的平均响应时间(秒级)均超过阈值(count,以 ms 为单位),那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地熔断(抛出 DegradeException)。注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要变更此上限可以通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。

SpringCloud Alibaba系统框架搭建 - 图54

配置:

SpringCloud Alibaba系统框架搭建 - 图55

代码:

  1. @GetMapping("/testD") public String testD() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } log.info("testD 测试RT"); return "------testD"; }

jmeter 压测:

SpringCloud Alibaba系统框架搭建 - 图56

SpringCloud Alibaba系统框架搭建 - 图57

  • 异常比例 (DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒请求量 >= N(可配置),并且每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之后,资源进入降级状态,即在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

SpringCloud Alibaba系统框架搭建 - 图58

配置:

SpringCloud Alibaba系统框架搭建 - 图59

代码:

  1. @GetMapping("/testD")
  2. public String testD()
  3. {
  4. log.info("testD 测试RT");
  5. int age = 10/0;
  6. return "------testD";
  7. }

jmeter 压测:

SpringCloud Alibaba系统框架搭建 - 图60

SpringCloud Alibaba系统框架搭建 - 图61

  • 异常数 (DEGRADE_GRADE_EXCEPTION_COUNT):当资源近 1 分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若 timeWindow 小于 60s,则结束熔断状态后仍可能再进入熔断状态。

SpringCloud Alibaba系统框架搭建 - 图62

配置:

SpringCloud Alibaba系统框架搭建 - 图63

代码+ jmeter 压测:同上(异常比例)

7.5 热点 key 限流

7.5.1 Overview

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。

7.5.2 承上启下复习 start:@SentinelResource

SpringCloud Alibaba系统框架搭建 - 图64

代码:

  1. @GetMapping("/testHotKey")
  2. @SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
  3. public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
  4. @RequestParam(value = "p2",required = false) String p2) {
  5. //int age = 10/0;
  6. return "------testHotKey";
  7. }
  8. //兜底方法
  9. public String deal_testHotKey (String p1, String p2, BlockException exception){
  10. return "------deal_testHotKey,o(╥﹏╥)o";
  11. }

配置 nacos:

SpringCloud Alibaba系统框架搭建 - 图65

注:方法 testHostKey 里面第一个参数只要 QPS 超过每秒 1 次,马上降级处理。如果参数索引为大于 0 的数则是连续多个参数;并不表示下标第几个。前提是不选择【高级选项】

测试成功

SpringCloud Alibaba系统框架搭建 - 图66

7.5.3 参数例外项

SpringCloud Alibaba系统框架搭建 - 图67

sentinel 配置热点:

SpringCloud Alibaba系统框架搭建 - 图68

测试成功

“p1=5”的时候可以访问 200/s

SpringCloud Alibaba系统框架搭建 - 图69

7.6 系统规则

系统自适应限流

Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

背景

在开始之前,我们先了解一下系统保护的目的:

  • 保证系统不被拖垮
  • 在系统稳定的前提下,保持系统的吞吐量

长期以来,系统保护的思路是根据硬指标,即系统的负载 (load1) 来做系统过载保护。当系统负载高于某个阈值,就禁止或者减少流量的进入;当 load 开始好转,则恢复流量的进入。这个思路给我们带来了不可避免的两个问题:

  • load 是一个“结果”,如果根据 load 的情况来调节流量的通过率,那么就始终有延迟性。也就意味着通过率的任何调整,都会过一段时间才能看到效果。当前通过率是使 load 恶化的一个动作,那么也至少要过 1 秒之后才能观测到;同理,如果当前通过率调整是让 load 好转的一个动作,也需要 1 秒之后才能继续调整,这样就浪费了系统的处理能力。所以我们看到的曲线,总是会有抖动。
  • 恢复慢。想象一下这样的一个场景(真实),出现了这样一个问题,下游应用不可靠,导致应用 RT 很高,从而 load 到了一个很高的点。过了一段时间之后下游应用恢复了,应用 RT 也相应减少。这个时候,其实应该大幅度增大流量的通过率;但是由于这个时候 load 仍然很高,通过率的恢复仍然不高。

TCP BBR 的思想给了我们一个很大的启发。我们应该根据系统能够处理的请求,和允许进来的请求,来做平衡,而不是根据一个间接的指标(系统 load)来做限流。最终我们追求的目标是 在系统不被拖垮的情况下,提高系统的吞吐率,而不是 load 一定要到低于某个阈值。如果我们还是按照固有的思维,超过特定的 load 就禁止流量进入,系统 load 恢复就放开流量,这样做的结果是无论我们怎么调参数,调比例,都是按照果来调节因,都无法取得良好的效果。

Sentinel 在系统自适应保护的做法是,用 load1 作为启动自适应保护的因子,而允许通过的流量由处理请求的能力,即请求的响应时间以及当前系统正在处理的请求速率来决定。

系统规则

系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。

SpringCloud Alibaba系统框架搭建 - 图70

系统规则支持以下的模式:

  • Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5
  • CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
  • 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

自行测试+简单+不重要

7.7 注解@SentinelResource

注意:注解方式埋点不支持 private 方法。

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource 注解包含以下属性:

  • value:资源名称,必需项(不能为空)
  • entryType:entry 类型,可选项(默认为 EntryType.OUT
  • blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称,可选项。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

  • /
    :fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了
    里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:

    1. fallback
    1. fallbackClass
    1. exceptionsToIgnore
    • 返回值类型必须与原函数返回值类型一致;
    • 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
    • fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

  • (since 1.6.0):默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了
    里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:

    1. defaultFallback
    1. exceptionsToIgnore
    • 返回值类型必须与原函数返回值类型一致;
    • 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
    • defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

注:1.6.0 之前的版本 fallback 函数只针对降级异常(DegradeException)进行处理,不能针对业务异常进行处理

示例:好用简单不做演示,有问题评论留言

  1. public class TestService {
  2. // 对应的 `handleException` 函数需要位于 `ExceptionUtil` 类中,并且必须为 static 函数.
  3. @SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
  4. public void test() {
  5. System.out.println("Test");
  6. }
  7. // 原函数
  8. @SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "helloFallback")
  9. public String hello(long s) {
  10. return String.format("Hello at %d", s);
  11. }
  12. // Fallback 函数,函数签名与原函数一致或加一个 Throwable 类型的参数.
  13. public String helloFallback(long s) {
  14. return String.format("Halooooo %d", s);
  15. }
  16. // Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.
  17. public String exceptionHandler(long s, BlockException ex) {
  18. // Do some log here.
  19. ex.printStackTrace();
  20. return "Oops, error occurred at " + s;
  21. }
  22. }

7.8 服务熔断功能

7.8.1Feign 系列

1.写 pom(略)+上边 案例已加过了

2.写 yml(略)+上边 案例已加过了

3.业务类

@FeignClient 注解的业务接口:

  1. package com.atguigu.springcloud.alibaba.service;
  2. import com.atguigu.springcloud.alibaba.entities.CommonResult;
  3. import com.atguigu.springcloud.alibaba.entities.Payment;
  4. import org.springframework.cloud.openfeign.FeignClient;
  5. import org.springframework.web.bind.annotation.GetMapping;
  6. import org.springframework.web.bind.annotation.PathVariable;
  7. @FeignClient(value = "nocas-csii-provider",fallback = PaymentFallbackService.class)
  8. public interface PaymentService
  9. {
  10. @GetMapping(value = "/paymentSQL/{id}")
  11. public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
  12. }

PaymentFallbackService 实现类:

  1. package com.atguigu.springcloud.alibaba.service;
  2. import com.atguigu.springcloud.alibaba.entities.CommonResult;
  3. import com.atguigu.springcloud.alibaba.entities.Payment;
  4. import org.springframework.stereotype.Component;
  5. @Component
  6. public class PaymentFallbackService implements PaymentService
  7. {
  8. @Override
  9. public CommonResult<Payment> paymentSQL(Long id)
  10. {
  11. return new CommonResult<>(44444,"服务降级返回,---PaymentFallbackService",new Payment(id,"errorSerial"));
  12. }
  13. }

Controller:

  1. // OpenFeign
  2. @Resource
  3. private PaymentService paymentService;
  4. @GetMapping(value = "/consumer/paymentSQL/{id}")
  5. public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
  6. return paymentService.paymentSQL(id);
  7. }

测试 6001 调用 5001,此时故意关闭 5001 微服务提供者,看 6001 消费侧自动降级,不会被耗死。

7.8.2 熔断框架比较

SpringCloud Alibaba系统框架搭建 - 图71

7.9 规则持久化

7.9.1 是什么?

一旦我们重启应用,Sentinel 规则将消失,生产环境需要将配置规则进行持久化.

7.9.2 怎么玩?

将限流配置规则持久化进 Nacos 保存,只要刷新 5001 某个 rest 地址,sentinel 控制台的流控规则就能看到,只要 Nacos 里面 的配置不删除,针对 5001 上 Sentinel 上的流控规则持续有效。

7.9.3 步骤:

1.修改 csii_service_regist5001

2.写 POM

  1. <dependency>
  2. <groupId>com.alibaba.csp</groupId>
  3. <artifactId>sentinel-datasource-nacos</artifactId>
  4. </dependency>

3.写 YML

  1. server:
  2. port: 5000
  3. spring:
  4. application:
  5. name: nocas-csii-provider
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: 192.168.XXX.XXX:8090 #Nacos服务注册中心地址
  10. config:
  11. server-addr: 192.168.XXX.XXX:8090 #Nacos作为配置中心地址
  12. file-extension: yaml #指定yaml格式的配置
  13. group: DEFAULT_GROUP
  14. #group: DEV_GROUP
  15. namespace: bd677bce-c69e-473e-8f71-da92c6987215
  16. sentinel:
  17. transport:
  18. dashboard: 192.168.XXX.XXX:8080
  19. port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
  20. datasource:
  21. ds1:
  22. nacos:
  23. server-addr: 192.168.XXX.XXX:8090 #nginx代理后的地址
  24. dataId: nocas-csii-provider
  25. groupId: DEFAULT_GROUP
  26. data-type: json
  27. rule-type: flow
  28. namespace: bd677bce-c69e-473e-8f71-da92c6987215
  29. management:
  30. endpoints:
  31. web:
  32. exposure:
  33. include: '*'
  34. feign:
  35. sentinel:
  36. enabled: true # 激活Sentinel对Feign的支持

4.添加 Nacos 业务规则配置

SpringCloud Alibaba系统框架搭建 - 图72

内容解析:

SpringCloud Alibaba系统框架搭建 - 图73

启动 5001 后刷新 sentinel 发现业务规则有了

SpringCloud Alibaba系统框架搭建 - 图74

八、Gateway 新一代网关

8.1 概述简介

2.2.1.RELEASE

SpringCloud Alibaba系统框架搭建 - 图75

1.如何包括 Spring Cloud Gateway

要将 Spring Cloud Gateway 包含在您的项目中,请使用启动器,其组 ID 为org.springframework.cloud,工件 ID 为spring-cloud-starter-gateway。有关使用当前 Spring Cloud Release Train 设置构建系统的详细信息,请参见Spring Cloud Project 页面

如果包括启动器,但不希望启用网关,请设置spring.cloud.gateway.enabled=false

Spring Cloud Gateway 是基于Spring Boot 2.xSpring WebFluxProject Reactor 构建的。结果,当您使用 Spring Cloud Gateway 时,许多您熟悉的同步库(例如,Spring Data 和 Spring Security)和模式可能不适用。如果您不熟悉这些项目,建议您在使用 Spring Cloud Gateway 之前先阅读它们的文档以熟悉一些新概念。

Spring Cloud Gateway 需要 Spring Boot 和 Spring Webflux 提供的 Netty 运行时。它不能在传统的 Servlet 容器中或作为 WAR 构建时使用。

SpringCloud Alibaba系统框架搭建 - 图76 SpringCloud Alibaba系统框架搭建 - 图77

源码架构:

SpringCloud Alibaba系统框架搭建 - 图78

能干嘛?

SpringCloud Alibaba系统框架搭建 - 图79

微服务架构中网关在哪里:

SpringCloud Alibaba系统框架搭建 - 图80

GateWay 模型 :

SpringCloud Alibaba系统框架搭建 - 图81

8.2 三大核心概念

SpringCloud Alibaba系统框架搭建 - 图82

总体:

SpringCloud Alibaba系统框架搭建 - 图83

8.3 Gateway 工作流程

官网总结:

SpringCloud Alibaba系统框架搭建 - 图84

SpringCloud Alibaba系统框架搭建 - 图85核心逻辑:

路由转发+执行过滤器链

8.4 通过微服务名实现动态路由配置

8.4.1 新建 Module

1.csii_gateway_gateway4001

2.写 POM

  1. <!--新增gateway-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-gateway</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>com.csii.dbus</groupId>
  8. <artifactId>csii_api_commons</artifactId>
  9. <version>1.0-SNAPSHOT</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-devtools</artifactId>
  14. <scope>runtime</scope>
  15. <optional>true</optional>
  16. </dependency>
  17. <dependency>
  18. <groupId>org.projectlombok</groupId>
  19. <artifactId>lombok</artifactId>
  20. <optional>true</optional>
  21. </dependency>
  22. <dependency>
  23. <groupId>org.springframework.boot</groupId>
  24. <artifactId>spring-boot-starter-test</artifactId>
  25. <scope>test</scope>
  26. </dependency>
  27. <!-- sentinel-datasource-nacos 后续持久化用 -->
  28. <dependency>
  29. <groupId>com.alibaba.csp</groupId>
  30. <artifactId>sentinel-datasource-nacos</artifactId>
  31. </dependency>
  32. <!--nacos客户端-->
  33. <dependency>
  34. <groupId>com.alibaba.nacos</groupId>
  35. <artifactId>nacos-client</artifactId>
  36. </dependency>
  37. <!-- sentinel-datasource-nacos 后续持久化用 -->
  38. <dependency>
  39. <groupId>com.alibaba.cloud</groupId>
  40. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  41. </dependency>
  42. <dependency>
  43. <groupId>org.springframework.cloud</groupId>
  44. <artifactId>spring-cloud-starter-openfeign</artifactId>
  45. </dependency>
  46. <!--spring-boot-starter-webflux:反应式Web框架-->
  47. <dependency>
  48. <groupId>org.springframework.boot</groupId>
  49. <artifactId>spring-boot-starter-webflux</artifactId>
  50. </dependency>
  51. <!-- <dependency>
  52. <groupId>com.alibaba.cloud</groupId>
  53. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  54. </dependency>-->
  55. <!--nacos-discovery-->
  56. <dependency>
  57. <groupId>com.alibaba.cloud</groupId>
  58. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  59. </dependency>
  60. <dependency>
  61. <groupId>com.alibaba.csp</groupId>
  62. <artifactId>sentinel-datasource-nacos</artifactId>
  63. </dependency>
  64. <dependency>
  65. <groupId>cn.hutool</groupId>
  66. <artifactId>hutool-all</artifactId>
  67. <version>4.6.3</version>
  68. </dependency>

3.写 yml(默认情况下 Gateway 会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能)

注意:需要注意的是 uri 的协议为 lb,表示启用 Gateway 的负载均衡功能

  1. server:
  2. port: 4001
  3. spring:
  4. application:
  5. name: csii_gateway
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: 192.168.xxx.xxx:8090 #Nacos服务注册中心地址
  10. gateway:
  11. discovery:
  12. locator:
  13. enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
  14. routes:
  15. - id: regist_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
  16. #uri: http://192.168.xxx.xxx:5000 #匹配后提供服务的路由地址
  17. uri: lb://nocas-csii-provider
  18. predicates:
  19. #- Path=/getregist/get/** #断言,路径相匹配的进行路由
  20. - Path=/**
  21. #- id: regist_routh2 #路由的ID,没有固定规则但要求唯一,建议配合服务名
  22. # uri: lb://cloud-payment-service
  23. # predicates:
  24. # - Path=/payment/lb/** #断言,路径相匹配的进行路由
  25. # 显示详细健康信息
  26. # management.endpoint.health.show-details=always
  27. # 开启所有端点允许HTTP查看
  28. management:
  29. endpoints:
  30. web:
  31. exposure:
  32. include: '*'

lb://serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri

4.业务类(无)

5.主启动类

  1. package com.csii.gateway;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  5. @SpringBootApplication
  6. //@EnableEurekaClient//Eureka
  7. @EnableDiscoveryClient
  8. public class GateWayMain4001 {
  9. public static void main(String[] args) {
  10. SpringApplication.run(GateWayMain4001.class, args);
  11. }
  12. }

测试:http://localhost:4001/getregist/nacos/1 微服务名动态路由成功

8.5 Predicate 的使用

8.5.1 是什么?

SpringCloud Alibaba系统框架搭建 - 图86

SpringCloud Alibaba系统框架搭建 - 图87

SpringCloud Alibaba系统框架搭建 - 图88 8.5.1 常用的 Route Predicate

SpringCloud Alibaba系统框架搭建 - 图89

After 时间 API

  1. ZonedDateTime zonedDateTime = ZonedDateTime.now();
  2. System.out.println(zonedDateTime);

yml 配置

  1. server:
  2. port: 9527
  3. spring:
  4. application:
  5. name: cloud-gateway
  6. cloud:
  7. gateway:
  8. discovery:
  9. locator:
  10. enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
  11. routes:
  12. - id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
  13. #uri: http://localhost:8001 #匹配后提供服务的路由地址
  14. uri: lb://cloud-payment-service
  15. predicates:
  16. - Path=/payment/get/** #断言,路径相匹配的进行路由
  17. - id: payment_routh2
  18. #uri: http://localhost:8001 #匹配后提供服务的路由地址
  19. uri: lb://cloud-payment-service
  20. predicates:
  21. - Path=/payment/lb/** #断言,路径相匹配的进行路由
  22. #- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
  23. #- Cookie=username,zhangshuai #并且Cookie是username=zhangshuai才能访问
  24. #- Header=X-Request-Id, \d+ #请求头中要有X-Request-Id属性并且值为整数的正则表达式
  25. #- Host=**.atguigu.com
  26. #- Method=GET
  27. #- Query=username, \d+ #要有参数名称并且是正整数才能路由
  28. eureka:
  29. instance:
  30. hostname: cloud-gateway-service
  31. client:
  32. service-url:
  33. register-with-eureka: true
  34. fetch-registry: true
  35. defaultZone: http://eureka7001.com:7001/eureka

总结:

说白了,Predicate 就是为了实现一组匹配规则,让请求过来找到对应的 Route 进行处理。

8.6 Filter 的使用

8.6.1 是什么?

SpringCloud Alibaba系统框架搭建 - 图90

SpringCloud Alibaba系统框架搭建 - 图91

单一常用的 GatewayFilter 与自定义全局 GlobalFilter, 演示比较简单官网搞起来。

九、Seata 处理分布式事务

9.1 Seata 简介

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

9.2 分布式事务问题

1.分布式前

SpringCloud Alibaba系统框架搭建 - 图92

2.分布式之后

SpringCloud Alibaba系统框架搭建 - 图93

SpringCloud Alibaba系统框架搭建 - 图94

问题:一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用,就会产生分布式事务问题.

9.3 Seata-Server 安装

9.4 Seata 之原理简介

十、Sleuth 分布式请求链路追踪

10.1 概述

10.1.1 是什么?

1.Spring Cloud Sleuth 提供了一套完整的服务跟踪的解决方案。

2.在分布式系统中提供追踪解决方案并且兼容支持了 zipkin

10.1.2 为什么会出现这个技术?需要解决哪些问题?

SpringCloud Alibaba系统框架搭建 - 图95

10.1.3 解决

SpringCloud Alibaba系统框架搭建 - 图96

10.2 搭建链路监控步骤

10.2.1 zipkin

1.下载

SpringCloud 从 F 版起已不需要自己构建 Zipkin server 了,只需要调用 jar 包即可

https://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/

zipkin-server-2.12.9.exec.jar

SpringCloud Alibaba系统框架搭建 - 图97

2.运行控制台

访问路径:http://localhost:9411/zipkin/

完整的调用链路:

SpringCloud Alibaba系统框架搭建 - 图98

简化图:

SpringCloud Alibaba系统框架搭建 - 图99 名词解释:

Trace:类似于树结构的 Span 集合,表示一条调用链路,存在唯一标识。

span:表示调用链路来源,通俗的理解 span 就是一次请求信息。

10.2.2 csii_service_regist5001

1.写 pom

  1. <!--包含了sleuth+zipkin-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-zipkin</artifactId>
  5. </dependency>

2.写 yml

  1. spring:
  2. application:
  3. name: nocas-csii-provider
  4. zipkin:
  5. base-url: http://192.168.xxx.xxx:9411
  6. sleuth:
  7. sampler:
  8. probability: 1 #表示全部采集

测试访问: http://localhost:4001/getregist/nacos/1

打开:http://localhost:9411/zipkin/

SpringCloud Alibaba系统框架搭建 - 图100

SpringCloud Alibaba系统框架搭建 - 图101

备注:谨记教诲:“理论+实战+小总结”。欢迎大家一起探讨,有问题请大家评论留言。

感谢语:感谢尚硅谷无私奉献

更新中…… 去除 iconfinder 上 icon 的水印

原理

利用水印像素点和原图像素点颜色合并的原理,如果拥有加过水印的图片和水印图片,就可以反向推出原图原像素点的颜色;前提是你得拥有他的水印图片