微服务保护

目录

初识Sentinel

雪崩问题

认识Sentinel

安装Sentinel控制台

引入cloud-demo

微服务整合sentinel

限流规则

簇点链路

快速入门

流控模式

流控模式-关联

流控模式-链路 

流控效果

流控效果-warm up

流控模式-排队等待

热点参数限流

隔离和降级

隔离和降级

Feign整合sentinel

线程隔离

熔断降级

熔断策略-慢调用

熔断策略-异常比例、异常数

授权规则及规则持久化

授权规则

自定义异常结果

规则管理模式

实现push模式


什么是雪崩问题?
1、微服务之间相互调用,因为调用链中的一个服务故障,引起整个链路都无法访问的情况。
如何避免因瞬间高并发流量而导致服务故障?

1、流量控制
如何避免因服务故障引起的雪崩问题?

1、超时处理
2、线程隔离

3、降级熔断


流控模式有哪些?
1、直接:对当前资源限流
2、关联:高优先级资源触发阈值,对低优先级资源限流。

3、链路:阈值统计时,只统计从指定资源进入当前资源的请求,是对请求来源的限流


流控效果有哪些?
1、快速失败:QPS超过阈值时,拒绝新的请求
2、warm up:QPS超过阈值时,拒绝新的请求;QPS阈值是逐渐提升的,可以避免冷启动时高并发导致服务宕机。
3、排队等待:请求会进入队列,按照阈值允许的时间间隔依次执行请求;如果请求预期等待时长大于超时时间,直接拒绝


Sentinel支持的雪崩解决方案:
1、线程隔离(仓壁模式)
2、降级熔断
Feign整合Sentinel的步骤:
1、在application.yml中配置:feign.sentienl.enable=true
2、给Feignclient编写FallbackFactory并注册为Bean
3、将FallbackFactory配置到FeignClient


线程隔离的两种手段是?
1、信号量隔离
2、线程池隔离
信号量隔离的特点是?
1、基于计数器模式,简单,开销小
线程池隔离的特点是?
1、基于线程池模式,有额外开销,但隔离控制更强


sentinel熔断降级的策略有哪些?
1、慢调用比例:超过指定时长的调用为慢调用,统计单位时长内慢调用的比例,超过阈值则熔断
2、异常比例:统计单位时长内异常调用的比例,超过阈值则熔断
3、常数:统计单位时长内异常调用的次数,超过阈值则熔断


获取请求来源的接口是什么?

1、Request0riginParser
处理BlockException的接口是什么?

1、BlockExceptionHandler


sentinel的三种配置管理模式是什么?
1、原始模式:保存在内存
2、pull模式:存在本地文件或数据库,定时去读取

3、push模式:保存在nacos,监听变更实时更新

初识Sentinel

雪崩问题

微服务调用链路中的某个服务故障,引起整个链路中的所有微服务都不可用,这就是雪崩。

解决雪崩问题的常见方式有四种: 

1、超时处理:设定超时时间,请求超过一定时间没有响应就返回错误信息,不会无休止等待2、舱壁模式:限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离。
3、熔断降级:由断路器统计业务执行的异常比例,如果超出阈值则会熔断该业务,拦截访问该业务的一切请求。

4、流量控制:限制业务访问的QPS,避免服务因流量的突增而故障。

认识Sentinel

Sentinel是阿里巴巴开源的一款微服务流量控制组件。

Sentinel具有以下特征:

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

安装Sentinel控制台

将该文件下载并拷贝到一个非中文路径的目录

sentinel-dashboard-1.8.1icon-default.png?t=N7T8https://pan.baidu.com/s/13FRnAXR7QTN5BexD5Zb5qQ?pwd=gil1

在该目录下cmd进入控制台运行以下命令

java -jar sentinel-dashboard-1.8.1.jar

然后访问localhost:8080,输入账号和密码,都是sentinel

如果要修改sentinel的默认端口、账号、密码,可以通过下列配置:

该命令启动时,使用的端口就成了8090了

java -jar sentinel-dashboard-1.8.1.jar -Dserver.port=8090

配置项默认值说明
server.port8080服务端口
sentinel.dashboard.auth.usernamesentinel默认用户名
sentinel.dashboard.auth.passwordsentinel默认密码

引入cloud-demo

下载该代码,用以前的那个cloud-demo也可以,不过可能需要修改一些代码:

1、所有yml文件的nacos:8848改成localhost:8848

2、所有yml文件的mysql:3306改成localhost:3306

3、有一个服务的端口是8080,这会与sentinel的端口发生冲突,需要改成其他端口

cloud-demoicon-default.png?t=N7T8https://pan.baidu.com/s/1_a4YzJr6R_EsRK6Z9tievQ?pwd=7rg1

把nacos和刚下载的sentinel启动后,再把该项目的三个服务启动,否则会报错 

微服务整合sentinel

1、引入sentinel依赖

在order-service的pom文件,导入依赖

