目录

代码随记 SpringBoot Sentinel 服务保护

系列 - 代码随记

雪崩问题:当多个为微服务需要调用某个微服务时,某个微服务崩溃会导致血崩 ,所有微服务不可用。 解决方案:请求限流,线程隔离(限制每个服务可使用的线程数量)。

java -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

http://localhost:8090/#/login

<!--sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId> 
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
spring:
  cloud: 
    sentinel:
      transport:
        dashboard: localhost:8090
      http-method-specify: true # 开启请求方式前缀

请求限流:限制请求的QPS,但是这并不能解决问题。 线程隔离:按需分配线程资源,例如其他业务分配10线程,查询购物车分配20线程,假如查询购物车崩溃了,也不会影响其他业务。

服务熔断:通过上面设置限流后,正常查询20ms的,在多线程并发查询下需要500ms,我们希望 当被限流后直接返回null, 而不是继续等待, 从而保持 20ms 的返回

在API中定义

package com.hmall.api.client.fallback;

import com.hmall.api.client.ItemClient;
import com.hmall.api.dto.ItemDTO;
import com.hmall.api.dto.OrderDetailDTO;
import com.hmall.common.exception.BizIllegalException;
import com.hmall.common.utils.CollUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;

import java.util.Collection;
import java.util.List;

@Slf4j
public class ItemClientFallback implements FallbackFactory<ItemClient> {
    @Override
    public ItemClient create(Throwable cause) {
        return new ItemClient() {
            @Override
            public List<ItemDTO> queryItemByIds(Collection<Long> ids) {
                log.error("远程调用ItemClient#queryItemByIds方法出现异常,参数:{}", ids, cause);
                // 查询购物车允许失败,查询失败,返回空集合
                return CollUtils.emptyList();
            }

            @Override
            public void deductStock(List<OrderDetailDTO> items) {
                // 库存扣减业务需要触发事务回滚,查询失败,抛出异常
                throw new BizIllegalException(cause);
            }
        };
    }
}

再去CONFIG中注册 Bean

public class DefaultFeignConfig {
    ...
    @Bean
    public ItemClientFallback itemClientFallback() {
        return new ItemClientFallback();
    }
}

在接口中调用

@FeignClient(value = "item-service", fallbackFactory = ItemClientFallback.class)  
public interface ItemClient {  
    @GetMapping("/items")  
    List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);  
  
    @PutMapping("/items/stock/deduct")  
    void deductStock(@RequestBody List<OrderDetailDTO> items);  
}

Seata

  • 三个重要角色
    • TC 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚
    • TM 事务管理:定义全局事务的范围、开始全局事务、提交或回滚全局事务
      • 定位回滚的范围,在什么时候
    • RM 资源管理器:管理分支事务,与TC交谈以注册分支事务和报告分支事务的状态
<!--统一配置管理-->
  <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  </dependency>
  <!--读取bootstrap文件-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-bootstrap</artifactId>
  </dependency>
  <!--seata-->
  <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
  </dependency>
seata:
  registry: # TC服务注册中心的配置,微服务根据这些信息去注册中心获取tc服务地址
    type: nacos # 注册中心类型 nacos
    nacos:
      server-addr: 127.0.0.1:8848 # nacos地址
      namespace: "" # namespace,默认为空
      group: DEFAULT_GROUP # 分组,默认是DEFAULT_GROUP
      application: seata-server # seata服务名称
      username: nacos
      password: nacos
  tx-service-group: hmall # 事务组名称
  service:
    vgroup-mapping: # 事务组与tc集群的映射关系
      hmall: "default"

有个坑,SEATA_IP 一定要填IP地址,不然他就报错

  seata:
    image: seataio/seata-server:1.5.2
    container_name: seata
    environment:
      - SEATA_IP=192.168.3.4   # 这里写宿主机局域网IP
      - SEATA_PORT=8099
    volumes:
      - ./seata:/seata-server/resources
    ports:
      - 8099:8099
      - 7099:7099
    restart: unless-stopped

全局事务锁的一种

seata:
  data-source-proxy-mode: XA

然后添加 @GlobalTransactional 就可以了

  • 流程
    • 每个TM下的微服务
    • 1、执行所有SQL
    • 2、报告事务状态状态
    • 然后 TC 等待所有微服务的状态
    • 最后微信服务分别自行提交

缺点是需要事务等待所有服务缺点通过后,才会提交,导致表会一直锁。

XA模式的优点是什么?

  • 事务的强一致性,满足ACID原则
  • 常用数据库都支持,实现简单,并且没有代码侵入

XA模式的缺点是什么?

  • 因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差
  • 依赖关系型数据库实现事务

和XA模式不同点在于,先记录undo-log记录数据快找,然后再执行SQL并且直接提交

简述AT模式与XA模式最大的区别是什么?

  • XA模式一阶段不提交事务,锁定资源;AT模式一阶段直接提交,不锁定资源。
  • XA模式依赖数据库机制实现回滚;AT模式利用数据快照实现数据回滚。
  • XA模式强一致;AT模式最终一致

可见,AT模式使用起来更加简单,无业务侵入,性能更好。因此企业90%的分布式事务都可以用AT模式来解决。