基于缓存的流控实现

项目场景:

由于针对单品的线上抢购导致库存中心出现不可控的宕机危机,出于系统安全等方面考虑,为此需要添加到单品维度的流控功能。

问题描述:

基于此次宕机危机,从中也是有可以分析的地方,通过对日志或监控信息的分析,发现是针对具体商品进行的高频率调用,为此,流控方案从这个方面入手,限制同一维度并发处理量,对限制的处理明细直接封装返回信息。鉴于不同系统的判断及处理标准并不一致,因此对于同一维度的判断及返回信息的处理由项目组具体实现。

@Override
        public void run() {
            bytes = mmInStream.read(buffer);
            mHandler.obtainMessage(READ_DATA, bytes, -1, buffer).sendToTarget();
        }

实现方案:

实现逻辑基于以下几点考虑

1.当批量请求出现一个超出阀值的记录,则认为该次请求异常,全部封装异常返回

2.基于ConcurrentHashMap构建缓存用以存储接口各明细并发处理量,容器以Key=判断维度,Value=并发处理记录为Entry。

在每次请求进入处理方法时增加,离开处理方法时减少或移除(value=0时)

3.基于SNF-SCM配置,可以在生产环境中及时调整阀值处理


![在这里插入图片描述](https://img-blog.csdnimg.cn/e5cc2c52d75c4e3c97c318feca23832a.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5p625p6E6ICB5YW1,size_20,color_FFFFFF,t_70,g_se,x_16)

使用:

1.依赖Jar包
依赖Jar包为库存项目中使用到的关联Jar包,实际Jar包版本可视项目组具体调整.
Spring-aop-3.1.2.RELEASE.jar+
aop-alliance-1.0.jar
aspectjweaver-1.7.0.jar
cglib-nodep-2.2.2.jar
commons-collections-3.2.1.jar+
commons-lang3-3.1.jar+
snf-scm-client-2.1.0.jar
slf4j-api.16.4.jar+

2.SCM配置
1.SCM申请及其使用
A002-016-统一配置管理平台(SCM)

2.在SCM平台创建属性文件
在scm平台创建属性文件,文件路径无特别要求,属性文件配置如下属性

属性 key属性值说明
capacity10000缓存容纳请求上限,多于capacity的请求忽略流控功能
threshold5单个JVM限制的并发处理量
powerOntrue/false流控功能开关true表启用false表关闭

3.本地SCM文件及使用

U002-016–统一配置管理平台(SCM)

3.注册组件
1.实现CacheKeyGenerator接口,该组件用于构建缓存键值,该键值表示流控判断的维度信息。

2.实现ResponseFaker接口,该组件用于模拟返回结果,超过阀值的请求将通过该组件模拟返回结果。

3.新建有且只有一个类继承GenericThrottleCompFactory,且通过@Component等注解交由Spring管理,用于注册上述组件,支持注册多组组件,用于对多个接口进行流控。

4.Spring配置
1.添加切面

2.通过AOP实现代码切入,因此需要在Spring配置文件中增加aop命名空间

<aop:aspectj-autoproxy proxy-target-class=“true” />

5.文件调整
1.在需要流控的服务类上添加@Filter,注解name=缓存名称,用于绑定组件,获取缓存信息等,path=SCM配置文件路径.

2.注解属性说明

name=缓存名称,用于绑定组件,获取监控信息,内容必填

path=SCM配置文件路径,内容必填

requestIndex=请求参数索引,从0开始,用于在多个入参时绑定需要拦截请求参数,默认值为0

当需要拦截的方法存在多个入参时,如

Resp serve(Cond cond,Req reqs),此时需要关注的业务请求为reqs,需要设置requestIndex=1,便于切面获取业务参数

caller=绑定上层调用类,保证Service组件复用的纯净性,默认为“”

由于我们的拦截方法可能存在多个模块的复用功能,但我们仅希望对接口过来的请求进行拦截时,可通过caller参数绑定其调用类

例如com.suning.ebuy.cis.web.controller.ATPCheckController

6.监控功能
2.0.0版本提供主动探测缓存功能,展示信息格式为TimeStamp|HostIP|Interface|key|Threshold,

e.g.

2015-02-13 11:27:36:648|10.19.214.9| PromotionaArticleMgmt-searchSalesShowService | 000000000120128737|20

ThrottleMonitor为线程安全的,若需多次创建,建议创建final对象,以供使用.

ThrottleMonitor#defaultInfos(String cacheName,int topSize)

cacheName为缓存名称

topSize为展示的Top * 条目数

7.案例介绍
1.在SCM平台上创建属性文件(SCM申请及本地配置此处并不介绍,可参考相关页面进行配置)

在这里插入图片描述
0.0.8新增功能配置文件中添加

distinct=true

该配置将启用排重功能,即同一个请求中相同KEY的行项目会排重之后进行流控。

2.增加Spring配置

<aop:aspectj-autoproxy proxy-target-class=“true” />

3.继承GenericThrottleCompFactory并注册组件
在这里插入图片描述
0.07版本新增功能

使用ExcludeCacheKeyGenerator,实现其中exclude方法,可自定义添加排除功能,该方法返回true时对应的行项目将不进行流控

4.添加注解@Filter绑定缓存及SCM配置
在这里插入图片描述
5.测试一把

<?xml version="1.0"?>
<MbfService>
    <output1>
        <MbfHeader>
            <ServiceCode>InventoryInquire</ServiceCode>
            <Operation>checkATP</Operation>
            <UId>65297457222546a7b3e70f96bddb0068e3fa2280b62142ed</UId>
            <ServiceResponse>
               <Status>COMPLETE</Status>
            </ServiceResponse>
        </MbfHeader>
        <MbfBody>
            <list>
               <ATPCheckResp>
                   <orderNo>9411374476</orderNo>
                   <orderItemNo>000010</orderItemNo>
                   <plantCode>D025</plantCode>
                   <cmmdtyCode>000000000101051959</cmmdtyCode>
                   <invLocat>0001</invLocat>
                   <supplierCode>0010045247</supplierCode>
                   <arrivalDate>2013-09-08 00:00:00.0 CST</arrivalDate>
                   <arrivalQty>0.000</arrivalQty>
                   <supplierInvLocat />
                   <failMsg>系统繁忙</failMsg>
                   <successFlag>N</successFlag>
              </ATPCheckResp>
              <ATPCheckResp>
                   <orderNo>9411374476</orderNo>
                   <orderItemNo>000010</orderItemNo>
                   <plantCode>D025</plantCode>
                   <cmmdtyCode>000000000101051959</cmmdtyCode>
                   <invLocat>0001</invLocat>
                   <supplierCode>0010045247</supplierCode>
                   <arrivalDate>2013-09-08 00:00:00.0 CST</arrivalDate>
                   <arrivalQty>0.000</arrivalQty>
                   <supplierInvLocat />
                   <failMsg>系统繁忙</failMsg>
                   <successFlag>N</successFlag>
               </ATPCheckResp>
            </list>
        </MbfBody>
    </output1>
</MbfService>

6.添加监控信息

private final ThrottleMonitor throttleMonitor = new ThrottleMonitor();

@ResponseBody
@RequestMapping("topInfos.htm")
public String getCacheTopInfo(int size) {
        StringBuilder sb = new StringBuilder();
        List<String> records = throttleMonitor.defaultInfos("ATPCheck", size);
        for (String record : records) {
            sb.append(record + "\n");
        }
        return sb.toString();
}

日志记录:

SCM配置调整后,通过以下内容显示各接口生效内容

LOGGER.info(this.name + “'s powerOn is=” + powerOn);
LOGGER.info(this.name + “'s threshold is=” + threshold);
LOGGER.info(this.name + “'s capacity is=” + capacity);
e.g.ATPCheck‘s powerOn is=true

当发生超出阀值限制时,通过以下内容显示超出记录
LOGGER.info(“接口” + throttle.getName() + “键值” + r + “超出阀值” + throttle.getThreshold());
e.g. 接口ATPCheck键值101002405#10042005#D025#0001#5超出阀值5
LOGGER.warn(info(throttle.getName(), r, throttle.getThreshold()));
输出格式为:
TimeStamp|IpAddress|CacheName|Key|Threshold

8.备注
关于组件构建的一些说明:

GenericThrottleCompFactory非线程安全,作为提供组件的注册容器,因此不允许在初始化后添加新的组件,需要使用者在构造方法内添加需要使用的组件.
关于CacheKeyGenerator接口及ResponseFaker实现的一些小说明,目前支持形如 Resp serve(Req )的服务接口,其中关于Req及Resp支持的结构可以支持Object和List。
由于基于Cglib作为AOP动态代理,因此对于final方法和私有方法无法进行拓展
目前该版本的代码基于SNF-SCM-2.1.0.jar(下称2.1)进行开发测试,但在推广过程中发现部分项目组使用的为SNF-SCM-2.0.0.jar(下称2.0),通过比对两个版本的jar包,2.1将ZNode节点的监听器动作从2.0的Client剥离放入ZNode中,并通过sync()动作处理读取滞后最新更新的可能性.
9.Maven支持
目前在苏宁Maven私服上已上传flowCtrl.jar包

其中包含两个版本flowCtrl和flowCtrl_scm2.0(后者基于snf-scm-client-2.0.0版本)

最新版本

Maven依赖

<dependency>
   <groupId>com.suning.cis.component</groupId>
   <artifactId>flowCtrl</artifactId>
   <version>0.0.8-SNAPSHOT</version>
</dependency>

scm2.0Maven依赖
<dependency>
   <groupId>com.suning.cis.component</groupId>
   <artifactId>flowCtrl_scm2.0</artifactId>
   <version>0.0.8-SNAPSHOT</version>
</dependency>

Jar包上传私服参考maven私服jar包管理

五、后期维护
增加开发监控API,支持针对具体维度,Top * 展示(在0.0.2中已完成)
目前针对不同接口需配置多个SCM配置文件,后期将通过name.property整合归并为一个配置文件,通过name属性绑定各个缓存
目前更多的场景是将过滤动作横切至Service层,这样在Service组件复用中会出现多次横切限流,通过堆栈信息绑定上层调用类在注解绑定的基础上增加流程横切(在0.0.1中已完成)
增加具体明细的业务信息过滤功能(在0.0.7中已完成)
六、更新版本日志
0.0.1:流控基本功能
0.0.2:丰富日志及开发主动探测API
0.0.3:格式化日志输出格式
0.0.4:Fix the BUG Committed By 牛广,当从SCM切换开关true->false时,存在已经加锁的缓存记录未移除(由于开关已经关闭.)(Deprecated)
0.0.5:Fix the BUG Committed BY 何石山,0.0.4版本由于加载顺序问题,导致启动失败,同时废弃0.0.4
0.0.6:调整超过阀值时日志输出格式及级别
0.0.7:添加流控排除功能,自定义满足指定条件不进行流控
0.0.8:添加流控排重功能,可添加配置实现,同一个请求中相同KEY的请求排重之后进行流控

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值