<!--引入sentinel依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud-demo</artifactId>
        <groupId>cn.itcast.demo</groupId>
        <version>1.0</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>

    <artifactId>order-service</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--eureka客户依赖-->
<!--        <dependency>-->
<!--            <groupId>org.springframework.cloud</groupId>-->
<!--            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!--        </dependency>-->
        <!-- nacos客户端依赖包 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--feign依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--引入HttpClient依赖-->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>
        <!--引入feign统一的api-->
        <dependency>
            <groupId>cn.itcast.demo</groupId>
            <artifactId>feign-api</artifactId>
            <version>1.0</version>
        </dependency>
        <!--引入sentinel依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>

    </dependencies>
    <build>
        <finalName>app</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2、配置控制台地址

sentinel:
  transport:
    dashboard: localhost:8080 #sentinel控制台地址
server:
  port: 8088
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
    username: root
    password: 1234
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: orderservice #order的微服务名称
  cloud:
    nacos:
      server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080 #sentinel控制台地址
      datasource:
        flow:
          nacos:
            server-addr: localhost:8848 #nacos地址
            dataId: orderservice-flow-rules
            groupId: SENTINEL_GROUP
            rule-type: flow #规则类型。还可以是:degrade,authority,param-flow
#      discovery:
#        cluster-name: HZ #集群名称
##        namespace: 8279562b-ce89-420a-b765-f8b2adfdbe49 #命名空间id
#        ephemeral: false #是否为临时实例
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
#eureka:
#  client:
#    service-url: #eureka地址信息1
#      defaultZone: http://127.0.0.1:10086/eureka
userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule #负载均衡规则:随机。范围:userservice服务
ribbon:
  eager-load:
    enabled: true #开启饥饿加载
    clients:  #指定饥饿加载的服务
      - userservice
#feign:
#  client:
#    config:
#      default: #这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
#        loggerLevel: FULL #日志级别
feign:
  httpclient:
    enable: true #支持httpClient的开关
    max-connections: 200 #最大连接数
    max-connections-per-route: 50 #单个路径的最大连接数

3、访问微服务的任意端点,触发sentinel监控 

先访问服务的数据

再刷新查看sentinel控制台的内容

限流规则

簇点链路

簇点链路:就是项目内的调用链路,链路中被监控的每个接口就是一个资源。默认情况下sentinel会监控SpringMVC的每一个端点(Endpoint),因此SpringMVC的每一个端点(Endpoint)就是调用链路中的一个资源。

流控、熔断等都是针对簇点链路中的资源来设置的,因此我们可以点击对应资源后面的按钮来设置规则:
 

快速入门

点击资源/order/[orderld}后面的流控按钮,就可以弹出表单。表单中可以添加流控规则,如下图所示:

其含义是限制/order/{orderld}这个资源的单机QPS为5,即每秒只允许5次请求,超出的请求会被拦截并报错。

例如:现在限制为5,我在一秒内访问10次,就会有5个通过,5 个拒绝

流控模式

在添加限流规则时,点击高级选项,可以选择三种流控模式:

直接:统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认的模式

关联:统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流
链路:统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流

流控模式-关联

关联模式:统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流

使用场景:比如用户支付时需要修改订单状态,同时用户要查询订单。查询和修改操作会争抢数据库锁,产生竞争。业务需求是有限支付和更新订单的业务,因此当修改订单业务触发阈值时,需要对查询订单业务限流。

当/order/update资源访问量触发阈值时,就会对/order/query资源限流,避免影响/order/update资源。

在orderController.java添加代码

@GetMapping("/query")
public String queryOrder(){
    //查询订单
    System.out.println("查询订单");
    return "查询订单成功";
}
@GetMapping("/update")
public String updateOrder(){
    return "更新订单成功";
}
package cn.itcast.order.web;

import cn.itcast.order.pojo.Order;
import cn.itcast.order.service.OrderService;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.beans.factory.annotation.Autowired;
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;

@RestController
@RequestMapping("order")
public class OrderController {

   @Autowired
   private OrderService orderService;

    GetMapping("{orderId}")
    public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
        //根据id查询订单并返回
        return orderService.queryOrderById(orderId);
    }

    @GetMapping("/query")
    public String queryOrder(){
        //查询订单
        System.out.println("查询订单");
        return "查询订单成功";
    }


    @GetMapping("/update")
    public String updateOrder(){
        return "更新订单成功";
    }
}

重启orderservice,并访问localhost:8088/order/update和localhost:8088/order/query

再刷新sentinel控制台,会发现新增了:/order/update和/order/query两条资源名

给谁限流,就给谁加流控。要给query限流,就给它加流控

当/order/update资源访问量触发阈值时,就会对/order/query资源限流,避免影响/order/update资源。

 

此时会看到流控规则新增了一条

此时,每秒访问10次update,都是成功的,但此时的query被限流了,无法访问 

流控模式-链路 

链路模式:只针对从指定链路访问到本资源的请求做统计,判断是否超过阈值。

