课程计划

  • 微服务、分布式概念、微服务架构
  • 注册中心:Eureka
  • 负载均衡:Ribbon
  • 声明式调用远程方法:OpenFeign
  • 熔断、降级、监控:Hystrix
  • 网关:Gateway
  • 链路跟踪:Sleuth
  • 服务注册和配置中心:Spring Cloud Alibaba Nacos
  • 熔断、降级、限流:Spring Cloud Alibaba Sentinel

1 微服务理论

https://www.martinfowler.com/articles/microservices.html 微服务microservices
http://blog.cuicc.com/blog/2015/07/22/microservices/
In short(简言之), the microservice architectural style 【架构风格】[1] is an approach to developing a single application as a suite of small services【独立应用变成一套小服务】, each running in its own process and communicating with lightweight(轻量级沟通) mechanisms(每一个都运行在自己的进程内(容器)), often an HTTP resource API(用HTTP,将功能写成能接受请求). These services are built around business capabilities (独立业务能力)and independently deployable by fully automated deployment machinery(应该自动化独立部署). There is a bare minimum of centralized management of these services(应该有一个能管理这些服务的中心), which may be written in different programming languages (独立开发语言)and use different data storage technologies(独立的数据存储).

2 分布式概念

2.1 什么是分布式

《分布式系统原理与范型》定义:“分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”。
分布式系统(distributed system)是建立在网络之上的软件系统。

2.2 分布式与集群的关系

集群指的是将几台服务器集中在一起,实现同一业务。
分布式中的每一个节点,都可以做集群。 而集群并不一定就是分布式的。

2.3 软件架构演变

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图1

单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图2
垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图3
分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图4
流动计算架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图5

2.4 RPC是什么

RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。
它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。
即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。

2.4.1 解决分布式系统的各个服务之间互相交互问题

2.4.2 RPC思想原理

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图6

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图7

2.4.3 服务之间的交互可以用两种方式

看一下http和socket的区别!!https://blog.csdn.net/honghailiang888/article/details/51121257

  • RPC
    1. - NettySocket)+自定义序列化
  • RestAPI (严格来说,SpringCloud是使用Rest方式进行服务之间交互的,不属于RPC)
    1. - HTTP+JSON

    2.5 分布式思想与基本概念

    2.5.1 高并发

  1. 通过设计保证系统可以并行处理很多请求。应对大量流量与请求
  • Tomcat最多支持并发多少用户?

Tomcat 默认配置的最大请求数是 150,也就是说同时支持 150 个并发,当然了,也可以将其改大。
当某个应用拥有 250 个以上并发的时候,应考虑应用服务器的集群。
具体能承载多少并发,需要看硬件的配置,CPU 越多性能越高,分配给 JVM 的内存越多性能也就越高,但也会加重 GC 的负担。

  • 操作系统对于进程中的线程数有一定的限制:

Windows 每个进程中的线程数不允许超过 2000
Linux 每个进程中的线程数不允许超过 1000
另外,在 Java 中每开启一个线程需要耗用 1MB 的 JVM 内存空间用于作为线程栈之用。
Tomcat 默认的 HTTP 实现是采用阻塞式的 Socket 通信,每个请求都需要创建一个线程处理。这种模式下的并发量受到线程数的限制,但对于 Tomcat 来说几乎没有 BUG 存在了。
Tomcat 还可以配置 NIO 方式的 Socket 通信,在性能上高于阻塞式的,每个请求也不需要创建一个线程进行处理,并发能力比前者高。但没有阻塞式的成熟。
这个并发能力还与应用的逻辑密切相关,如果逻辑很复杂需要大量的计算,那并发能力势必会下降。如果每个请求都含有很多的数据库操作,那么对于数据库的性能也是非常高的。
对于单台数据库服务器来说,允许客户端的连接数量是有限制的。
并发能力问题涉及整个系统架构和业务逻辑。
系统环境不同,Tomcat版本不同、JDK版本不同、以及修改的设定参数不同。并发量的差异还是满大的。

  • maxThreads=”1000” 最大并发数 ,默认值为200
  • minSpareThreads=”100”//初始化时创建的线程数,默认值为10
  • acceptCount=”700”// 指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理,默认值为100

https://tomcat.apache.org/tomcat-8.0-doc/config/http.html

  1. 高并发衡量指标
  • 响应时间(RT)
    • 请求做出响应的时间,即一个http请求返回所用的时间
  • 吞吐量
    • 系统在单位时间内处理请求的数量
  • QPS(Query/Request Per Second)、 TPS(Transaction Per Second)
  • 每秒查询(请求)数、每秒事务数
    • 专业的测试工具:Load Runner
    • Apache ab
    • Apache JMeter
  • 并发用户数

    • 承载的正常使用系统功能的用户的数量

      2.5.2 高可用

      服务集群部署
      数据库主从+双机热备
  • 主-备方式(Active-Standby方式)

主-备方式即指的是一台服务器处于某种业务的激活状态(即Active状态),另一台服务器处于该业务的备用状态(即Standby状态)。

  • 双主机方式(Active-Active方式)

双主机方式即指两种不同业务分别在两台服务器上互为主备状态(即Active-Standby和Standby-Active状态)

2.5.3 注册中心

保存某个服务所在地址等信息,方便调用者实时获取其他服务信息

  • 服务注册
    • 服务提供者
  • 服务发现

    • 服务消费者

      2.5.4 负载均衡

  • 动态将请求派发给比较闲的服务器

策略:

  • 轮询(Round Robin)
  • 加权轮询(Weighted Round Robin)
  • 随机Random
  • 哈希Hash
  • 最小连接数LC
  • 最短响应时间LRT

    2.5.5 服务雪崩

    服务之间复杂调用,一个服务不可用,导致整个系统受影响不可用
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图8

    2.5.6 熔断

    某个服务频繁超时,直接将其短路,快速返回mock(模拟/虚拟)值
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图9

    2.5.7 限流

    限制某个服务每秒的调用本服务的频率
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图10

    2.5.8 API网关

    API网关要做很多工作,它作为一个系统的后端总入口,承载着所有服务的组合路由转换等工作,除此之外,我们一般也会把安全,限流,缓存,日志,监控,重试,熔断等放到 API 网关来做

    2.5.9 服务跟踪

    追踪服务的调用链,记录整个系统执行请求过程。如:请求响应时间,判断链中的哪些服务属于慢服务(可能存在问题,需要改善)。

    2.5.10 弹性云

    Elastic Compute Service(ECS)弹性计算服务
    动态扩容,压榨服务器闲时能力
    例如:双11,618,高峰时多配置些服务器,平时减少多余的服务器配置(用于其他服务应用),避免资源浪费

    3 SpringCloud背景

    3.1 背景介绍

    3.1.1 微服务架构

    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图11

    物联网( IoT ,Internet of things )即“万物相连的互联网”,是互联网基础上的延伸和扩展的网络,将各种信息传感设备与互联网结合起来而形成的一个巨大网络,实现在任何时间、任何地点,人、机、物的互联互通。
    Breaker dashboard 断路器仪表板
    Distributed Tracing分布式跟踪 (分布式处理程序链跟踪用于监视网络等待时间,并可视化通过微服务的请求流)

    3.1.2 微服务框架之SpringBoot

    https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/reference/htmlsingle/

    3.1.3 分布式系统微服务架构之SpringCloud

    https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/
    英文困难的同学,也不耽误学习的
    https://www.bookstack.cn/read/spring-cloud-docs/docs-index.md

    3.1.4 组件概述

    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图12

    3.2 关于SpringBoot和SpringCloud版本

    3.2.1 SpringCloud版本选择

    SpringBoot2.X版和SpringCloud H版
    SpringCloud Alibaba 2.1

    3.2.2 Springboot版本选择

    git源码地址:
    https://github.com/spring-projects/spring-boot/releases/
    SpringBoot2.0新特性:
    https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Release-Notes
    通过上面官网发现,Boot官方强烈建议你升级到2.X以上版本
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图13

    3.2.3 官网看Boot版本

    springboot(截至2020.4.4)
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图14

    3.2.4 SpringCloud版本选择

  • git源码地址: https://github.com/spring-projects/spring-cloud/wiki

  • 官网: https://spring.io/projects/spring-cloud

官网看Cloud版本

  • Cloud命名规则

Spring Cloud采用了英国伦敦地铁站的名称来命名,并由地铁站名称字母A-Z依次类推的形式来发布迭代版本。
Spring Cloud 是一个由许多子项目组成的综合项目,各子项目有不同的发布节奏。为了管理SpringCloud与各子项目的版本依赖关系,发布了一个清单,其中包括了某个SpringCloud版本对应的子项目版本。为了避免SpringCloud版本号与子项目版本号混淆,SpringCloud版本采用了名称而非版本号的命名,这些版本的名字采用了伦敦地铁站的名字,根据字母表的顺序来应对版本时间顺序。例如Angel是第一个版本,Brixton是第二个版本。当SpringCloud的发布内容积累到临界点或者一个重大BUG被解决后,会发布一个”service releases”版本,简称SRX版本,比如Greenwich.SR2就是SpringCloud发布的Greenwich版本的第二个SRX版本。

  • SpringCloud(截至2020.4.4)

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图15

3.2.5 SpringCloud和Springboot之间的依赖关系

https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图16
最新版本对应关系:截止2020年4月初
https://cloud.spring.io/spring-cloud-static/Hoxton.SR3/reference/html/spring-cloud.html
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图17
更详细的版本对应查看方法: https://start.spring.io/actuator/info
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图18

3.2.6 SpringCloud(授课选择版本)

  • cloud
    • Hoxton.SR1
  • boot
    • 2.2.2.RELEASE
  • cloud Alibaba
    • 2.1.0.RELEASE
  • java
    • JAVA8
  • maven
    • 3.5及以上
  • mysql
    • 5.7及以上

      3.3 微服务架构编码构建-IDEA新建project工作空间

      3.3.1 微服务cloud整体聚合父工程Project

      4 New Project

      01_尚硅谷_SpringCloud课件_2020_V2.4 - 图19

      5 聚合总工程名字

      01_尚硅谷_SpringCloud课件_2020_V2.4 - 图20

      6 Maven选版本

      01_尚硅谷_SpringCloud课件_2020_V2.4 - 图21

      7 工程名字

      01_尚硅谷_SpringCloud课件_2020_V2.4 - 图22

      8 字符编码

      01_尚硅谷_SpringCloud课件_2020_V2.4 - 图23

      9 注解生效激活

      01_尚硅谷_SpringCloud课件_2020_V2.4 - 图24

      10 java编译版本

      01_尚硅谷_SpringCloud课件_2020_V2.4 - 图25

      11 File Type过滤【可选】

      01_尚硅谷_SpringCloud课件_2020_V2.4 - 图26

      11.1 父工程POM

      | <?xml version=”1.0” encoding=”UTF-8”?>
      xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd“>

      4.0.0

      com.atguigu.springcloud
      cloud2020
      1.0-SNAPSHOT
      pom



      UTF-8
      1.8
      1.8
      4.12
      1.2.17
      1.16.18
      5.1.47
      1.1.16
      1.3.0







      org.springframework.boot
      spring-boot-dependencies
      2.2.2.RELEASE
      pom
      import



      org.springframework.cloud
      spring-cloud-dependencies
      Hoxton.SR1
      pom
      import



      com.alibaba.cloud
      spring-cloud-alibaba-dependencies
      2.1.0.RELEASE
      pom
      import



      mysql
      mysql-connector-java
      ${mysql.version}


      com.alibaba
      druid
      ${druid.version}


      org.mybatis.spring.boot
      mybatis-spring-boot-starter
      ${mybatis.spring.boot.version}


      junit
      junit
      ${junit.version}


      log4j
      log4j
      ${log4j.version}


      org.projectlombok
      lombok
      ${lombok.version}
      true







      org.springframework.boot
      spring-boot-maven-plugin

      true
      true





      | | —- |

11.1.1 Maven工程落地细节复习

Maven中的dependencyManagementdependencies区别
maven中跳过单元测试【可选】
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图27

11.1.2 父工程创建完成执行mvn:install

11.2 微服务架构编码构建-Rest微服务-【服务提供者】

11.2.1 建cloud-provider-payment8001

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图28
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图29
创建完成后请回到父工程查看pom文件变化,增加了聚合模块


cloud-provider-payment8001

11.2.2 改POM文件

<?xml version=”1.0” encoding=”UTF-8”?>
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd“>

cloud2020
com.atguigu.springcloud
1.0-SNAPSHOT

4.0.0

cloud-provider-payment8001



org.springframework.boot
spring-boot-starter-web


org.springframework.boot
spring-boot-starter-actuator


org.mybatis.spring.boot
mybatis-spring-boot-starter


com.alibaba
druid-spring-boot-starter
1.1.10


mysql
mysql-connector-java


org.springframework.boot
spring-boot-starter-jdbc


org.springframework.boot
spring-boot-devtools
runtime
true


org.projectlombok
lombok
true


org.springframework.boot
spring-boot-starter-test
test



11.2.3 写YML

server:
port: 8001

spring:
application:
name: cloud-payment-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/cloud2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root

