Sentinel 使用 Nacos 持久化流控规则

发布时间 2023-11-07 20:46:20作者: 乔京飞

早期大家都使用 netflix 公司的 Hystrix 组件,通过编写代码实现对微服务接口的限流、熔断、隔离等保护措施,由于 Hystrix 组件不再更新迭代,逐渐被大家抛弃。当前大家基本上都使用阿里的 Sentinel 技术实现对微服务接口的访问监控和保护,其最大的优点就在于基本上不需要编代码,只需要通过图形化界面进行配置,就可以实现对微服务接口的监控和保护,实在是太方便了。

Sentinel 默认情况下,配置的规则都是存储在微服务的内存中,一旦微服务重启,配置的规则就会丢失。我们常用的微服务保护规则主要是限流规则,本篇博客主要采用官方已经实现的代码,实现 Nacos 作为限流规则的存储。也就是说通过 Sentinel 的 Dashboard 界面配置限流规则,将限流规则存储到 Nacos 中,相应的微服务从 Nacos 中读取限流规则。这样无论 Nacos 重启以及微服务重启,所设置的流控规则都不会丢失。

Sentinel 的官网地址:https://sentinelguard.io/zh-cn/index.html


一、下载源码

Sentinel 的源码下载地址为:https://github.com/alibaba/Sentinel/releases

如果你的 GitHub 网站打不开,建议你下载 Watt Toolkit 加速器,非常好用。

Watt Toolkit 加速器的下载地址为:https://steampp.net/download

image

只要在加速器上,勾选 GitHub 然后点击【一键加速】,你就可以在任何时候轻松打开 GitHub,非常好用。

访问 Sentinel 的 GitHub 网站,目前我能够看到的最新稳定版本是 1.8.6,如下所示:

image

Sentinel-dashboard-1.8.6.jar 是官网打包好的 jar 包,仅支持规则存储在内存中。我们需要下载的是 zip 源码包,然后进行解压缩,使用 IDEA 进行打开就能看到 Sentinel 的源代码,我们需要修改的是 sentinel-dashboard 模块的源码,如下图所示:

image


二、修改源码

打开 sentinel-dashboard 模块的 pom 文件,找到 sentinel-datasource-nacos 依赖包:

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <!--<scope>test</scope>-->
</dependency>

默认情况下,其 scope 是 test,删掉或者注释掉 scope 配置,如上所示。

在 sentinel-dashboard 的 test 下面 rule 包下,官方已经编写了 nacos、apollo 等对限流规则持久化存储的支持。

image

我们使用的是 Nacos 进行持久化存储,因此我们只需要把 nacos 包下的内容,拷贝到 main 下的 rule 包下即可,如下图所示:

image

然后打开 NacosConfig 类,将其内容修改成如下结果:

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.config.ConfigFactory;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;

@Configuration
public class NacosConfig {

    //配置的 nacos 地址,如果配置文件没有找到配置,则使用默认的localhost
    @Value("${nacos.addr:localhost}")
    private String addr;

    @Bean
    public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
        return JSON::toJSONString;
    }

    @Bean
    public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
        return s -> JSON.parseArray(s, FlowRuleEntity.class);
    }

    @Bean
    public ConfigService nacosConfigService() throws Exception {
        return ConfigFactory.createConfigService(addr);
    }
}

我们使用 addr 私有变量,从配置文件中读取 nacos.addr 配置内容(该配置内容需要配置 nacos 的连接地址),如果配置文件中没有找到 nacos.addr 配置节,则使用默认的 localhost 内容作为配置值。当然你也可以在 application.properties 文件中增加上 nacos.addr 配置内容。其实加不加都无所谓,因为我们在 addr 使用配置表达式中指定的有默认值。

在 application.properties 文件中,你可以发现:

  • Sentinel Dashboard 服务没有端口配置,因此服务启动后使用的就是 SpringBoot 默认的 8080 端口
  • Sentinel Dashboard 中 auth.username 和 auth.password 都是 sentinel ,这里配置的是登录的用户名和密码

然后打开 controller 下面 v2 包下面的 FlowControllerV2 类,如下图所示:

image

将 ruleProvider 变量上面的 @Qualifier 值修改为 flowRuleNacosProvider

将 rulePublisher 变量上面的 @Qualifier 值修改为 flowRuleNacosPublisher