例如:有查询订单和创建订单业务,两者都需要查询商品。针对从查询订单进入到查询商品的请求统计,并设置限流。

步骤:

1、在orderService中添加一个queryGoods方法,不用实现业务

public void queryGoods(){
    System.err.println("查询商品");
}
package cn.itcast.order.service;

import cn.itcast.feign.clients.UserClient;
import cn.itcast.feign.pojo.User;
import cn.itcast.order.mapper.OrderMapper;
import cn.itcast.order.pojo.Order;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private UserClient userClient;

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        // 2.用Feign远程调用
        User user = userClient.findById(order.getUserId());
        // 3.封装user到order
        order.setUser(user);
        // 4.返回
        return order;
    }

 
    public void queryGoods(){
        System.err.println("查询商品");
    }

//    @Autowired
//    private RestTemplate restTemplate;
//
//    public Order queryOrderById(Long orderId) {
//        // 1.查询订单
//        Order order = orderMapper.findById(orderId);
//        // 2.利用RestTemplate发送http请求,查询用户
//        // 2.1.url路径
//        String url = "http://userservice/user/" + order.getUserId();
//        // 2.2.发送http请求,实现远程调用
//        User user = restTemplate.getForObject(url, User.class);//第一个参数是路径,第二个参数是返回的类=类型
//        // 3.封装user到order
//        order.setUser(user);
//        // 4.返回
//        return order;
//    }
}

2、在orderController中,改造/order/query端点,调用orderService中的queryGoods方法

3、在orderController中添加一个/order/save的端点,调用orderService的queryGoods方法

@GetMapping("/query")
public String queryOrder(){
    //查询商品
    orderService.queryGoods();
    //查询订单
    System.out.println("查询订单");
    return "查询订单成功";
}
@GetMapping("/save")
public String saveOrder(){
    //查询商品
    orderService.queryGoods();
    //查询订单
    System.out.println("新增订单");
    return "新增订单成功";
}
package cn.itcast.order.web;

import cn.itcast.order.pojo.Order;
import cn.itcast.order.service.OrderService;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.beans.factory.annotation.Autowired;
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;

@RestController
@RequestMapping("order")
public class OrderController {

   @Autowired
   private OrderService orderService;

    GetMapping("{orderId}")
    public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
        //根据id查询订单并返回
        return orderService.queryOrderById(orderId);
    }

    @GetMapping("/query")
    public String queryOrder(){
        //查询商品
        orderService.queryGoods();
        //查询订单
        System.out.println("查询订单");
        return "查询订单成功";
    }

    @GetMapping("/save")
    public String saveOrder(){
        //查询商品
        orderService.queryGoods();
        //查询订单
        System.out.println("新增订单");
        return "新增订单成功";
    }


    @GetMapping("/update")
    public String updateOrder(){
        return "更新订单成功";
    }
}

注意:因为sentinel只会监控controller的内容,但是我的controller都会访问orderService的内容,我需要监控service的内容。此时需要两步:

第一步:需要利用@SentinelResource注解

@SentinelResource("goods")
package cn.itcast.order.service;

import cn.itcast.feign.clients.UserClient;
import cn.itcast.feign.pojo.User;
import cn.itcast.order.mapper.OrderMapper;
import cn.itcast.order.pojo.Order;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private UserClient userClient;

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        // 2.用Feign远程调用
        User user = userClient.findById(order.getUserId());
        // 3.封装user到order
        order.setUser(user);
        // 4.返回
        return order;
    }

    @SentinelResource("goods")
    public void queryGoods(){
        System.err.println("查询商品");
    }

//    @Autowired
//    private RestTemplate restTemplate;
//
//    public Order queryOrderById(Long orderId) {
//        // 1.查询订单
//        Order order = orderMapper.findById(orderId);
//        // 2.利用RestTemplate发送http请求,查询用户
//        // 2.1.url路径
//        String url = "http://userservice/user/" + order.getUserId();
//        // 2.2.发送http请求,实现远程调用
//        User user = restTemplate.getForObject(url, User.class);//第一个参数是路径,第二个参数是返回的类=类型
//        // 3.封装user到order
//        order.setUser(user);
//        // 4.返回
//        return order;
//    }
}

第二步: Sentinel默认会将Controller方法做context整合,导致链路模式的流控失效,需要修改application.yml添加配置

web-context-unify: false #关闭context整合
server:
  port: 8088
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
    username: root
    password: 1234
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: orderservice #order的微服务名称
  cloud:
    nacos:
      server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080 #sentinel控制台地址
      web-context-unify: false #关闭context整合
      datasource:
        flow:
          nacos:
            server-addr: localhost:8848 #nacos地址
            dataId: orderservice-flow-rules
            groupId: SENTINEL_GROUP
            rule-type: flow #规则类型。还可以是:degrade,authority,param-flow
