第二十二章 alibaba sentinel详解-sentinel持久化

发布于:2022-11-09 ⋅ 阅读:(11) ⋅ 点赞:(0) ⋅ 评论:(0)

目录

一、持久化方式

二、持久化步骤

第一步:引入依赖

第二步:编辑配置文件

第三步:在nacos中配置规则

三、持久化原理

1、持久化接口

2、抽象类

3、案例操作


一、持久化方式

        直接使用dashboard和sentinel配置各种规则时,默认是存在了内存直接使用dashboard和sentinel配置各种规则时,默认是存在了内存中。如果服务器重启那么数据就会丢失,从而Sentinel提供了5中持久化的方式,将各种配置数据进行持久化,若服务器重启就重新加载持久化的数据,防止数据丢失。

        目前 Sentinel 中默认实现了5种规则持久化的方式,分别是:file、redis、nacos、zk和apollo。 可以在 sentinel 控制台中编辑 限流配置,并且同步到 nacos 做持久化。在 nacos 中修改了限流配置,也可以同步到 sentinel 控制台。

二、持久化步骤

   对sentinel中的配置进行持久化需要三步:

第一步:引入依赖


<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.2.1.RELEASE</version>
</dependency>

<!-- 引入 sentinel 持久化到 nacos 中的依赖 -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <version>1.7.2</version>
</dependency>

第二步:编辑配置文件

server:
  port: 9000

spring:
  application:
    name: ORDER-SERVICE-COSTUMER
  cloud:
    #配置 nacos server 注册中心总的地址
    nacos:
      server-addr: localhost:8848 # 配置nacos server 注册中心地址

    sentinel:
      enabled: true #开启sentinel保护
      transport:
        dashboard: localhost:8080 #配置连接到 dashboard 的web的地址
        port: 8719 #指定sentinel组件与 sentinel dashboard的TCP通信地址192.168.56.21:8719
      datasource:
        ds1:  # 这个名字任意起
          naccs:
            server-addr: localhost:8848 # 配置nacos server 注册中心地址
            dataId: ${spring.application.name}  # 和nacos中保持对应
            groupId: DEFAULT_GROUP # 和 nacos中保持对应
            data-type: json  # 规则类型:流控
            rule-type: flow  # 对于 nacos 数据类型

第三步:在nacos中配置规则

以资源进行限流为案例。

[

   {

       "resource": "/order/buy/{id}",  #保护的资源

       "limitApp": "default",  #来源应用

       "grade": 0,  #阈值线程数 0表示阈值,1表示线程数

       "count": 1,  # 单机阈值

       "strategy": 0,  # 流控模式 0表示直接 1表示关联 2表示链路

       "controlBehavior": 0,  #0表示快速失败 1表示预热 2表示排队等待

       "clusterMode": false  #是否是集群

   }

]

对应 sentinel中的规则如下图

三、持久化原理

image.png

1、持久化接口

         Sentinel 为我们提供了两个接口来实现规则的持久化,他们分别是:ReadableDataSource 和 WritableDataSource。其中主要关注ReadableDataSource。 

public interface ReadableDataSource<S, T> {
	//将原始数据转换成我们所需的格式
    T loadConfig() throws Exception;
	//从数据源中读取原始的数据
    S readSource() throws Exception;
	//获取该种数据源的SentinelProperty对象,数据变化监听器
    SentinelProperty<T> getProperty();
}

2、抽象类

       Sentinel 还为我们提供了一个抽象类:AbstractDataSource,该抽象类中实现了两个方法,具体的数据源实现类只需要实现一个 readSource 方法即可。

public abstract class AbstractDataSource<S, T> implements ReadableDataSource<S, T> {
	// Converter接口负责转换数据
    protected final Converter<S, T> parser;
    //SentinelProperty接口负责触发PropertyListener的configUpdate方法的回调
    protected final SentinelProperty<T> property;

    public AbstractDataSource(Converter<S, T> parser) {
        if (parser == null) {
            throw new IllegalArgumentException("parser can't be null");
        }
        this.parser = parser;
        this.property = new DynamicSentinelProperty<T>();
    }

    @Override
    public T loadConfig() throws Exception {
        return loadConfig(readSource());
    }

    public T loadConfig(S conf) throws Exception {
        T value = parser.convert(conf);
        return value;
    }

    @Override
    public SentinelProperty<T> getProperty() {
        return property;
    }
}

实际上每个具体的DataSource主要要做三件事情:

  • 实现 readSource 方法将数据源中的原始数据转换成我们可以处理的数据S
  • 提供一个 Converter 来将数据S转换成最终的数据T
  • 将最终的数据T更新到具体的 RuleManager 中去。

3、案例操作

以Redis做持久化数据源为例。

public RedisDataSource(RedisConnectionConfig connectionConfig, String ruleKey, String channel,
                           Converter<String, T> parser) {
    super(parser);
    this.redisClient = getRedisClient(connectionConfig);
    this.ruleKey = ruleKey;
    //从Redis中加载原数据
    loadInitialConfig();
}


private void loadInitialConfig() {
    try {
        //调用AbstractDatasource的方法,父类会调用readSource方法获得原数据
        T newValue = loadConfig();
       	//将加载的到的数据,通过监听器更新规则的数据
        getProperty().updateValue(newValue);
    } catch (Exception ex) {
        RecordLog.warn("[RedisDataSource] Error when loading initial config", ex);
    }
}

@Override
public String readSource() {
    RedisCommands<String, String> stringRedisCommands = redisClient.connect().sync();
    return stringRedisCommands.get(ruleKey);
}