国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

從0到1構(gòu)造自定義限流組件 | 京東云技術(shù)團隊

這篇具有很好參考價值的文章主要介紹了從0到1構(gòu)造自定義限流組件 | 京東云技術(shù)團隊。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一 背景

在系統(tǒng)高可用設(shè)計中,接口限流是一個非常重要環(huán)節(jié),一方面是出于對自身服務(wù)器資源的保護,另一方面也是對依賴資源的一種保護措施。比如對于 Web 應(yīng)用,我限制單機只能處理每秒 1000 次的請求,超過的部分直接返回錯誤給客戶端。雖然這種做法損害了用戶的使用體驗,但是它是在極端并發(fā)下的無奈之舉,是短暫的行為,因此是可以接受的。

二 設(shè)計思路

常見的限流有2種思路

  • 第一種是限制總量,也就是限制某個指標的累積上限,常見的是限制當(dāng)前系統(tǒng)服務(wù)的用戶總量,例如:某個搶購活動商品數(shù)量只有 100 個,限制參與搶購的用戶上限為 1 萬個,1 萬以后的用戶直接拒絕。

  • 第二種是限制時間量,也就是限制一段時間內(nèi)某個指標的上限,例如 1 分鐘內(nèi)只允許 10000 個用戶訪問;每秒請求峰值最高為 10 萬。

三 限流算法

目前實現(xiàn)限流算法主要分為3類,這里不詳細展開介紹:

1)時間窗口

固定時間窗口算法是最簡單的限流算法,它的實現(xiàn)原理就是控制單位時間內(nèi)請求的數(shù)量,但是這個算法有個缺點就是臨界值問題。
為了解決臨界值的問題,又推出滑動時間窗口算法,其實現(xiàn)原理大致上是將時間分為一個一個小格子,在統(tǒng)計請求數(shù)量的時候,是通過統(tǒng)計滑動時間周期內(nèi)的請求數(shù)量。

2)漏斗算法

漏斗算法的核心是控制總量,請求流入的速率不確定,超過流量部分益出,該算法比較適用于針對突發(fā)流量,想要盡可能的接收全部請求的場景。其缺點也比較明顯,這個總量怎么評估,大小怎么配置,而且一旦初始化也沒法動態(tài)調(diào)整。

3)令牌桶算法

令牌桶算法的核心是控制速率,令牌產(chǎn)生的速度是關(guān)鍵,不斷的請求獲取令牌,獲取不到就丟棄。該算法比較適用于針對突發(fā)流量,以保護自身服務(wù)資源以及依賴資源為主,支持動態(tài)調(diào)整速率。缺點的話實現(xiàn)比較復(fù)雜,而且會丟棄很多請求。

四 實現(xiàn)步驟

我們自定義的這套限流組件有是基于guava RateLimiter封裝的,采用令牌桶算法以控制速率為主,支持DUCC動態(tài)配置,同時支持限流后的降級措施。接下來看一下整體實現(xiàn)方案

1、自定義RateLimiter Annotation標簽

這里主要對限流相關(guān)屬性的一個定義,包括每秒產(chǎn)生的令牌數(shù)、獲取令牌超時時間、降級邏輯實現(xiàn)以及限流開關(guān)等內(nèi)容

@Documented
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SysRateLimit {

    /**
     * 每秒產(chǎn)生的令牌數(shù) 默認500
     *
     * @return
     */
    double permitsPerSecond() default 500D;

    /**
     * 獲取令牌超時時間 默認100
     *
     * @return
     */
    long timeout() default 100;

    /**
     * 獲取令牌超時時間單位 默認毫秒
     *
     * @return
     */
    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;

    /**
     * 服務(wù)降級方法名稱 Spring bean id
     *
     * @return
     */
    String fallbackBeanId() default "";

    /**
     * 限流key 唯一
     *
     * @return
     */
    String limitKey() default "";
}

2、基于Spring Aspect 構(gòu)造切面