#      discovery:
#        cluster-name: HZ #集群名称
##        namespace: 8279562b-ce89-420a-b765-f8b2adfdbe49 #命名空间id
#        ephemeral: false #是否为临时实例
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
#eureka:
#  client:
#    service-url: #eureka地址信息1
#      defaultZone: http://127.0.0.1:10086/eureka
userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule #负载均衡规则:随机。范围:userservice服务
ribbon:
  eager-load:
    enabled: true #开启饥饿加载
    clients:  #指定饥饿加载的服务
      - userservice
#feign:
#  client:
#    config:
#      default: #这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
#        loggerLevel: FULL #日志级别
feign:
  httpclient:
    enable: true #支持httpClient的开关
    max-connections: 200 #最大连接数
    max-connections-per-route: 50 #单个路径的最大连接数
 

重启服务,再访问localhost:8088/order/query和localhost:8088/order/save,刷新sentinel控制台。

可以看到save和query变成了两个独立的资源名。这是因为刚才的第二步的原因

这两个goods其实是同一个,所以随便点一个,进行流控。

4、给queryGoods设置限流规则,从/order/query进入queryGoods的方法限制QPs必须小于2

监控从/order/query进来的goods,限制每秒2个。但是从/order/save进来的goods没有限制。

 

每秒给 /order/query和/order/save各访问4个。可以看到每秒有6个通过,2个拒绝

流控效果

流控效果是指请求达到流控阈值时应该采取的措施,包括三种:

1、快速失败:达到阈值后,新的请求会被立即拒绝并抛出FlowException异常。是默认的处理方式。
2、warm up:预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从一个较小值逐渐增加到最大阈值。
3、排队等待:让所有的请求按照先后次序排队执行,两个请求的间隔不能小于指定时长

流控效果-warm up

warm up也叫预热模式,是应对服务冷启动的一种方案。请求阈值初始值是threshold / coldFactor,持续指定时长后,逐渐提高到threshold值。而coldFactor的默认值是3

例如:给/order/{orderld}这个资源设置限流,最大QPs为10,利用warm up效果,预热时长为5秒

可以看到新增了一条规则

每秒访问10个,可以看到刚开始只能访问3个,其余的被拒绝,慢慢的可以访问到10个

流控模式-排队等待

当请求超过QPs阈值时,快速失败和warm up会拒绝新的请求并抛出异常。而排队等待则是让所有请求进入一个队列中,然后按照阈值允许的时间间隔依次执行。后来的请求必须等待前面执行完成,如果请求预期的等待时间超出最大时长,则会被拒绝。

比如:QPS=5,意味着每200ms处理一个队列中的请求;timeout = 2000,意味着预期等待超过2000ms的请求会被拒绝并抛出异常

例如:给/order/{orderld}这个资源设置限流,最大QPs为10,利用排队的流控效果,超时时长设置为5s

给上次配的warm up进行编辑,使用排队等待

可以看到warm up的规则发生了改变,变成了排队等待

每秒访问15个,可以看到,并没有出现拒绝,最多10个,因为进行了排队等待,但是响应时间挺长的

热点参数限流

之前的限流是统计访问某个资源的所有请求,判断是否超过QPs阈值。而热点参数限流是分别统计参数值相同的请求,判断是否超过QPs阈值。

例如:给/order/{orderld}这个资源添加热点参数限流,规则如下:

1、默认的热点参数规则是每1秒请求量不超过2
2、给102这个参数设置例外:每1秒请求量不超过4

3、给103这个参数设置例外:每1秒请求量不超过10

注意:热点参数限流对默认的SpringMVC资源无效。需要加注解,起名为hot

@SentinelResource("hot")
package cn.itcast.order.web;

import cn.itcast.order.pojo.Order;
import cn.itcast.order.service.OrderService;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.beans.factory.annotation.Autowired;
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;

@RestController
@RequestMapping("order")
public class OrderController {

   @Autowired
   private OrderService orderService;

   @SentinelResource("hot")
    @GetMapping("{orderId}")
    public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
        // 根据id查询订单并返回
        return orderService.queryOrderById(orderId);
    }

    @GetMapping("/query")
    public String queryOrder(){
        //查询商品
        orderService.queryGoods();
        //查询订单
        System.out.println("查询订单");
        return "查询订单成功";
    }

    @GetMapping("/save")
    public String saveOrder(){
        //查询商品
        orderService.queryGoods();
        //查询订单
        System.out.println("新增订单");
        return "新增订单成功";
    }

    @GetMapping("/update")
    public String updateOrder(){
        return "更新订单成功";
    }
}

重启服务,并访问localhost:8088/order/101,此时可以看到该资源名

按要求配置

每秒给三个请求发送5个,可以看到,最高的时候为11,因为一个限制了2,一个限制了4,一个限制了10,所以是2+4+5=11

隔离和降级

隔离和降级

虽然限流可以尽量避免因高并发而引起的服务故障,但服务还会因为其它原因而故障。而要将这些故障控制在一定范围,避免雪崩,就要靠线程隔离(舱壁模式)和熔断降级手段了。
不管是线程隔离还是熔断降级,都是对客户端(调用方)的保护。

