【开源项目】热点监测降级框架Akali源码解读

项目地址

https://gitee.com/dromara/Akali

项目介绍

Akali(阿卡丽)是一个轻量级本地化热点检测/降级框架,适用于大流量场景,可轻松解决业务中超高流量的并发查询等场景。并且接入和使用极其简单,10秒钟即可接入使用!

Akali框架的理念就是小巧,实用,来无影去无踪,丝血团战,满血退场,所到之处,皆为虚无。

核心功能

对于核心方法,发现该方法高频使用,要么使用原有的数据进行返回(@AkaliHot),要么使用指定的方法进行降级(@AkaliFallback)。

源码拆解

系统启动

AkaliScanner实现了InstantiationAwareBeanPostProcessor,如果注册到Spring容器中的Bean存在AkaliFallbackAkaliHot注解标注的方法,创建代理类AkaliProxy

public class AkaliScanner implements InstantiationAwareBeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {Class<?> clazz = bean.getClass();if (AkaliStrategy.class.isAssignableFrom(clazz)){AkaliStrategyManager.addStrategy((AkaliStrategy) bean);return bean;}AtomicBoolean needProxy = new AtomicBoolean(false);List<Method> fallbackMethodList = new ArrayList<>();List<Method> hotspotMethodList = new ArrayList<>();Arrays.stream(clazz.getDeclaredMethods()).forEach(method -> {AkaliFallback akaliFallback = searchAnnotation(method, AkaliFallback.class);if (ObjectUtil.isNotNull(akaliFallback)){fallbackMethodList.add(method);S.addMethodStr(MethodUtil.resolveMethodName(method), new Tuple2<>(AkaliStrategyEnum.FALLBACK, akaliFallback));needProxy.set(true);}AkaliHot akaliHot = searchAnnotation(method, AkaliHot.class);if (ObjectUtil.isNotNull(akaliHot)){hotspotMethodList.add(method);AkaliMethodManager.addMethodStr(MethodUtil.resolveMethodName(method), new Tuple2<>(AkaliStrategyEnum.HOT_METHOD, akaliHot));needProxy.set(true);}});if (needProxy.get()){try{AkaliProxy akaliProxy = new AkaliProxy(bean, fallbackMethodList, hotspotMethodList);Object obj = akaliProxy.proxy();return obj;}catch (Exception e){throw new BeanInitializationException(e.getMessage());}}else{return bean;}}
}

系统拦截

AopInvocationHandler,拦截器的核心方法。注册对应的FlowRule,执行SphEngine.process

    public class AopInvocationHandler implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodStr = MethodUtil.resolveMethodName(method);if (AkaliMethodManager.contain(methodStr)){AkaliStrategyEnum akaliStrategyEnum = AkaliMethodManager.getAnnoInfo(methodStr).r1;Annotation anno = AkaliMethodManager.getAnnoInfo(methodStr).r2;if (anno instanceof AkaliFallback){AkaliRuleManager.registerFallbackRule((AkaliFallback) anno, method);}else if (anno instanceof AkaliHot){AkaliRuleManager.registerHotRule((AkaliHot) anno, method);}else{throw new RuntimeException("annotation type error");}return SphEngine.process(bean, method, args, methodStr, akaliStrategyEnum);}else {return method.invoke(bean, args);}}}

AkaliRuleManager#registerHotRule,利用Sentinel框架注册流控规则。

    public static void registerHotRule(AkaliHot akaliHot, Method method){String resourceKey = MethodUtil.resolveMethodName(method);if (!ParamFlowRuleManager.hasRules(resourceKey)){ParamFlowRule rule = new ParamFlowRule();rule.setResource(MethodUtil.resolveMethodName(method));rule.setGrade(akaliHot.grade().getGrade());rule.setCount(akaliHot.count());rule.setDurationInSec(akaliHot.duration());rule.setParamIdx(0);ParamFlowRuleManager.loadRules(ListUtil.toList(rule));log.info("[AKALI] Add Hot Rule [{}]", rule.getResource());}}

SphEngine的处理逻辑就是如果流控是允许的,执行核心方法,如果流控不允许,执行对应的策略。

