KiwiFly · 2019年09月22日

【Sentinel】sentinel 集成 apollo 最佳实践

【Sentinel】sentinel 集成 apollo 最佳实践

sentinel

前言

  在 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. 你可以使用我已经打好的包 地址

自定义配置

配置名称是否必填默认值作用
envDEV指定 apollo 使用的环境
app.idsentinel-apollo指定保存 sentinel 规则的 apollo 应用 ID
cluster.namedefault指定保存 sentinel 使用的 apollo 集群
namespace.nameapplication指定保存 sentinel 使用的 apollo 命名空间
modify.user apollo 控制台显示的修改人账号,此账号务必要有此应用的权限
modify.commentmodify by sentinel-dashboardapollo 控制台显示的修改备注
release.user apollo 控制台显示的发布人账号,此账号务必要有此应用的权限
release.commentrelease by sentinel-dashboardapollo 控制台显示的发布备注
apollo.portal.url  apollo 控制台的地址
apollo.application.token 指定保存 sentinel 规则的 apollo 应用 openapi 的 token
authority.key.suffixauthority认证规则保存在 apollo 中的 key 的后缀
degrade.key.suffixdegrade熔断规则保存在 apollo 中的 key 的后缀
flow.key.suffixflow限流规则保存在 apollo 中的 key 的后缀
param.key.suffixparam_flow参数限流规则保存在 apollo 中的 key 的后缀
system.key.suffixsystem系统限流规则保存在 apollo 中的 key 的后缀
auth.usernamesentinelsentinel 控制台的登录用户名
auth.passwordsentinelsentinel 控制台的登录密码
server.port8080sentinel 控制台的启动端口

Apollo 配置

创建用于保存 sentinel 的项目

  1. 点击创建项目按钮

  1. 输入项目信息

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

    1. 点击右下角添加 Namespace 按钮

    1. 创建 Namespace

    1. 名称对应上面表格中的 **namespace.name**,注意名称是要包含部门名的,这里脱敏了
    2. 类型一定要选择 public ,原因后面会说
  2. 发布 Namespace

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

    1. 点击右上角的开放平台授权管理

    1. 创建应用

    1. **第三方应用 ID** 就是你上面创建的项目的 appId
    2. **第三方应用名称** 随便写
    1. 赋权

    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. 察看结果树,随便找一条红包的记录,看响应数量
![](/img/bVdlg)
3. 可以看到返回的是 "**Blocked by Sentinel (flow limiting)**",这个就是集成后配置的限流页面的返回值,可以通过 **spring.cloud.sentinel.servlet.block-page** 指定成你自己的页面
  1. 另外打开 apollo 可以看到,多了一个规则,这就是你刚刚添加的限流规则

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

推荐阅读
关注数
0
文章数
5
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息