Feign整合sentinel

SpringCloud中,微服务调用都是通过Feign来实现的,因此做客户端保护必须整合Feign和Sentinel。

1、修改OrderService的application.yml文件,开启Feign的Sentinel功能

feign:
  sentinel:
    enabled: true #开启Feign对sentinel的支持
server:
  port: 8088
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
    username: root
    password: 1234
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: orderservice #order的微服务名称
  cloud:
    nacos:
      server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080 #sentinel控制台地址
      web-context-unify: false #关闭context整合
      datasource:
        flow:
          nacos:
            server-addr: localhost:8848 #nacos地址
            dataId: orderservice-flow-rules
            groupId: SENTINEL_GROUP
            rule-type: flow #规则类型。还可以是:degrade,authority,param-flow
#      discovery:
#        cluster-name: HZ #集群名称
##        namespace: 8279562b-ce89-420a-b765-f8b2adfdbe49 #命名空间id
#        ephemeral: false #是否为临时实例
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
#eureka:
#  client:
#    service-url: #eureka地址信息1
#      defaultZone: http://127.0.0.1:10086/eureka
userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule #负载均衡规则:随机。范围:userservice服务
ribbon:
  eager-load:
    enabled: true #开启饥饿加载
    clients:  #指定饥饿加载的服务
      - userservice
#feign:
#  client:
#    config:
#      default: #这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
#        loggerLevel: FULL #日志级别
feign:
  httpclient:
    enable: true #支持httpClient的开关
    max-connections: 200 #最大连接数
    max-connections-per-route: 50 #单个路径的最大连接数
  sentinel:
    enabled: true #开启Feign对sentinel的支持

2、给FeignClient编写失败后的降级逻辑
方式一:FallbackClass,无法对远程调用的异常做处理
方式二:FallbackFactory,可以对远程调用的异常做处理,我们选择这种

步骤一:在feing-api的模块中的cn.itcast.feign的clients新建fallback包,新建UserClientFallbackFactory.java

package cn.itcast.feign.clients.fallback;

import cn.itcast.feign.clients.UserClient;
import cn.itcast.feign.pojo.User;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class UserClientFallbackFactory implements FallbackFactory<UserClient> {
    @Override
    public UserClient create(Throwable throwable) {
        return new UserClient() {
            @Override
            public User findById(Long id) {
                log.error("查询用户异常",throwable);
                return new User();
            }
        };
    }
}

步骤二:在feing-api模块中的DefaultFeignConfiguration类中将UserClientFallbackFactory注册为一个Bean

@Bean
public UserClientFallbackFactory userClientFallbackFactory(){
    return new UserClientFallbackFactory();
}
package cn.itcast.feign.config;

import cn.itcast.feign.clients.fallback.UserClientFallbackFactory;
import feign.Logger;
import org.springframework.context.annotation.Bean;

public class DefaultFeignConfiguration {
    @Bean
    public Logger.Level loglevel(){
        return Logger.Level.BASIC;
    }

    @Bean
    public UserClientFallbackFactory userClientFallbackFactory(){
        return new UserClientFallbackFactory();
    }
}

步骤三:在feing-api模块中的UserClient接口中使用UserClientFallbackFactory

注意:在cloud-demo的pom文件中,找到<spring-cloud.version></spring-cloud.version>,把它写上<spring-cloud.version>Hoxton.SR8</spring-cloud.version>。不然会因为版本问题报错

package cn.itcast.feign.clients;

import cn.itcast.feign.clients.fallback.UserClientFallbackFactory;
import cn.itcast.feign.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "userservice", fallbackFactory = UserClientFallbackFactory.class)
public interface UserClient {

    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

重启服务,并访问localhost:8088/order/101,再刷新sentinel控制台。可以看到GET的这个链路,这就是Feign的请求路径

线程隔离

线程隔离有两种方式实现:

线程池隔离

优点:支持主动超时、支持异步调用

缺点:线程的额外开销比较大

场景:低扇出
信号量隔离(Sentinel默认采用)

优点:轻量级、无额外开销

缺点:不支持主动超时、不支持异步调用

场景:高频调用、高扇出

在添加限流规则时,可以选择两种阈值类型:

QPS:就是每秒的请求数,在快速入门中已经演示过
线程数:是该资源能使用用的tomcat线程数的最大值。也就是通过限制线程数量,实现舱壁模式

例如:给UserClient的查询用户接口设置流控规则,线程数不能超过2。

对GET://http://userservice/user/{id}添加流控管理

 

一瞬间发送10次请求,可以看到前2个请求正常,但是后面的请求都是空而没有报错。因为UserClientFallbackFactory.java里已经写了降级逻辑,当访问被拒绝时,返回空的内容。

熔断降级

熔断降级是解决雪崩问题的重要手段。其思路是由断路器统计服务调用的异常比例、慢请求比例,
如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。

断路器熔断策略有三种:慢调用、异常比例、异常数

熔断策略-慢调用

慢调用:业务的响应时长(RT)大于指定时长的请求认定为慢调用请求。在指定时间内,如果请求数量超过设定的最小数量,慢调用比例大于设定的阈值,则触发熔断。

例如:给UserClient的查询用户接口设置降级规则,慢调用的RT阈值为50ms,统计时间为1秒,最小请求数量为5,失败阈值比例为0.4,熔断时长为5

提示:为了触发慢调用规则,我们需要修改UserService中的业务,增加业务耗时

在user-service的模块中,UserController.java里,修改为该代码

@GetMapping("/{id}")                                  //请求头      变量名为Truth     可以不传
public User queryById(@PathVariable("id") Long id,@RequestHeader(value = "Truth",required = false) String truth) throws InterruptedException {
    if(id == 1){
        //休眠,触发熔断
        Thread.sleep(60);
    }
    return userService.queryById(id);
}
package cn.itcast.user.web;

import cn.itcast.user.config.PatternProperties;
import cn.itcast.user.pojo.User;
import cn.itcast.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;

import java.text.DateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Slf4j
@RestController
@RequestMapping("/user")
//@RefreshScope
public class UserController {