@Autowired
@Qualifier("flowRuleNacosProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;

@Autowired
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;

最后打开 webapp 下的 sidebar.html 静态页面,如下图所示:

image

找到如下注释内容:

<!--<li ui-sref-active="active" ng-if="entry.appType==0">
    <a ui-sref="dashboard.flow({app: entry.app})">
    	<i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;流控规则-V1</a>
</li>-->

取消注释,为了区分普通的流控规则菜单,此处可以修改一下菜单的名称,如下所示:

<li ui-sref-active="active" ng-if="entry.appType==0">
    <a ui-sref="dashboard.flow({app: entry.app})">
        <i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;流控规则Nacos</a>
</li>

OK,经过以上步骤,就完成了修改,我们对 sentinel-dashboard 模块进行清理并打包

image

然后在 sentinel-dashboard 模块的 targart 目录下,就能够找到打包好的最新 jar 包:

image


三、部署 Sentinel 包

我将打包好的最新 sentinel-dashboard.jar 部署到虚拟机上,方便后续使用。

我的虚拟机是 CentOS7(ip 地址是 192.168.136.128),并且已经部署好了单机版的 nacos(有关 nacos 的部署,可以参考我之前的博客),nacos 的访问地址是 http://192.168.136.128:8848/nacos,当然这里部署的 nacos 是不需要验证用户名和密码的。

我创建一个目录 mkdir -p /app/sentinel ,把 jar 包上传到这个目录中。

在 /etc/systemd/system 下,新建一个 sentinel.service 文件,内容填写如下:

[Unit]
Description=sentinel 
After=syslog.target network.target

[Service]
Type=simple

#注意:ExecStart 后面的命令脚本都是写在一行中,没有手动进行换行,只是横向空间不够,自动换行了
ExecStart=/app/jdk1.8/bin/java -jar -Dnacos.addr=192.168.136.128:8848 /app/sentinel/sentinel-dashboard.jar
ExecStop=/bin/kill -15 $MAINPID 
 
User=root
Group=root 
 
[Install]
WantedBy=multi-user.target

注意:由于我的 jdk 安装路径在 /app/jdk1.8 中,所以 java 命令在 /app/jdk1.8/bin 目录下,你可以根据自己的 jdk 安装路径进行调整。另外在启动 sentinel-dashboard.jar 时,可以通过 -D 指定参数,这里使用 -Dnacos.addr=192.168.136.128:8848 指定了 nacos 的连接地址,当然你也可以通过 -D 指定 sentinel dashboard 界面登录的用户名和密码,如 -Dauth.username=xxx 和 -Dauth.password=xxx(注意 -D 和参数之间没有空格)

然后运行一下命令,启动服务,以及将服务设置为开机自动启动,服务名称就是文件名称,其中 .service 可以省略。

# 修改了服务文件后,需要执行此命令
systemctl daemon-reload

# 启动服务
# 服务的名称,就是文件的名称,因为新建的文件名称是 sentinel.service
# 服务的名称中 .service 可以省略
systemctl start sentinel

# 将服务设置为开机自动启动
systemctl enable sentinel

最后访问 http://192.168.138.128:8080 即可看到 sentinel dashboard 的登录页面:

image

使用默认的用户名和密码,都是 sentinel 登录进去:

image

在没有监控微服务接口的情况下,登录进入什么都没有。

我提前开发好了一个 Demo ,配置了使用 sentinel 进行监控请求,效果如下所示:

image

可以看到左侧菜单中,出现了被监控的微服务:consumer-app 和 provider-app

每个微服务中,都有我们修改源码后的菜单:流控规则Nacos,在该菜单中设置的流控规则,会持久化存储到 Nacos 中,Nacos 重启以及被监控的微服务重启都不会丢失。直接在每个请求后面的流控按钮中设置的流控规则,存储被监控的微服务内存中,微服务重启后会丢失。

对于微服务来说,要想被 sentinel 监控请求,以及将设置的流控规则,存储到 Nacos 中,需要引入下面的依赖包:

<!--引入 sentinel 依赖包-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--使用官方的示例代码改造的 sentinel 可将限流配置保存到 nacos 中,
    引入该依赖包,可以是微服务从 nacos 中读取限流配置-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

以 consumer-app 微服务来说,还需要在 application.yml 中配置如下内容:

spring:
  application:
    name: consumer-app
  cloud:
    nacos:
      server-addr: 192.168.136.128:8848
    sentinel:
      transport:
        dashboard: 192.168.136.128:8080
      datasource:
        flow:
          nacos:
            server-addr: 192.168.136.128:8848
            dataId: consumer-app-flow-rules
            groupId: sentinel-group
            rule-type: flow
      # Sentinel 默认会对资源请求链路进行整合,这样会导致流控模式中的链路模式无法使用
      # 因此需要关闭 context 整合,这样 sentinel 监控界面会单独展示出每种链路请求路径
      web-context-unify: false

feign:
  sentinel:
    # 开启 feign 对 sentinel 的支持,允许 sentinel 监控 feign 的调用请求
    enabled: true

这里先把 Demo 的源代码提供出来,由于篇幅有限,下篇博客再详细介绍 Demo 源代码实现的功能:

源代码下载地址为:https://files.cnblogs.com/files/blogs/699532/springcloud_sentinel.zip