public class SphEngine {private static final Logger log = LoggerFactory.getLogger(SphEngine.class);public static Object process(Object bean, Method method, Object[] args, String methodStr, AkaliStrategyEnum akaliStrategyEnum) throws Exception{switch (akaliStrategyEnum){case FALLBACK:if (SphO.entry(methodStr)){try{return method.invoke(bean, args);}finally {SphO.exit();}}else{log.info("[AKALI]Trigger fallback strategy for [{}]", methodStr);return AkaliStrategyManager.getStrategy(akaliStrategyEnum).process(bean, method, args);}case HOT_METHOD:String convertParam = DigestUtil.md5Hex(JSON.toJSONString(args));Entry entry = null;try{entry = SphU.entry(methodStr, EntryType.IN, 1, convertParam);return method.invoke(bean, args);}catch (BlockException e){log.info("[AKALI]Trigger hotspot strategy for [{}]", methodStr);return AkaliStrategyManager.getStrategy(akaliStrategyEnum).process(bean, method, args);}finally {if (entry != null){entry.exit(1, convertParam);}}default:throw new Exception("[AKALI] Strategy error!");}}
}

FallbackStrategy回退策略是获取方法名称是指定方法+Fallback的方法,进行方法调用。

public class FallbackStrategy implements AkaliStrategy{private final Map<String, Method> fallBackMethodMap = new ConcurrentHashMap<>();@Overridepublic AkaliStrategyEnum getStrategy() {return AkaliStrategyEnum.FALLBACK;}@Overridepublic Object process(Object bean, Method method, Object[] args) throws Exception{String fallbackMethodName = StrUtil.format("{}Fallback", method.getName());Method fallbackMethod;if (fallBackMethodMap.containsKey(fallbackMethodName)){fallbackMethod = fallBackMethodMap.get(fallbackMethodName);}else{fallbackMethod = ReflectUtil.getMethod(bean.getClass(), fallbackMethodName, method.getParameterTypes());fallBackMethodMap.put(fallbackMethodName, fallbackMethod);}if (ObjectUtil.isNull(fallbackMethod)){throw new RuntimeException(StrUtil.format("[AKALI] Can't find fallback method [{}] in bean [{}]", fallbackMethodName, bean.getClass().getName()));}return fallbackMethod.invoke(bean, args);}
}

MethodHotspotStrategy使用缓存,缓存中有数据就返回,没数据就调用方法。该地方使用的是hutool的缓存类。

