SpringCloudAlibaba初步了解

SpringCloudAlibaba

Spring Boot -> Spring Cloud -> Spring Cloud Alibaba

版本说明

地址

服务治理

Nacos

点击到对应版本的spring cloud alibaba的版本 查看对应的nacus中去githup查看对应的版本

  • 服务注册

    • 配置spring.cloud.nacos.discovery.server-addr:地址
    • 在启动类上开启注解 @EnableDiscoveryClient
  • 服务发现

    • 开启注解 @EnableDiscoveryClient

    • 获取所有的服务

      • 通过discoveryClient和服务Id获取所有的serviceInstance,然后通过自己的策略获取单个实例,然后调用服务
    • 负载均衡获取

      • loadBalancerClient.choose(服务Id)
    • 获取成功之后在通过服务调用框架调用

服务调用

RestTemplate

  • 需要初始化RestTemplate,Spring容器中默认没有该实例,Ribbon的调用基于RestTemplate

Ribbon

  • 定义

    • 不是spring cloud alibaba 的组件,是nexfix提供的组件
  • 负载均衡

    • 提供了七种算法

    • 常用算法

      • 默认采用轮询的算法

      • 随机算法

        • 全局配置

          • 注册对应的bean进入pring容器 RandomRule
        • 针对单个服务

          • 在消费的配置文件中添加

            • ${服务Id}.ribbon.NFLoadBalancerRuleClassName:com.netflix.loadbancer.RandomRule
      • 基于权重的算法

        • 全局配置

          • 1.继承AbstractLoadBalanceRule 重写choose方法
          • 2.注册对应的bean进入pring容器 重写的类
        • 针对单个服务

          • 1.继承AbstractLoadBalanceRule 重写choose方法
          • 2.修改消费服务的配置文件 ${服务Id}.ribbon.NFLoadBalancerRuleClassName:指定class的路径
    • 注意

      • 在RestTemplate的创建配置中添加@loadBalanced
      • 不加@loadBalanced就不能通过http://服务名/调用后缀 查找

熔断器

解决的问题

  • 雪崩效应:有一个服务错误导致其他服务调用该服务时一直处于阻塞状态,进而导致其他服务也处于阻塞状态,引起服务器资源被占满导致的服务瘫痪。

解决办法

  • 设置线程超时
  • 设置限流
  • 熔断器 Sentinel、Hystrix

