微服务架构03 ------ 降级,热点,系统,授权规则,网关,负载均衡,过滤器,限流

微服务架构03 ------ 降级,热点,系统,授权规则,网关,负载均衡,过滤器,限流,第1张

微服务架构03 ------ 降级,热点,系统,授权规则,网关,负载均衡,过滤器,限流 1 Sentinel降级应用实践

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

2 Sentinel热点规则分析(重点)

概述
何为热点?热点即经常访问的数据。比如:

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

热点参数限流会统计传入参数中的热点数据,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。其中,Sentinel会利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。

第一步:在sca-provider中添加如下方法,例如:

//http://localhost:8081/provider/doFindById?id=10
    @GetMapping("/doFindById")
    @SentinelResource("resource")//aop 切入点
    public String doFindById(@RequestParam Integer id){
        return "Get Resource By"+id;
    }

3 Sentinel系统规则(了解)

概述

系统在生产环境运行过程中,我们经常需要监控服务器的状态,看服务器CPU、内存、IO等的使用率;主要目的就是保证服务器正常的运行,不能被某些应用搞崩溃了;而且在保证稳定的前提下,保持系统的最大吞吐量。
快速入门

Sentinel的系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体 Load(负载)、RT(响应时间)、入口 QPS 、线程数和CPU使用率五个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。如图所示:


系统规则是一种全局设计规则,其中,

  1. Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5。
  2. CPU使用率:当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0)。
  3. RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  4. 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  5. 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

说明,系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务。

小节面试分析
如何理解sentinel中的系统规则?(是对所有链路的控制规则,是一种系统保护策略)
Sentinel的常用系统规则有哪些?(RT,QPS,CPU,线程,Load-linux,unix)
Sentinel系统保护规则被触发以后底层会抛出什么异常?(SystemBlockException)
4 Sentinel授权规则(重要)

概述

很多时候,我们需要根据调用方来限制资源是否通过,这时候可以使用 Sentinel 的黑白名单控制的功能。黑白名单根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。例如微信中的黑名单。
快速入门

基于请求参数,进行黑白名单设计

sentinel可以基于黑白名单方式进行授权规则设计,如图所示:

@Component
public class DefaultRequestOriginParser implements RequestOriginParser {
    
    @Override
    public String parseOrigin(HttpServletRequest request) {
        //基于请求参数,进行黑白名单设计
        String origin = request.getParameter("origin");//获取请求参数
        return origin;
    }
}




基于请求ip等方式进行黑白名单的规则设计
String ip= request.getRemoteAddr();
System.out.println("ip="+ip);
return ip;


5 网关

网关本质上要提供一个各种服务访问的入口,并提供服务接收并转发所有内外部的客户端调用,还有就是权限认证,限流控制等等。

Spring Cloud Gateway

性能强劲:是第一代网关Zuul的1.6倍。
功能强大:内置了很多实用的功能,例如转发、监控、限流等

缺点:
依赖Netty与WebFlux(Spring5.0),不是传统的Servlet编程模型(Spring MVC就是基于此模型实现),学习成本高。
需要Spring Boot 2.0及以上的版本,才支持
        
            org.springframework.cloud
            spring-cloud-starter-gateway
        

server:
  port: 9000