public class MethodHotspotStrategy implements AkaliStrategy{private TimedCache<String, Object> timedCache;public MethodHotspotStrategy() {timedCache = CacheUtil.newTimedCache(1000 * 60);timedCache.schedulePrune(1000);}@Overridepublic AkaliStrategyEnum getStrategy() {return AkaliStrategyEnum.HOT_METHOD;}@Overridepublic Object process(Object bean, Method method, Object[] args) throws Exception{String hotKey = StrUtil.format("{}-{}", MethodUtil.resolveMethodName(method), DigestUtil.md5Hex(JSON.toJSONString(args)));if (timedCache.containsKey(hotKey)){return timedCache.get(hotKey);}else{Object result = method.invoke(bean, args);timedCache.put(hotKey, result);return result;}}
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/162454.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Visual NLP:图像信息自动提取的未来

本文旨在以简单的方式解释 Visual NLP 的关键概念&#xff0c;让你了解 Visual NLP 的含义、它的用例是什么、如何使用它以及为什么它是构建自动提取管道的未来 。 NSDT在线工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在…

微信小程序-空值操作符

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 空值合并操作符&#xff08;??&#xff09; 空值合并操作符&#xff08;??&#xff09; 在编写代码时&#xff0c;如果某个属性不为 null 和 undefined&#x…

C++ 函数、数组、指针、输入输出、日期时间

一、C函数&#xff1a; 函数是一组执行一个任务的语句。每个C程序至少有一个函数&#xff0c;即主函数main()。函数有很多叫法&#xff0c;比如方法、子例程或程序等等。函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实际主体。 return_type function…

一站式解决Mac音视频转换需求——Xilisoft Video Converter Ultimate for Mac

在数字化时代&#xff0c;音视频的应用越来越广泛&#xff0c;不同的设备和平台对音视频格式的要求也不尽相同。因此&#xff0c;如何找到一款功能强大、易于操作的音视频转换软件成为了Mac用户的迫切需求。而Xilisoft Video Converter Ultimate for Mac&#xff08;曦力音视频…

4.18每日一题(极坐标累次积分到直角坐标累次积分的转换)

注&#xff1a;rdr化为直角坐标以后r直接消去了&#xff0c;不需要计算

可编程交流回馈式负载箱在电源设备中的应用

可编程交流回馈式负载箱可以用于测试电源设备的输出能力&#xff0c;通过在负载箱中设置不同的负载条件&#xff0c;可以模拟不同的工作负载情况&#xff0c;从而测试电源设备在不同负载下的输出能力和稳定性。这对于电源设备的设计和生产非常重要&#xff0c;可以帮助制造商评…

2023年亚太杯数学建模亚太赛C题思路解析+代码+论文

下文包含&#xff1a;2023年亚太杯数学建模亚太赛C题思路解析代码参考论文等及如何准备数学建模竞赛&#xff08;23号比赛开始后逐步更新&#xff09; C君将会第一时间发布选题建议、所有题目的思路解析、相关代码、参考文献、参考论文等多项资料&#xff0c;帮助大家取得好成…

SELinux refpolicy详解(1)

本文部分内容参考&#xff1a; SELinux - ArchWiki SELinux_百度百科 一、SELinux介绍 1. SELinux简介 SELinux&#xff08;Security-Enhanced Linux&#xff0c;安全增强型Linux&#xff09;是美国国家安全局&#xff08;NSA&#xff09;对于强制访问控制的实现&#xff0…

【python学习】基础篇-常用函数-偏函数

偏函数(Partial function)是指固定一个函数的部分参数&#xff0c;返回一个新的函数。 在Python中&#xff0c;可以使用functools模块中的partial()函数来创建偏函数。 偏函数的用法如下&#xff1a; 1.首先&#xff0c;导入functools模块中的partial()函数。 from functool…

css实现水波纹效果

css实现水波纹效果 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><styl…

HarmonyOS ArkTS Video组件的使用(七)

概述 在手机、平板或是智慧屏这些终端设备上&#xff0c;媒体功能可以算作是我们最常用的场景之一。无论是实现音频的播放、录制、采集&#xff0c;还是视频的播放、切换、循环&#xff0c;亦或是相机的预览、拍照等功能&#xff0c;媒体组件都是必不可少的。以视频功能为例&a…

C 语言嵌套结构体

C 语言嵌套结构体 C为我们提供了将一个结构嵌套在另一个结构中的功能&#xff0c;从而创建复杂的数据类型。例如&#xff0c;我们可能需要在结构中存储实体员工的地址。而地址也可以包含其他信息&#xff0c;例如街道编号&#xff0c;城市&#xff0c;地区和密码。因此&#x…

CVE-2022-21661

简介 CVE-2022-21661是一个与WordPress相关的漏洞&#xff0c;涉及到SQL注入问题。该漏洞主要源于WordPress的WQ_Tax_Query类中的clean_query函数&#xff0c;可能允许攻击者通过控制传递给该函数的数据来控制生成的SQL查询&#xff0c;从而执行任意的SQL代码。 当WordPress的…

【ROS 2 进阶-MoveIt!】MoveIt!中的关键节点

所有内容请查看&#xff1a;博客学习目录_Howe_xixi的博客-CSDN博客 原文档链接&#xff1a;Docs

自动驾驶轨迹预测学习笔记

目录 VectorNet&#xff1a;自动驾驶轨迹预测 CVPR2023 轨迹预测冠军方案 QCNeXt VectorNet&#xff1a;自动驾驶轨迹预测 VectorNet&#xff1a;自动驾驶轨迹预测 - 知乎 CVPR2023 轨迹预测冠军方案 QCNeXt CVPR2023 轨迹预测冠军方案&#xff01;QCNeXt&#xff1a;新一代…

什么是索引下推

索引下推介绍 索引下推&#xff08;INDEX CONDITION PUSHDOWN&#xff0c;简称 ICP&#xff09;是在 MySQL 5.6 针对扫描二级索引的一项优化改进。总的来说是通过把索引过滤条件下推到存储引擎&#xff0c;来减少 MySQL 存储引擎访问基表的次数以及 MySQL 服务层访问存储引擎的…

持续格式刷

双击格式刷即可

专访|OpenTiny 开源社区 常浩:完成比完美更重要

前言 2023年已过大半&#xff0c;备受关注的 OpenTiny*开源之夏活动也顺利结项。开源之夏由中国科学院软件研究所发起的计划&#xff0c;目的在于鼓励在校学生积极参与开源软件的开发维护&#xff0c;推动优秀开源软件社区的繁荣发展。该活动联合各大开源社区&#xff0c;聚焦…

令人赞叹的花里胡哨的代码雨动画效果

【点我-这里送书】 本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(…

element emitter broadcast向下广播 dispatch向上分派

emitter 项目使用element的emitter.js&#xff0c;做个使用记录 function broadcast(componentName, eventName, params) {this.$children.forEach(child > {const name child.$options.name;if (name componentName) {child.$emit.apply(child, [eventName].concat(para…