    @Autowired
    private UserService userService;

//    @Value("${pattern.dateformat}")
//    //注解读取该配置
//    private String dateformat;

    @Autowired
    private PatternProperties properties;//注入新的java类

    @GetMapping("prop")
    public  PatternProperties properties(){
        return properties;
    }

    @GetMapping("now")
    public String now(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(properties.getDateformat()));//通过该配置改变时间格式
    }

    /**
     * 路径: /user/110
     *
     * @param id 用户id
     * @return 用户
     */
    @GetMapping("/{id}")                                  //请求头      变量名为Truth     可以不传
    public User queryById(@PathVariable("id") Long id,@RequestHeader(value = "Truth",required = false) String truth) throws InterruptedException {
        if(id == 1){
            //休眠,触发熔断
            Thread.sleep(60);
        }
        return userService.queryById(id);
    }
}

重启服务,访问localhost:8088/order/101,把以前的GET://http://userservice/user/{id}流控规则删掉。

给GET://http://userservice/user/{id}配置降级

可以看到新增的规则

一秒内请求5次localhost:8088/order/101,之后再请求localhost:8088/order/102会发现数据为空

熔断策略-异常比例、异常数

异常比例或异常数:统计指定时间内的调用,如果调用次数超过指定请求数,并且出现异常的比例达到设定的比例阈值(或超过指定异常数),则触发熔断。

例如:给UserClient的查询用户接口设置降级规则,统计时间为1秒,最小请求数量为5,失败阈值比例为0.4,熔断时长为5S

提示:为了触发异常统计,我们需要修改UserService中的业务,抛出异常:

@GetMapping("/{id}")                                  //请求头      变量名为Truth     可以不传
public User queryById(@PathVariable("id") Long id,@RequestHeader(value = "Truth",required = false) String truth) throws InterruptedException {
    if(id == 1){
        //休眠,触发熔断
        Thread.sleep(60);
    }else if(id == 2){
        throw new RuntimeException("故意出错,触发熔断");
    }
    return userService.queryById(id);
}
package cn.itcast.user.web;

import cn.itcast.user.config.PatternProperties;
import cn.itcast.user.pojo.User;
import cn.itcast.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;

import java.text.DateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Slf4j
@RestController
@RequestMapping("/user")
//@RefreshScope
public class UserController {

    @Autowired
    private UserService userService;

//    @Value("${pattern.dateformat}")
//    //注解读取该配置
//    private String dateformat;

    @Autowired
    private PatternProperties properties;//注入新的java类

    @GetMapping("prop")
    public  PatternProperties properties(){
        return properties;
    }

    @GetMapping("now")
    public String now(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(properties.getDateformat()));//通过该配置改变时间格式
    }

    /**
     * 路径: /user/110
     *
     * @param id 用户id
     * @return 用户
     */
    @GetMapping("/{id}")                                  //请求头      变量名为Truth     可以不传
    public User queryById(@PathVariable("id") Long id,@RequestHeader(value = "Truth",required = false) String truth) throws InterruptedException {
        if(id == 1){
            //休眠,触发熔断
            Thread.sleep(60);
        }else if(id == 2){
            throw new RuntimeException("故意出错,触发熔断");
        }
        return userService.queryById(id);
    }
}

重启服务,访问localhost:8088/order/101,把以前的GET://http://userservice/user/{id}流控规则删掉。

给GET://http://userservice/user/{id}配置降级

访问5次localhost:8088/order/102,触发熔断规则,再访问localhost:8088/order/103,会发现数据也为空

 

授权规则及规则持久化

授权规则

授权规则可以对调用方的来源做控制,有白名单和黑名单两种方式。

1、白名单:来源(origin)在白名单内的调用者允许访问
2、黑名单:来源(origin)在黑名单内的调用者不允许访问

例如,我们尝试从request中获取一个名为origin的请求头,作为origin的值

