【Sentinel】sentinel 集成 apollo 最佳实践

【Sentinel】sentinel 集成 apollo 最佳实践

sentinel

前言

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

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

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

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

  添加与实现了全部的规则的 Provider 与 Publisher 的配置拉取的与推送。github

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

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

修改点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 转换的代码。spring

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

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

  添加的配置在下面bootstrap

使用修改的控制台版本

  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. 点击建立项目按钮
  2. 输入项目信息
    1. 应用 ID 对应 上面表格中的 app.id
    2. 应用负责人 对应 上面表格中的 modify.userrelease.user
  3. 建立一个公共命名空间
    1. 点击右下角添加 Namespace 按钮
    2. 建立 Namespace
      1. 名称对应上面表格中的 namespace.name,注意名称是要包含部门名的,这里脱敏了
      2. 类型必定要选择 public ,缘由后面会说
  4. 发布 Namespace
    1. 私有的空间是不能被继承的,application 没有用,能够删除
      1. 这里的用意是咱们独立出一个单独的用于保存规则的 apollo 应用,由于是公共的,因此其它apollo 应用能够继承,这样对于已经集成 apollo 的项目来讲,改动最小
      2. 注意红色的提示,咱们建的公共空间要首先发布一次,不然 api 没法访问到
  5. 建立此项目的开放平台受权
    1. 点击右上角的开放平台受权管理
    2. 建立应用
      1. 第三方应用 ID 就是你上面建立的项目的 appId
      2. 第三方应用名称 随便写
    3. 赋权
      1. token 你点击建立应用后自动生成的
      2. 被管理的 Appid 就是你上面建立的项目的 appId
      3. 受权类型 必定要选 App

spring boot 集成 sentinel

源码地址segmentfault

引入依赖

<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 是没有应用数据,只要请求几回你应用的接口就能够了
  2. 请求以后能够看到咱们的应用在右侧列表了
  3. 首先点击簇点监控,若是是空白的话说明,接口尚未被请求过,经过上面提供的 jmeter 脚本,能够快速访问全部接口,访问后以下图所示
    1. 能够看到除了咱们手动经过注解定义的资源名,还多了一些是经过咱们的 controller 路径的资源名,这些都是咱们客户端集成 spring-cloud-starter-alibaba-sentinel 包后,自动适配的。这两种其实在使用上有区别的
      1. 自动适配的限流后会返回 Blocked by Sentinel (flow limiting)
      2. 经过注解的是会抛出 UndeclaredThrowableException 异常,咱们能够经过 文章 说的方法转成咱们想的限流异常处理。
    2. 右边的操做就是添加各类规则,这里修改后会实时同步到客户端并同步保存到 apollo

jmeter 配置

  jmeter 是用于测试与验证规则使用的,由于能够设置线程数,因此能够很好的测试限流状况。测试脚本下载api

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

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

  3. xx 规则填写测试接口地址,参数限流由于要作对照实验因此写了两个

  4. 查看结果树能够看到你每次请求的内容与结果

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

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

测试步骤

  1. 在簇点链路中找到 /test/flowRule,并点击流控按钮
  2. 单机阈值填入 10,点击新增
  3. 新增后会跳转到流程规则页面
  4. 运行jemter,能够看到失败率为90%,这表明你的限流成功了
    1. 上面说了失败是由于断言没有成功,也就是说没有返回 success,那他如今返回的是什么呢?
    2. 察看结果树,随便找一条红包的记录,看响应数量
    3. 能够看到返回的是 "Blocked by Sentinel (flow limiting)",这个就是集成后配置的限流页面的返回值,能够经过 spring.cloud.sentinel.servlet.block-page 指定成你本身的页面
  5. 另外打开 apollo 能够看到,多了一个规则,这就是你刚刚添加的限流规则

欢迎关注个人公众号「KIWI的碎碎念」,也能够收藏 个人博客

相关文章
相关标签/搜索