mybatis:
mapperLocations: classpath:/mapper/*.xml
type-aliases-package: com.atguigu.springcloud.entities

11.2.4 主启动

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class,args);
}
}

11.2.5 业务类

12 建表SQL

CREATE DATABASE IF NOT EXISTS cloud2020 DEFAULT CHARACTER SET utf8 ;

USE cloud2020 ;

DROP TABLE IF EXISTS payment ;

CREATE TABLE payment (
id BIGINT (20) NOT NULL AUTO_INCREMENT COMMENT ‘ID’,
SERIAL VARCHAR (300) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB AUTO_INCREMENT = 33 DEFAULT CHARSET = utf8 ;

INSERT INTO payment (id, SERIAL) VALUES(31, ‘尚硅谷001’),(32, ‘atguigu002’) ;

13 Entitles

14 主实体Payment
package com.atguigu.springcloud.entities;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable {
private Long id;
private String serial;
}

15 Json封装体CommonResult
package com.atguigu.springcloud.entities;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult implements Serializable{

private Integer code;
private String message;
private T data;

public CommonResult(Integer code,String message){
this(code,message,null);//如果这行报错,请安装lombok插件
}
}

16 安装lombok插件

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图30

https://www.projectlombok.org/
@Data:提供getter/setter
@NoArgsConstructor, 无参构造器 @RequiredArgsConstructor @AllArgsConstructor 全参数构造器
@EqualsAndHashCode:提供equals和hashCode方法
@Getter/@Setter
@Slf4j 内置log对象,直接调用日志方法输出日志

17 Dao

18 接口PaymentDao
package com.atguigu.springcloud.dao;

import com.atguigu.springcloud.entities.Payment;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

@Component //代替@Repository声明bean
@Mapper //mybatis提供的,等价:@MapperScan(“com.atguigu.springcloud.dao”)
//@Repository //spring提供的。在此,只是为了声明bean对象
public interface PaymentDao {
public int create(Payment payment);
public Payment getPaymentById(@Param(“id”) Long id);
}

19 mybatis的映射文件

src\main\resources\mapper\PaymentMapper.xml

<?xml version=”1.0” encoding=”UTF-8”?>
<!DOCTYPE mapper PUBLIC “-//mybatis.org//DTD Mapper 3.0//EN” “http://mybatis.org/dtd/mybatis-3-mapper.dtd“>



insert into payment(serial) values(#{serial});









20 Service

21 接口PaymentService
package com.atguigu.springcloud.service;

import com.atguigu.springcloud.entities.Payment;
import org.apache.ibatis.annotations.Param;

public interface PaymentService {
public int create(Payment payment); //写
public Payment getPaymentById(Long id); //读取
}

22 实现类PaymentServiceImpl
package com.atguigu.springcloud.service.impl;

import com.atguigu.springcloud.dao.PaymentDao;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.PaymentService;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

@Service
public class PaymentServiceImpl implements PaymentService {

@Resource
//@Autowired
private PaymentDao paymentDao;

public int create(Payment payment){
return paymentDao.create(payment);
}

public Payment getPaymentById( Long id){
return paymentDao.getPaymentById(id);
}
}

23 Controller

package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

@RestController
@Slf4j
public class PaymentController {

@Resource
private PaymentService paymentService;

@PostMapping(value = “/payment/create”)
public CommonResult create(Payment payment){ //埋雷
int result = paymentService.create(payment);
log.info(“*插入结果:”+result);
if (result>0){ //成功
return new CommonResult(200,”插入数据库成功”,result);
}else {
return new CommonResult(444,”插入数据库失败”,null);
}
}

@GetMapping(value = “/payment/get/{id}”)
public CommonResult getPaymentById(@PathVariable(“id”) Long id){
Payment payment = paymentService.getPaymentById(id);
log.info(“*查询结果:”+payment);
if (payment!=null){ //说明有数据,能查询成功
return new CommonResult(200,”查询成功”,payment);
}else {
return new CommonResult(444,”没有对应记录,查询ID:”+id,null);
}
}
}

23.1 测试

24 postman测试get请求

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图31

25 postman测试post请求

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图32

26 快速运行设置

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图33

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图34

26.1 开发步骤-小总结

  1. 建module
  2. 改POM
  3. 写YML
  4. 主启动
  5. 业务类

    26.1.1 热部署Devtools

    27 Adding devtools to your project

    |
    org.springframework.boot
    spring-boot-devtools
    runtime
    true
    | | —- |

28 Adding plugin to your pom.xml

下一段配置黏贴到父工程当中的pom里



org.springframework.boot
spring-boot-maven-plugin

true
true



29 Enabling automatic build

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图35

30 Update the value of

Ctrl+Shift+Alt+/选择Registry…
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图36
compiler.automake.allow.when.app.running -> 自动编译
compile.document.save.trigger.delay -> 自动更新文件;它主要是针对静态文件如JS CSS的更新,将延迟时间减少后,直接按F5刷新页面就能看到效果!
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图37

31 重启IDEA

31.1 微服务架构编码构建-Rest微服务-【服务消费者】

31.1.1 建cloud-consumer-order80

31.1.2 改POM

<?xml version=”1.0” encoding=”UTF-8”?>
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd“>

cloud2020
com.atguigu.springcloud
1.0-SNAPSHOT

4.0.0
cloud-consumer-order80



org.springframework.boot
spring-boot-starter-web


org.springframework.boot
spring-boot-starter-actuator


org.springframework.boot
spring-boot-devtools
runtime
true


org.projectlombok
lombok
true


org.springframework.boot
spring-boot-starter-test
test


31.1.3 写YML

server:
port: 80
spring:
application:
name: cloud-consumer-order80

31.1.4 主启动

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class,args);
}
}

31.1.5 业务类

32 创建entities

(将cloud-provider-payment8001工程下的entities包下的两个实体类复制过来)

33 RestTemplate

  • 是什么

RestTemplate提供了多种便捷访问远程Http服务的方法,是一种简单便捷的访问Restful服务模板类,是Spring 提供的用于访问Rest服务的客户端模板工具集

  • 官网及使用

官网地址: https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html
使用RestTemplate访问Restful接口非常的简单粗暴无脑。(url,requestMap,ResponseBean.class)这三个参数分别代表REST请求地址、请求参数、Http响应转换被转换成的对象类型。

34 config配置类

ApplicationContextConfig

package com.atguigu.springcloud.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

//@Configuration
@SpringBootConfiguration
public class ApplicationContextConfig {

@Bean
//@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}

}

35 创建controller

package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;

@RestController
@Slf4j
public class OrderController {

public static final String PAYMENT_URL = “http://localhost:8001“;

@Resource
private RestTemplate restTemplate;

@PostMapping(“/consumer/payment/create”)
public CommonResult create(Payment payment){
return restTemplate.postForObject(PAYMENT_URL+”/payment/create”,payment,CommonResult.class); //写操作
}

@GetMapping(“/consumer/payment/get/{id}”)
public CommonResult getPayment(@PathVariable(“id”) Long id){
return restTemplate.getForObject(PAYMENT_URL+”/payment/get/“+id,CommonResult.class);
}
}

35.1 测试

  1. 先启动cloud-provider-payment8001
  2. 再启动cloud-consumer-order80
  3. http://localhost/consumer/payment/get/32
  4. 不要忘记@RequestBody注解
  5. 服务提供者接口方法需要增加@RequestBody注解(踩雷or破雷);否则,接收不到数据。

    35.2 工程重构

    35.2.1 观察问题

    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图38

    35.2.2 新建:cloud-api-commons

    35.2.3 POM

    | <?xml version=”1.0” encoding=”UTF-8”?>
    xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
    xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd“>

    cloud2020
    com.atguigu.springcloud
    1.0-SNAPSHOT

    4.0.0
    cloud-api-commons



    org.springframework.boot
    spring-boot-devtools
    runtime
    true



    org.projectlombok
    lombok
    true


    cn.hutool
    hutool-all
    5.1.0



    | | —- |

35.2.4 entities

Payment实体
CommonResult通用封装类

35.2.5 maven命令clean install

35.2.6 订单80和支付8001分别改造

删除各自的原先有过的entities
各自黏贴POM内容,依赖于cloud-api-commons公共项目


com.atguigu.springcloud
cloud-api-commons
${project.version}

35.3 目前工程样图

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图39

36 Eureka服务注册与发现

36.1 Eureka基础知识

36.1.1 什么是服务治理

SpringCloud封装了Netflix公司开发的Eureka模块来实现服务治理。
在传统的RPC远程调用框架中,管理每个服务与服务之间依赖关系比较复杂、所以需要进行服务治理,管理服务与服务之间依赖关联,以实现服务调用,负载均衡、容错等,实现服务发现与注册。

36.1.2 什么是服务注册

Eureka采用了CS的设计架构,Eureka Server作为服务注册功能的服务器,它是服务注册中心。
而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接。这样系统的维护人员可以通过Eureka Server来监控系统中各个微服务是否正常运行。
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息,比如:服务通讯地址等以别名方式注册到注册中心上。
另一方(消费者服务),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后,再实现本地RPC远程调用。
RPC远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。
在任何RPC远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))。
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图40

36.1.3 Eureka两组件

  • Eureka Server提供服务注册服务

各个微服务节点通过配置启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。

  • Eureka Client通过注册中心进行访问

是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会在Eureka Server发送心跳(默认周期30秒)。如果Eureka Server在多个心跳周期内没有收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移出(默认90秒)

36.2 单机Eureka构建步骤

36.2.1 IDEA生成eurekaServer端服务注册中心

37 建Module:cloud-eureka-server7001

38 改POM

<?xml version=”1.0” encoding=”UTF-8”?>
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd“>

cloud2020
com.atguigu.springcloud
1.0-SNAPSHOT

4.0.0
cloud-eureka-server7001



org.springframework.cloud
spring-cloud-starter-netflix-eureka-server



com.atguigu.springcloud
cloud-api-commons
${project.version}


org.springframework.boot
spring-boot-starter-web


org.springframework.boot
spring-boot-starter-actuator


org.springframework.boot
spring-boot-devtools
runtime
true


org.projectlombok
lombok


org.springframework.boot
spring-boot-starter-test
test


junit
junit


  • 1.X和2.X的对比说明 | 1.X版本

    org.springframework.cloud
    spring-cloud-starter-eureka


    2.X版本

    org.springframework.cloud
    spring-cloud-starter-netflix-eureka-server
    | | —- |

39 写YML

server:
port: 7001

eureka:
instance:
hostname: localhost

client:
register-with-eureka: false
fetchRegistry: false
service-url:
defaultZone: http://localhost:7001/eureka

40 主启动

@EnableEurekaServer

41 测试

http://localhost:7001/

41.1 服务提供者

EurekaClient端cloud-provider-payment8001将注册进EurekaServer成为服务提供者provider

42 建Module:cloud-provider-payment8001

43 改POM


org.springframework.cloud
spring-cloud-starter-netflix-eureka-client

44 写YML

eureka:
client:
register-with-eureka: true
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka

45 主启动

@EnableEurekaClient

46 测试

先启动EurekaServer
http://localhost:7001/

46.1 服务消费者

EurekaClient端cloud-consumer-order80将注册进EurekaServer成为服务消费者consumer

47 建Module:cloud-consumer-order80

48 POM


org.springframework.cloud
spring-cloud-starter-netflix-eureka-client

49 写YML

eureka:
client:
register-with-eureka: true
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka

50 主启动

@EnableEurekaClient

51 测试

  1. 先要启动EurekaServer,7001服务
  2. 再要启动服务提供者8001服务和服务消费者80服务
  3. eureka服务器

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图41

  1. 测试查询:http://localhost/consumer/payment/get/31
  2. 测试添加:postman测试添加
  3. 测试8001服务和80服务效果一样

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图42

52 Ribbon负载均衡服务调用

52.1 概述

52.1.1 是什么

Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。
Ribbon客户端组件提供一系列完善的配置项,如:连接超时,重试等。
简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。

52.1.2 官网资料

https://github.com/Netflix/ribbon/wiki/Getting-Started
Ribbon目前也进入维护模式
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图43

  • 未来替换方案
    • Spring Cloud LoadBalancer

      52.1.3 能干嘛

      53 LB(负载均衡)

  1. 简单的说就是将用户的请求平均分配到多个服务器上,从而达到系统的HA(高可用)。
  2. 常见的负载均衡有软件Nginx,LVS,硬件F5等。
  3. Ribbon的本地负载均衡客户端 VS Nginx服务端负载均衡区别
    1. - Nginx是服务器负载均衡,客户端所有请求都会交给Nginx,然后,由nginx实现转发请求。即负载均衡是由服务器端完成的。
    2. - Ribbon本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用。
  4. 集中式LB
    1. - 即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5,也可以是软件,如Nginx),由该设施负责把访问请求通过某种策略转发至服务的提供方;
  5. 进程内LB
    1. - LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。
    2. - Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。

    54 一句话

    Ribbon=负载均衡+RestTemplate调用

    54.1 Ribbon负载均衡演示

    54.1.1 架构说明

    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图44
    Ribbon在工作时分成两步:
    第一步,先选择EurekaServer,它优先选择在同一个区域内负载较少的server。
    第二步,再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址。其中Ribbon提供了多种策略。比如:轮询、随机和根据响应时间加权。
    总结:Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例。

    54.1.2 POM

    |
    org.springframework.cloud
    spring-cloud-starter-netflix-ribbon
    | | —- |

注意:这个不需要手动引用,Eureka客户端自带Ribbon
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图45

54.2 Ribbon核心组件Irule

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图46

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图47

54.2.1 IRule:根据特定算法从服务列表中选取一个要访问的服务

  1. com.netflix.loadbalancer.RoundRobinRule 轮询,默认策略。
  2. com.netflix.loadbalancer.RandomRule 随机
  3. com.netflix.loadbalancer.RetryRule 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务
  4. WeightedResponseTimeRule 对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择
  5. BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
  6. AvailabilityFilteringRule 先过滤掉故障实例,再选择并发较小的实例
  7. ZoneAvoidanceRule 默认规则,复合判断server所在区域的性能和server的可用性选择服务器

    54.2.2 如何替换

  • 修改cloud-consumer-order80
  • 注意配置细节

官方文档明确给出警告:
https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/#customizing-the-ribbon-client
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图48
这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化订制的目的了。

54.2.3 新建package(注意:包的位置)

com.atguigu.myrule

54.2.4 上面包下新建MySelfRule规则类

package com.atguigu.myrule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MySelfRule {

@Bean
public IRule myRule(){
return new RandomRule();//定义为随机
}
}

54.2.5 主启动类添加@RibbonClient

package com.atguigu.springcloud;

import com.atguigu.myrule.MySelfRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

@EnableEurekaClient
@SpringBootApplication
@RibbonClient(name = “CLOUD-PAYMENT-SERVICE”,configuration = MySelfRule.class)
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class,args);
}
}

54.2.6 测试

http://localhost/consumer/payment/get/31

54.3 Ribbon负载均衡算法

54.3.1 原理

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图49

55 OpenFeign服务接口调用

55.1 概述

55.1.1 OpenFeign是什么

  • Feign是一个声明式的web服务客户端,让编写web服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可
  • SpringCloud对Feign进行了封装,使其支持了SpringMVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。

https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/#spring-cloud-openfeign
https://github.com/spring-cloud/spring-cloud-openfeign

55.1.2 能干嘛

  • Feign能干什么?

Feign旨在使用编写Java Http客户端变得更容易。
前面在使用Ribbon+RestTemplate时,利用RestTemplate对Http请求的封装处理,形成了一套模板化的调用方法。
但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务端额调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。
在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是DAO接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring Cloud Ribbon时,自动封装服务调用客户端的开发量。

  • Feign集成了 Ribbon

利用Ribbon维护了Payment的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。

  • Feign和OpenFeign两者区别

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图50

55.2 OpenFeign使用步骤

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图51

55.2.1 接口+注解

微服务调用接口+@FeignClient

55.2.2 新建Module:cloud-consumer-feign-order80

55.2.3 POM

注意:openFeign也是自带bibbon

<?xml version=”1.0” encoding=”UTF-8”?>
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd“>

cloud2020
com.atguigu.springcloud
1.0-SNAPSHOT

4.0.0
cloud-consumer-feign-order80




org.springframework.cloud
spring-cloud-starter-openfeign


org.springframework.cloud
spring-cloud-starter-netflix-eureka-client


com.atguigu.springcloud
cloud-api-commons
${project.version}


org.springframework.boot
spring-boot-starter-web


org.springframework.boot
spring-boot-starter-actuator


org.springframework.boot
spring-boot-devtools
runtime
true


org.projectlombok
lombok
true


org.springframework.boot
spring-boot-starter-test
test


55.2.4 YML

server:
port: 80
spring:
application:
name: cloud-consumer-feign-order80
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka

55.2.5 主启动类

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class OrderFeignMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderFeignMain80.class,args);
}
}

55.2.6 业务类

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

57 新建PaymentFeignService接口并新增注解@FeignClient

package com.atguigu.springcloud.service;

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import feign.Param;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@Component
@FeignClient(value = “CLOUD-PAYMENT-SERVICE”)
public interface PaymentFeignService {
@GetMapping(value = “/payment/get/{id}”)
public CommonResult getPaymentById(@PathVariable(“id”) Long id);
}

58 控制层Controller

package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.PaymentFeignService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

@RestController
public class OrderFeignController {

@Resource
private PaymentFeignService paymentFeignService; //调用远程的微服接口

@GetMapping(value = “/consumer/payment/get/{id}”)
public CommonResult getPaymentById(@PathVariable(“id”) Long id){
return paymentFeignService.getPaymentById(id);
}
}

58.1 测试

  1. 先启动Eureka7001
  2. 再启动2个微服务8001/8002
  3. 启动OpenFeign微服务:cloud-consumer-feign-order80
  4. http://localhost/consumer/payment/get/31
  5. Feign自带负载均衡配置项

    58.1.1 小总结

    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图52

    58.2 OpenFeign超时控制

    58.2.1 超时设置,故意设置超时演示出错情况

    59 服务提供方8001故意写暂停程序

    | @GetMapping(value = “/payment/feign/timeout”)
    public String paymentFeignTimeout(){
    try { TimeUnit.SECONDS.sleep(3); }catch (Exception e) {e.printStackTrace();} //单位秒
    return serverPort;
    } | | —- |

60 服务消费方80添加超时方法PaymentFeignService

@GetMapping(value = “/payment/feign/timeout”)
public String paymentFeignTimeout();

61 服务消费方80添加超时方法OrderFeignController

@GetMapping(value = “/consumer/payment/feign/timeout”)
public String paymentFeignTimeout(){
return paymentFeignService.paymentFeignTimeout();
}

62 测试

http://localhost/consumer/payment/feign/timeout
错误页面,OpenFeign默认等待一秒钟,超过后报错
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图53

62.1 是什么

默认Feign客户端只等待一秒钟,但是,服务端处理需要超过1秒钟,导致Feign客户端不想等待了,直接报错。
为了避免这样的情况,有时候我们需要设置Feign客户端的超时控制,也即Ribbon的超时时间,因为Feign集成了Ribbon进行负载均衡。

62.1.1 YML中需要开启OpenFeign客户端超时控制

Feign设置超时时间
使用Feign调用接口分两层,ribbon的调用和hystrix的调用,所以ribbon的超时时间和Hystrix的超时时间的结合就是Feign的超时时间

#设置Feign客户端超时时间(openfeign默认支持ribbon)
ribbon:
ReadTimeout: 3000
ConnectTimeout: 3000
MaxAutoRetries: 1 #同一台实例最大重试次数,不包括首次调用
MaxAutoRetriesNextServer: 1 #重试负载均衡其他的实例最大重试次数,不包括首次调用
OkToRetryOnAllOperations: false #是否所有操作都重试
#hystrix的超时时间
hystrix:
command:
default:
execution:
timeout:
enabled: true
isolation:
thread:
timeoutInMilliseconds: 9000

一般情况下 都是 ribbon 的超时时间(<)hystrix的超时时间(因为涉及到ribbon的重试机制)
因为ribbon的重试机制和Feign的重试机制有冲突,所以源码中默认关闭Feign的重试机制,源码如下
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图54
要开启Feign的重试机制如下:(Feign默认重试五次 源码中有)

@Bean
Retryer feignRetryer() {
return new Retryer.Default();
}

根据上面的参数计算重试的次数:MaxAutoRetries+MaxAutoRetriesNextServer+(MaxAutoRetries MaxAutoRetriesNextServer) 即重试3次 则一共产生4次调用
如果在重试期间,时间超过了hystrix的超时时间,便会立即执行熔断,fallback。所以要根据上面配置的参数计算hystrix的超时时间,使得在重试期间不能达到hystrix的超时时间,不然重试机制就会没有意义
hystrix超时时间的计算: (1 + MaxAutoRetries + MaxAutoRetriesNextServer)
ReadTimeout 即按照以上的配置 hystrix的超时时间应该配置为 (1+1+1)*3=9秒
当ribbon超时后且hystrix没有超时,便会采取重试机制。当OkToRetryOnAllOperations设置为false时,只会对get请求进行重试。如果设置为true,便会对所有的请求进行重试,如果是put或post等写操作,如果服务器接口没做幂等性,会产生不好的结果,所以OkToRetryOnAllOperations慎用。
如果不配置ribbon的重试次数,默认会重试一次
注意:
默认情况下,GET方式请求无论是连接异常还是读取异常,都会进行重试
非GET方式请求,只有连接异常时,才会进行重试

62.2 OpenFeign日志打印功能

62.2.1 日志打印功能

62.2.2 是什么

Feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign中Http请求的细节。说白了就是对Feign接口的调用情况进行监控和输出。

62.2.3 日志级别

NONE:默认的,不显示任何日志
BASIC:仅记录请求方法、RUL、响应状态码及执行时间
HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息
FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据

62.2.4 配置日志bean

package com.atguigu.springcloud.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfig {

@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}

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

logging:
level:
com.atguigu.springcloud.service.PaymentFeignService: debug

62.2.6 后台日志查看

http://localhost/consumer/payment/get/31
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图55

63 Hystrix断路器

63.1 概述

63.1.1 分布式系统面临的问题

复杂分布式体系结构中的应用程序有数十个依赖关系,每一个依赖关系在某些时候将不可避免的失败。
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图56
服务雪崩
多个微服务之间调用的时候,假如微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的”扇出”。
如果扇出的链路上某个微服务的调用响应的时间过长或者不可用,对微服A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的”雪崩效应”。
对于高流量的应用来说,单一的后端依赖可能会导致所有的服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
所以,通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫雪崩。

63.1.2 是什么

Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,
Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(Fallback),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

63.1.3 能干嘛

  • 服务降级
  • 服务熔断
  • 接近实时的监控
  • 。。。

    63.1.4 官网资料

https://github.com/Netflix/Hystrix/wiki/How-To-Use

63.1.5 Hystrix官宣,停更进维

https://github.com/Netflix/Hystrix
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图57

63.2 Hystrix重要概念

63.2.1 服务降级Fallback

  • 服务器忙,请稍候再试,不让客户端等待并立刻返回一个友好提示
  • 哪些情况会触发降级

    • 程序运行异常
    • 超时自动降级
    • 服务熔断触发服务降级
    • 线程池/信号量打满也会导致服务降级
    • 人工降级

      63.2.2 服务熔断Breaker

  • 类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示

  • 就是保险丝
    • 服务的降级->进而熔断->恢复调用链路

      63.2.3 服务限流Flowlimit

      秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行

      63.3 hystrix案例

      63.3.1 构建

      64 新建Module:cloud-provider-hystrix-payment8001

      65 POM

      | <?xml version=”1.0” encoding=”UTF-8”?>
      xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
      xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd“>

      cloud2020
      com.atguigu.springcloud
      1.0-SNAPSHOT

      4.0.0

      cloud-provider-hystrix-payment8001




      org.springframework.cloud
      spring-cloud-starter-netflix-hystrix


      org.springframework.cloud
      spring-cloud-starter-netflix-eureka-client


      com.atguigu.springcloud
      cloud-api-commons
      ${project.version}


      org.springframework.boot
      spring-boot-starter-web


      org.springframework.boot
      spring-boot-starter-actuator


      org.springframework.boot
      spring-boot-devtools
      runtime
      true


      org.projectlombok
      lombok
      true


      org.springframework.boot
      spring-boot-starter-test
      test


      | | —- |

66 YML

server:
port: 8001

spring:
application:
name: cloud-hystrix-payment-service

eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka/

67 主启动

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class,args);
}
}

68 业务类

Service/ServiceImpl
package com.atguigu.springcloud.service;

public interface PaymentService {
public String paymentInfo_OK(Integer id);
public String payment_Timeout(Integer id);
}
package com.atguigu.springcloud.service.impl;

import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;

@Service
public class PaymentServiceImpl implements PaymentService {

//成功
public String paymentInfo_OK(Integer id){
return “线程池:”+Thread.currentThread().getName()+” paymentInfo_OK,id: “+id+”\t”+”哈哈哈” ;
}

//失败
public String payment_Timeout(Integer id){
int timeNumber = 3;
try { TimeUnit.SECONDS.sleep(timeNumber); }catch (Exception e) {e.printStackTrace();}
return “线程池:”+Thread.currentThread().getName()+” paymentInfo_TimeOut,id: “+id+”\t”+”呜呜呜”+” 耗时(秒)”+timeNumber;
}
}

Controller
package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

@RestController
@Slf4j
public class PaymentController {

@Resource
private PaymentService paymentService;

@Value(“${server.port}”)
private String serverPort;

@GetMapping(“/payment/hystrix/ok/{id}”)
public String paymentInfo_OK(@PathVariable(“id”) Integer id){
String result = paymentService.paymentInfo_OK(id);
log.info(“*result:”+result);
return result;
}
@GetMapping(“/payment/hystrix/timeout/{id}”)
public String paymentInfo_TimeOut(@PathVariable(“id”) Integer id){
String result = paymentService.paymentInfo_TimeOut(id);
log.info(“*result:”+result);
return result;
}
}

69 正常测试

  • 启动eureka7001
  • 启动cloud-provider-hystrix-payment8001
  • 访问

访问: http://localhost:8001/payment/hystrix/ok/31
每次调用耗费3秒钟: http://localhost:8001/payment/hystrix/timeout/31

  • 上述module均OK

以上述为根基平台,从正确->错误->降级熔断->恢复

69.1 高并发测试

70 上述在非高并发情形下,还能勉强满足 but…..

71 Jmeter压测测试

下载地址:https://archive.apache.org/dist/jmeter/binaries/
开启Jmeter,来20000个并发压死8001,20000个请求都去访问paymentInfo_TimeOut服务
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图58
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图59

  • 压测的过程中再来访问一下微服务

http://localhost:8001/payment/hystrix/ok/31
http://localhost:8001/payment/hystrix/timeout/31

  • 演示结果
  • 两个都在自己转圈圈
  • 为什么会被卡死

tomcat的默认的工作线程数被打满了,没有多余的线程来分解压力和处理。

72 Jmeter压测结论

上面还是服务提供者8001自己测试,假如此时外部的消费者80也来访问,那消费者只能干等,最终导致消费端80不满意,服务端8001直接被拖死

73 看热闹不嫌弃事大,80新建加入:cloud-consumer-feign-hystrix-order80

74 新建:cloud-consumer-feign-hystrix-order80

75 POM
<?xml version=”1.0” encoding=”UTF-8”?>
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd“>

cloud2020
com.atguigu.springcloud
1.0-SNAPSHOT

4.0.0
cloud-consumer-feign-hystrix-order80




org.springframework.cloud
spring-cloud-starter-netflix-hystrix


org.springframework.cloud
spring-cloud-starter-openfeign


org.springframework.cloud
spring-cloud-starter-netflix-eureka-client


com.atguigu.springcloud
cloud-api-commons
${project.version}


org.springframework.boot
spring-boot-starter-web


org.springframework.boot
spring-boot-starter-actuator


org.springframework.boot
spring-boot-devtools
runtime
true


org.projectlombok
lombok
true


org.springframework.boot
spring-boot-starter-test
test


76 YML
server:
port: 80

spring:
application:
name: cloud-provider-hystrix-payment-service

eureka:
client:
register-with-eureka: true #表识不向注册中心注册自己
fetch-registry: true #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://localhost:7001/eureka/

77 主启动
package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class OrderHystrixMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderHystrixMain80.class,args);
}
}

78 业务类

PaymentHystrixService

package com.atguigu.springcloud.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(“CLOUD-HYSTRIX-PAYMENT-SERVICE”)
public interface PaymentHystrixService {
@GetMapping(“/payment/hystrix/ok/{id}”)
public String paymentInfo_OK(@PathVariable(“id”) Integer id);

@GetMapping(“/payment/hystrix/timeout/{id}”)
public String payment_Timeout(@PathVariable(“id”) Integer id);
}

OrderHystrixController

package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.service.PaymentHystrixService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

@RestController
@Slf4j
public class OrderHystrixController {
@Resource
private PaymentHystrixService paymentHystrixService;

@GetMapping(“/consumer/payment/hystrix/ok/{id}”)
public String paymentInfo_OK(@PathVariable(“id”) Integer id){
String result = paymentHystrixService.paymentInfo_OK(id);
log.info(“*result:”+result);
return result;
}
@GetMapping(“/consumer/payment/hystrix/timeout/{id}”)
public String paymentInfo_TimeOut(@PathVariable(“id”) Integer id){
String result = paymentHystrixService.payment_Timeout(id);
log.info(“*result:”+result);
return result;
}

}

79 正常测试

http://localhost/consumer/payment/hystrix/ok/32

80 高并发测试

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图60

80.1 故障现象和导致原因

  • 8001同一层次的其他接口服务被困死,因为tomcat线程里面的工作线程已经被挤占完毕
  • 80此时调用8001,客户端访问响应缓慢,转圈圈

    80.1.1 上诉结论

  • 正因为有上述故障或不佳表现,才有我们的降级/容错/限流等技术诞生

    80.1.2 如何解决?解决的要求

  • 超时导致服务器变慢(转圈)

  • 超时不再等待
  • 出错(宕机或程序运行出错)
  • 出错要有兜底
  • 解决
  • 对方服务(8001)超时了,调用者(80)不能一直卡死等待,必须有服务降级
  • 对方服务(8001)down机了,调用者(80)不能一直卡死等待,必须有服务降级
  • 对方服务(8001)OK,调用者(80)自己出故障或有自我要求(自己的等待时间小于服务提供者),自己处理降级

    80.1.3 服务降级

    81 降低配置

    @HystrixCommand

    82 8001先从自身找问题

    设置自身调用超时时间的峰值,峰值内可以正常运行,超过了需要有兜底的方法处理,作服务降级fallback

    83 8001fallback

    业务类启用阶级处理:使用@HystrixCommand注解来干活。
package com.atguigu.springcloud.service.impl;

import com.atguigu.springcloud.service.PaymentService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;

@Service
public class PaymentServiceImpl implements PaymentService {

@Override
public String paymentInfoOK(Integer id) {
return “线程池:”+Thread.currentThread().getName()+” paymentInfo_OK,id=”+id +” \t O(∩
∩)O哈哈~”;
}

//超时降级演示
@HystrixCommand(fallbackMethod = “payment_TimeoutHandler”,commandProperties = {
@HystrixProperty(name=”execution.isolation.thread.timeoutInMilliseconds”,value=”5000”) //5秒钟以内就是正常的业务逻辑
})
@Override
public String payment_Timeout(Integer id) {
//int timeNumber = 3; //小于等于3秒算是正常情况
int timeNumber = 15; //模拟非正常情况
//int i = 1/0 ; //模拟非正常情况
try {
TimeUnit.SECONDS.sleep(timeNumber);
} catch (InterruptedException e) {
e.printStackTrace();
}
return “线程池:”+Thread.currentThread().getName()+” payment_Timeout,id=”+id+” \t o(╥﹏╥)o 耗时:”+timeNumber;
}

//兜底方法,上面方法出问题,我来处理,返回一个出错信息
public String payment_TimeoutHandler(Integer id) {
return “线程池:”+Thread.currentThread().getName()+” payment_TimeoutHandler,系统繁忙,请稍后再试\t o(╥﹏╥)o “;
}
}

一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法
主启动类激活
@EnableCircuitBreaker
测试超时和算数异常,都会走兜底方法——服务降级
http://localhost:8001/payment/hystrix/timeout/1
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图61

84 80fallback

  1. 80订单微服务,也可以更好的保护自己,自己也依样画葫芦进行客户端降级保护。注意:服务降级可以在服务提供者侧,也可以在服务消费者侧。更多是在服务消费者侧。
  2. 题外话,切记

我们自己配置过的热部署方式对java代码的改动明显,但对@HystrixCommand内属性的修改建议重启微服务

  1. YML | feign:
    hystrix:
    enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。 | | —- |

  2. 主启动

@EnableHystrix

  1. 业务类:OrderHystrixController | //超时降级演示
    @HystrixCommand(fallbackMethod = “payment_TimeoutHandler”,commandProperties = {
    @HystrixProperty(name=”execution.isolation.thread.timeoutInMilliseconds”,value=”1500”)//超过1.5秒就降级自己
    })
    @GetMapping(“/consumer/payment/hystrix/timeout/{id}”)
    public String paymentInfo_TimeOut(@PathVariable(“id”) Integer id){
    //int age= 1/0;
    String result = paymentHystrixService.payment_Timeout(id);
    log.info(“*result:”+result);
    return result;
    }

    //兜底方法,上面方法出问题,我来处理,返回一个出错信息
    public String payment_TimeoutHandler(Integer id) {
    return “我是消费者80,对方支付系统繁忙请10秒后再试。或自己运行出错,请检查自己。”;
    } | | —- |

  2. 测试超时

http://localhost/consumer/payment/hystrix/timeout/1
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图62

85 目前问题

每个业务方法对应一个兜底的方法,代码膨胀,代码耦合
统一通用处理和自定义独立处理的分开

86 解决问题

87 每个方法配置一个???膨胀

feign接口系列
@DefaultProperties(defaultFallback = “”)
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图63
说明
@DefaultProperties(defaultFallback = “”)
1:1 每个方法配置一个服务降级方法,技术上可以,但实际上傻X
1:N 除了个别重要核心业务有专属,其它普通的可以通过@DefaultProperties(defaultFallback = “”)统一跳转到统一处理结果页面
通用的和独享的各自分开,避免了代码膨胀,合理减少了代码量
controller配置

package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.service.PaymentHystrixService;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

@RestController
@Slf4j
@DefaultProperties(defaultFallback = “payment_Global_FallbackMethod”) //全局的
public class OrderHystrixController {

@Resource
private PaymentHystrixService paymentHystrixService;

@GetMapping(“/consumer/payment/hystrix/ok/{id}”)
public String paymentInfo_OK(@PathVariable(“id”) Integer id){
String result = paymentHystrixService.paymentInfo_OK(id);
return result;
}

@HystrixCommand
public String paymentInfo_TimeOut(@PathVariable(“id”) Integer id){
int age = 10/0;
String result = paymentHystrixService.paymentInfo_TimeOut(id);
return result;
}

//兜底方法
public String paymentTimeOutFallbackMethod(@PathVariable(“id”) Integer id){
return “我是消费者80,对付支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,(┬_┬)”;
}

//下面是全局fallback方法
public String payment_Global_FallbackMethod(){
return “Global异常处理信息,请稍后再试,(┬_┬)”;
}
}

测试结果
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图64

88 和业务逻辑混一起???混乱

服务降级,客户端去调用服务端,碰上服务端宕机或关闭
本次案例服务降级处理是在客户端80实现完成的,与服务端8001没有关系,只需要为Feign客户端定义的接口添加一个服务降级处理的实现类即可实现解耦
未来我们要面对的异常

  • 运行
  • 超时
  • 宕机

再看我们的业务类PaymentController
修改cloud-consumer-feign-hystrix-order80
根据cloud-consumer-feign-hystrix-order80已经有的PaymentHystrixService接口,重新新建一个类(PaymentFallbackService)实现该接口,统一为接口里面的方法进行异常处理
PaymentFallbackService类实现PaymentFeignClientService接口

package com.atguigu.springcloud.service;

import org.springframework.stereotype.Component;

@Component
public class PaymentFallbackService implements PaymentHystrixService {
@Override
public String paymentInfo_OK(Integer id) {
return “——-PaymentFallbackService fall back-paymentInfo_OK , (┬_┬)”;
}

@Override
public String paymentInfo_TimeOut(Integer id) {
return “——-PaymentFallbackService fall back-paymentInfo_TimeOut , (┬_┬)”;
}
}

YML

feign:
hystrix:
enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。

PaymentFeignClientService接口

package com.atguigu.springcloud.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@Component
@FeignClient(value = “CLOUD-PROVIDER-HYSTRIX-PAYMENT”,fallback = PaymentFallbackService.class)
public interface PaymentHystrixService {

@GetMapping(“/payment/hystrix/ok/{id}”)
public String paymentInfo_OK(@PathVariable(“id”) Integer id);

@GetMapping(“/payment/hystrix/timeout/{id}”)
public String paymentInfo_TimeOut(@PathVariable(“id”) Integer id);
}

89 测试

单个eureka先启动7001
PaymentHystrixMain8001启动
正常访问测试:http://localhost/consumer/payment/hystrix/ok/31
故意关闭微服务8001
客户端自己调用提升
此时服务端provider已经down了,但是我们做了服务降级处理,让客户端在服务端不可用时也会获得提示信息而不会挂起耗死服务器

89.1 服务熔断

90 断路器

一句话就是家里保险丝

91 熔断是什么

熔断机制概述
熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。
当检测到该节点微服务调用响应正常后,恢复调用链路。
在SpringCloud框架里,熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状态,当失败的调用到一定阈值,缺省是5秒内20次调用失败,就会启动熔断机制。熔断机制的注解是@HystrixCommand

92 大神论文:

https://martinfowler.com/bliki/CircuitBreaker.html
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图65

93 实操

94 修改cloud-provider-hystrix-payment8001

95 PaymentServiceImpl

com.netflix.hystrix.HystrixCommandProperties

//服务熔断
@HystrixCommand(fallbackMethod = “paymentCircuitBreaker_fallback”,commandProperties = {
@HystrixProperty(name = “circuitBreaker.enabled”,value = “true”), //是否开启断路器
@HystrixProperty(name = “circuitBreaker.requestVolumeThreshold”,value = “10”), //当在配置时间窗口内达到此数量的失败后,打开断路,默认20个
@HystrixProperty(name = “circuitBreaker.sleepWindowInMilliseconds”,value = “10000”), //断路多久以后开始尝试是否恢复,默认5s
@HystrixProperty(name = “circuitBreaker.errorThresholdPercentage”,value = “60”), //出错百分比阈值,当达到此阈值后,开始短路。默认50%
})
public String paymentCircuitBreaker(Integer id){
if (id < 0){
throw new RuntimeException(“*id 不能负数”);
}
String serialNumber = IdUtil.simpleUUID();//hutool.cn工具包

return Thread.currentThread().getName()+”\t”+”调用成功,流水号:”+serialNumber;
}
public String paymentCircuitBreaker_fallback(@PathVariable(“id”) Integer id){
return “id 不能负数,请稍候再试,(┬_┬)/~~ id: “ +id;
}

96 PaymentController
//===服务熔断
@GetMapping(“/payment/circuit/{id}”)
public String paymentCircuitBreaker(@PathVariable(“id”) Integer id){
String result = paymentService.paymentCircuitBreaker(id);
log.info(“*result:”+result);
return result;
}

97 测试

自测cloud-provider-hystrix-payment8001
正确: http://localhost:8001/payment/circuit/31
错误: http://localhost:8001/payment/circuit/-31
一次正确一次错误trytry
重点测试
多次错误(狂点),然后慢慢正确,发现刚开始不满足条件,就算是正确的访问地址也不能进行访问,需要慢慢的恢复链路

98 原理(小总结)

99 大神结论

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图66

100 熔断类型

熔断打开
请求不再进行调用当前服务,内部设置时钟一般为MTTR(平均故障处理时间),当打开时长达到所设时钟则进入熔断状态
熔断关闭
熔断关闭不会对服务进行熔断
熔断半开
部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断

101 官网断路器流程图

101.1 官网步骤

101.2 断路器在什么情况下开始起作用
  1. //服务熔断<br />@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {<br />@HystrixProperty(name = "circuitBreaker.enabled",value = "true"), //是否开启断路器<br />@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "20"), //当快照时间窗(默认10秒)内达到此数量才有资格打开断路,默认20个<br />@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "50000"), //断路多久以后开始尝试是否恢复,默认5s<br />@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50"), //出错百分比阈值,当达到此阈值后,开始短路。默认50%<br /> })<br />涉及到断路器的三个重要参数:**快照时间窗、请求总数阈值、错误百分比阈值。**<br />1、快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒。<br />2、请求总数阈值:在快照时间窗内,必须满足请求总数阈值才有资格熔断。默认20,意味着在10秒内,如果该hystrix命令的调用次数不足20次,即使所有的请求都超时或其他原因失败,断路器都不会打开。<br />3、错误百分比阈值:当请求总数在快照时间窗内超过了阈值,比如发生了30次调用,如果在这30次调用,有15次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%阈值情况下,这时候就会将断路器打开。

③断路器开启或者关闭的条件

当满足一定阀值的时候(默认10秒内超过20个请求次数)
当失败率达到一定的时候(默认10秒内超过50%请求失败)
到达以上阀值,断路器将会开启
当开启的时候,所有请求都不会进行转发
一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,断路器会关闭,若失败,继续开启。重复4和5

101.3 断路器打开之后

1:再有请求调用的时候,将不会调用主逻辑,而是直接调用降级fallbak。通过断路器,实现了自动地发现错误并将降级逻辑切换为主逻辑,减少响应延迟的效果。
2:原来的主逻辑要如何恢复呢?
对于这一个问题,hystrix也为我们实现了自动恢复功能。
当断路器打开,对主逻辑进行熔断之后,hystrix会启动一个休眠时间窗,在这个时间窗内,降级逻辑是临时的成为主逻辑,当休眠时间窗到期,断路器将进入半开状态,释放一次请求到原来的主逻辑上,如果此次请求正常返回,那么断路器将继续闭合,主逻辑恢复,如果这次请求依然有问题,断路器继续进入打开状态,休眠时间窗重新计时。

101.4 All配置

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图67

101.4.1 服务限流

后面讲

101.5 服务监控hystrixDashboard

101.5.1 概述

除了隔离依赖服务的调用以外,Hystrix还提供了准实时的调用监控(Hystrix Dashboard),Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。Netflix通过hystrix-metrics-event-stram项目实现了对以上指示的监控。Spring Cloud也提供了Hystrix Dashboard的整合,对监控内容转化成可视化界面。

101.5.2 仪表盘9001

102 新建Module:cloud-consumer-hystrix-dashboard9001

103 POM

<?xml version=”1.0” encoding=”UTF-8”?>
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd“>

cloud2020
com.atguigu.springcloud
1.0-SNAPSHOT

4.0.0
cloud-consumer-hystrix-dashboard9001




org.springframework.cloud
spring-cloud-starter-netflix-hystrix-dashboard


org.springframework.boot
spring-boot-starter-actuator


org.springframework.boot
spring-boot-devtools
runtime
true


org.projectlombok
lombok
true


org.springframework.boot
spring-boot-starter-test
test


104 YML

server:
port: 9001

105 HystrixDashboardMain9001+新注解@EnableHystrixDashboard

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardMain9001 {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardMain9001.class,args);
}
}

106 所有Provider微服务提供类(8001/8002/8003)都需要监控依赖配置


org.springframework.boot
spring-boot-starter-actuator

107 启动cloud-consumer-hystrix-dashboard9001该微服务后续将监控微服务8001

http://localhost:9001/hystrix
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图68

107.1 断路器演示

108 修改cloud-provider-hystrix-payment8001

注意:新版本Hystrix需要在主启动类MainAppHystrix8001中指定监控路径

/*
此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑
ServletRegistrationBean因为springboot的默认路径不是”/hystrix.stream”,
只要在自己的项目里配置上下面的servlet就可以了
*/
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings(“/hystrix.stream”);
registrationBean.setName(“HystrixMetricsStreamServlet”);
return registrationBean;
}