在order-service模块中的cn.itcast.order中新增一个sentinel包,新增HeaderOriginParser.java

package cn.itcast.order.sentinel;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import io.netty.util.internal.StringUtil;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Component
public class HeaderOriginParser implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest request) {
        //1、获取请求头
        String origin = request.getHeader("origin");
        //2、非空判断
        if(StringUtils.isEmpty(origin)){
            origin = "blank";
        }
        return origin;
    }
}

需要在gateway服务中,利用网关的过滤器添加名为gateway的origin头

- AddRequestHeader=origin,gateway #添加情求头
server:
  port: 10010 #网关端口
spring:
  application:
    name: gateway #服务名称
  cloud :
    nacos:
      server-addr: localhost:8848 #nacos地址
    gateway:
      routes: #网关路由配置
        - id: user-service #路由id,自定义,只要唯一即可
        # uri: http://127.0.0.1:8081 #路由的目标地址 http就是固定地址
          uri: lb://userservice #路由的目标地址lb就是负载均衡,后面跟服务名称
          predicates: #路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/user/** #这个是按照路径匹配,只要以/user/开头就符合要求
#          filters:
#            - AddRequestHeader=Truth,Itcast is freaking awesome! #添加请求头
        - id: order-service #路由id,自定义,只要唯一即可
          uri: lb://orderservice #路由的目标地址lb就是负载均衡,后面跟服务名称
          predicates: #路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/order/** #这个是按照路径匹配,只要以/user/开头就符合要求
#            - After=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] #要求访问时间在这个之后
            - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] #要求访问时间在这个之后
      default-filters: #默认过滤器,会对所有的路由请求都生效
        - AddRequestHeader=Truth,Itcast is freakina awesome! #添加情求头
        - AddRequestHeader=origin,gateway #添加情求头
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        corsConfigurations:
          '[/**]':
            allowedOrigins: # 允许哪些网站的跨域请求
              - "http://localhost:8090"
              - "http://www.leyou.com"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 这次跨域检测的有效期

重启服务,访问localhost:8088/order/101给/order/{orderld}配置授权规则

访问 localhost:8088/order/103报错,访问localhost:8088/order/103?authorization=admin成功

自定义异常结果

默认情况下,发生限流、降级、授权拦截时,都会抛出异常到调用方。如果要自定义异常时的返回结果,需要实现BlockExceptionHandler接口

在order-service模块中的cn.itcast.order中的sentinel包,新增SentinelExceptionHandler.java

package cn.itcast.order.sentinel;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        String msg = "未知异常";
        int status = 429;

        if (e instanceof FlowException) {
            msg = "请求被限流了";
        } else if (e instanceof ParamFlowException) {
            msg = "请求被热点参数限流";
        } else if (e instanceof DegradeException) {
            msg = "请求被降级了";
        } else if (e instanceof AuthorityException) {
            msg = "没有权限访问";
            status = 401;
        }

        response.setContentType("application/json;charset=utf-8");
        response.setStatus(status);
        response.getWriter().println("{\"msg\": " + msg + ", \"status\": " + status + "}");
    }
}

重启服务, 访问 localhost:8088/order/103,给/order/{orderId}添加流控规则

访问2次localhost:8088/order/103,出现限流

把刚配的限流规则删掉,新增授权规则

 

这次为没有权限 

规则管理模式

sentinel的控制台规则管理有三种模式:

1、原始模式:Sentinel的默认模式,将规则保存在内存,重启服务会丢失

2、pull模式
3、push模式

pull模式:控制台将配置的规则推送到Sentinel客户端,而客户端会将配置规则保存在本地文件或数据库中。以后会定时去本地文件或数据库中查询,更新本地规则。

push模式:控制台将配置规则推送到远程配置中心,例如Nacos。Sentinel客户端监听Nacos,获取配置变更的推送消息,完成本地配置更新。

实现push模式

push模式实现最为复杂,依赖于nacos,并且需要修改Sentinel控制台源码。

1、引入依赖

在order-service中引入sentinel监听nacos的依赖

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud-demo</artifactId>
        <groupId>cn.itcast.demo</groupId>
        <version>1.0</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>

    <artifactId>order-service</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--eureka客户依赖-->
<!--        <dependency>-->
<!--            <groupId>org.springframework.cloud</groupId>-->
<!--            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!--        </dependency>-->
        <!-- nacos客户端依赖包 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--feign依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--引入HttpClient依赖-->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>
        <!--引入feign统一的api-->
        <dependency>
            <groupId>cn.itcast.demo</groupId>
            <artifactId>feign-api</artifactId>
            <version>1.0</version>
        </dependency>
        <!--引入sentinel依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
    </dependencies>
    <build>
        <finalName>app</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

配置nacos地址

在order-service中的application.yml文件配置nacos地址及监听的配置信息

spring:
  cloud:
    sentinel:
      datasource:
        flow:
          nacos:
            server-addr: localhost:8848 #nacos地址
            dataId: orderservice-flow-rules
            groupId: SENTINEL_GROUP
            rule-type: flow #规则类型。还可以是:degrade,authority,param-flow
