乐趣区

Sentinelsentinel-集成-apollo-最佳实践

【Sentinel】sentinel 集成 apollo 最佳实践

前言

  在 sentinel 的控制台设置的规则信息默认都是存在内存当中的。所以无论你是重启了 sentinel 的客户端还是 sentinel 的控制台。你所设置的规则都会丢失。如果想要 sentinel 在线上环境使用,要么花钱用阿里云上的付费版本,要么自己去实现规则的持久化,如果你或你所在的公司不差钱,那么关掉这篇文章,直接用付费版吧,省掉了一大堆坑要踩。或者你是一个特立独行的人,那么我们接着往下说。
  首先说一下写这篇文章的原因,因为真得在与 apllo 集成时,踩坑踩到怀疑人生。另一点是,找了一大堆关于集成的 apollo 的文章,都清一色的都是仿照官方给的限流规则的 DEMO 做的。但是 sentinel 规则还有熔断规则、参数限流、系统限流、黑白名单等很多规则,每个规则还有细节上的不一致,这些都没有提,还有一些客户端的坑就更没有了。踩了这么多坑,有了一点心得与体会,梳理与此,希望能帮助到读者。

拉取 sentinel 控制台源码进行修改

  因为修改内容过多,本文不会详述,下面的截图是所有修改内容,并且因为写这篇文章时,1.7 版本在 master 开发,有大量快照版本。所以是切到当前稳定的 1.6 分支进行修改的。我已经 fork sentinel 到我的 github,下面是修改的内容 地址

修改点 1:实现所有规则的拉取与推送接口

  添加与实现了所有的规则的 Provider 与 Publisher 的配置拉取的与推送。

修改点 2:修改控制台使用的规则操作 api

规则在控制台的操作 controller 进行大量改造。

修改点 3:修改 xxEntity

  最后一点也是最坑的修改了大量的 xxEntity 类,这些类是规则的实体类,本身没什么,源码是直接 json 化保存的,但是用于客户端集成的 spring-cloud-alibaba 使用了 json 校验,如果 apollo 保存的 json 与客户端的实体类有一丁点不一样就报 convert 0 rules but there are 1 rules from datasource . RuleCLass: FlowRule。 是不是觉得很摸不着头脑,这报错跟 json 格式转换错误有什么,下面是 spring-cloud-alibaba json 转换的代码。

  写这段代码的老哥,把这个异常吃了,并补上了一个 // won’t be happen 的注释,你能理解我当时被这个报错坑的死去活来,后来发现是这里的问题吗?后来在 github 上找到两个同样的问题问题 1、问题 2,按照方法把 xxEntity 中用不到的字段全部加上 @JSONField(serialize = false) 解决。

修改点 4:抽离配置使得可以在启动的时传入

  添加的配置在下面

使用修改的控制台版本

  1. 你可以 fork sentinel 官方代码按上述的自行修改,然后打包
  2. 你可以拉取我 fork 的 sentinel 代码下来直接打包
  3. 你可以使用我已经打好的包 地址

自定义配置

配置名称 是否必填 默认值 作用
env DEV 指定 apollo 使用的环境
app.id sentinel-apollo 指定保存 sentinel 规则的 apollo 应用 ID
cluster.name default 指定保存 sentinel 使用的 apollo 集群
namespace.name application 指定保存 sentinel 使用的 apollo 命名空间
modify.user apollo 控制台显示的修改人账号,此账号务必要有此应用的权限
modify.comment modify by sentinel-dashboard apollo 控制台显示的修改备注
release.user apollo 控制台显示的发布人账号,此账号务必要有此应用的权限
release.comment release by sentinel-dashboard apollo 控制台显示的发布备注
apollo.portal.url  apollo 控制台的地址
apollo.application.token 指定保存 sentinel 规则的 apollo 应用 openapi 的 token
authority.key.suffix authority 认证规则保存在 apollo 中的 key 的后缀
degrade.key.suffix degrade 熔断规则保存在 apollo 中的 key 的后缀
flow.key.suffix flow 限流规则保存在 apollo 中的 key 的后缀
param.key.suffix param_flow 参数限流规则保存在 apollo 中的 key 的后缀
system.key.suffix system 系统限流规则保存在 apollo 中的 key 的后缀
auth.username sentinel sentinel 控制台的登录用户名
auth.password sentinel sentinel 控制台的登录密码
server.port 8080 sentinel 控制台的启动端口