Unable to connect to Command Metric Stream
404

109 监控测试

110 启动1个eureka

111 观察监控窗口

9001监控8001
http://localhost:9001/hystrix
http://localhost:8001/hystrix.stream
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图69
测试地址
http://localhost:8001/payment/circuit/31
http://localhost:8001/payment/circuit/-31
上述测试通过
ok
先访问正确地址,再访问错误地址,再正确地址,会发现图示断路器都是慢慢放开的
监控结果,成功
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图70
监控结果,失败
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图71

如何看
7色
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图72
1圈
实心圆:共有两种含义。它通过颜色的变化代表了实例的健康程度,它的健康度从绿色<黄色<橙色<红色递减。
该实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化,流量越大该实心圆就越大。所以通过该实心圆的展示,就可以在大量的实体中快速的发现故障实例和高压力实例。
1线
曲线:用来记录2分钟内流量的相对变化,可以通过它来观察到流量的上升和下降趋势。
整图说明
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图73

整图说明2
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图74
搞懂一个才能看懂复杂的
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图75

112 Gateway新一代网关

112.1 概述简介

112.1.1 官网

https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图76

112.1.2 是什么

Cloud全家桶中有个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关https://github.com/Netflix/zuul/wiki
但在2.x版本中,zuul的升级一直跳票,SpringCloud最后自己研发了一个网关代替Zull,那就是SpringCloud Geteway;