首先就是我們需要構(gòu)造一個Aspect切面用于掃描我們自定義的SysRateLimit標簽

@Slf4j
@EnableAspectJAutoProxy
@Aspect
public class SysRateLimitAspect {
    
    /**
     * 自定義切入點
     */
    @Pointcut("@annotation(com.jd.smb.service.ratelimiter.annotation.SysRateLimit)")
    public void pointCut() {

    }

    /**
     * 方法前執(zhí)行限流方案
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 如果未獲取到對象,直接執(zhí)行方法
        if (signature == null) {
            return joinPoint.proceed();
        }

        try {
            Method method = joinPoint.getTarget().getClass().getDeclaredMethod(signature.getName(), signature.getMethod().getParameterTypes());
            // 獲取注解對象
            SysRateLimit sysRateLimit = method.getAnnotation(SysRateLimit.class);
            if (sysRateLimit == null) {
                return joinPoint.proceed();
            }
            
        } catch (Exception e) {
            // todo log
        }
        return joinPoint.proceed();
    }
}

獲取自定義SysRateLimit標簽的各種屬性

 // 限流key
String limitKey = sysRateLimit.limitKey();
if (StringUtils.isBlank(limitKey)) {
    return joinPoint.proceed();
}
// 令牌桶數(shù)量
double permitsPerSecond = sysRateLimit.permitsPerSecond();
// 獲取令牌超時時間
long timeout = sysRateLimit.timeout();
// 獲取令牌超時時間單位
TimeUnit timeUnit = sysRateLimit.timeUnit();

將我們自定義的SysRateLimiter 和 Guava RateLimiter 進行整合

  1. 首先我們需要構(gòu)造一個全局Map,用于存儲我們開啟限流的方法,key就是我們定義的limitKey, value就是我們轉(zhuǎn)換后的Guava RateLimiter
 /**
 * 存儲RateLimiter(key: limitKey value:RateLimiter )
 */
private static final Map<String, RateLimiter> LIMITER_MAP = new ConcurrentHashMap<>();
  1. 接著就是核心邏輯:這里首先從我們創(chuàng)建的Map中獲取Guava RateLimiter,獲取不到就創(chuàng)建RateLimiter.create(permitsPerSecond) ;然后調(diào)用RateLimiter.tryAcquire()嘗試獲取令牌桶,獲取成功則執(zhí)行后續(xù)的邏輯,這里重點獲取失敗后,我們需要執(zhí)行我們的降級方法。(注意:Guava RateLimiter 有很多API,這里我們不展開討論,后續(xù)會針對Guava限流的源碼進行詳細的解析)
RateLimiter rateLimiter;
// Map中是否存在 存在直接獲取
if (LIMITER_MAP.containsKey(limitKey)) {
    rateLimiter = LIMITER_MAP.get(limitKey);
} else {
    // 不存在創(chuàng)建后放到Map中
    rateLimiter = RateLimiter.create(permitsPerSecond);
    LIMITER_MAP.put(limitKey, rateLimiter);
}
// 嘗試獲取令牌
if (!rateLimiter.tryAcquire(timeout, timeUnit)) {
    // todo 限流后降級措施
    return this.fallBack(sysRateLimit, joinPoint, signature);
}

降級方案執(zhí)行

上面我們在獲取令牌桶超時后,需要執(zhí)行我們的降級邏輯,怎么做呢?也很簡單,我們在定義SysRateLimiter的時候有個fallBackBeanId,這個就是我們執(zhí)行降級邏輯的bean對象Id,需要我們提前進行創(chuàng)建。接著我們看一下是怎么實現(xiàn)的。