server:
  port: 8088
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
    username: root
    password: 1234
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: orderservice #order的微服务名称
  cloud:
    nacos:
      server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080 #sentinel控制台地址
      web-context-unify: false #关闭context整合
      datasource:
        flow:
          nacos:
            server-addr: localhost:8848 #nacos地址
            dataId: orderservice-flow-rules
            groupId: SENTINEL_GROUP
            rule-type: flow #规则类型。还可以是:degrade,authority,param-flow
#      discovery:
#        cluster-name: HZ #集群名称
##        namespace: 8279562b-ce89-420a-b765-f8b2adfdbe49 #命名空间id
#        ephemeral: false #是否为临时实例
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
#eureka:
#  client:
#    service-url: #eureka地址信息1
#      defaultZone: http://127.0.0.1:10086/eureka
userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule #负载均衡规则:随机。范围:userservice服务
ribbon:
  eager-load:
    enabled: true #开启饥饿加载
    clients:  #指定饥饿加载的服务
      - userservice
#feign:
#  client:
#    config:
#      default: #这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
#        loggerLevel: FULL #日志级别
feign:
  httpclient:
    enable: true #支持httpClient的开关
    max-connections: 200 #最大连接数
    max-connections-per-route: 50 #单个路径的最大连接数
  sentinel:
    enabled: true #开启Feign对sentinel的支持

重启服务

下载该文件,并把它放到跟sentinel-dashboard-1.8.1同一目录下

sentinel-dashboard.jaricon-default.png?t=N7T8https://pan.baidu.com/s/1MLvwJiHHrntl9vals3yFNQ?pwd=egh4

在该目录下cmd进入控制台运行以下命令

java -jar -Dnacos.addr=localhost:8848 sentinel-dashboard.jar

访问loaclhost:8848,进入nacos,访问localhost:8088/order/103, 刷新sentinel控制台,可以看到新的列表

在这里新增的流控规则会作用到nacos,点新增

 

此时刷新nacos,可以看到新的配置

访问localhost:8088/order/103,发现成功限流

再重启服务,看sentinel控制台的规则是否被重置

可以看到规则还在,规则持久化完成 

代码文件,点击下载icon-default.png?t=N7T8https://pan.baidu.com/s/1sdroaa2GxZ_L3nq9BKqLzQ?pwd=i0et

上一篇:数据聚合、自动补全、数据同步、es集群

 

  • 79
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
拍拍贷微服务rpc框架源码.zip # 拍拍贷微服务体系 拍拍贷微服务体系是拍拍贷基础框架部总结内部微服务多年实践,参考、吸收大量业内解决方案形成的适合中型互联网公司的微服务解决方案。 拍拍贷微服务体系主要组成部分: - Raptor rpc框架。 - Radar服务注册中心。 - Kong网关。 微服务实例启动之后,会自动注册到radar服务注册中心,实例启动正常后,kong网关周期性的将实例信息同步到kong的插件配置。微服务之间的调用、zuul网关调用微服务,都是通过域名进行调用,域名解析到kong网关。Kong网关根据域名和微服务的对应关系,对微服务实例进行负载均衡运算后,得到一个实例,最终进行调用。 拍拍贷微服务体系主要架构考虑: - 由Kong网关形成的集中式服务治理。降低由于客户端服务治理bugfix等引起的升级成本。 - 采用HTTP 1.1作为底层传输协议,从外部到内部无需进行协议转换。 - 采用HTTP 1.1 作为底层传输协议,不会引起原有基于HTTP协议的已有设施失效。 # Raptor微服务rpc组件 Raptor微服务rpc组件是拍拍贷基础框架部参考、借鉴了大量已有rpc框架、rpc组件的设计,研发的一款基于google protobuf的轻量级,可扩展的rpc组件。 **Raptor设计理念:** - 微内核。Raptor核心实现raptor rpc必须的服务定义、protobuf序列化/反序列化、扩展接口和最小化实现。 - 可扩展。Raptor核心预留了Client、Endpoint等可扩展接口,提供相应的实现即可替换掉默认的实现。 - 模块化。Raptor核心不提供组装能力,raptor核心提供了rpc框架所需的核心组件,由外部框架进行组装。例如,raptor默认实现提供了基于spring-boot的组装方式。 **Raptor的价值:** - 契约驱动开发模式,以protobuf为契约,帮助企业规模化生产。 - JAVA语言开发,工程性好,保护原有技术投资。 - 预留兼容性,以protobuf为契约,符合社区技术趋势,为后续以protobuf为基础做技术升级留下兼容性。例如,引入grpc,业务契约无需改变。 - 灵活性,可采用集中治理,也可以采用客户端治理;可使用protobuf binary over HTTP也可以使用protobuf json over HTTP,服务提供方根据HTTP头自适应;为架构师留下灵活的选择余地。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@katoumegumi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值