【開源項目】熱點監測降級框架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.pswp.cn/news/162454.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/162454.shtml
英文地址,請注明出處:http://en.pswp.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…