日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

基于Redis实现分布式应用限流--转

發布時間:2025/4/5 数据库 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于Redis实现分布式应用限流--转 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文地址:https://my.oschina.net/giegie/blog/1525931

摘要: 限流的目的是通過對并發訪問/請求進行限速或者一個時間窗口內的的請求進行限速來保護系統,一旦達到限制速率則可以拒絕服務。

限流的目的是通過對并發訪問/請求進行限速或者一個時間窗口內的的請求進行限速來保護系統,一旦達到限制速率則可以拒絕服務。

前幾天在DD的公眾號,看了一篇關于使用 瓜娃 實現單應用限流的方案 --》原文,參考《redis in action》 實現了一個jedis版本的,都屬于業務層次限制。 實際場景中常用的限流策略:

  • Nginx接入層限流
    按照一定的規則如帳號、IP、系統調用邏輯等在Nginx層面做限流

  • 業務應用系統限流
    通過業務代碼控制流量這個流量可以被稱為信號量,可以理解成是一種鎖,它可以限制一項資源最多能同時被多少進程訪問。

代碼實現

import redis.clients.jedis.Jedis; import redis.clients.jedis.Transaction; import redis.clients.jedis.ZParams;import java.util.List; import java.util.UUID; /** * @email wangiegie@gmail.com * @data 2017-08 */ public class RedisRateLimiter { private static final String BUCKET = "BUCKET"; private static final String BUCKET_COUNT = "BUCKET_COUNT"; private static final String BUCKET_MONITOR = "BUCKET_MONITOR"; static String acquireTokenFromBucket( Jedis jedis, int limit, long timeout) { String identifier = UUID.randomUUID().toString(); long now = System.currentTimeMillis(); Transaction transaction = jedis.multi(); //刪除信號量 transaction.zremrangeByScore(BUCKET_MONITOR.getBytes(), "-inf".getBytes(), String.valueOf(now - timeout).getBytes()); ZParams params = new ZParams(); params.weightsByDouble(1.0,0.0); transaction.zinterstore(BUCKET, params, BUCKET, BUCKET_MONITOR); //計數器自增 transaction.incr(BUCKET_COUNT); List<Object> results = transaction.exec(); long counter = (Long) results.get(results.size() - 1); transaction = jedis.multi(); transaction.zadd(BUCKET_MONITOR, now, identifier); transaction.zadd(BUCKET, counter, identifier); transaction.zrank(BUCKET, identifier); results = transaction.exec(); //獲取排名,判斷請求是否取得了信號量 long rank = (Long) results.get(results.size() - 1); if (rank < limit) { return identifier; } else {//沒有獲取到信號量,清理之前放入redis 中垃圾數據 transaction = jedis.multi(); transaction.zrem(BUCKET_MONITOR, identifier); transaction.zrem(BUCKET, identifier); transaction.exec(); } return null; } }

調用

測試接口調用 @GetMapping("/") public void index(HttpServletResponse response) throws IOException {Jedis jedis = jedisPool.getResource();String token = RedisRateLimiter.acquireTokenFromBucket(jedis, LIMIT, TIMEOUT);if (token == null) { response.sendError(500); }else{ //TODO 你的業務邏輯 } jedisPool.returnResource(jedis); }

優化

使用攔截器 + 注解優化代碼

攔截器

@Configuration static class WebMvcConfigurer extends WebMvcConfigurerAdapter {private Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);@Autowiredprivate JedisPool jedisPool;public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new HandlerInterceptorAdapter() { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); RateLimiter rateLimiter = method.getAnnotation(RateLimiter.class); if (rateLimiter != null){ int limit = rateLimiter.limit(); int timeout = rateLimiter.timeout(); Jedis jedis = jedisPool.getResource(); String token = RedisRateLimiter.acquireTokenFromBucket(jedis, limit, timeout); if (token == null) { response.sendError(500); return false; } logger.debug("token -> {}",token); jedis.close(); } return true; } }).addPathPatterns("/*"); } }

定義注解

/*** @email wangiegie@gmail.com* @data 2017-08* 限流注解*/@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RateLimiter { int limit() default 5; int timeout() default 1000; }

使用

@RateLimiter(limit = 2, timeout = 5000) @GetMapping("/test") public void test() { }

并發測試

工具:apache-jmeter-3.2
說明: 沒有獲取到信號量的接口返回500,status是紅色,獲取到信號量的接口返回200,status是綠色。
當限制請求信號量為2,并發5個線程:?
當限制請求信號量為5,并發10個線程:

資料

基于reids + lua的實現

張開濤-聊聊高并發系統之限流特技-1

總結

  • 對于信號量的操作,使用事務操作。
  • 不要使用時間戳作為信號量的排序分數,因為在分布式環境中,各個節點的時間差的原因,會出現不公平信號量的現象。
  • 可以使用把這塊代碼抽成@rateLimiter注解,然后再方法上使用就會很方便啦
  • 不同接口的流控,可以參考源碼的里面RedisRateLimiterPlus,無非是每個接口生成一個監控參數
  • 源碼http://git.oschina.net/boding1/pig-cloud
  • 轉載于:https://www.cnblogs.com/davidwang456/p/7457830.html

    《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的基于Redis实现分布式应用限流--转的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。