尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Redis+Lua实现高并发Token限流系统设计与实践
1. 项目概述为什么需要精准Token限流上周团队里有个新上线的Go网关服务差点酿成事故——由于未做请求限流某合作方突然发起大量高频请求15分钟内产生了近万元的云服务账单。这件事让我意识到在微服务架构中网关作为流量入口必须实现精准的请求控制。传统的IP限流在面对Token认证体系时会显得力不从心比如同一个IP可能对应多个用户企业NAT出口不同Token可能有差异化的QPS权限VIP用户 vs 普通用户突发流量可能导致雪崩效应如秒杀场景经过多轮方案对比我们最终采用RedisLua实现了一套基于Token的分布式限流系统。实测在百万级QPS压力下平均延迟仅增加1.2ms且完美避免了天价账单的再次出现。2. 核心设计思路2.1 限流算法选型常见的四种限流算法对比如下算法类型实现复杂度平滑度内存消耗适用场景计数器固定窗口低差低简单粗暴的防刷场景滑动日志窗口高优秀高金融级精准控制漏桶算法中优秀中流量整形令牌桶算法中优秀中突发流量处理我们选择令牌桶算法因其独特的优势允许突发流量短时间内消耗积攒的令牌支持动态调整速率通过修改Redis中存储的配置实现相对简单Redis原子操作即可支持2.2 数据结构设计在Redis中为每个Token维护一个Hash结构HSET rate_limit:token123 burst 100 # 桶容量 rate 50 # 每秒生成令牌数 last_time 1630000000 # 最后更新时间戳 tokens 80 # 当前令牌数这种设计相比简单的KV存储有以下好处避免为每个字段单独建立Key可通过HMGET一次性获取所有参数方便后续扩展新字段3. 关键实现细节3.1 Lua脚本实现使用Lua保证原子性是本方案的核心要点。以下是核心逻辑local key KEYS[1] local now tonumber(ARGV[1]) local requested tonumber(ARGV[2]) local burst tonumber(ARGV[3]) local rate tonumber(ARGV[4]) local data redis.call(HMGET, key, tokens, last_time) local tokens tonumber(data[1]) or burst local last_time tonumber(data[2]) or now -- 计算时间差并生成新令牌 local delta math.max(0, now - last_time) local new_tokens math.min(burst, tokens delta * rate) -- 判断是否允许请求 if new_tokens requested then redis.call(HMSET, key, tokens, new_tokens - requested, last_time, now) return 1 else redis.call(HSET, key, last_time, now) return 0 end重要提示必须使用tonumber()显式转换类型否则Redis返回的字符串会导致计算错误3.2 Go集成方案在Go中通过redis.Eval调用Lua脚本func AllowRequest(token string, n int) (bool, error) { keys : []string{fmt.Sprintf(rate_limit:%s, token)} now : time.Now().Unix() args : []interface{}{now, n, config.Burst, config.Rate} res, err : redisClient.Eval( context.Background(), luaScript, keys, args..., ).Result() if err ! nil { return false, err } return res.(int64) 1, nil }实测性能数据单次调用平均耗时1.3ms本地Redis100并发QPS约7500次/秒内存占用每个Token约150字节4. 生产环境优化技巧4.1 热点Key处理当某个Token突然变成热点时可以采用本地缓存在Go服务内存中缓存热点Token的限流结果设置合理的过期时间分片存储对高频Token使用多个Key如token123_1, token123_2提前加载在网关启动时预热已知的高频Token配置4.2 动态配置更新通过Redis Pub/Sub实现实时配置更新func watchConfigChanges() { pubsub : redisClient.Subscribe(context.Background(), rate_limit_updates) ch : pubsub.Channel() for msg : range ch { var update ConfigUpdate if err : json.Unmarshal([]byte(msg.Payload), update); err nil { updateLocalConfig(update) } } }4.3 监控与告警建议采集以下指标限流触发次数按Token分类Redis操作延迟内存使用量增长趋势使用Prometheus的示例配置metrics: key: gateway_rate_limit labels: - token_type - status buckets: [10, 50, 100, 500]5. 常见问题排查5.1 Redis连接池调优我们曾遇到连接泄漏导致的问题解决方案redis.NewClient(redis.Options{ PoolSize: 1000, // 根据QPS调整 MinIdleConns: 100, // 保持最小空闲连接 IdleTimeout: 5 * time.Minute, })5.2 Lua脚本超时当Redis负载高时可能出现脚本执行超时建议优化脚本复杂度避免循环操作设置适当的脚本超时时间redisClient.ConfigSet(context.Background(), lua-time-limit, 5000)5.3 突发流量处理对于秒杀类场景可以采用分级限流策略第一层全局QPS限制简单计数器第二层用户级令牌桶第三层业务特定规则如库存校验6. 扩展思考这套方案稍作改造就能支持更多场景API计费系统将Token替换为AppKey爬虫控制结合User-Agent和IP多维度限流灰度发布为不同用户组设置不同速率我在实际使用中发现配合HTTP头部的Retry-After返回能显著提升用户体验if !allowed { w.Header().Set(Retry-After, 1) // 1秒后重试 w.WriteHeader(http.StatusTooManyRequests) }
RELATED

相关推荐

双轮平衡车DIY:从原理到实现的完整指南

双轮平衡车DIY:从原理到实现的完整指南

1. 双轮载人平衡车设计概述 第一次接触平衡车是在2015年的CES展会上,当时就被这种依靠人体重心控制前进后退的交通工具深深吸引。作为机电一体化产品的典型代表,平衡车完美展现了传感器技术、控制算法和机械结构的精妙结合。经过三个月的业余时间研发&am…

📅 2026/8/23 20:42:02
山西商家小程序开发优选方案:源码可控、售后无忧

山西商家小程序开发优选方案:源码可控、售后无忧

山西不少个体户、初创门店、中小微企业做小程序时,经常踩坑:通用模板不贴合门店业务、开发成本高、数据不归自己掌控、售后没人管、后期没法升级迭代。市面上多数开发服务同质化严重,做出来的程序实用性差,不仅起不到经营助力作用…

📅 2026/9/11 22:41:14
2026年,正规的核酸标准物质生产商究竟有哪些?

2026年,正规的核酸标准物质生产商究竟有哪些?

在生物科研和医学检测领域,核酸标准物质的重要性不言而喻,它是确保检测结果准确可靠的关键因素之一。随着科技的不断发展,2026年市场上有不少正规的核酸标准物质生产商,下面为大家详细介绍。北纳创联生物科技有限公司(…

📅 2026/8/23 20:42:02
MORE NEWS

更多资讯

📰

Yolo 小白入门 70:封装 FastAPI 推理接口——从 best.pt 到可调用服务

Yolo 小白入门 70:封装 FastAPI 推理接口——从 best.pt 到可调用服务 [!NOTE] 你现在位于《Yolo 全速入门到精通【持续更新中】》的 第七章 推理工程化。这一篇不追求堆满参数,而是带你交付“FastAPI推理服务”的最小可验证闭环,并能说清它在数据、模型与业务之间的位置。…

📰

MySQL连接假活报错:The last packet sent successfully解析与根治方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

低代码平台落地指南:技术管理者如何选型、治理与量化价值

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

微信聊天记录导出指南:用 WeChatMsg 本地导出 HTML、Word 与 CSV 文档

微信聊天记录导出指南:用 WeChatMsg 本地导出 HTML、Word 与 CSV 文档 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Tr…

📰

SQL中UNION与UNION ALL的区别:去重逻辑、性能差异与实战写法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

Navicat试用期重置风险与合规数据库工具选型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