    /**
     * 執(zhí)行降級邏輯
     *
     * @param sysRateLimit
     * @param joinPoint
     * @param signature
     * @return
     */
    private Object fallBack(SysRateLimit sysRateLimit, ProceedingJoinPoint joinPoint, MethodSignature signature) {
        String fallbackBeanId = sysRateLimit.fallbackBeanId();
        // 當(dāng)沒有配置具體的降級實現(xiàn)方案的時候 可以結(jié)合業(yè)務(wù)世紀情況設(shè)置限流錯誤碼
        if (StringUtils.isBlank(fallbackBeanId)) {
            // 自定義的 可以結(jié)合自己系統(tǒng)里的進行設(shè)置
            return ApiResult.error(ResultCode.REACH_RATE_LIMIT);
        }

        try {
            // SpringContext中通過BeanId獲取對象 SpringUtils只是獲取bean對象的工具類 有多種實現(xiàn)方式 可自行百度
            Object bean = SpringUtils.getBean(fallbackBeanId);
            Method method = bean.getClass().getMethod(signature.getName(), signature.getParameterTypes());
            // 執(zhí)行對應(yīng)的方法
            return method.invoke(bean, joinPoint.getArgs());
        } catch (Exception e) {
            // todo error log
        }
        return ApiResult.error(ResultCode.REACH_RATE_LIMIT);
    }

這樣我們大概的一個架子就弄好了。 接下來我們看看實際該如何使用

3、具體應(yīng)用

在方法入口引入SysRateLimiter標簽

@Slf4j
@RestController
@RequestMapping("/api/user")
@RequiredArgsConstructor
public class UserQueryController extends AbstractController {

    /**
     * 查詢用戶信息
     *
     * @param request
     * @return
     */
    @GetMapping("/info/{id}")
    @SysRateLimit(permitsPerSecond = 500, limitKey = "UserQueryController.info", fallbackBeanId = "userQueryControllerFallBack",
            timeout = 100, timeUnit = TimeUnit.MILLISECONDS)
    public ApiResult<UserInfo> info(@PathVariable Long id, HttpServletRequest request) {
        // todo 業(yè)務(wù)邏輯查詢 這里不展開
        return ApiResult.success();
    }
}

設(shè)置降級方法

@Service
public class UserQueryControllerFallBack {

    /**
     * 降級后執(zhí)行的邏輯
     *
     * @param request
     * @return
     */
    public ApiResult<UserInfo> info(Long id, HttpServletRequest request) {
        // todo 編寫限流降級后的邏輯 可以是降級碼 也可以是默認對象
        return ApiResult.success(null);
    }
}

當(dāng)請求進來的時候,會結(jié)合我們設(shè)置的閾值進行令牌桶的獲取,獲取失敗后會執(zhí)行限流,這里我們進行了限流后的降級處理。其實到這里我們完成限流組件的簡單封裝和使用,但是仍有一些點需要我們進行處理,例如如何動態(tài)設(shè)置令牌的數(shù)量,接下來我們就看一下如何實現(xiàn)令牌的動態(tài)設(shè)置。

4、動態(tài)設(shè)置令牌數(shù)量

通過DUCC配置令牌數(shù)量 我們需要定義一個DUCC配置,這里面內(nèi)容很簡單,配置我們設(shè)置limitKey的令牌數(shù)量

@Data
@Slf4j
@Component
public class RateLimitConfig {

    /**
     * 配置config key: limitKey value: 數(shù)量
     */
    private Map<String, Integer> limitConfig;

    /**
     * 監(jiān)聽ducc配置
     *
     * @param json
     */
    @LafValue(key = "rate.limit.conf")
    public void setConfig(String json) {
        if (StringUtils.isBlank(json)) {
            return;
        }
        Map<String, Integer> map = JsonModelUtils.getModel(json, Map.class, null);
        if (map != null) {
            Wrapper.wrapperBean(map, this, true);
        }
    }
}

通過DUCC配置獲取指定limitKey的令牌數(shù)量,獲取失敗則采用方法設(shè)置默認數(shù)量,這樣我們后面設(shè)置令牌數(shù)量就可以通過DUCC動態(tài)的配置了

