nova api limit源码剖析

本文深入剖析了OpenStack Nova项目的API限流机制,重点介绍了RateLimitingMiddleware组件的工作原理及其实现流程。通过分析代码结构,展示了如何利用Limit、Limiter等类实现对API请求的精细控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

nova api limit

nova的一天请求量大概在30w条,大量的并发操作经常会block到某一个点上,比如数据库读写。如何使得nova集群可以有条不紊的处理请求是保证服务稳定性的一个难点。对于解决上述问题,我们希望在nova拒绝掉处理不过来的请求,而保证用户可以及时获取响应,而不是等待600s后的timeout。

*ratelimit是一个用来限制api响应的wsgi中间件,只需要配置即可方便使用。本文着重分析其实现流程。

源码分析:

从代码结构来看,该功能主要由以下几个calss实现:
- 1 Limit
- 2 Limiter
- 3 LimitsController
- 4 RateLimitingMiddleware

1. class Limit

该类主要功能是从配置文件中读取limit信息并将其封装一个Limit对象。并且在其中判断响应是否接受。
配置示例如下:

limits =(GET, ““, ., 1, MINUTE);(POST, “*/servers”, ^/servers, 1, MINUTE);

该示例有两个limit,一个是针对GET请求,一个是针对POST方法下的*/server 请求。
针对 (GET, ““, ., 120, MINUTE) 其意思是,每分钟可以接受120个GET方法的请求
封装内容如下

    self.verb = verb        # GET
    self.uri = uri        # *
    self.regex = regex        # .*
    self.value = int(value)        # 120
    self.unit = unit        # 60
    self.unit_string = self.display_unit().lower()        # minute
    self.remaining = int(value)        # 120
    if value <= 0:
        raise ValueError("Limit value must be > 0")
    self.last_request = None
    self.next_request = None
    self.water_level = 0
    self.capacity = self.unit
    self.request_value = float(self.capacity) / float(self.value)        # 0.5 即每0.5秒接受一个请求

2. class Limiter

该类主要功能持有Limit对象,并将其内容,状态缓存在内存中。

    self.limits = copy.deepcopy(limits)
    self.levels = collections.defaultdict(lambda: copy.deepcopy(limits))

该init主要是持有Limit对象,冰球保存状态,其中self.levels生成一个类似dict的数据结构,可以针对每个user做不同的limit。

3.class LimitsController

该类主要功能是实现对Limit对象的增删改查,在H版本还未实现主要功能,仅仅实现了一个index功能。

4.class RateLimitingMiddleware

该类主要功能主要作为wsgi一个中间件,对外提供入口,处理每一个请求。

流程分析:

示例:
客户端输入: nova service-list
实际执行的请求是: GET http://127.0.0.1:8774/v2/13d216f5470b49328e78dd3a11164259/os-services

代码片段 (一)
/nova/api/openstack/compute/limits.py(289)call()

    verb = req.method
    url = req.url
    context = req.environ.get("nova.context")
    if context:
        username = context.user_id
    else:
        username = None
    delay, error = self._limiter.check_for_delay(verb, url, username)      
    if delay:
        msg = _("This request was rate-limited.")
        retry = time.time() + delay
        return wsgi.RateLimitFault(msg, error, retry)
    req.environ["nova.limits"] = self._limiter.get_limits(username)
    return self.application

首先分析请求属于什么http方法,以及url是什么
verb :get
url : http://127.0.0.1:8774/v2/13d216f5470b49328e78dd3a11164259/os-services
delay用于接受请求被判断后需要延迟多久,并将这个错误以code429形式返回给用户。

代码片段(二)
/nova/api/openstack/compute/limits.py(328)check_for_delay()

def check_for_delay(self, verb, url, username=None): 
    delays = []
    for limit in self.levels[username]:
        delay = limit(verb, url)
        if delay:
            delays.append((delay, limit.error_message))
    if delays:
        delays.sort()
        return delays[0]
    return None, None

self.levels是nova预先从配置文件加载的所有limit的条件。
delays用来存limit判断需要延迟响应的请求,示例如下:

[(39.632054805755615, u’Only 1 GET request(s) can be made to “*” every minute.’)]

代码片段(三)
/nova/api/openstack/compute/limits.py(178)call()
*该方法主要判断当前请求是否在阈值内,即阈值算法*

    if self.verb != verb or not re.match(self.regex, url):
        return
    now = self._get_time()
    if self.last_request is None:
        self.last_request = now
    leak_value = now - self.last_request
    self.water_level -= leak_value
    self.water_level = max(self.water_level, 0)
    self.water_level += self.request_value
    difference = self.water_level - self.capacity
    self.last_request = now
    if difference > 0:
        self.water_level -= self.request_value
        self.next_request = now + difference
        return difference
    cap = self.capacity
    water = self.water_level
    val = self.valu
    self.remaining = math.floor(((cap - water) / cap) * val)
    self.next_request = now

主要是self.water_level控制水位,来判断两次请求之间时间是否超过阈值,比如对于1分钟120次请求的limit。那么判断两次请求之间是否大于0.5秒,如果difference>0,则认为两次请求之间过短,把需要延迟的时间,补齐0.5s-两次请求间隔的时间返回。否则则认为请求可以接受。

总结:

对api限制请求响应,大致有两种做法,一种使用一个bucket,采用计数方式,每一个请求拿一个令牌,先到先得。另外一种是计算时间间隔。nova采用的后一种,看起来实现过程简单,并且粒度很细,可以针对某个http方法限制,也可以针对某个url限制,还可以针对某个用户限制。limit模块做一个wsgi中间件,与nova本身解耦,使用的时候,只需要在apt-paste.ini文件中添加,并且该模块可以很方便的移植到openstack其他项目中。真正的难点在于如何合理的限制api,限制哪些api,阈值是多少。这部分可以借鉴elk,通过比对14天nova各api响应数量,可以初步得到一个正常使用值。但该值并不是阈值,阈值需要借助qa性能组力量进行压力测试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值