Django Ninja下用户API请求存储、限流与历史数据统计实现方案咨询
问题1:请求总次数统计方案
存储选型不用纠结,根据你的实际需求选就行:
- 要是只需要统计总请求数,用户规模在10万以内,直接在
APIKey模型里加个request_total = models.PositiveBigIntegerField(default=0)字段就够了;要是后续还要做按日/周/月的维度统计,优先新增独立的日统计模型,参考定义如下:
from django.db import models from datetime import date class APIKeyDailyStats(models.Model): apikey = models.ForeignKey(APIKey, on_delete=models.CASCADE, related_name="daily_stats") stat_date = models.DateField(default=date.today) request_count = models.PositiveIntegerField(default=0) class Meta: constraints = [ models.UniqueConstraint(fields=["apikey", "stat_date"], name="unique_apikey_per_day") ]
实现方案优先选Redis+定时任务的组合,完全不会拖累你现有接口的低延迟特性:
- 每次请求鉴权通过后,调用Redis的
INCR命令,分别对apikey:<apikey_id>:total(总请求数)、apikey:<apikey_id>:day:<当日日期>(当日请求数)两个key做自增,Redis单命令是原子操作,不会出现并发计数错误的问题 - 配置定时任务(可用Django Q、Celery Beat甚至系统crontab实现),每小时同步一次Redis的总请求数到
APIKey模型的request_total字段,每日0点10分同步前一天的日请求数到APIKeyDailyStats表,同步完成后删除对应过期的Redis key即可
如果你的用户量非常小(比如小于1万),也可以用自定义中间件实现,但是要注意用select_for_update加锁避免并发计数错误,性能会比Redis方案差一些。
问题2:每日请求上限实现方案
最优方案直接用Redis的过期特性实现,完全不需要自己写重置逻辑:
- 给当日请求数的Redis key设置TTL,TTL值计算为「次日0点01分的时间戳 - 当前时间戳」,到期后Redis会自动删除该key
- 每次请求执行
INCR后,判断返回的计数值是否超过你设置的单日上限(比如100),超过就直接返回429状态码提示请求超限即可 - 第二天第一次请求时,该key已经被删除,
INCR会自动从1开始计数,刚好满足你00:01自动重置的需求
该方案性能损耗极低,完全适配你现有接口无数据库操作的特性,并发场景下也不会有问题。
问题3:最近7天请求量统计方案
直接基于你存储在数据库的APIKeyDailyStats表查询即可,Django ORM就能快速实现:
from datetime import datetime, timedelta def get_7days_stats(apikey): end_date = datetime.now().date() start_date = end_date - timedelta(days=6) # 包含当天共7天 # 查询该apikey最近7天的统计数据 stats = APIKeyDailyStats.objects.filter( apikey=apikey, stat_date__gte=start_date, stat_date__lte=end_date ).values_list("stat_date", "request_count") # 转成字典方便查找 stats_dict = {item[0]: item[1] for item in stats} # 补全没有请求记录的日期,计数为0 result = [] for i in range(7): current_date = start_date + timedelta(days=i) result.append({ "date": current_date.strftime("%Y-%m-%d"), "count": stats_dict.get(current_date, 0) }) return result
如果没有提前存日统计数据,也可以临时从Redis中拉取最近7天的key对应的值,但是长期来看数据库存储的历史统计数据更稳定,查询和后续扩展都更方便。
内容的提问来源于stack exchange,提问作者fhmisml
相关产品推荐
相关产品推荐