 /**
     * 獲取令牌桶數(shù)量
     *
     * @param sysRateLimit
     * @return
     */
    private double getPermitsPerSecond(SysRateLimit sysRateLimit) {
        // 方法默認令牌數(shù)量
        double defaultValue = sysRateLimit.permitsPerSecond();
        if (rateLimitConfig == null || rateLimitConfig.getLimitConfig() == null) {
            return defaultValue;
        }
        // 配置的令牌數(shù)量
        Integer value = rateLimitConfig.getLimitConfig().get(sysRateLimit.limitKey());
        if (value == null) {
            return defaultValue;
        }
        return value;
    }

5、后續(xù)其他配置

其實后續(xù)我們的其他屬性都可以通過DUCC動態(tài)化的來配置,這里呢因為和令牌桶數(shù)量類似,就不再展開描述了。感興趣的小伙伴可以自行設(shè)置,根據(jù)我們的使用,使用默認配置即可。

作者:京東零售 王磊

來源:京東云開發(fā)者社區(qū)文章來源地址http://www.zghlxwxcb.cn/news/detail-494839.html

到了這里,關(guān)于從0到1構(gòu)造自定義限流組件 | 京東云技術(shù)團隊的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 基于AIGC的京東購物助手的技術(shù)方案設(shè)想 | 京東云技術(shù)團隊

    基于AIGC的京東購物助手的技術(shù)方案設(shè)想 | 京東云技術(shù)團隊

    隨著AIGC的爆火,ChatGPT,GPT-4的發(fā)布,我作為一個算法工作者,深感AI發(fā)展的迅猛。最近,OpenAI的插件和聯(lián)網(wǎng)功能陸續(xù)向用戶公開,我也在第一時間試用了這些最新的功能。在OpenAI的插件市場上,我被一個可以幫助分析食譜,并生成購物清單的功能所吸引。我開始思考,如果我

    2024年02月12日
    瀏覽(26)
  • 技術(shù)賦能-混流編排功能,助力京東618直播重保 | 京東云技術(shù)團隊

    技術(shù)賦能-混流編排功能,助力京東618直播重保 | 京東云技術(shù)團隊

    每每到618、雙11這樣的大型活動的時候,每天都有幾個重要的大v或者品牌直播需要保障。 以往的重點場次監(jiān)播方式是這么造的: 對每路直播的源流、各檔轉(zhuǎn)碼流分別起一個ffplay播放窗口,再手動調(diào)整尺寸在顯示器桌面進行布局,排到一屏里來監(jiān)播。 這樣做的缺點: 操作復(fù)雜

    2024年02月08日
    瀏覽(22)
  • 商品推薦系統(tǒng)淺析 | 京東云技術(shù)團隊

    商品推薦系統(tǒng)淺析 | 京東云技術(shù)團隊

    本文主要做推薦系統(tǒng)淺析,主要介紹推薦系統(tǒng)的定義,推薦系統(tǒng)的基礎(chǔ)框架,簡單介紹設(shè)計推薦的相關(guān)方法以及架構(gòu)。適用于部分對推薦系統(tǒng)感興趣的同學(xué)以及有相關(guān)基礎(chǔ)的同學(xué),本人水平有限,歡迎大家指正。 2.1 推薦系統(tǒng)的定義 推薦系統(tǒng)本質(zhì)上還是解決信息過載的問題,

    2024年02月13日
    瀏覽(26)
  • 初探webAssembly | 京東物流技術(shù)團隊

    初探webAssembly | 京東物流技術(shù)團隊

    一種運行在現(xiàn)代網(wǎng)絡(luò)瀏覽器中的新型代碼,并且提供新的性能特性和效果 W3C WebAssembly Community Group開發(fā)的一項網(wǎng)絡(luò)標準,對于瀏覽器而言,WebAssembly 提供了一條途徑,讓各種語言編寫的代碼以接近原生的速度在 Web 中運行。在這種情況下,以前無法以此方式運行的客戶端軟件等

    2024年02月15日
    瀏覽(19)
  • Spring源碼核心剖析 | 京東云技術(shù)團隊

    Spring源碼核心剖析 | 京東云技術(shù)團隊

