iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >怎么使用Go+Redis实现常见限流算法
  • 331
分享到

怎么使用Go+Redis实现常见限流算法

2023-07-05 20:07:56 331人浏览 独家记忆
摘要

本文小编为大家详细介绍“怎么使用Go+Redis实现常见限流算法”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么使用Go+Redis实现常见限流算法”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。固定窗口使用R

本文小编为大家详细介绍“怎么使用Go+Redis实现常见限流算法”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么使用Go+Redis实现常见限流算法”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

    固定窗口

    使用Redis实现固定窗口比较简单,主要是由于固定窗口同时只会存在一个窗口,所以我们可以在第一次进入窗口时使用pexpire命令设置过期时间为窗口时间大小,这样窗口会随过期时间而失效,同时我们使用incr命令增加窗口计数。

    因为我们需要在counter==1的时候设置窗口的过期时间,为了保证原子性,我们使用简单的lua脚本实现。

    const fixedWindowLimiterTryAcquireRedisScript = `-- ARGV[1]: 窗口时间大小-- ARGV[2]: 窗口请求上限local window = tonumber(ARGV[1])local limit = tonumber(ARGV[2])-- 获取原始值local counter = tonumber(redis.call("get", KEYS[1]))if counter == nil then    counter = 0end-- 若到达窗口请求上限,请求失败if counter >= limit then   return 0end-- 窗口值+1redis.call("incr", KEYS[1])if counter == 0 then    redis.call("pexpire", KEYS[1], window)endreturn 1`
    package redisimport (   "context"   "errors"   "GitHub.com/go-redis/redis/v8"   "time")// FixedWindowLimiter 固定窗口限流器type FixedWindowLimiter struct {   limit  int           // 窗口请求上限   window int           // 窗口时间大小   client *redis.Client // Redis客户端   script *redis.Script // TryAcquire脚本}func NewFixedWindowLimiter(client *redis.Client, limit int, window time.Duration) (*FixedWindowLimiter, error) {   // redis过期时间精度最大到毫秒,因此窗口必须能被毫秒整除   if window%time.Millisecond != 0 {      return nil, errors.New("the window uint must not be less than millisecond")   }   return &FixedWindowLimiter{      limit:  limit,      window: int(window / time.Millisecond),      client: client,      script: redis.NewScript(fixedWindowLimiterTryAcquireRedisScript),   }, nil}func (l *FixedWindowLimiter) TryAcquire(ctx context.Context, resource string) error {   success, err := l.script.Run(ctx, l.client, []string{resource}, l.window, l.limit).Bool()   if err != nil {      return err   }   // 若到达窗口请求上限,请求失败   if !success {      return ErrAcquireFailed   }   return nil}

    滑动窗口

    hash实现

    我们使用Redis的hash存储每个小窗口的计数,每次请求会把所有有效窗口的计数累加到count,使用hdel删除失效窗口,最后判断窗口的总计数是否大于上限。

    我们基本上把所有的逻辑都放到Lua脚本里面,其中大头是对hash的遍历,时间复杂度是O(N),N是小窗口数量,所以小窗口数量最好不要太多。

    const slidingWindowLimiterTryAcquireRedisScriptHashImpl = `-- ARGV[1]: 窗口时间大小-- ARGV[2]: 窗口请求上限-- ARGV[3]: 当前小窗口值-- ARGV[4]: 起始小窗口值local window = tonumber(ARGV[1])local limit = tonumber(ARGV[2])local currentSmallWindow = tonumber(ARGV[3])local startSmallWindow = tonumber(ARGV[4])-- 计算当前窗口的请求总数local counters = redis.call("hgetall", KEYS[1])local count = 0for i = 1, #(counters) / 2 do    local smallWindow = tonumber(counters[i * 2 - 1])   local counter = tonumber(counters[i * 2])   if smallWindow < startSmallWindow then      redis.call("hdel", KEYS[1], smallWindow)   else       count = count + counter   endend-- 若到达窗口请求上限,请求失败if count >= limit then   return 0end-- 若没到窗口请求上限,当前小窗口计数器+1,请求成功redis.call("hincrby", KEYS[1], currentSmallWindow, 1)redis.call("pexpire", KEYS[1], window)return 1`
    package redisimport (   "context"   "errors"   "github.com/go-redis/redis/v8"   "time")// SlidingWindowLimiter 滑动窗口限流器type SlidingWindowLimiter struct {   limit        int           // 窗口请求上限   window       int64         // 窗口时间大小   smallWindow  int64         // 小窗口时间大小   smallwindows int64         // 小窗口数量   client       *redis.Client // Redis客户端   script       *redis.Script // TryAcquire脚本}func NewSlidingWindowLimiter(client *redis.Client, limit int, window, smallWindow time.Duration) (   *SlidingWindowLimiter, error) {   // redis过期时间精度最大到毫秒,因此窗口必须能被毫秒整除   if window%time.Millisecond != 0 || smallWindow%time.Millisecond != 0 {      return nil, errors.New("the window uint must not be less than millisecond")   }   // 窗口时间必须能够被小窗口时间整除   if window%smallWindow != 0 {      return nil, errors.New("window cannot be split by integers")   }   return &SlidingWindowLimiter{      limit:        limit,      window:       int64(window / time.Millisecond),      smallWindow:  int64(smallWindow / time.Millisecond),      smallWindows: int64(window / smallWindow),      client:       client,      script:       redis.NewScript(slidingWindowLimiterTryAcquireRedisScriptHashImpl),   }, nil}func (l *SlidingWindowLimiter) TryAcquire(ctx context.Context, resource string) error {   // 获取当前小窗口值   currentSmallWindow := time.Now().UnixMilli() / l.smallWindow * l.smallWindow   // 获取起始小窗口值   startSmallWindow := currentSmallWindow - l.smallWindow*(l.smallWindows-1)   success, err := l.script.Run(      ctx, l.client, []string{resource}, l.window, l.limit, currentSmallWindow, startSmallWindow).Bool()   if err != nil {      return err   }   // 若到达窗口请求上限,请求失败   if !success {      return ErrAcquireFailed   }   return nil}

    list实现

    如果小窗口数量特别多,可以使用list优化时间复杂度,list的结构是:

    [counter, smallWindow1, count1, smallWindow2, count2, smallWindow3, count3...]

    也就是我们使用list的第一个元素存储计数器,每个窗口用两个元素表示,第一个元素表示小窗口值,第二个元素表示这个小窗口的计数。不直接把小窗口值和计数放到一个元素里是因为Redis Lua脚本里没有分割字符串的函数。

    具体操作流程:

    获取list长度

    如果长度是0,设置counter,长度+1

    如果长度大于1,获取第二第三个元素

    如果该值小于起始小窗口值,counter-第三个元素的值,删除第二第三个元素,长度-2

    如果counter大于等于limit,请求失败

    如果长度大于1,获取倒数第二第一个元素

    • 如果倒数第二个元素小窗口值大于等于当前小窗口值,表示当前请求因为网络延迟的问题,到达服务器的时候,窗口已经过时了,把倒数第二个元素当成当前小窗口(因为它更新),倒数第一个元素值+1

    • 否则,添加新的窗口值,添加新的计数(1),更新过期时间

    否则,添加新的窗口值,添加新的计数(1),更新过期时间

    counter + 1

    返回成功

    const slidingWindowLimiterTryAcquireRedisScriptListImpl = `-- ARGV[1]: 窗口时间大小-- ARGV[2]: 窗口请求上限-- ARGV[3]: 当前小窗口值-- ARGV[4]: 起始小窗口值local window = tonumber(ARGV[1])local limit = tonumber(ARGV[2])local currentSmallWindow = tonumber(ARGV[3])local startSmallWindow = tonumber(ARGV[4])-- 获取list长度local len = redis.call("llen", KEYS[1])-- 如果长度是0,设置counter,长度+1local counter = 0if len == 0 then    redis.call("rpush", KEYS[1], 0)   redis.call("pexpire", KEYS[1], window)   len = len + 1else   -- 如果长度大于1,获取第二第个元素   local smallWindow1 = tonumber(redis.call("lindex", KEYS[1], 1))   counter = tonumber(redis.call("lindex", KEYS[1], 0))   -- 如果该值小于起始小窗口值   if smallWindow1 < startSmallWindow then       local count1 = redis.call("lindex", KEYS[1], 2)      -- counter-第三个元素的值      counter = counter - count1      -- 长度-2      len = len - 2      -- 删除第二第三个元素      redis.call("lrem", KEYS[1], 1, smallWindow1)      redis.call("lrem", KEYS[1], 1, count1)   endend-- 若到达窗口请求上限,请求失败if counter >= limit then    return 0end -- 如果长度大于1,获取倒数第二第一个元素if len > 1 then   local smallWindown = tonumber(redis.call("lindex", KEYS[1], -2))   -- 如果倒数第二个元素小窗口值大于等于当前小窗口值   if smallWindown >= currentSmallWindow then      -- 把倒数第二个元素当成当前小窗口(因为它更新),倒数第一个元素值+1      local countn = redis.call("lindex", KEYS[1], -1)      redis.call("lset", KEYS[1], -1, countn + 1)   else       -- 否则,添加新的窗口值,添加新的计数(1),更新过期时间      redis.call("rpush", KEYS[1], currentSmallWindow, 1)      redis.call("pexpire", KEYS[1], window)   endelse    -- 否则,添加新的窗口值,添加新的计数(1),更新过期时间   redis.call("rpush", KEYS[1], currentSmallWindow, 1)   redis.call("pexpire", KEYS[1], window)end -- counter + 1并更新redis.call("lset", KEYS[1], 0, counter + 1)return 1`

    算法都是操作list头部或者尾部,所以时间复杂度接近O(1)

    漏桶算法

    漏桶需要保存当前水位和上次放水时间,因此我们使用hash来保存这两个值。

    const leakyBucketLimiterTryAcquireRedisScript = `-- ARGV[1]: 最高水位-- ARGV[2]: 水流速度/秒-- ARGV[3]: 当前时间(秒)local peakLevel = tonumber(ARGV[1])local currentVelocity = tonumber(ARGV[2])local now = tonumber(ARGV[3])local lastTime = tonumber(redis.call("hget", KEYS[1], "lastTime"))local currentLevel = tonumber(redis.call("hget", KEYS[1], "currentLevel"))-- 初始化if lastTime == nil then    lastTime = now   currentLevel = 0   redis.call("hmset", KEYS[1], "currentLevel", currentLevel, "lastTime", lastTime)end -- 尝试放水-- 距离上次放水的时间local interval = now - lastTimeif interval > 0 then   -- 当前水位-距离上次放水的时间(秒)*水流速度   local newLevel = currentLevel - interval * currentVelocity   if newLevel < 0 then       newLevel = 0   end    currentLevel = newLevel   redis.call("hmset", KEYS[1], "currentLevel", newLevel, "lastTime", now)end-- 若到达最高水位,请求失败if currentLevel >= peakLevel then   return 0end-- 若没有到达最高水位,当前水位+1,请求成功redis.call("hincrby", KEYS[1], "currentLevel", 1)redis.call("expire", KEYS[1], peakLevel / currentVelocity)return 1`
    package redisimport (   "context"   "github.com/go-redis/redis/v8"   "time")// LeakyBucketLimiter 漏桶限流器type LeakyBucketLimiter struct {   peakLevel       int           // 最高水位   currentVelocity int           // 水流速度/秒   client          *redis.Client // Redis客户端   script          *redis.Script // TryAcquire脚本}func NewLeakyBucketLimiter(client *redis.Client, peakLevel, currentVelocity int) *LeakyBucketLimiter {   return &LeakyBucketLimiter{      peakLevel:       peakLevel,      currentVelocity: currentVelocity,      client:          client,      script:          redis.NewScript(leakyBucketLimiterTryAcquireRedisScript),   }}func (l *LeakyBucketLimiter) TryAcquire(ctx context.Context, resource string) error {   // 当前时间   now := time.Now().Unix()   success, err := l.script.Run(ctx, l.client, []string{resource}, l.peakLevel, l.currentVelocity, now).Bool()   if err != nil {      return err   }   // 若到达窗口请求上限,请求失败   if !success {      return ErrAcquireFailed   }   return nil}

    令牌桶

    令牌桶可以看作是漏桶的相反算法,它们一个是把水倒进桶里,一个是从桶里获取令牌。

    const tokenBucketLimiterTryAcquireRedisScript = `-- ARGV[1]: 容量-- ARGV[2]: 发放令牌速率/秒-- ARGV[3]: 当前时间(秒)local capacity = tonumber(ARGV[1])local rate = tonumber(ARGV[2])local now = tonumber(ARGV[3])local lastTime = tonumber(redis.call("hget", KEYS[1], "lastTime"))local currentTokens = tonumber(redis.call("hget", KEYS[1], "currentTokens"))-- 初始化if lastTime == nil then    lastTime = now   currentTokens = capacity   redis.call("hmset", KEYS[1], "currentTokens", currentTokens, "lastTime", lastTime)end -- 尝试发放令牌-- 距离上次发放令牌的时间local interval = now - lastTimeif interval > 0 then   -- 当前令牌数量+距离上次发放令牌的时间(秒)*发放令牌速率   local newTokens = currentTokens + interval * rate   if newTokens > capacity then       newTokens = capacity   end    currentTokens = newTokens   redis.call("hmset", KEYS[1], "currentTokens", newTokens, "lastTime", now)end-- 如果没有令牌,请求失败if currentTokens == 0 then   return 0end-- 果有令牌,当前令牌-1,请求成功redis.call("hincrby", KEYS[1], "currentTokens", -1)redis.call("expire", KEYS[1], capacity / rate)return 1`
    package redisimport (   "context"   "github.com/go-redis/redis/v8"   "time")// TokenBucketLimiter 令牌桶限流器type TokenBucketLimiter struct {   capacity int           // 容量   rate     int           // 发放令牌速率/秒   client   *redis.Client // Redis客户端   script   *redis.Script // TryAcquire脚本}func NewTokenBucketLimiter(client *redis.Client, capacity, rate int) *TokenBucketLimiter {   return &TokenBucketLimiter{      capacity: capacity,      rate:     rate,      client:   client,      script:   redis.NewScript(tokenBucketLimiterTryAcquireRedisScript),   }}func (l *TokenBucketLimiter) TryAcquire(ctx context.Context, resource string) error {   // 当前时间   now := time.Now().Unix()   success, err := l.script.Run(ctx, l.client, []string{resource}, l.capacity, l.rate, now).Bool()   if err != nil {      return err   }   // 若到达窗口请求上限,请求失败   if !success {      return ErrAcquireFailed   }   return nil}

    滑动日志

    算法流程与滑动窗口相同,只是它可以指定多个策略,同时在请求失败的时候,需要通知调用方是被哪个策略所拦截。

    const slidingLogLimiterTryAcquireRedisScriptHashImpl = `-- ARGV[1]: 当前小窗口值-- ARGV[2]: 第一个策略的窗口时间大小-- ARGV[i * 2 + 1]: 每个策略的起始小窗口值-- ARGV[i * 2 + 2]: 每个策略的窗口请求上限local currentSmallWindow = tonumber(ARGV[1])-- 第一个策略的窗口时间大小local window = tonumber(ARGV[2])-- 第一个策略的起始小窗口值local startSmallWindow = tonumber(ARGV[3])local strategiesLen = #(ARGV) / 2 - 1-- 计算每个策略当前窗口的请求总数local counters = redis.call("hgetall", KEYS[1])local counts = {}-- 初始化countsfor j = 1, strategiesLen do   counts[j] = 0endfor i = 1, #(counters) / 2 do    local smallWindow = tonumber(counters[i * 2 - 1])   local counter = tonumber(counters[i * 2])   if smallWindow < startSmallWindow then      redis.call("hdel", KEYS[1], smallWindow)   else       for j = 1, strategiesLen do         if smallWindow >= tonumber(ARGV[j * 2 + 1]) then            counts[j] = counts[j] + counter         end      end   endend-- 若到达对应策略窗口请求上限,请求失败,返回违背的策略下标for i = 1, strategiesLen do   if counts[i] >= tonumber(ARGV[i * 2 + 2]) then      return i - 1   endend-- 若没到窗口请求上限,当前小窗口计数器+1,请求成功redis.call("hincrby", KEYS[1], currentSmallWindow, 1)redis.call("pexpire", KEYS[1], window)return -1`
    package redisimport (   "context"   "errors"   "fmt"   "github.com/go-redis/redis/v8"   "sort"   "time")// ViolationStrategyError 违背策略错误type ViolationStrategyError struct {   Limit  int           // 窗口请求上限   Window time.Duration // 窗口时间大小}func (e *ViolationStrategyError) Error() string {   return fmt.Sprintf("violation strategy that limit = %d and window = %d", e.Limit, e.Window)}// SlidingLogLimiterStrategy 滑动日志限流器的策略type SlidingLogLimiterStrategy struct {   limit        int   // 窗口请求上限   window       int64 // 窗口时间大小   smallWindows int64 // 小窗口数量}func NewSlidingLogLimiterStrategy(limit int, window time.Duration) *SlidingLogLimiterStrategy {   return &SlidingLogLimiterStrategy{      limit:  limit,      window: int64(window),   }}// SlidingLogLimiter 滑动日志限流器type SlidingLogLimiter struct {   strategies  []*SlidingLogLimiterStrategy // 滑动日志限流器策略列表   smallWindow int64                        // 小窗口时间大小   client      *redis.Client                // Redis客户端   script      *redis.Script                // TryAcquire脚本}func NewSlidingLogLimiter(client *redis.Client, smallWindow time.Duration, strategies ...*SlidingLogLimiterStrategy) (   *SlidingLogLimiter, error) {   // 复制策略避免被修改   strategies = append(make([]*SlidingLogLimiterStrategy, 0, len(strategies)), strategies...)   // 不能不设置策略   if len(strategies) == 0 {      return nil, errors.New("must be set strategies")   }   // redis过期时间精度最大到毫秒,因此窗口必须能被毫秒整除   if smallWindow%time.Millisecond != 0 {      return nil, errors.New("the window uint must not be less than millisecond")   }   smallWindow = smallWindow / time.Millisecond   for _, strategy := range strategies {      if strategy.window%int64(time.Millisecond) != 0 {         return nil, errors.New("the window uint must not be less than millisecond")      }      strategy.window = strategy.window / int64(time.Millisecond)   }   // 排序策略,窗口时间大的排前面,相同窗口上限大的排前面   sort.Slice(strategies, func(i, j int) bool {      a, b := strategies[i], strategies[j]      if a.window == b.window {         return a.limit > b.limit      }      return a.window > b.window   })   for i, strategy := range strategies {      // 随着窗口时间变小,窗口上限也应该变小      if i > 0 {         if strategy.limit >= strategies[i-1].limit {            return nil, errors.New("the smaller window should be the smaller limit")         }      }      // 窗口时间必须能够被小窗口时间整除      if strategy.window%int64(smallWindow) != 0 {         return nil, errors.New("window cannot be split by integers")      }      strategy.smallWindows = strategy.window / int64(smallWindow)   }   return &SlidingLogLimiter{      strategies:  strategies,      smallWindow: int64(smallWindow),      client:      client,      script:      redis.NewScript(slidingLogLimiterTryAcquireRedisScriptHashImpl),   }, nil}func (l *SlidingLogLimiter) TryAcquire(ctx context.Context, resource string) error {   // 获取当前小窗口值   currentSmallWindow := time.Now().UnixMilli() / l.smallWindow * l.smallWindow   args := make([]interface{}, len(l.strategies)*2+2)   args[0] = currentSmallWindow   args[1] = l.strategies[0].window   // 获取每个策略的起始小窗口值   for i, strategy := range l.strategies {      args[i*2+2] = currentSmallWindow - l.smallWindow*(strategy.smallWindows-1)      args[i*2+3] = strategy.limit   }   index, err := l.script.Run(      ctx, l.client, []string{resource}, args...).Int()   if err != nil {      return err   }   // 若到达窗口请求上限,请求失败   if index != -1 {      return &ViolationStrategyError{         Limit:  l.strategies[index].limit,         Window: time.Duration(l.strategies[index].window),      }   }   return nil}

    读到这里,这篇“怎么使用Go+Redis实现常见限流算法”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网精选频道。

    --结束END--

    本文标题: 怎么使用Go+Redis实现常见限流算法

    本文链接: https://www.lsjlt.com/news/354976.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • 怎么使用Go+Redis实现常见限流算法
      本文小编为大家详细介绍“怎么使用Go+Redis实现常见限流算法”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么使用Go+Redis实现常见限流算法”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。固定窗口使用R...
      99+
      2023-07-05
    • Go+Redis实现常见限流算法的示例代码
      目录固定窗口滑动窗口hash实现list实现漏桶算法令牌桶滑动日志总结限流是项目中经常需要使用到的一种工具,一般用于限制用户的请求的频率,也可以避免瞬间流量过大导致系统崩溃,或者稳定消息处理速率。并且有时候我们还需要使用...
      99+
      2023-04-02
      Go Redis实现限流算法 Go Redis限流算法 Go 限流算法
    • Java常见的限流算法怎么实现
      这篇“Java常见的限流算法怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java常见的限流算法怎么实现”文章吧。为...
      99+
      2023-06-29
    • Golang怎么实现常见的限流算法
      本篇内容介绍了“Golang怎么实现常见的限流算法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!固定窗口每开启一个新的窗口,在窗口时间大小内...
      99+
      2023-07-05
    • redis实现的四种常见限流策略
      目录引言固定时间窗口算法实现滑动时间窗口算法实现漏桶算法实现令牌桶算法引言 在web开发中功能是基石,除了功能以外运维和防护就是重头菜了。因为在网站运行期间可能会因为突然的...
      99+
      2024-04-02
    • redis lua限流算法实现示例
      目录限流算法计数器算法场景分析算法实现漏铜算法令牌桶算法:算法实现限流算法 常见的限流算法 计数器算法漏桶算法令牌桶算法 计数器算法   顾名思义,计数器算法是指...
      99+
      2024-04-02
    • redis lua限流算法如何实现
      本篇内容介绍了“redis lua限流算法如何实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!限流算法常见的限流算法计数器算法漏...
      99+
      2023-07-02
    • Golang实现常见的限流算法的示例代码
      目录固定窗口滑动窗口漏桶算法令牌桶滑动日志总结限流是项目中经常需要使用到的一种工具,一般用于限制用户的请求的频率,也可以避免瞬间流量过大导致系统崩溃,或者稳定消息处理速率 这个文章主...
      99+
      2023-05-14
      Golang常见限流算法 Golang限流算法 Go 限流算法
    • Java常见的限流算法详细分析并实现
      目录为什么要限流限流算法计数器限流漏桶限流令牌桶限流为什么要限流 在保证可用的情况下尽可能多增加进入的人数,其余的人在排队等待,或者返回友好提示,保证里面的进行系统的用户可以正常使用...
      99+
      2024-04-02
    • 使用Java实现Redis限流的方法
      1、概述   限流的含义是在单位时间内确保发往某个模块的请求数量小于某个数值,比如在实现秒杀功能时,需要确保在10秒内发往支付模块的请求数量小于500个。限流...
      99+
      2024-04-02
    • Redis限流怎么实现
      这篇文章给大家分享的是有关Redis限流怎么实现的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。面对越来越多的高并发场景,限流显示的尤为重要。当然,限流有许多种实现的方式,Redi...
      99+
      2024-04-02
    • 使用AOP+redis+lua做方法限流的实现
      目录需求实现方式源码Limit 注解LimitKeyLimitTypeRedisLimiterHelperLimitInterceptorTestService需求 公司里使用One...
      99+
      2024-04-02
    • GO语言中常见的排序算法怎么使用
      今天小编给大家分享一下GO语言中常见的排序算法怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。快排package&nb...
      99+
      2023-06-30
    • 详解基于redis实现的四种常见的限流策略
      目录一、引言二、固定时间窗口算法三、滑动时间窗口算法四、漏桶算法五、令牌桶算法一、引言 在web开发中功能是基石,除了功能以外运维和防护就是重头菜了。因为在网站运行期间可能...
      99+
      2024-04-02
    • 如何用Go语言和Redis实现API限流
      如何用Go语言和Redis实现API限流概述:随着互联网的快速发展,API接口的使用量也在不断增加,而某些API接口可能会因为请求过多而导致系统负载过高甚至瘫痪。为了保障系统的稳定性和可靠性,我们需要对API接口进行限流。本文将介绍如何使用...
      99+
      2023-10-26
      Go语言 redis API限流
    • Java常见排序算法怎么实现
      本文小编为大家详细介绍“Java常见排序算法怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java常见排序算法怎么实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。汇总:1. 冒泡排序每轮循环确定最值;...
      99+
      2023-06-29
    • 怎么使用Java实现常见的负载均衡算法
      在Java中实现常见的负载均衡算法,可以使用以下几种方法: 轮询算法(Round Robin):实现一个列表来存储服务器节点,并...
      99+
      2024-04-09
      Java
    • Springboot使用redis实现接口Api限流的方法
      这篇文章主要介绍“Springboot使用redis实现接口Api限流的方法”,在日常操作中,相信很多人在Springboot使用redis实现接口Api限流的方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答...
      99+
      2023-06-20
    • Golang怎么实现常见排序算法
      这篇文章主要介绍“Golang怎么实现常见排序算法”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Golang怎么实现常见排序算法”文章能帮助大家解决问题。五种基础排序算法对比五种基础排序算法对比1、...
      99+
      2023-06-30
    • 怎么用Redis Lua脚本实现ip限流
      这篇文章主要讲解了“怎么用Redis Lua脚本实现ip限流”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么用Redis Lua脚本实现ip限流”吧!引言分布式限流最关...
      99+
      2023-07-02
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作