Sentinel

  • 详细步骤

    • 依赖引入

      com.alibaba.cloud spring-cloud-starter-alibaba-sentinel org.springframework.boot spring-boot-starter-actuator
      • spring-cloud-starter-alibaba-sentinel
      • spring-boot-starter-actuator
    • 开放接口权限

      • management.endpoints.web.exposure.include: ‘*’
    • 配置sentinel控制台

      • spring.cloud.sentinel.transport.dashbord: 控制台项目地址
  • 流控规则

    • 流控模式

      • 直接限流

        • 超过阈值(QPS)后不可用
      • 关联限流

        • 与之关联的资源超过阈值(QPS)后,这个资源不可用, a 关联 b ,b超过阈值 则a不可用
      • 链路限流

        • 1.通过@SentinelResource(“资源名字”) 来标识
        • 2.流控对应的标注资源然后设置阈值和入口资源,则通过入口资源路径进入的请求超过阈值后会被限流
        • 注意:1.6.3版本以上的sentinel 默认收敛所有的url入口 导致链路限流不生效,需要手动去开启收敛,1.7.0以上的版本官方提供了参数配置是否收敛,需要导入 sentinel-core 和 sentinel-web-servlet,来关闭收敛,还需要写一个配置类
    • 流控效果

      • 快速失败

        • 直接返回错误界面
      • Warm up(预热等待)

        • 在预热时长内 阈值为设置的1/3
      • 排队等待

        • 第一次请求失败后,不会直接返回错误界面,会在设置的超时时间过后再次请求,如果成功则返回成功结果,失败则返回错误界面
  • 降级规则

    • 降级策略

      • RT

        • 单个请求的响应时间超过阈值,则进入准降级状态,接下来 1 S 内连续 5 个请求响应时间均超过阈值,就进行降级,持续时间为时间窗口的值。
      • 异常比例

        • 每秒异常数量占通过量的比例大于阈值,就进行降级处理,持续时间为时间窗口的值。
      • 异常数

        • 1 分钟内的异常数超过阈值就进行降级处理,时间窗口的值要大于 60S,否则刚结束熔断又进入下一次熔断了。
  • 热点规则

    • 定义

      • 热点规则是流控规则的更细粒度操作,可以具体到对某个热点参数的限流,设置限流之后,如果带着限流参数的请求量超过阈值,则进行限流,时间为统计窗口时长。
    • 注意

      • 必须要添加 @SentinelResource,即对资源进行流控。
  • 授权规则

    • 定义

      • 给指定的资源设置流控应用(追加参数),可以对流控应用进行访问权限的设置,具体就是添加白名单和黑名单。

      • 如何给请求指定流控应用,通过实现 RequestOriginParser 接口来完成

        import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
        import org.springframework.util.StringUtils;

        import javax.servlet.http.HttpServletRequest;

        public class RequestOriginParserDefinition implements RequestOriginParser {
        @Override
        public String parseOrigin(HttpServletRequest httpServletRequest) {
        String name = httpServletRequest.getParameter(“name”);
        if(StringUtils.isEmpty(name)){
        throw new RuntimeException(“name is null”);
        }
        return name;
        }
        }

      • 要让 RequestOriginParserDefinition 生效,需要在配置类中进行配置。

        import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
        import org.springframework.context.annotation.Configuration;

        import javax.annotation.PostConstruct;

        @Configuration
        public class SentinelConfiguration {

        @PostConstruct
        public void init(){
        WebCallbackManager.setRequestOriginParser(new RequestOriginParserDefinition());
        }
        }

  • 自定义规则异常返回

    • 分类

      • 限流的异常处理 FlowException
      • 降级的异常处理 DegradeException
    • 步骤

      • 实现 UrlBlockHandler

        import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
        import com.alibaba.csp.sentinel.slots.block.BlockException;
        import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
        import com.alibaba.csp.sentinel.slots.block.flow.FlowException;

        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;
        import java.io.IOException;

        public class ExceptionHandler implements UrlBlockHandler {
        @Override
        public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException {
        httpServletResponse.setContentType(“text/html;charset=utf-8”);
        String msg = null;
        if(e instanceof FlowException){
        msg = “限流”;
        }else if(e instanceof DegradeException){
        msg = “降级”;
        }
        httpServletResponse.getWriter().write(msg);
        }
        }

      • 配置 WebCallbackManager.setUrlBlockHandler(自定义异常处理类);

        @Configuration
        public class SentinelConfiguration {

        @PostConstruct
        public void init(){
        WebCallbackManager.setUrlBlockHandler(new ExceptionHandler());
        }
        }

常用消息中间件

ActiveMQ , RabbitMQ ,RocketMQ ,Kafka

服务网关

Zuul

  • 第一代网关 Netflix公司提供的