spring:
  application:
    name: sca-gateway #没有向nacos中心注册,可以不写
  cloud:
    gateway: #网关配置
      routes: #路由配置(routes下可有多个路由 ,id作为唯一标示)
        - id: route01
          uri: http://localhost:8081/ #请求转发路径
          predicates: #谓词判断逻辑(定义请求转发条件,谓词所有条件满足才会执行请求转发)
            - Path=/nacos/provider/echo/** #nacos前缀,服务保护
          filters: #局部过滤器,针对于当前路由进行设计谓词返回值都为true则执行这里的filters
            - StripPrefix=1 #去除前缀过滤器,这里1表示去掉Path中第一层目录 nacos


依次启动sca-provider,sca-gateway服务,然后打开浏览器,进行访问测试

小结分析

1.什么是网关?服务访问(流量)的一个入口,类似生活中的“海关“
2.为什么使用网关?(服务安全,统一服务入口管理,负载均衡,限流,鉴权)
3.Spring Cloud Gateway 应用的初始构建过程(添加依赖,配置)
4.Gateway 服务的启动底层是通过谁去实现的?(Netty网络编程框架-ServerSocket)
5.Gateway 服务做请求转发时一定要在注册中心进行注册吗?(不一定,可以直接通过远端url进行服务访问)

6 负载均衡设计 为什么负载均衡?

网关才是服务访问的入口,所有服务都会在网关层面进行底层映射,所以在访问服务时,要基于服务serivce id(服务名)去查找对应的服务,让请求从网关层进行均衡转发,以平衡服务实例的处理能力。

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

修改yml

执行流程分析 (重要)

客户端向Spring Cloud Gateway发出请求。 如果Gateway Handler Mapping 通过谓词predicates(predicates)的集合确定请求与路由(Routers)匹配,则将其发送到Gateway Web Handler。 Gateway Web Handler 基于路由配置调用过滤链中的过滤器(也就是所谓的责任链模式)进一步的处理请求。 Filter由虚线分隔的原因是, Filter可以在发送请求之前和之后执行拓展逻辑。基于官方的处理流程,进行源码分析如下:

重要类,词 说明
  1. 全局过滤器GlobalFilter
  2. gateway中yml 局部过滤器

  1. PathRoutePredicateFactory谓词工厂
debug 断点



测试


1.1




2



7 过滤器(Filter)增强分析(了解) 局部过滤器
spring:
  cloud:
    gateway:
      routes:
        - id: add_request_header_route
          uri: https://example.org
          filters:
            - AddRequestHeader=X-Request-Foo, Bar #原始请求添加名为 X-Request-Foo ,值为 Bar 的请求头
            - AddRequestParameter=foo, bar #为原始请求添加名为foo,值为bar的参数,即:foo=bar
            - 

全局过滤器设计及实现

全局过滤器(GlobalFilter)作用于所有路由, 无需配置。在系统初始化时加载,并作用在每个路由上。通过全局过滤器可以实现对权限的统一校验,安全性验证等功能。一般内置的全局过滤器已经可以完成大部分的功能,但是对于企业开发的一些业务功能处理,还是需要我们 自己编写过滤器来实现的,那么我们一起通过代码的形式自定义一个过滤器,去完成统一的权限校验。 例如,当客户端第一次请求服务时,服务端对用户进行信息认证(登录), 认证通过,将用户信息进行加密形成token,返回给客户端,作为登录凭证 以后每次请求,客户端都携带认证的token 服务端对token进行解密,判断是否有效。学过spring中的webflux技术的同学可以对如下代码进行尝试实现(没学过的可以忽略).

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String username = request.getQueryParams().getFirst("username");

        if (!"admin".equals(username)){
            System.out.println("认证失败");
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
8 限流设计及实现 限流简述

网关是所有外部请求的公共入口,所以可以在网关进行限流,而且限流的方式也很多,我们采用Sentinel组件来实现网关的限流。Sentinel支持对SpringCloud Gateway、Zuul等主流网关进行限流。参考网址如下:


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



    com.alibaba.cloud
    spring-cloud-alibaba-sentinel-gateway



启动时,添加sentinel的jvm参数,通过此菜单可以让网关服务在sentinel控制台显示不一样的菜单,代码如下。

-Dcsp.sentinel.app.type=1



自定义API维度限流(重点)

自定义API分组,是一种更细粒度的限流规则定义,它允许我们利用sentinel提供的API,将请求路径进行分组,然后在组上设置限流规则即可。


定制流控网关返回值

定义配置类,设计流控返回值,代码如下:

@Component
public class GatewayConfig {
    public GatewayConfig(){
        GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
            @Override
            public Mono handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                Map map=new HashMap<>();
                map.put("state",429);
                map.put("message","two many request");
                String jsonStr = JSON.toJSONString(map);//序列化
                return ServerResponse.ok().body(Mono.just(jsonStr), String.class);
            }
        });
    }

}

其中,Mono 是一个发出(emit)0-1个元素的Publisher对象。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5684588.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存