112.1.2.1 一句话:Geteway是原Zuul1.x版的替代

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图77

112.1.2.2 概述

Gateway是在spring生态系统之上构建的API网关服务,基于Spring5,SpringBoot2和Project Reactor等技术。
Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试等
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图78
SpringCloud Gateway是SpringCloud的一个全新项目,基于Spring5.0+SpringBoot2.0和Project Reactor等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的API路由管理方式。
为了提升网关的性能,SpringCloud Gatway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通讯框架Netty
SpringCloud Gateway的目标提供统一的路由方式且基于Filter链的方式提供了网关基本的功能,例如:安全、监控/指标、和限流。

112.1.2.3 一句话

Spring Cloud Gateway 使用的Webflux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架
源码架构
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图79

112.1.3 能干嘛

  • 反向代理
  • 鉴权
  • 流量控制
  • 熔断
  • 日志监控
  • 。。。。。。

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

    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图80

    112.2 三大核心概念

    112.2.1 Route(路由)

    路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由

    112.2.2 Predicate(断言)

    参考的是java8的java.util.function.Predicate开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由

    112.2.3 Filter(过滤)

    指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。

    112.2.4 总体

    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图81
    Web请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化控制。
    Predicate就是我们的匹配条件: 而Filter,就是可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标uri,就可以实现一个具体的路由了。

    112.3 Gateway工作流程

    112.3.1 官网总结

    https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gateway-how-it-works
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图82

    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图83
    客户端向Spring Cloud Gateway发出请求。然后在Gateway Handler Mapping中找到与请求匹配的路由,将其发送到Gateway Web Handler.
    Handler再通过指定的过滤器链来将请求发送给我们实际的服务执行业务逻辑,然后返回。
    过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(”pre”)或之后(“post”)执行业务逻辑。
    Filter在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在“post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量控制等有着非常重要的作用

    112.3.2 核心逻辑:路由转发+执行过滤器链

    112.4 入门配置

    112.4.1 新建Module:cloud-gateway-gateway9527

    112.4.2 POM

    | <?xml version=”1.0” encoding=”UTF-8”?>
    xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
    xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd“>

    cloud2020
    com.atguigu.springcloud
    1.0-SNAPSHOT

    4.0.0
    cloud-gateway-gateway9527




    org.springframework.cloud
    spring-cloud-starter-gateway


    com.atguigu.springcloud
    cloud-api-commons
    1.0-SNAPSHOT


    org.springframework.cloud
    spring-cloud-starter-netflix-hystrix


    org.springframework.cloud
    spring-cloud-starter-netflix-eureka-client


    org.springframework.boot
    spring-boot-devtools
    runtime
    true


    org.projectlombok
    lombok
    true


    org.springframework.boot
    spring-boot-starter-test
    test


    | | —- |