Apollo 配置

创建用于保存 sentinel 的项目

  1. 点击创建项目按钮

  1. 输入项目信息

1. ** 应用 ID** 对应 上面表格中的 **app.id**
2. ** 应用负责人 ** 对应 上面表格中的 **modify.user** 和 **release.user**
  1. 创建一个公共命名空间

    1. 点击右下角添加 Namespace 按钮
![](https://image-static.segmentfault.com/374/694/3746942159-5d876f5fb6eae_articlex)
2. 创建 Namespace
![](https://image-static.segmentfault.com/264/649/2646495152-5d876f6069998_articlex)
    1. 名称对应上面表格中的 **namespace.name**,注意名称是要包含部门名的,这里脱敏了
    2. 类型一定要选择 public,原因后面会说
  1. 发布 Namespace

1. 私有的空间是不能被继承的,application 没有用,可以删除
    1. 这里的用意是我们独立出一个单独的用于保存规则的 apollo 应用,因为是公共的,所以其它 apollo 应用可以继承,这样对于已经集成 apollo 的项目来说,改动最小
    2. 注意红色的提示,我们建的公共空间要首先发布一次,否则 api 无法访问到
  1. 创建此项目的开放平台授权

    1. 点击右上角的 开放平台授权管理
![](https://image-static.segmentfault.com/334/163/3341632927-5d876f624f7f3_articlex)
2. 创建应用
![](https://image-static.segmentfault.com/325/514/3255145947-5d876f6318ff5_articlex)
    1. ** 第三方应用 ID** 就是你上面创建的项目的 appId
    2. ** 第三方应用名称 ** 随便写
3. 赋权
![](https://image-static.segmentfault.com/343/196/3431968872-5d876f63bf622_articlex)
    1. **token** 你点击创建应用后自动生成的
    2. ** 被管理的 Appid** 就是你上面创建的项目的 appId
    3. ** 授权类型 ** 一定要选 App

spring boot 集成 sentinel

源码地址

引入依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>0.9.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-apollo</artifactId>
            <version>1.5.2</version>
        </dependency>

测试 controller

package cn.coder4j.study.example.sentinel;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author buhao
 * @version TestController.java, v 0.1 2019-09-19 20:53 buhao
 */
@RequestMapping("/test")
@Controller
public class TestController {

    /**
     * 没有注解通过自适应的限流
     * @return
     */
    @GetMapping("/flowRule")
    @ResponseBody
    public String flowRule(){return "success";}

    /**
     * 通过手动注解的限流
     * @return
     */
    @GetMapping("/flowRuleWithAnno")
    @ResponseBody
    @SentinelResource("flowRuleWithAnno")
    public String flowRuleWithAnno(){return "success";}

    /**
     * 参数限流规则测试
     * @param param
     * @return
     */
    @GetMapping("/paramFlowRule")
    @ResponseBody
    @SentinelResource("paramFlowRule")
    public String paramFlowRule(String param){return "success";}

    /**
     * 熔断规则测试
     * @return
     */
    @GetMapping("/degradeRule")
    @ResponseBody
    @SentinelResource("degradeRule")
    public String degradeRule(){throw new RuntimeException("服务器异常");
    }
}

配置 application.yml

apollo:
  bootstrap:
    enabled: true # 开启 apollo
  meta: xxx       # 指定 apollo 注册地址
app:
  id: sentinel-apollo  # 指定规则项目在 apollo 的 app.id,要与 sentinel 控制台启动参数一致
spring:
  application:
    name: study-sentinel-example  # 应用名称,不同项目要唯一,会把他做为规则 Key 的前缀
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8989  # sentinel 控制台的地址
      datasource:
        ds1:
          apollo:
            namespace-name: {部门名}.sentinel-rule  # 保存规则的 apollo 应用的公共 namespace,要与 sentinel 控制台启动参数一致
            rule-type: flow   # 指定该数据源是限流规则
            flow-rules-key: ${spring.application.name}-${spring.cloud.sentinel.datasource.ds1.apollo.rule-type} # 指定该规则在 apollo 应用中 key 名称
        ds2:
          apollo:
            namespace-name: {部门名}.sentinel-rule
            rule-type: degrade # 指定该数据源是熔断规则
            flow-rules-key: ${spring.application.name}-${spring.cloud.sentinel.datasource.ds2.apollo.rule-type} # 指定该规则在 apollo 应用中 key 名称
        ds3:
          apollo:
            namespace-name: {部门名}.sentinel-rule
            rule-type: param_flow # 指定该数据源是参数限流规则
            flow-rules-key: ${spring.application.name}-${spring.cloud.sentinel.datasource.ds3.apollo.rule-type} # 指定该规则在 apollo 应用中 key 名称
        ds4:
          apollo:
            namespace-name: {部门名}.sentinel-rule
            rule-type: system  # 指定该数据源是系统限流规则
            flow-rules-key: ${spring.application.name}-${spring.cloud.sentinel.datasource.ds4.apollo.rule-type} # 指定该规则在 apollo 应用中 key 名称
        ds5:
          apollo:
            namespace-name: {部门名}.sentinel-rule
            rule-type: authority # 指定该数据源是认证限流 (黑白名单) 规则
            flow-rules-key: ${spring.application.name}-${spring.cloud.sentinel.datasource.ds5.apollo.rule-type} # 指定该规则在 apollo 应用中 key 名称

sentinel 控制台配置

  1. 第一次启动时 sentinel 是没有应用数据,只要请求几次你应用的接口就可以了

  1. 请求之后可以看到我们的应用在右侧列表了

  1. 首先点击簇点监控,如果是空白的话说明,接口还没有被请求过,通过上面提供的 jmeter 脚本,可以快速访问所有接口,访问后如下图所示

1. 可以看到除了我们手动通过注解定义的资源名,还多了一些是通过我们的 controller 路径的资源名,这些都是我们客户端集成 spring-cloud-starter-alibaba-sentinel 包后,自动适配的。这两种其实在使用上有区别的
    1. 自动适配的限流后会返回 **Blocked by Sentinel (flow limiting)**
    2. 通过注解的是会抛出 **UndeclaredThrowableException** 异常,我们可以通过 [文章](https://segmentfault.com/a/1190000012262244) 说的方法转成我们想的限流异常处理。2. 右边的操作就是添加各种规则,这里修改后会实时同步到客户端并同步保存到 apollo

jmeter 配置

  jmeter 是用于测试与验证规则使用的,因为可以设置线程数,所以可以很好的测试限流情况。测试脚本下载

  1. 线程组要把线程设置成 100,方便后面的统计,另外为了在一秒内执行完,Ramp-Up 时间设为 0

  1. 请求默认值就是填写你本地的启的测试项目的地址

  1. xx 规则填写测试接口地址,参数限流因为要做对照实验所以写了两个

  1. 查看结果树可以看到你每次请求的内容与结果

  1. 可以看到上张图片内有红色的有绿色的,红色说明断言失败,绿色说明断言成功,断言的内容就是包含 success

  1. 聚合统计,这个可以统计出 100 个线程请求后的总体结果,我们只要看 Error% 的失败率就可以了。图中可以看到除了熔断限流,其它限流失败率是 0

测试步骤

  1. 在簇点链路中找到 /test/flowRule,并点击 流控 按钮

  1. 单机阈值填入 10,点击新增

  1. 新增后会跳转到流程规则页面

  1. 运行 jemter,可以看到失败率为 90%,这代表你的限流成功了

1. 上面说了失败是因为断言没有成功,也就是说没有返回 success,那他现在返回的是什么呢?2. 察看结果树,随便找一条红包的记录,看响应数量
![](https://image-static.segmentfault.com/182/321/182321129-5d876f7924b1d_articlex)
3. 可以看到返回的是 "**Blocked by Sentinel (flow limiting)**",这个就是集成后配置的限流页面的返回值,可以通过 **spring.cloud.sentinel.servlet.block-page** 指定成你自己的页面
  1. 另外打开 apollo 可以看到,多了一个规则,这就是你刚刚添加的限流规则

欢迎关注我的公众号「KIWI 的碎碎念」,也可以收藏 我的博客

退出移动版