    SpringAOP作為Spring最核心的能力之一,其重要性不言而喻。然后需要知道的是AOP并不只是Spring特有的功能,而是一種思想,一種通用的功能。而SpringAOP只是在AOP的基礎(chǔ)上將能力集成到SpringIOC中,使其作為bean的一種,從而我們能夠很方便的進行使用。 1.1 使用場景 當(dāng)我們在日常業(yè)

    2024年02月10日
    瀏覽(23)
  • 定時任務(wù)原理方案綜述 | 京東云技術(shù)團隊

    定時任務(wù)原理方案綜述 | 京東云技術(shù)團隊

    本文主要介紹目前存在的定時任務(wù)處理解決方案。業(yè)務(wù)系統(tǒng)中存在眾多的任務(wù)需要定時或定期執(zhí)行,并且針對不同的系統(tǒng)架構(gòu)也需要提供不同的解決方案。京東內(nèi)部也提供了眾多定時任務(wù)中間件來支持,總結(jié)當(dāng)前各種定時任務(wù)原理,從定時任務(wù)基礎(chǔ)原理、單機定時任務(wù)(單線

    2024年02月09日
    瀏覽(54)
  • 事務(wù),不只ACID | 京東物流技術(shù)團隊

    事務(wù),不只ACID | 京東物流技術(shù)團隊

    1. 什么是事務(wù)? 應(yīng)用在運行時可能會發(fā)生數(shù)據(jù)庫、硬件的故障,應(yīng)用與數(shù)據(jù)庫的網(wǎng)絡(luò)連接斷開或多個客戶端端并發(fā)修改數(shù)據(jù)導(dǎo)致預(yù)期之外的數(shù)據(jù)覆蓋問題,為了提高應(yīng)用的可靠性和數(shù)據(jù)的一致性, 事務(wù) 應(yīng)運而生。 從概念上講,事務(wù)是 應(yīng)用程序?qū)⒍鄠€讀寫操作組合成一個邏

    2024年02月13日
    瀏覽(16)
  • 618技術(shù)揭秘:探究競速榜頁面核心前端技術(shù) | 京東云技術(shù)團隊

    618技術(shù)揭秘:探究競速榜頁面核心前端技術(shù) | 京東云技術(shù)團隊

    H5頁面作為移動端Web應(yīng)用的重要形式之一,已經(jīng)成為了現(xiàn)代Web開發(fā)的熱門話題。在H5頁面的開發(fā)過程中,前端技術(shù)的應(yīng)用至關(guān)重要。本文將探究京東競速榜H5頁面的核心前端技術(shù),包括動畫、樣式配置化、皮膚切換、海報技術(shù)、調(diào)試技巧等方面,希望能夠為廣大前端開發(fā)者提供

    2024年02月12日
    瀏覽(21)
  • 楠姐技術(shù)漫話:圖計算的那些事 | 京東云技術(shù)團隊

    不知道大家在平時的工作中 有沒有聽說過“圖計算”這個名詞 但大家一定在各工作匯報,技術(shù)分享中聽說過“智能化”,“人工智能”這樣的字眼 而我們今天要嘮的這個圖計算 就是人工智能領(lǐng)域內(nèi)近幾年炙手可熱的前沿寵兒 也是我們風(fēng)控反欺詐中常用的“大殺器” 在了解

    2024年02月05日
    瀏覽(28)
  • 插件化工程R文件瘦身技術(shù)方案 | 京東云技術(shù)團隊

    隨著業(yè)務(wù)的發(fā)展及版本迭代,客戶端工程中不斷增加新的業(yè)務(wù)邏輯、引入新的資源,隨之而來的問題就是安裝包體積變大,前期各個業(yè)務(wù)模塊通過無用資源刪減、大圖壓縮或轉(zhuǎn)上云、AB實驗業(yè)務(wù)邏輯下線或其他手段在降低包體積上取得了一定的成果。 在瘦身的過程中我們關(guān)注

    2024年02月08日
    瀏覽(28)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包