112.4.3 YML

server:
port: 9527
spring:
application:
name: cloud-gateway

eureka:
instance:
hostname: cloud-gateway-service
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka

112.4.4 业务类

112.4.5 主启动类

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {
public static void main(String[] args) {
SpringApplication.run( GateWayMain9527.class,args);
}
}

112.4.6 9527网关如何做路由映射呢???

我们目前不想暴露8001端口,希望在8001外面套一层9527

112.4.7 YML新增网关配置

server:
port: 9527

spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/ #断言,路径相匹配的进行路由

- id: payment_routh2
uri: http://localhost:8001
predicates:
- Path=/payment/lb/
#断言,路径相匹配的进行路由

eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://localhost:7001/eureka

112.4.8 测试

启动7001:cloud-eureka-server7001
启动8001:cloud-provider-payment8001
启动9527网关:cloud-gateway-gateway9527
访问说明
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图84
添加网关前: http://localhost:8001/payment/get/31
添加网关后: http://localhost:9527/payment/get/31

112.5 通过微服务名实现动态路由

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

112.5.1 启动

一个eureka7001+两个服务提供者8001/8002

112.5.2 POM

112.5.3 YML

server:
port: 9527

spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service
predicates:
- Path=/payment/get/ #断言,路径相匹配的进行路由

- id: payment_routh2
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service
predicates:
- Path=/payment/lb/
#断言,路径相匹配的进行路由

eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://localhost:7001/eureka

需要注意的是uri的协议为lb,表示启用Gateway的负载均衡功能。
lb://serviceName是spring cloud gateway在微服务中自动为我们创建的负载均衡uri

112.5.4 测试

http://localhost:9527/payment/lb
8001/8002两个端口切换

112.6 Predicate的使用

112.6.1 是什么

启动我们的gatewat9527,查看启动日志
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图85

112.6.2 Route Predicate Factories这个是什么东东?

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图86

Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapper基础框架的一部分。
Spring Cloud Gateway包括许多内置的Route Predicate工厂。所有这些Predicate都与HTTP请求的不同属性匹配。多个Route Predicate工厂可以进行组合
Spring Cloud Gateway创建Route对象时,使用RoutePredicateFactory创建Predicate对象,Predicate对象可以赋值给 Route。Spring Cloud Gateway包含许
多内置的Route Predicate Factories。

所有这些谓词都匹配HTTP请求的不同属性。多种谓词工厂可以组合,并通过逻辑and 。

112.6.3 常用的Route Predicate

1.After Route Predicate

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图87
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println(zonedDateTime);

    • After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
  • 测试:没到时间进行测试报错

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图88

2.Before Route Predicate

  • YML

      • Before=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]

        3.Between Route Predicate

  • YML

      • Between=2020-03-08T10:59:34.102+08:00[Asia/Shanghai] , 2020-03-08T10:59:34.102+08:00[Asia/Shanghai]

        4.Cookie Route Predicate

        01_尚硅谷_SpringCloud课件_2020_V2.4 - 图89
  • YML

      • Cookie=username,atguigu #并且Cookie是username=zhangshuai才能访问
  • 不带cookies访问

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图90

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图91

  • 加入curl返回中文乱码(帖子): https://blog.csdn.net/leedee/article/details/82685636

    5.Header Route Predicate

    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图92

  • YML

  • Header=X-Request-Id, \d+ #请求头中要有X-Request-Id属性并且值为整数的正则表达式
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图93

    6.Host Route Predicate

    YML: - Host=**.atguigu.com

    7.Method Route Predicate

    YML:- Method=GET

    8.Path Route Predicate

    YML:

    9. Query Route Predicate

    YML: - Query=username, \d+ #要有参数名称并且是正整数才能路由

    10.小总结

  • All | server:
    port: 9527

    spring:
    application:
    name: cloud-gateway
    cloud:
    gateway:
    discovery:
    locator:
    enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
    routes:
    - id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
    #uri: http://localhost:8001 #匹配后提供服务的路由地址
    uri: lb://cloud-payment-service
    predicates:
    - Path=/payment/get/ #断言,路径相匹配的进行路由

    - id: payment_routh2
    #uri: http://localhost:8001 #匹配后提供服务的路由地址
    uri: lb://cloud-payment-service
    predicates:
    - Path=/payment/lb/
    #断言,路径相匹配的进行路由
    #- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
    #- Cookie=username,zhangshuai #并且Cookie是username=zhangshuai才能访问
    #- Header=X-Request-Id, \d+ #请求头中要有X-Request-Id属性并且值为整数的正则表达式
    #- Host=**.atguigu.com
    #- Method=GET
    #- Query=username, \d+ #要有参数名称并且是正整数才能路由


    eureka:
    instance:
    hostname: cloud-gateway-service
    client:
    service-url:
    register-with-eureka: true
    fetch-registry: true
    defaultZone: http://localhost:7001/eureka | | —- |

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

112.7 Filter的使用

112.7.1 是什么

路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。
SpringCloud Gateway内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生。
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图94

112.7.2 Spring Cloud Gateway的Filter

113 生命周期,Only Two

  1. - pre
  2. - 在业务逻辑之前
  3. - post
  4. - 在业务逻辑之后

114 种类,Only Two

https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#gatewayfilter-factories

115 GatewayFilter(31种之多)

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图95

116 GlobalFilter

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图96

116.1 常用的GatewayFilter

AddRequestParameter
YML
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图97
省略

116.1.1 自定义过滤器

117 自定义全局GlobalFilter

两个主要接口介绍
impiemerts GlobalFilter ,Ordered

118 能干嘛

全局日志记录
统一网关鉴权
。。。。。。

119 案例代码

package com.atguigu.springcloud.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Date;

@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter,Ordered {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info(“*come in MyLogGateWayFilter: “+new Date());
String uname = exchange.getRequest().getQueryParams().getFirst(“username“);
if(StringUtils.isEmpty(username)){
log.info(“*用户名为Null 非法用户,(┬_┬)”);
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}

@Override
public int getOrder() {
return 0;
}
}

120 测试

启动
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图98
正确:http://localhost:9527/payment/lb?username=z3
错误:http://localhost:9527/payment/lb?uname=z3

121 SpringCloud Sleuth分布式链路请求跟踪

121.1 概述

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

问题
在微服务框架中,一个由客户端发起的请求在后端系统中会经过多个不同的服务节点调用来协同产生最后的请求结果,每一个前端请求都会形成一个复杂的分布式服务调用链路,链路中的任何一环出现高延时或错误都会引起整个请求最后的失败。
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图99

121.1.2 是什么

Spring Cloud Sleuth提供了一套完整的服务跟踪的解决方案
在分布式系统中提供追踪解决方案并且兼容支持了zipkin(负责展现)

https://github.com/spring-cloud/spring-cloud-sleuth
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图100

https://cloud.spring.io/spring-cloud-sleuth/reference/html/
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图101

121.1.3 解决

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图102

121.2 搭建链路监控步骤

121.2.1 zipkin

下载
SpringCloud从F版起已不需要自己构建Zipkin server了,只需要调用jar包即可
https://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/
zipkin-server-2.12.9.exec.jar
运行jar
java -jar zipkin-server-2.12.9-exec.jar
运行控制台
http://localhost:9411/zipkin/
术语
完整的调用链路
表示一请求链路,一条链路通过Trace Id唯一标识,Span标识发起的请求信息,各span通过parent id 关联起来。

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图103

上图what
一条链路通过Trace Id唯一标识,Span标识发起的请求信息,各span通过parent id 关联起来。
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图104
整个链路的依赖关系如下:
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图105
名词解释
Trace:类似于树结构的Span集合,表示一条调用链路,存在唯一标识
span:表示调用链路来源,通俗的理解span就是一次请求信息

121.2.2 服务提供者

122 修改:cloud-provider-payment8001

123 POM



org.springframework.cloud
spring-cloud-starter-zipkin

124 YML

server:
port: 8001

spring:
application:
name: cloud-payment-service
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
#采样率值介于0~1之间,1表示全部采样
probability: 1
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/cloud2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root

