python 基于redis的令牌桶限流

不用redis的简化版,不区分ip和接口

# -*- coding: utf-8 -*-
import time

from flask import Flask

app = Flask(__name__)

capacity = 10  # 桶容量
rate = 1  # 速率 每秒增加一个令牌
last_time = int(time.time())  # 上次访问时间
current_tokens = capacity  # 当前令牌桶中令牌数量


def can_access():
    global current_tokens
    global last_time

    now = int(time.time())
    increase_tokens = (now - last_time) * rate
    current_tokens = min(capacity, current_tokens + increase_tokens)

    if current_tokens > 0:
        current_tokens -= 1
        last_time = int(time.time())
        return True
    else:
        return False


@app.route('/')
def tokens_bucket():
    if not can_access():
        return '速率超限制'
    return 'Hello, 令牌桶!'


if __name__ == '__main__':
    app.run()

利用redis,区分ip和接口

# -*- coding: utf-8 -*-
import time

from flask import Flask
from flask import request
from redis import Redis

redis_client = Redis()

app = Flask(__name__)

capacity = 5  # 桶容量
rate = 1  # 速率 每秒增加一个令牌


def can_access(ip, func):
    # 限制指定ip访问指定接口的速率,过ip和函数名确定key
    func_name = func.__name__
    redis_key = ip + func_name
    now = int(time.time())
    current_tokens = redis_client.hget(redis_key, 'current_tokens')
    last_time = redis_client.hget(redis_key, 'last_time')

    current_tokens = int(current_tokens) if current_tokens else capacity
    last_time = int(last_time) if last_time else now

    increase_tokens = (now - last_time) * rate # 增加的令牌桶
    current_tokens = min(capacity, current_tokens + increase_tokens)

    if current_tokens > 0:
        redis_client.hset(redis_key, 'current_tokens', current_tokens - 1)
        redis_client.hset(redis_key, 'last_time', int(time.time()))
        return True
    else:
        return False


@app.route('/')
def tokens_bucket():
    ip = request.remote_addr
    if not can_access(ip, tokens_bucket):
        return '当前ip:{}访问:{}接口速率超限制'.format(ip, tokens_bucket.__name__)
    return 'Hello, 令牌桶!'


if __name__ == '__main__':
    app.run()

 更通用的装饰器版:

# -*- coding: utf-8 -*-
import time

from flask import Flask
from flask import request
from redis import Redis

redis_client = Redis()
app = Flask(__name__)
current_tokens_key = 'current_tokens'
last_time_key = 'last_time'


def can_access(rate=1, capacity=5):
    """

    :param rate: 令牌桶添加速率,默认每秒1个
    :param capacity: 令牌桶容量,默认5
    :return:
    """
    def wrapper(func):
        def inner(*arg, **kwargs):
            func_name = func.__name__
            ip = request.remote_addr
            hash_name = ip + func_name
            now = int(time.time())
            current_tokens = redis_client.hget(hash_name, current_tokens_key)
            last_time = redis_client.hget(hash_name, last_time_key)

            current_tokens = int(current_tokens) if current_tokens else capacity
            last_time = int(last_time) if last_time else now

            increase_tokens = (now - last_time) * rate  # 增加的令牌桶
            current_tokens = min(capacity, current_tokens + increase_tokens)

            if current_tokens > 0:
                redis_client.hset(hash_name, current_tokens_key, current_tokens - 1)
                redis_client.hset(hash_name, last_time_key, int(time.time()))
                return func(*arg, **kwargs)
            else:
                return '当前ip:{}访问:{}接口速率超限制'.format(ip, func_name)

        return inner

    return wrapper


@app.route('/')
@can_access(rate=1, capacity=10)
def tokens_bucket():
    return 'Hello, 令牌桶!'


if __name__ == '__main__':
    app.run()

 

 

 
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Redis令牌桶限流是一种常见的限流算法,它基于令牌桶算法实现。根据引用\[1\]中的代码,可以看出Redis令牌桶限流需要一个ScheduledThread来定时放入令牌。具体实现是通过使用ScheduledThreadExecutor.scheduleAtFixedRate方法,在规定的时间间隔内放入令牌到令牌桶中。 与漏桶算法相比,令牌桶算法允许一定程度的突发情况,同时可以方便地改变速率。引用\[2\]中提到,令牌桶算法可以根据需要提高放入桶中令牌的速率,从而提高限流速度。因此,令牌桶算法是限流框架中的核心算法。 在使用Redis令牌桶限流时,可以通过调用相关方法来获取令牌。引用\[3\]中的代码示例展示了如何使用Redis令牌桶限流来限制上传操作的频率。在该示例中,通过调用redisRaterLimiter.acquireToken方法来获取令牌,如果获取到令牌则可以进行上传操作,否则会抛出限流异常。 综上所述,Redis令牌桶限流是一种基于令牌桶算法实现的限流方法,它可以通过定时放入令牌来控制请求的频率,并允许一定程度的突发情况。 #### 引用[.reference_title] - *1* *2* *3* [分布式限流实战--redis实现令牌桶限流](https://blog.csdn.net/u011296165/article/details/107761489)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值