spring-cloud-gateWay

  • 定义

    • 第二代网关,Spring官方提供的,基于netty实现的,所以工程中不能出现Servlet的组件
  • 路由映射

    • 通过配置路由来映射地址

      • 步骤

        • 1.引入spring.cloud.starter-getway

        • 2.配置spring.cloud.gateway.discovery.locator.enabled=true

          • 是否与服务发现组件进行结合,通过 serviceId 转发到具体的服务实例。默认为false,设为true便开启通过服务中心的自动根据 serviceId 创建路由的功能。
        • 3.配置路由映射

          spring:
          cloud:
          gateway:
          routes:
          #服务ID,自定义
          - id: provider_route
          #映射路径
          uri: http://localhost:8081
          #访问的服务前缀
          predicates:
          - Path=/provider/**
          #忽略真实访问的前缀个数
          filters:
          - StripPrefix=1

    • 注册到nacos来映射地址

      • 步骤

        • 1.引入spring.cloud.starter-getway
        • 2.引入spring-cloud-starter-alibaba-nacos-discovery
        • 3.配置spring.cloud.gateway.discovery.locator.enabled=true
  • 限流

    • 路由限流

      • 步骤

        • 1.引入spring-cloud-starter-gateway

        • 2.引入sentinel和gataway的适配依赖 sentinel-spring-cloud-gateway-adapter

        • 3.定义网关的配置类

          import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
          import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
          import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
          import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
          import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
          import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
          import org.springframework.beans.factory.ObjectProvider;
          import org.springframework.cloud.gateway.filter.GlobalFilter;
          import org.springframework.context.annotation.Bean;
          import org.springframework.context.annotation.Configuration;
          import org.springframework.core.Ordered;
          import org.springframework.core.annotation.Order;
          import org.springframework.http.HttpStatus;
          import org.springframework.http.MediaType;
          import org.springframework.http.codec.ServerCodecConfigurer;
          import org.springframework.web.reactive.function.BodyInserters;
          import org.springframework.web.reactive.function.server.ServerResponse;
          import org.springframework.web.reactive.result.view.ViewResolver;
          import org.springframework.web.server.ServerWebExchange;
          import reactor.core.publisher.Mono;

          import javax.annotation.PostConstruct;
          import java.util.*;

          @Configuration
          public class GatewayConfiguration {
          private final List viewResolvers;
          private final ServerCodecConfigurer serverCodecConfigurer;

          public GatewayConfiguration(ObjectProvider<List> viewResolversProvider,
          ServerCodecConfigurer serverCodecConfigurer) {
          this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
          this.serverCodecConfigurer = serverCodecConfigurer;
          }

          //配置限流的异常处理
          @Bean
          @Order(Ordered.HIGHEST_PRECEDENCE)
          public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
          return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
          }

          //配置初始化的限流参数
          @PostConstruct
          public void initGatewayRules(){
          Set rules = new HashSet<>();
          rules.add(
          new GatewayFlowRule(“provider_route”)
          .setCount(1)
          .setIntervalSec(1)
          );
          GatewayRuleManager.loadRules(rules);
          }

          //初始化限流过滤器
          @Bean
          @Order(Ordered.HIGHEST_PRECEDENCE)
          public GlobalFilter sentinelGatewayFilter() {
          return new SentinelGatewayFilter();
          }

          //自定义限流异常页面
          @PostConstruct
          public void initBlockHandlers(){
          BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
          @Override
          public Mono handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
          Map map = new HashMap();
          map.put(“code”,0);
          map.put(“msg”,“被限流了”);
          return ServerResponse.status(HttpStatus.OK)
          .contentType(MediaType.APPLICATION_JSON)
          .body(BodyInserters.fromObject(map));
          }
          };
          GatewayCallbackManager.setBlockHandler(blockRequestHandler);
          }
          }

          • 配置限流的异常处理
          • 配置初始化的限流参数
          • 初始化限流过滤器
          • 自定义限流异常返回
        • 4.配置路由映射配置

          server:
          port: 8010
          spring:
          application:
          name: gateway
          cloud:
          gateway:
          discovery:
          locator:
          enabled: true
          routes:
          - id: provider_route
          uri: http://localhost:8081
          predicates:
          - Path=/provider/**
          filters:
          - StripPrefix=1

    • API分组限流

      • 步骤

        • 1.引入依赖

          • spring-cloud-starter-gateway

            • 网关服务
          • spring-cloud-starter-alibaba-nacos-descovery

            • nacos服务
          • sentinel-spring-cloud-gateway-adpter

            • sentinel和gateway的适配器
        • 2.修改路由限流的配置类

          import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
          import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
          import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
          import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
          import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
          import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
          import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
          import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
          import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
          import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
          import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
          import org.springframework.beans.factory.ObjectProvider;
          import org.springframework.cloud.gateway.filter.GlobalFilter;
          import org.springframework.context.annotation.Bean;
          import org.springframework.context.annotation.Configuration;
          import org.springframework.core.Ordered;
          import org.springframework.core.annotation.Order;
          import org.springframework.http.HttpStatus;
          import org.springframework.http.MediaType;
          import org.springframework.http.codec.ServerCodecConfigurer;
          import org.springframework.web.reactive.function.BodyInserters;
          import org.springframework.web.reactive.function.server.ServerResponse;
          import org.springframework.web.reactive.result.view.ViewResolver;
          import org.springframework.web.server.ServerWebExchange;
          import reactor.core.publisher.Mono;

          import javax.annotation.PostConstruct;
          import java.util.*;

          @Configuration
          public class GatewayConfiguration {

          private final List viewResolvers;
          private final ServerCodecConfigurer serverCodecConfigurer;

          public GatewayConfiguration(ObjectProvider<List> viewResolversProvider,
          ServerCodecConfigurer serverCodecConfigurer) {
          this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
          this.serverCodecConfigurer = serverCodecConfigurer;
          }

          //配置限流的异常处理
          @Bean
          @Order(Ordered.HIGHEST_PRECEDENCE)
          public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
          return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
          }

          //配置初始化的限流参数
          @PostConstruct
          public void initGatewayRules(){
          Set rules = new HashSet<>();
          rules.add(new GatewayFlowRule(“provider_api1”).setCount(1).setIntervalSec(1));
          rules.add(new GatewayFlowRule(“provider_api2”).setCount(1).setIntervalSec(1));
          GatewayRuleManager.loadRules(rules);
          }

          //初始化限流过滤器
          @Bean
          @Order(Ordered.HIGHEST_PRECEDENCE)
          public GlobalFilter sentinelGatewayFilter() {
          return new SentinelGatewayFilter();
          }

          //自定义限流异常页面
          @PostConstruct
          public void initBlockHandlers(){
          BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
          @Override
          public Mono handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
          Map map = new HashMap();
          map.put(“code”,0);
          map.put(“msg”,“被限流了”);
          return ServerResponse.status(HttpStatus.OK)
          .contentType(MediaType.APPLICATION_JSON)
          .body(BodyInserters.fromObject(map));
          }
          };
          GatewayCallbackManager.setBlockHandler(blockRequestHandler);
          }

          //自定义API分组
          @PostConstruct
          private void initCustomizedApis(){
          Set definitions = new HashSet<>();
          ApiDefinition api1 = new ApiDefinition(“provider_api1”)
          .setPredicateItems(new HashSet(){{
          add(new ApiPathPredicateItem().setPattern("/provider/api1/**")
          .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
          }});
          ApiDefinition api2 = new ApiDefinition(“provider_api2”)
          .setPredicateItems(new HashSet(){{
          add(new ApiPathPredicateItem().setPattern("/provider/api2/demo1"));
          }});
          definitions.add(api1);
          definitions.add(api2);
          GatewayApiDefinitionManager.loadApiDefinitions(definitions);
          }
          }

          • 添加基于 API 分组限流的方法
          • 修改初始化的限流参数
        • 3.开启服务发现的配置

          • spring.cloud.gateway.discovery.locator.enabled=true
        • 4.controller的服务请求路径前缀添加

          @GetMapping("/api1/demo1")
          public String demo1(){
          return “demo”;
          }

          @GetMapping("/api1/demo2")
          public String demo2(){
          return “demo”;
          }

          @GetMapping("/api2/demo1")
          public String demo3(){
          return “demo”;
          }

          @GetMapping("/api2/demo2")
          public String demo4(){
          return “demo”;
          }

        • 4.注意

          • 如果服务提供方的serverId发生变化,我们也因该改为 discovery 中的服务名。
    • 注意

      • 都是针对网关层面的限流,并未像sentinel一样针对的是服务本身
  • 注意

    • 一定不能出现 spring web 的依赖,因为 Gateway 与 Servlet 不兼容。

分布式事务

分布式事务需要考虑的事情

  • 业务侵入性(基于注解、XML,补偿逻辑)
  • 隔离性(写隔离/读隔离/读未提交,业务隔离/技术隔离)
  • TM/TC部署形态(单独部署、与应用部署一起)
  • 错误恢复(自动恢复、手动恢复)
  • 性能(回滚的概率、付出的代价,响应时间、吞吐)
  • 高可用(注册中心、数据库)
  • 持久化(数据库、文件、多副本一致算法)
  • 同步/异步(2PC执行方式)
  • 日志清理(自动、手动)

好的分布式事务宽假应用尽可能具备的特性

  • 1.业务改造成本低
  • 2.性能损耗低
  • 3.隔离性保证完整

Seata

  • 定义

    • 阿里提供的分布式解决方案
  • 整体情况

    • 文档地址

      • http://seata.io/zh-cn/
    • 优点

      • 业务少感知
      • DB操作简单
    • 缺点

      • 响应时间长
      • DB写操作较多
      • 调用链较长
    • 特性

      • 业务改造成本低
      • 隔离性保证完整
  • 模式

    • AT模式

      • 前提

        • 基于支持本地 ACID 事务的关系型数据库。
        • Java 应用,通过 JDBC 访问数据库。
      • 整体机制

        • 一阶段:

          • 业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
        • 二阶段:

          • 提交异步化,非常快速地完成。
          • 回滚通过一阶段的回滚日志进行反向补偿。
    • TCC模式

    • Saga模式

Saga

  • 特性

    • 业务改造成本低
    • 性能损耗低

TCC

  • 特性

    • 性能损耗低
    • 隔离性保证完整
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值