mybatis:
mapperLocations: classpath:/mapper/*.xml
type-aliases-package: com.atguigu.springcloud.entities

eureka:
client:
register-with-eureka: true
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka

125 业务类PaymentController

@GetMapping(“/payment/zipkin”)
public String paymentZipkin(){
return “hi ,i’am paymentzipkin server,welcome to atguigu,O(∩_∩)O哈哈~”;
}

125.1 服务消费者(调用方)

126 修改:cloud-consumer-order80

127 POM



org.springframework.cloud
spring-cloud-starter-zipkin

128 YML

server:
port: 80

spring:
application:
name: cloud-order-service
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1

eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: false
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#单机
defaultZone: http://localhost:7001/eureka
#集群
#defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版

129 业务类PaymentController

//==> zipkin+sleuth
@GetMapping(“/consumer/payment/zipkin”)
public String paymentZipkin(){
String result = restTemplate.getForObject(“http://localhost:8001"+"/payment/zipkin/“, String.class);
return result;
}

129.1 依次启动eureka7001/8001/80

80调用8001几次测试下

129.1.1 打开浏览器访问: http://localhost:9411

会出现以下界面
查看
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图106
查看依赖关系
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图107

130 SpringCloud Alibaba入门简介

130.1 why会出现SpringCloud alibaba

Spring Cloud Netflix项目进入维护模式
https://spring.io/blog/2018/12/12/spring-cloud-greenwich-rc1-available-now
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图108
说明:
Spring Cloud Netflix项目进入维护模式
最近,Netflix宣布Hystrix正在进入维护模式。自2016年以来,Ribbon已处于类似状态。
虽然Hystrix和Ribbon现已处于维护模式,但它们仍然在Netflix大规模部署。
Hystrix Dashboard和Turbine已被Atlas取代。这些项目的最后一次提交是2年和4年前。Zuul1和Archaius1都被后来不兼容的版本所取代。
这不包括Eureka或并发限制模块。
什么是维护模式?
将模块置于维护模式,意味着SpringCloud团队将不会再向模块添加新功能。我们将修复block级别的bug以及安全问题,我们也会考虑并审查社区的小型pull request。
我们打算继续支持这些模块,直到Greenwich版本被普遍采用至少一年。
进入维护模式意味着什么?
Spring Cloud Netflix将不再开放新的组件
我们都知道SpringCloud版本迭代算是比较快的,因而出现了很多重大ISSU都还来不及Fix就又推出另一个Release了。
进入维护模式意思就是目前以致以后一段时间SpringCloud netflix提供的服务和功能就这么多了,不再开发新的组件和功能了。以后将以维护和Merge分支Pull Request为主。
新组件功能将以其他替代的方式实现
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图109

130.2 SpringCloud alibaba带来了什么?

130.2.1 是什么

诞生:2018.10.31,Spring Cloud Alibaba正式入驻了Spring Cloud官网孵化器,并在Maven中央库发布了第一个版本。
https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图110

130.2.2 能干嘛

  • 服务限流降级:默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
  • 服务注册与发现:适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。
  • 分布式配置管理:支持分布式系统中的外部化配置,配置更改时自动刷新。
  • 消息驱动能力:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。
  • 分布式事务:使用 @GlobalTransactional 注解, 高效并且对业务零侵入地解决分布式事务问题。。
  • 阿里云对象存储:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。
  • 分布式任务调度:提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有 Worker(schedulerx-client)上执行。
  • 阿里云短信服务:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。

    130.2.3 去哪下

    |


    com.alibaba.cloud
    spring-cloud-alibaba-dependencies
    2.2.0.RELEASE
    pom
    import


    | | —- |

130.2.4 怎么玩

一整套解决方案,简单理解就是替换Netflix那一套
Sentinel:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Nacos:一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
RocketMQ:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
Dubbo:Apache Dubbo™ 是一款高性能 Java RPC 框架。
Seata:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
Alibaba Cloud ACM:一款在分布式架构环境中对应用配置进行集中管理和推送的应用配置中心产品。
Alibaba Cloud OSS: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。
Alibaba Cloud SMS: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。

130.3 SpringCloud alibaba学习资料获取

官网:https://spring.io/projects/spring-cloud-alibaba#overview
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图111

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图112
英文
https://github.com/alibaba/spring-cloud-alibaba
https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html
中文
https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md

131 SpringCloud Alibaba Nacos服务注册和配置中心

131.1 Nacos简介

131.1.1 为什么叫Nacos

前四个字母分别为Naming和Configuration的前两个字母,最后的s为Service

131.1.2 是什么

一个更易于构建云原生应用的动态服务发现,配置管理和服务管理中心
Nacos:Dynamic Naming and Configuration Service
Nacos就是注册中心+配置中心的组合
等价于:Nacos = Eureka+Config+Bus

131.1.3 能干嘛

替代Eureka做服务注册中心
替代Config做服务配置中心

131.1.4 去哪下

https://github.com/alibaba/Nacos
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图113
官网文档
https://nacos.io/zh-cn/index.html
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图114

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图115

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图116
https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图117

131.1.5 各种注册中心比较

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图118
据说nacos在阿里巴巴内部有超过10万的实例运行,已经过了类似双十一等各种大型流量的考验
CAP原则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。

131.2 安装并运行Nacos

131.2.1 本地Java8+Maven环境已经OK

131.2.2 先从官网下载Nacos

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

131.2.3 解压安装包,直接运行bin/startup.cmd

131.2.4 命令运行成功后直接访问

http://localhost:8848/nacos
默认账号密码都是nacos

131.2.5 登录结果页面

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图119

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

131.3.1 官网文档

https://spring.io/projects/spring-cloud-alibaba#learn
https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图120

131.3.2 基于Nacos的服务提供者

132 新建Module:cloudalibaba-provider-payment9001

133 POM

  1. - POM


com.alibaba.cloud
spring-cloud-alibaba-dependencies
2.1.0.RELEASE
pom
import
  • 本模块POM |

    com.alibaba.cloud
    spring-cloud-starter-alibaba-nacos-discovery


    org.springframework.boot
    spring-boot-starter-web


    org.springframework.boot
    spring-boot-starter-actuator


    org.springframework.boot
    spring-boot-devtools
    runtime
    true


    org.projectlombok
    lombok
    true


    org.springframework.boot
    spring-boot-starter-test
    test

    | | —- |

134 YML

server:
port: 9001

spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos地址

management:
endpoints:
web:
exposure:
include: ‘*’ #默认只公开了/health和/info端点,要想暴露所有端点只需设置成星号

135 主启动

package com.atguigu.springcloud.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class PaymentMain9001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain9001.class,args);
}
}

136 业务类

package com.atguigu.springcloud.alibaba.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PaymentController{
@Value(“${server.port}”)
private String serverPort;

@GetMapping(value = “/payment/nacos/{id}”)
public String getPayment(@PathVariable(“id”) Long id) {
return “nacos registry, serverPort: “+ serverPort+”\t id”+id;
}
}

137 测试

http://localhost:9001/payment/nacos/1
nacos控制台
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图121
nacos服务注册中心+服务提供者9001都ok了

138 为了下一章节演示nacos的负载均衡,参照9001新建9002

新建cloudalibaba-provider-payment9002
9002其他步骤你懂的
或者取巧不想新建重复体力劳动,直接拷贝虚拟端口映射
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图122

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图123

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图124

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图125

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图126

138.1 基于Nacos的服务消费者

139 新建Module:cloudalibaba-consumer-nacos-order83

140 POM




com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery


com.atguigu.springcloud
cloud-api-commons
${project.version}


org.springframework.boot
spring-boot-starter-web


org.springframework.boot
spring-boot-starter-actuator


org.springframework.boot
spring-boot-devtools
runtime
true


org.projectlombok
lombok
true


org.springframework.boot
spring-boot-starter-test
test

为什么nacos支持负载均衡
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图127

141 YML

server:
port: 83

spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者【可选】,注意:nacos-payment-provider含有IP和端口)
service-url:
nacos-user-service: http://nacos-payment-provider

142 主启动

package com.atguigu.springcloud.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class OrderNacosMain83{
public static void main(String[] args){
SpringApplication.run(OrderNacosMain83.class,args);
}
}

143 业务类

ApplicationContextBean

package com.atguigu.springcloud.alibaba.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig{
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}

144 OrderNacosController

package com.atguigu.springcloud.alibaba.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;

@RestController
@Slf4j
public class OrderNacosController{
@Resource
private RestTemplate restTemplate;

@Value(“${service-url.nacos-user-service}”)
private String serverURL;

@GetMapping(value = “/consumer/payment/nacos/{id}”)
public String paymentInfo(@PathVariable(“id”) Long id){
return restTemplate.getForObject(serverURL+”/payment/nacos/“+id,String.class);
}

}

145 测试

nacos控制台
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图128
http://localhost:83/consumer/payment/nacos/1
83访问9001/9002,轮询负载OK

145.1 服务注册中心对比

146 Nacos和CAP

CAP原则又称CAP定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
分区容忍性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
CAP原则的精髓就是要么AP,要么CP,要么AC,但是不存在CAP。
如果在某个分布式系统中数据无副本, 那么系统必然满足强一致性条件, 因为只有独一数据,不会出现数据不一致的情况,此时C和P两要素具备,但是如果系统发生了网络分区状况或者宕机,必然导致某些数据不可以访问,此时可用性条件就不能被满足,即在此情况下获得了CP系统,但是CAP不可同时满足。
因此在进行分布式架构设计时,必须做出取舍。当前一般是通过分布式缓存中各节点的最终一致性来提高系统的性能,通过使用多节点之间的数据异步复制技术来实现集群化的数据一致性。
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图129

147 Nacos支持AP和CP模式的切换

curl -X PUT ‘$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP’

147.1 Nacos作为服务配置中心演示

147.1.1 Nacos作为配置中心-基础配置

148 创建Module:cloudalibaba-config-nacos-client3377

149 POM




com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config



com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery



org.springframework.boot
spring-boot-starter-web


org.springframework.boot
spring-boot-starter-actuator



org.springframework.boot
spring-boot-devtools
runtime
true


org.projectlombok
lombok
true


org.springframework.boot
spring-boot-starter-test
test

150 YML

Nacos同springcloud-config一样,在项目初始化时,要保证先从配置中心进行配置拉取,拉取配置之后,才能保证项目的正常启动
springboot中配置文件的加载是存在优先级顺序的,bootstrap优先级高于application
bootstrap.yml

server:
port: 3377

spring:
application:
name: nacos-config-client
cloud:
nacos:
discovery:
server-addr: localhost:8848 #服务注册中心地址
config:
server-addr: localhost:8848 #配置中心地址
file-extension: yaml #指定yaml格式的配置(yml和yaml都可以)

#${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}
#nacos-config-client-dev.yaml (一定要与file-extension值保持一致)

application.yml

spring:
profiles:
active: dev #表示开发环境

151 主启动

package com.atguigu.springcloud.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class NacosConfigClientMain3377{
public static void main(String[] args) {
SpringApplication.run(NacosConfigClientMain3377.class, args);
}
}

152 业务类:ConfigClientController

package com.atguigu.springcloud.alibaba.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RefreshScope //通过SpringCould原生注解@RefreshScope实现配置自动更新
public class ConfigClientController{
@Value(“${config.info}”) //对应nacos配置:nacos-config-client-dev.yaml
private String configInfo;

@GetMapping(“/config/info”)
public String getConfigInfo() {
return configInfo;
}
}

153 在Nacos中添加配置信息

Nacos中的匹配规则
Nacos中的dataid的组成格式与SpringBoot配置文件中的匹配规则
官网 https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图130
最后公式:
${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
nacos-config-client-dev.yaml
Nacos界面配置对应

config:
info: “config info for dev,from nacos config center.”

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图131

设置DataId
公式: ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}
小总结说明
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图132
历史配置:Nacos会记录配置文件的历史版本默认保留30天

154 测试

启动前需要在nacos客户端-配置管理-配置管理栏目下有没有对应的yaml配置文件
运行cloud-config-nacos-client3377的主启动类
调用接口查看配置信息: http://localhost:3377/config/info

155 自带动态刷新

修改Nacos中的yaml配置文件,查看配置已经刷新

155.1 Nacos作为配置中心-分类配置

156 问题

多环境多项目管理
问题1

  • 实际开发中,通常一个系统会准备
  • dev开发环境
  • test测试环境
  • prod生产环境
  • 如何保证指定环境启动时服务能正确读取到 Nacos上相应环境的配置文件呢?

问题2

  • 一个大型分布式微服务心痛会有很多微服务子项目
  • 每一个微服务项目又会相应的开发环境、测试环境、预发环境、正式环境….
  • 那怎么对这些微服务配置进行管理呢?

    157 Nacos的图形化管理界面

  • 配置管理

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图133

  • 命名空间

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图134

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

最外层的namespace是可以用于区分部署环境的,Group和DataID逻辑上区分两个目标对象。
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图135
默认情况:Namespace=public,Group=DEFAULT_GROUP,默认Cluster是DEFAULT

  • Nacos默认的命名空间是public,Namespace主要用来实现隔离。

比方说我们现在有三个环境:开发、测试、生产环境,我们就可以创建三个Namespace,不同的 Namespace之间是隔离的。

  • Group默认是DEFAULT_GROUP,Group可以把不同的微服务划分到同一个分组里面去。Service就是微服务;一个Service可以包含多个Cluster(集群),Nacos默认Cluster是DEFAULT,Cluster是对指定微服务的一个虚拟划分。

比方说为了容灾,将Service微服务分别部署在了杭州机房广州机房,这时就可以给杭州机房的Service微服务起一个集群名称(HZ),给广州机房的Service微服务起一个集群名字(GZ),还可以尽量让同一个机房的微服务互相调用,以提升性能。

  • 最后是Instance,就是微服务的实例。

    159 Case

    160 DataID方案
    指定spring.profile.active和配置文件的DataID来使不同环境下读取不同的配置
    默认空间+默认分组+新建dev和test两个DataID
    新建dev配置DataID
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图136
    新建test配置DataID
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图137
    通过spring.profile.active属性就能进行多环境下配置文件的读取
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图138
    测试
    http://localhost:3377/config/info
    配置是什么就加载什么
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图139
    161 Group方案
    通过Group实现环境区分
    新建Group
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图140

    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图141
    在nacos图形界面控制台上面新建配置文件DataID
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图142
    bootstrap+application
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图143
    在config下增加一条group的配置即可。可配置为DEV_GROUP或TEST_GROUP
    162 Namespace方案
    新建dev/test的Namespace
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图144

    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图145
    回到服务管理-服务列表查看
    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图146
    按照域名配置填写
nacos-config-client-dev.yaml

config:
info: 9f62d48c-ef2e-4d83-a9fb-c9db5833f93b DEFAULT_GROUP nacos-config-client-dev.yaml

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图147
YML
bootstrap

# nacos配置
server:
port: 3377

spring:
application:
name: nacos-config-client
cloud:
nacos:
discovery:
server-addr: localhost:8848 #Nacos服务注册中心地址
config:
server-addr: localhost:8848 #Nacos作为配置中心地址
file-extension: yaml #指定yaml格式的配置
group: DEV_GROUP
namespace: 7d8f0f5a-6a53-4785-9686-dd460158e5d4

# ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}
# nacos-config-client-dev.yaml

application

spring:
profiles:
active: dev # 表示开发环境
#active: test # 表示测试环境
#active: info

图解:
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图148
测试结果:
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图149

162.1 Nacos集群和持久化配置(重要)

162.1.1 官网说明

https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html

163 官网架构图

集群部署架构图
推荐用户把所有服务列表放到一个vip下面,然后挂到一个域名下面
http://ip1:port/openAPI 直连ip模式,机器挂则需要修改ip才可以使用。
http://VIP:port/openAPI 挂载VIP模式,直连vip即可,下面挂server真实ip,可读性不好。
http://nacos.com:port/openAPI 域名 + VIP模式,可读性好,而且换ip方便,推荐模式
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图150

164 上图官网翻译,真实情况

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图151

165 说明

默认Nacos使用嵌入式数据库实现数据的存储。所以,如果启动多个默认配置下的Nacos节点,数据存储是存在一致性问题多的。
为了解决这个问题,Nacos采用了集中式存储的方式来支持集群化部署,目前只支持MySQL 的存储。
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图152

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图153
https://nacos.io/zh-cn/docs/deployment.html

165.1 Nacos持久化配置解释

166 Nacos默认自带的是嵌入式数据库derby

https://github.com/alibaba/nacos/blob/develop/config/pom.xml

167 derby到mysql切换配置步骤

nacos-server-1.1.4\nacos\conf目录下找到sql脚本
nacos-mysql.sql
执行脚本
nacos-server-1.1.4\nacos\conf目录下找到application.properties

spring.datasource.platform=mysql

db.num=1
db.url.0=jdbc:mysql://11.162.196.16:3306/nacos_devtest?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=nacos_devtest
db.password=youdontknow

168 启动nacos,可以看到是个全新的空记录界面,以前是记录进derby

169 测试:新建配置,发现配置信息写入了MySQL数据库

169.1 Linux版Nacos+MySQL生产环境配置

170 预计需要,1个nginx+3个nacos注册中心+1个mysql

171 Nacos下载linux版本

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图154
https://github.com/alibaba/nacos/releases/tag/1.1.4
nacos-server-1.1.4.tar.gz

172 集群配置步骤(重点)

1.Linux服务器上mysql数据库配置
  • SQL脚本在哪里

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图155

  • Linux上创建Mysql数据库

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图156

2.application.properties配置
spring.datasource.platform=mysql

db.num=1
db.url.0=jdbc:mysql://192.168.137.128:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=zhang3
db.password=123456

3.Linux服务器上nacos的集群配置cluster.conf

梳理出3台nacos机器的不同服务端口号
复制出cluster.conf
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图157
内容

192.168.137.128:3333
192.168.137.128:4444
192.168.137.128:5555

这个IP不能写127.0.0.1,必须是Linux命令hostname -i能够识别的IP
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图158

4.编辑Nacos的启动脚本startup.sh,使它能够接受不同的启动端

/mynacos/nacos/bin目录下有startup.sh
在什么地方,修改什么,怎么修改
思考
/mynacos/nacos/bin目录下有startup.sh
平时单机版的启动,都是./startup.sh即可。
但是
集群启动,我们希望可以类似其它软件的shell命令,传递不同的端口号启动不同的nacos实例。
命令:./startup.sh -p 3333表示启动端口号为3333的nacos服务器实例,和上一步的cluster.conf配置的一致。
修改内容
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图159

修改前
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图160
修改后
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图161
修改前
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图162
修改后01_尚硅谷_SpringCloud课件_2020_V2.4 - 图163


执行方式
启动时,需要修改内存大小,否则,内存可能不够用。
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图164

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图165
查看进程:ps -ef | grep nacos
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图166

5.Nginx的配置,由它作为负载均衡器

修改nginx的配置文件:vim /usr/local/nginx/conf/nginx.conf
nginx.conf

upstream cluster{
server 192.168.137.128:3333;
server 192.168.137.128:4444;
server 192.168.137.128:5555;
}

server{
listen 1111;
server_name 192.168.137.128;
location / {
proxy_pass http://cluster;
}
….省略

启动Nginx:
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图167

6.截止到此处,1个Nginx+3个nacos注册中心+1个mysql

测试通过nginx访问nacos
https:// 192.168.137.128:1111/nacos/#/login
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图168
新建一个配置测试
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图169
linux服务器的mysql插入一条记录
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图170

173 测试

微服务cloudalibaba-provider-payment9002启动注册进nacos集群
yml
server-addr: 写你自己的虚拟机ip:1111
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图171
结果
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图172

174 高可用小总结

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图173

175 SpringCloud Alibaba Sentinel实现熔断与限流

175.1 Sentinel介绍

175.1.1 官网

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

175.1.2 是什么

一句话解释,之前我们讲解过的Hystrix
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图174
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图175

175.1.3 能干嘛

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图176
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图177

175.1.4 去哪下

  1. [https://github.com/alibaba/Sentinel/releases](https://github.com/alibaba/Sentinel/releases)

175.1.5 怎么玩

https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图178

  • 服务使用中的各种问题

    • 服务雪崩
    • 服务降级
    • 服务熔断
    • 服务限流

      175.2 安装Sentinel控制台

      175.2.1 sentinel组件由2部分组成

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

  • 前台8080

    175.2.2 安装步骤

    176 下载

    https://github.com/alibaba/Sentinel/releases
    下载到本地sentinel-dashboard-1.7.0.jar

    177 运行命令

    前提
    java8环境OK
    8080端口不能被占用
    命令
    java -jar sentinel-dashboard-1.7.0.jar

    178 访问sentinel管理界面

    http://localhost:8080
    登录账号密码均为sentinel

    178.1 初始化演示工程

    178.1.1 启动Nacos8848成功

    http://localhost:8848/nacos/#/login

    178.1.2 案例

    179 创建Module:cloudalibaba-sentinel-service8401

    180 POM

    | <?xml version=”1.0” encoding=”UTF-8”?>
    xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
    xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd“>

    cloud2020
    com.atguigu.springcloud
    1.0-SNAPSHOT

    4.0.0
    cloudalibaba-sentinel-service8401



    com.atguigu.springcloud
    cloud-api-commons
    ${project.version}


    com.alibaba.cloud
    spring-cloud-starter-alibaba-nacos-discovery


    com.alibaba.csp
    sentinel-datasource-nacos


    com.alibaba.cloud
    spring-cloud-starter-alibaba-sentinel


    org.springframework.cloud
    spring-cloud-starter-openfeign


    org.springframework.boot
    spring-boot-starter-web


    org.springframework.boot
    spring-boot-starter-actuator


    org.springframework.boot
    spring-boot-devtools
    runtime
    true


    cn.hutool
    hutool-all
    4.6.3


    org.projectlombok
    lombok
    true


    org.springframework.boot
    spring-boot-starter-test
    test


    | | —- |

181 YML

server:
port: 8401

spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719 #默认8719,应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用HttpServer

management:
endpoints:
web:
exposure:
include: ‘*’

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图179
https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-endpoints
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图180

182 主启动

package com.atguigu.springcloud.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401{
public static void main(String[] args) {
SpringApplication.run(MainApp8401.class, args);
}
}

183 业务类FlowLimitController

package com.atguigu.springcloud.alibaba.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class FlowLimitController{
@GetMapping(“/testA”)
public String testA() {
return “———testA”;
}

@GetMapping(“/testB”)
public String testB() {
return “———testB”;
}
}

183.1 启动Sentinel8080

java -jar sentinel-dashboard-1.7.0

183.1.1 启动微服务8401

183.1.2 启动8401微服务后查看sentienl控制台

空空如也,啥都没有
Sentinel采用的懒加载说明
执行一次访问即可
http://localhost:8401/testA
http://localhost:8401/testB
效果
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图181
结论
sentinel8080正在监控微服务8401

183.2 流控规则

183.2.1 基本介绍

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图182

进一步解释说明
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图183
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图184

183.2.2 流控模式

184 直接(默认)

  1. - 直接->快速失败
  2. - 系统默认
  3. - 测试QPS
  4. - 配置及说明
  5. - 表示1秒钟内查询1次就是OK,若超过次数1,就直接-快速失败,报默认错误

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图185

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图186

  • 快速点击访问: http://localhost:8401/testA
  • 结果
    • 不会出现Blocked by Sentinel (flow limiting)(线程处理请求很快)

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图187
但是,在映射方法里添加sleep后,同样也会出现Blocked by Sentinel (flow limiting)默认提示信息。

  • 思考???

    • 直接调用默认报错信息,技术方面OK but,是否应该有我们自己的后续处理?

      • 类似有一个fallback的兜底方法?

        185 关联

    • 是什么?

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

        186 配置A

    • 设置效果:

      • 当关联资源/testB的QPS阀值超过1时,就限流/testA的REST访问地址,当关联资源到阀值后闲置配置的的资源名。

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图188

187 postman模拟并发密集访问testB

  • 访问testB成功

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图189

  • postman里新建多线程集合组,将请求保存到集合组

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图190

  • 运行线程集合组

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图191

  • 设置并发访问参数

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图192

  • Run
    • 大批量线程高并发访问B,导致A失效了
  • 运行后发现testA挂了

    • 点击访问http://localhost:8401/testA
    • 结果

      • Blocked by Sentinel (flow limiting)

        188 链路

    • 多个请求调用了同一个微服务

    • 家庭作业试试

      188.1 流控效果

      189 直接->快速失败(默认的流控处理)

  • 直接失败,抛出异常:Blocked by Sentinel (flow limiting)

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

    190 预热

    1. - 说明
    2. - 公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值
    3. - 官网: [https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6#%E5%9F%BA%E4%BA%8Eqps%E5%B9%B6%E5%8F%91%E6%95%B0%E7%9A%84%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6](https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6#%E5%9F%BA%E4%BA%8Eqps%E5%B9%B6%E5%8F%91%E6%95%B0%E7%9A%84%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6)

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图193

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图194

  • 限流 冷启动

https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81—-%E5%86%B7%E5%90%AF%E5%8A%A8

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

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图195

  • Warmup配置

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

  • 案例:阈值为10 + 预热时长设置5秒。
  • 系统初始化的阈值为10/3约等于3,即阈值刚开始为3;然后过了5秒后阈值才慢慢升高,恢复到10

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图196

  • 多次点击http://localhost:8401/testB
  • 刚开始不行,后续慢慢OK
  • 应用场景

    • 如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。

      191 排队等待

    • 匀速排队,让请求以均匀的速度通过,阈值类型必须设置成QPS,否则无效。

    • 设置含义:/testB每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒。

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图197

  • 官网

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图198

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

    • 增加打印语句 | @GetMapping(“/testB”)
      public String testB() {
      log.info(Thread.currentThread().getName()+”\t …testB”);
      return “———testB”;
      } | | —- |
  • 增加线程组:直接10个线程并发,排队被依次处理

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图199

191.1 降级规则

191.1.1 官网

https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图200

191.1.2 基本介绍

  • 整体介绍

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图201

  • RT(平均响应时间,秒级)
    • 平均响应时间 (DEGRADE_GRADE_RT):超过阈值 时间窗口内的请求>=5,两个条件同时满足后触发降级,窗口期过后关闭断路器
    • RT 最大4900 ms,更大的需要通过启动配置项

-Dcsp.sentinel.statistic.max.rt=xxx 来配置。

  • 异常比例(秒级)
    • QPS>=5且异常比例(秒级统计)超过阈值时,触发降级;时间窗口结束后,关闭降级
  • 异常数(分钟级)
    • 异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后,关闭降级
  • 进一步说明
    • Sentinel熔断降级会在调用链路中某个资源出现不稳定状态时(例如:调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其他的资源而导致级联错误。
    • 当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出DegradeException)。
  • Sentinel的断路器是没有半开状态的
    • 半开的状态系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用。具体可以参考Hystrix
    • 复习Hystrix

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图202

191.1.3 降级策略实战

192 RT

  1. - 是什么

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图203

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图204

  • 测试

    • 代码 | @GetMapping(“/testD”)
      public String testD(){
      try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
      log.info(“testD 测试RT”);
      return “———testD”;
      } | | —- |
  • 配置

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图205

  • jmeter压测

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图206

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图207

  • 结论

永远一秒钟打进来10个线程(大于5个了)调用testD,我们希望200毫秒处理完本次任务,
如果超过200毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了
后续停止jmeter,没有这么大的访问量了,断路器关闭(保险丝恢复),微服务恢复OK

193 异常比例

  • 是什么

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图208

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图209

  • 测试

    • 代码 | @GetMapping(“/testD”)
      public String testD() {
      log.info(“testD 测试异常比例”);
      int age = 10/0;
      return “———testD”;
      } | | —- |
  • 配置

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图210

  • jmeter

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图211

  • 演示

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图212

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图213

  • 结论
    • 按照上述配置
    • 单独访问一次,必然来一次报错一次(int age=10/0;),调一次错一次

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图214

  • 开启jmeter后,直接高并发送请求,多次调用达到我们的配置条件了。
  • 断路器开启(保险丝跳闸),微服务不可用了,不再报错error 而是服务降级了。

    194 异常数

    • 是什么

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图215
时间窗口一定要大于等于60秒

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图216

  • 测试

    • 代码 | @GetMapping(“/testE”)
      public String testE(){
      log.info(“testE 测试异常数”);
      int age = 10/0;
      return “———testE 测试异常数”;
      } | | —- |
  • 配置

    • http://localhost:8401/testE
    • 第一次访问绝对报错,因为除数不能为零,我们看到error窗口,但是达到5次报错后,进入熔断后降级。

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图217

  • 手动连续点5次后,进入降级

    194.1 热点key限流

    194.1.1 基本介绍

    • 是什么

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图218

194.1.2 官网

https://github.com/alibaba/Sentinel/wiki/热点参数限流
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图219

194.1.3 承上启下复习

  • 兜底方法
  • 分为系统默认和客户自定义,两种

    • 之前的case,限流出问题后,都是用sentinel系统默认的提示: Blocked by Sentinel(flow limiting)
    • 我们能不能自定义?类似hystrix,某个方法出现问题了,就找对应的兜底降级方法?
    • 结论

      • 从@HystrixCommand到@SentinelResource

        194.1.4 代码

        | @GetMapping(“/testHotKey”)
        @SentinelResource(value = “testHotKey”,blockHandler = “deal_testHotKey“)
        public String testHotKey(@RequestParam(value = “p1”,required = false) String p1,
        @RequestParam(value = “p2”,required = false) String p2) {
        //int age = 10/0;
        return “———testHotKey”;
        }

        //兜底方法
        public String deal_testHotKey (String p1, String p2, BlockException exception){
        return “———deal_testHotKey,o(╥﹏╥)o”;
        } | | —- |

      com.alibaba.csp.sentinel.slots.block.BlockException

      194.1.5 配置

  • 配置

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图220

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图221

  • 默认
    • @SentinelResource(value = “testHotKey”)
    • 异常打到了前台用户界面,不友好

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图222

  • 自定义
    • @SentinelResource(value = “testHotKey”,blockHandler = “deal_testHotKey”) //value值与资源名一致即可
    • 方法testHostKey里面第一个参数只要QPS超过每秒1次,马上降级处理
  • 测试
    • error (1秒1下可以,但是,超过则降级,和p1参数有关)

http://localhost:8401/testHotKey?p1=abc

  • error(1秒1下可以,但是,超过则降级,和p1参数有关)

http://localhost:8401/testHotKey?p1=abc&p2=33

  • right(狂点不会触发降级,与p2参数无关)

    http://localhost:8401/testHotKey?p2=abc

    194.1.6 参数例外项

    • 上述案例演示了第一个参数p1,当QPS超过1秒1次点击后马上被限流
    • 特殊情况
      • 普通
        • 超过1秒钟一个后,达到阈值1后马上被限流
      • 我们期望p1参数当它是某个特殊值时,它的限流值和平时不一样
      • 特例
        • 假如当p1的值等于5时,它的阈值可以达到200
    • 配置
      • 添加按钮不能忘

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图223

  • 测试

http://localhost:8401/testHotKey?p1=5
http://localhost:8401/testHotKey?p1=3

  • 当p1等于5的时候,阈值变为200
  • 当p1不等于5的时候,阈值就是平常的1
  • 前提条件
    • 热点参数的注意点,参数必须是基本类型或者String

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图224

194.1.7 其他

194.2.2 各项配置参数说明

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图225

194.2.3 配置全局QPS

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图226

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图227

194.3 @SentinelResource

194.3.1 按资源名称限流+后续处理

  • 启动Nacos成功
  • 启动Sentinel成功
  • Module
    • cloudalibaba-sentinel-service8401
    • POM
      • YML | server:
        port: 8401

        spring:
        application:
        name: cloudalibaba-sentinel-service
        cloud:
        nacos:
        discovery:
        server-addr: localhost:8848
        sentinel:
        transport:
        dashboard: localhost:8080
        port: 8719 #默认8719,应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer

        management:
        endpoints:
        web:
        exposure:
        include: ‘*’ | | —- |
  • 业务类RateLimitController | package com.atguigu.springcloud.alibaba.controller;

    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    import com.alibaba.csp.sentinel.slots.block.BlockException;
    import com.atguigu.springcloud.alibaba.entities.CommonResult;
    import com.atguigu.springcloud.alibaba.entities.Payment;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;

    @RestController
    public class RateLimitController{
    @GetMapping(“/byResource“)
    @SentinelResource(value = “byResource”,blockHandler = “handleException”)
    public CommonResult byResource(){
    return new CommonResult(200,”按资源名称限流测试OK”,new Payment(2020L,”serial001”));
    }
    public CommonResult handleException(BlockException exception){
    return new CommonResult(444,exception.getClass().getCanonicalName()+”\t 服务不可用”);
    }
    } | | —- |

  • 主启动 | package com.atguigu.springcloud.alibaba;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

    @EnableDiscoveryClient
    @SpringBootApplication
    public class MainApp8401{
    public static void main(String[] args) {
    SpringApplication.run(MainApp8401.class, args);
    }
    } | | —- |

  • 配置流控规则

    • 配置步骤

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图228

  • 图形配置和代码关系
  • 表示1秒钟内查询次数大于1,就跑到我们自定义的处理,限流
  • 测试
    • 1秒钟点击1下,OK
    • 超过上述问题,疯狂点击,返回了自己定义的限流处理信息,限流发生

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图229

  • 额外问题
    • 此时关闭微服务8401看看
    • Sentinel控制台,流控规则消失了?????
      • 临时/持久?

194.3.2 按照Url地址限流+后续处理

  • 通过访问的URL来限流,会返回Sentinel自带默认的限流处理信息
  • 业务类RateLimitController | @GetMapping(“/rateLimit/byUrl”)
    @SentinelResource(value = “byUrl”)
    public CommonResult byUrl(){
    return new CommonResult(200,”按url限流测试OK”,new Payment(2020L,”serial002”));
    } | | —- |
  • 访问一次
  • Sentinel控制台配置

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图230

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图231

194.3.3 上面兜底方法面临的问题

  • 系统默认的,没有体现我们自己的业务要求。
  • 依照现有条件,我们自定义的处理方法又和业务代码耦合在一起,不直观。
  • 每个业务方法都增加一个兜底的,那代码膨胀加剧。
    • 全局统一的处理方法没有体现。

194.3.4 客户自定义限流处理逻辑

  • 创建customerBlockHandler类用于自定义限流处理逻辑
  • 自定义限流处理类
    • 方法必须是public static修饰的。 | package com.atguigu.springcloud.alibaba.myhandler;

      import com.alibaba.csp.sentinel.slots.block.BlockException;
      import com.atguigu.springcloud.entities.CommonResult;

      public class CustomerBlockHandler {
      public static CommonResult handleException(BlockException exception){
      return new CommonResult(2020,”自定义限流处理信息…. CustomerBlockHandler —- 1”);
      }

      public static CommonResult handleException2(BlockException exception){
      return new CommonResult(2020,”自定义限流处理信息…. CustomerBlockHandler —- 2”);
      }
      } | | —- |
  • RateLimitController | @GetMapping(“/rateLimit/customerBlockHandler”)
    @SentinelResource(value = “customerBlockHandler”,
    blockHandlerClass = CustomerBlockHandler.class, blockHandler = “handleException2”)
    public CommonResult customerBlockHandler(){
    return new CommonResult(200,”按客戶自定义”,new Payment(2020L,”serial003”));
    } | | —- |

  • 启动微服务后先调用一次

http://localhost:8401/rateLimit/customerBlockHandler

  • Sentinel控制台配置
  • 测试后我们自定义的出来了
  • 进一步说明

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图232

194.3.5 更多注解属性说明

https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图233

194.4 服务熔断功能

194.4.1 sentinel整合ribbon+openFeign+fallback

194.4.2 Ribbon系列

195 启动nacos和sentinel

196 提供者9003/9004

197 新建Module:cloudalibaba-provider-payment9003/9004

198 POM



com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery


com.atguigu.springcloud
cloud-api-commons
${project.version}



org.springframework.boot
spring-boot-starter-web


org.springframework.boot
spring-boot-starter-actuator



org.springframework.boot
spring-boot-devtools
runtime
true


org.projectlombok
lombok
true


org.springframework.boot
spring-boot-starter-test
test

199 YML
server:
port: 9003

spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos地址

management:
endpoints:
web:
exposure:
include: ‘*’
  • 记得修改不同的端口号
    200 主启动
    | package com.atguigu.springcloud.alibaba;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

    @SpringBootApplication
    @EnableDiscoveryClient
    public class PaymentMain9003{
    public static void main(String[] args) {
    SpringApplication.run(PaymentMain9003.class, args);
    }
    } | | —- |

201 业务类
package com.atguigu.springcloud.alibaba.controller;

import com.atguigu.springcloud.alibaba.entities.CommonResult;
import com.atguigu.springcloud.alibaba.entities.Payment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;

@RestController
public class PaymentController{
@Value(“${server.port}”)
private String serverPort;

public static HashMap hashMap = new HashMap<>();
static{
hashMap.put(1L,new Payment(1L,”28a8c1e3bc2742d8848569891fb42181”));
hashMap.put(2L,new Payment(2L,”bba8c1e3bc2742d8848569891ac32182”));
hashMap.put(3L,new Payment(3L,”6ua8c1e3bc2742d8848569891xt92183”));
}

@GetMapping(value = “/paymentSQL/{id}”)
public CommonResult paymentSQL(@PathVariable(“id”) Long id){
Payment payment = hashMap.get(id);
CommonResult result = new CommonResult(200,”from mysql,serverPort: “+serverPort,payment);
return result;
}

}

202 测试地址

http://localhost:9003/paymentSQL/1
http://localhost:9004/paymentSQL/1

203 消费者84

204 新建Module:cloudalibaba-consumer-nacos-order84

205 POM
<?xml version=”1.0” encoding=”UTF-8”?>
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd“>

cloud2020
com.atguigu.springcloud
1.0-SNAPSHOT

4.0.0
cloudalibaba-consumer-nacos-order84



org.springframework.cloud
spring-cloud-starter-openfeign


com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery


com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel


com.atguigu.springcloud
cloud-api-commons
${project.version}


org.springframework.boot
spring-boot-starter-web


org.springframework.boot
spring-boot-starter-actuator


org.springframework.boot
spring-boot-devtools
runtime
true


org.projectlombok
lombok
true


org.springframework.boot
spring-boot-starter-test
test


206 YML
server:
port: 84

spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080 #配置Sentinel dashboard地址
port: 8719 #默认8719,应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer

service-url:
nacos-user-service: http://nacos-payment-provider

207 主启动
package com.atguigu.springcloud.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class OrderNacosMain84{
public static void main(String[] args) {
SpringApplication.run(OrderNacosMain84.class, args);
}
}

208 业务类
  • ApplicationContextConfig | package com.atguigu.springcloud.alibaba.config;

    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.client.RestTemplate;

    @Configuration
    public class ApplicationContextConfig{
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
    return new RestTemplate();
    }
    } | | —- |
  • CircleBreakerController的全部源码 | package com.atguigu.springcloud.alibaba.controller;

    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    import com.alibaba.csp.sentinel.slots.block.BlockException;
    import com.atguigu.springcloud.alibaba.entities.CommonResult;
    import com.atguigu.springcloud.alibaba.entities.Payment;
    import com.atguigu.springcloud.alibaba.service.PaymentService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    import javax.annotation.Resource;

    @RestController
    @Slf4j
    public class CircleBreakerController {

    public static final String SERVICE_URL = “http://nacos-payment-provider“;

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping(“/consumer/fallback/{id}”)
    @SentinelResource(value = “fallback”) //没有配置
    //@SentinelResource(value = “fallback”,blockHandler = “blockHandler”) //blockHandler只负责sentinel控制台配置违规
    //@SentinelResource(value = “fallback”,fallback = “handlerFallback”,blockHandler = “blockHandler”, exceptionsToIgnore = {IllegalArgumentException.class})
    public CommonResult fallback(@PathVariable(“id”) Long id) {
    CommonResult result = restTemplate.getForObject(SERVICE_URL + “/paymentSQL/{id}”, CommonResult.class,id);
    if (id == 4) {
    throw new IllegalArgumentException (“IllegalArgumentException,非法参数异常….”);
    }else if (result.getData() == null) {
    throw new NullPointerException (“NullPointerException,该ID没有对应记录,空指针异常”);
    }
    return result;
    }
    } | | —- |

209 目的

fallback管运行异常
blockHandler管配置违规
测试地址:实现84对9003/9004的负载均衡
http://localhost:84/consumer/fallback/1

实验1.没有任何配置

@SentinelResource(value = “fallback”)//没有配置
给客户error页面,不友好
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图234

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图235

实验2.只配置fallback

@SentinelResource(value = “fallback”,fallback = “handlerFallback”) //fallback只负责业务异常

//fallback
public CommonResult handlerFallback(@PathVariable(“id”) Long id,Throwable e) {
Payment payment = new Payment(id,”null”);
return new CommonResult(444,”兜底异常handlerFallback,exception内容 “+e.getMessage(),payment);
}

测试,出现异常,会采用兜底方法展示错误消息
http://localhost:84/consumer/fallback/4
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图236

实验3.只配置blockHandler

@SentinelResource(value=”fallback”,blockHandler=”blockHandler”)//blockHandler只负责sentinel控制台配置违规

//blockHandler
public CommonResult blockHandler(@PathVariable(“id”) Long id, BlockException blockException) {
Payment payment = new Payment(id,”null”);
return new CommonResult(445,”blockHandler-sentinel限流,无此流水: blockException “+blockException.getMessage(),payment);
}
  • 测试,出现Java异常,无人管

http://localhost:84/consumer/fallback/4
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图237

  • 测试,出现查找不到数据异常,无人管

http://localhost:84/consumer/fallback/44
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图238

  • 根据异常数进行降级处理

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图239

  • 测试,出现异常数超过2个,降级处理

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图240

实验4.fallback和blockHandler都配置

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图241

  • 结论

http://localhost:84/consumer/fallback/4
allback和blockHandler都配置:不超过降级规则执行fallback兜底处理;超过降级规则抛BlockException异常,被blockHandler处理

实验5.忽略属性…

exceptionsToIgnore = {IllegalArgumentException.class}
不考虑降级违规情况,发生IllegalArgumentException异常是不走兜底方法的。

209.1 Feign系列

210 修改84模块

  1. - 84消费者调用提供者9003
  2. - Feign组件一般是消费者

211 POM


org.springframework.cloud
spring-cloud-starter-openfeign

212 YML

server:
port: 84

spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719

service-url:
nacos-user-service: http://nacos-payment-provider

#对Feign的支持
feign:
sentinel:
enabled: true

213 业务类

  • 带@FeignClient注解的业务接口 | package com.atguigu.springcloud.alibaba.service;

    import com.atguigu.springcloud.alibaba.entities.CommonResult;
    import com.atguigu.springcloud.alibaba.entities.Payment;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;

    @Component
    @FeignClient(value = “nacos-payment-provider”,fallback = PaymentFallbackService.class)
    public interface PaymentFeignService{
    @GetMapping(value = “/paymentSQL/{id}”)
    public CommonResult paymentSQL(@PathVariable(“id”) Long id);
    } | | —- |
  • fallback = PaymentFallbackService.class
  • PaymentFallbackService实现类 | package com.atguigu.springcloud.alibaba.service;

    import com.atguigu.springcloud.alibaba.entities.CommonResult;
    import com.atguigu.springcloud.alibaba.entities.Payment;
    import org.springframework.stereotype.Component;

    @Component
    public class PaymentFallbackService implements PaymentService{
    @Override
    public CommonResult paymentSQL(@PathVariable(“id”) Long id){
    return new CommonResult<>(44444,”服务降级返回,—-PaymentFallbackService”,new Payment(id,”errorSerial”));
    }
    } | | —- |

  • CircleBreakerController | // OpenFeign
    @Resource
    private PaymentFeignService paymentService;

    @GetMapping(value = “/consumer/paymentSQL/{id}”)
    public CommonResult paymentSQL(@PathVariable(“id”) Long id) {
    return paymentService.paymentSQL(id);
    } | | —- |

214 主启动

  • 添加@EnableFeignClients启动Feign的功能

    215 http://localhost:84/consumer/paymentSQL/1

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

    216.1 熔断框架比较

    01_尚硅谷_SpringCloud课件_2020_V2.4 - 图242

    216.2 规则持久化

    216.2.1 是什么

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

    216.2.2 怎么玩

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

    216.2.3 步骤

    217 修改:cloudalibaba-sentinel-service8401

    218 POM

    |
    com.alibaba.csp
    sentinel-datasource-nacos
    | | —- |

219 YML

server:
port: 8401

spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848 #Nacos服务注册中心地址
sentinel:
transport:
dashboard: localhost:8080 #配置Sentinel dashboard地址
port: 8719
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: cloudalibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow

management:
endpoints:
web:
exposure:
include: ‘*’

feign:
sentinel:
enabled: true # 激活Sentinel对Feign的支持

220 添加Nacos业务规则配置

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图243

  • 内容解析 | [
    {
    “resource”: “/rateLimit/byUrl”,
    “limitApp”: “default”,
    “grade”: 1,
    “count”: 1,
    “strategy”: 0,
    “controlBehavior”: 0,
    “clusterMode”: false
    }
    ] | | —- |

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图244

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

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图245

222 快速访问测试接口

http://localhost:8401/rateLimit/byUrl
默认
01_尚硅谷_SpringCloud课件_2020_V2.4 - 图246

223 停止8401再看sentinel

01_尚硅谷_SpringCloud课件_2020_V2.4 - 图247

224 重新启动8401再看sentinel

扎一看还是没有,稍等一会儿
多次调用
http://localhost:8401/rateLimit/byUrl
重新配置出现了,持久化验证通过