首页 / 资讯中心 / 文章详情

ChatGPT 微服务应用分布式设计实战:从 Guava 本地缓存到 Redis 共享验证码的横向扩展改造

ChatGPT 微服务应用分布式设计实战:从 Guava 本地缓存到 Redis 共享验证码的横向扩展改造 ★ FEATURED ARTICLE
文档教程后端【免费下载链接】CodeGuide:books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总旨在为大家提供一个清晰详细的学习教程侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助请给予支持(关注、点赞、分享)项目地址https://gitcode.com/gh_mirrors/code/CodeGuide点击查看免费下载本篇技术指南聚焦于 CodeGuide 仓库中《ChatGPT 微服务应用体系构建》系列的 chatgpt-api 项目讲解其第 10 节「应用分布式设计」的核心改造将原本基于 Guava 内存缓存保存的登录验证码替换为 Redis 服务存储从而解决多实例部署下服务1 生成验证码、请求路由到服务2 后校验失败的状态不一致问题。读者读完本文可以掌握分布式登录状态共享的设计思路、验证码由本地缓存迁移到共享缓存的完整改造方案以及基于 Nginx 轮询 Docker Compose 环境的横向扩展部署路径。一、本章诉求单机缓存撑不起多实例登录当前的 OpenAiChatGPT、ChatGLM项目需要用户登录鉴权后才能使用服务其登录链路在第5节公众号发送验证码鉴权登录中已经完成落地——用户关注公众号、回复指定编号获取验证码服务端将验证码与 openid 绑定用户在网页端输入验证码换取 JWT Token。但这里存在一个分布式环境下的致命问题验证码的保存使用的是Guava 内存存储本地缓存。当应用以多实例方式横向扩展部署后用户在服务 1 上生成的验证码第二次请求可能被负载均衡轮询到服务 2 上服务 2 的本地缓存中并没有这条验证码记录自然无法完成校验导致用户登录失败。用户请求 ── Nginx 负载均衡 ── 服务1Guava 内存生成验证码 A └─ 服务2Guava 内存无验证码 A校验失败 ❌所以本章的核心诉求非常明确引入 Redis 服务来保存验证码让验证码从进程内本地缓存升级为跨实例共享缓存从而满足应用的横向扩展多副本部署需求。注意如果持有企业公众号则可以对接微信直接扫码登录利用扫码回调天然携带 openid 的特性无需验证码中转本改造方案面向个人公众号的验证码登录场景属于通用性更强的分布式方案。二、流程改造Guava → Redis 的替换思路整个改造的核心是将原有使用 Guava 做验证码存储和校验的流程全部替换为 Redis 服务。改造前后的存储介质对比维度改造前Guava改造后Redis存储位置单实例进程内 JVM 内存独立的 Redis 服务多实例共享数据可见性仅本实例可见所有实例可见失效清理依赖 Guava Cache 的过期策略Redis key 过期TTL机制分布式支持不支持各实例缓存不一致支持天然共享运维成本无额外组件需部署维护 Redis 容器此外项目在初始化开发环境的compose脚本中已经同步安装了redis-admin和phpmyadmin两个管理工具分别用于可视化管理 Redis 服务和 MySQL 服务方便在改造过程中直接查看验证码 key 的写入、过期情况以及用户数据的落库情况。这一点与Dev-Ops 部署章节中docker compose 含环境MySQL、Redis 等脚本的部署方式是相互印证的。1. 登录流程的改动点从第5节定义的验证码登录旅程来看需要替换的环节集中在两处写验证码用户在公众号回复指定数字后服务端生成验证码并写入缓存 —— 由Guava Cache.put(openid, code)改为Redis SET openid:code:xxx code EX 600之类带过期时间的写入验验证码用户在网页输入验证码后服务端从缓存读取并比对 —— 由Guava Cache.getIfPresent(openid)改为Redis GET openid:code:xxx并比对比对成功后删除该 key防止验证码被重复使用。改造后无论请求落在哪一台实例上读写的是同一个 Redis 中的同一份数据登录状态天然一致。2. 为什么必须改本地缓存的分布式失效本质用 Guava 缓存做验证码本质是把登录会话状态绑定在了单个进程的生命周期上。在分布式架构下这类**进程内状态in-process state**是导致业务不一致的主要来源。项目在面试问题复盘中对此有过精辟的总结一个项目是否支持分布式部署的标识在于它的数据处理是基于单体的还是基于分布式架构的——当一台机器宕机、用户在访问时轮询到下一台机器是否还可以保证业务进行。这套项目使用数据库存储用户、账户、商品、下单在 Redis 存放用户的登录鉴权就可以基于 Nginx 轮询的方式配置多态应用的负载以此支持分布式架构。也就是说Redis 承担的是跨实例共享状态层的职责与 MySQL 落库的用户、账户、商品、下单数据一起构成了分布式部署的两个数据底座。三、验证码存储改造的落地要点将 Guava 替换为 Redis 时需要在工程中完成三件事引入依赖、配置连接、替换读写代码。虽然本仓库以文档方式维护项目完整源码按课程授权方式提供见版权说明但结合工程搭建章节与 DDD 分层模型可以明确改造的落点1. 依赖与配置在 SpringBoot 工程对应 DDD 架构中的app启动模块引入 Spring Data Redis 依赖在application.yml中配置 Redis 连接地址、端口、密码spring: redis: host: 127.0.0.1 # 本地开发 port: 6379 password: xxx # 生产环境务必设置 database: 0本地开发时直接启动 Redis 容器云服务器部署时Redis 由 docker compose 一并拉起与 MySQL 同属基础环境容器。2. 代码替换位置按照 DDD 架构参考第4节工程重构的分层验证码属于鉴权领域的功能替换发生在**领域服务domain**层的验证码服务实现中// 改造前Guava 本地缓存 CacheString, String cache CacheBuilder.newBuilder() .expireAfterWrite(10, TimeUnit.MINUTES) .build(); cache.put(openid, code); // 写验证码 String cached cache.getIfPresent(openid); // 读验证码 // 改造后Redis 共享缓存 stringRedisTemplate.opsForValue().set(login:code: openid, code, 10, TimeUnit.MINUTES); String cached stringRedisTemplate.opsForValue().get(login:code: openid);需要注意的关键点设置过期时间验证码必须携带 TTL如 10 分钟与 Guava 的expireAfterWrite语义保持一致防止缓存无限堆积校验后删除比对成功后删除 keydelete(login:code: openid)防止同一验证码被多次使用这与单机场景下验证码一次性的业务约束一致key 设计建议统一前缀login:code: openid便于在 redis-admin 中按前缀检索、排查问题连接池与降级引入 Redis 后应用对缓存的依赖从必然可用变为依赖外部组件生产中需关注连接池配置与 Redis 不可用时的降级策略例如本项目其他模块也有能用 Redis 发布订阅就不用 MQ、不行就用 Guava 替代的降级思路见项目总结。四、分布式部署的整体配套验证码改造只是分布式化的第一步要让应用真正具备横向扩展能力还需要配套的部署方案这些在项目的 Dev-Ops 章节中均有落地1. Nginx 负载均衡多实例轮询第4节Nginx 环境配置给出了 Nginx 容器的启动方式在此基础上配置 upstream 即可实现多实例轮询upstream chatgpt_api { server 10.0.0.1:8080; # 服务1 server 10.0.0.2:8080; # 服务2 } server { listen 80; location / { proxy_pass http://chatgpt_api; } }当服务 1 宕机时Nginx 轮询将请求转发到服务 2只要验证码存放在 Redis用户在服务 2 上依然能完成登录校验业务不中断。2. Docker Compose环境容器统一拉起第5节服务镜像构建和容器部署与第6节前后端构建镜像部署展示了镜像打包与 compose 部署的完整流程。初始化环境的 compose 中包含 MySQL、Redis 等基础组件本章提及的redis-admin、phpmyadmin也在此环境中一并安装services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: xxx ports: - 3306:3306 redis: image: redis:7 command: redis-server --requirepass xxx ports: - 6379:6379 redis-admin: # 可视化管理 Redis image: erikdubbelboer/phpredisadmin ports: - 8081:80 phpmyadmin: # 可视化管理 MySQL image: phpmyadmin ports: - 8080:80 environment: PMA_HOST: mysql3. 应用镜像每实例一份 Dockerfile每个 API 实例通过 Dockerfile 打包为独立镜像然后以同一镜像、多容器副本的方式横向拉起配合 Nginx upstream 形成完整的横向扩展拓扑Nginx负载均衡/轮询 ├── chatgpt-api 实例1镜像:tag ├── chatgpt-api 实例2镜像:tag └── ... 基础环境MySQL用户/账户/订单数据、Redis验证码/登录鉴权状态五、改造完成后的验证方式验证分布式改造是否生效可以按以下步骤操作启动环境通过 compose 拉起 Redis 与 redis-admin登录验证码写入在公众号回复指定编号触发验证码下发打开 redis-admin 观察login:code:*前缀的 key 是否写入、TTL 是否生效模拟多实例本地以不同端口如 8080、8081启动两个应用实例或直接部署两个容器跨实例校验先请求实例 1 获取验证码再请求实例 2 完成验证码校验接口 —— 改造前会失败、改造后校验通过重复使用校验再次使用同一验证码应被拒绝校验后已删除过期校验等待 TTL 到期后再次校验应返回验证码失效。六、小结本章「应用分布式设计」是 chatgpt-api 项目从单体可运行走向分布式可扩展的关键一步。核心结论可归纳为三点状态必须外置凡是跨实例需要共享的状态登录验证码、会话、Token都不能放在 Guava 这类进程内缓存中必须下沉到 Redis 等共享存储改造要保语义从 Guava 迁移到 Redis 不是简单的 API 替换还要完整继承过期时间、一次性使用、key 命名等业务约束部署要配套Redis 共享存储 MySQL 持久化 Nginx 轮询负载均衡三者共同构成支持横向扩展的分布式架构底座相关部署细节可继续阅读 Dev-Ops 系列章节 以及项目的 面试复盘与简历要点。对于任何需要支持多实例部署、保证登录鉴权跨节点一致的业务场景本改造方案都是一份可直接复用的实践模板。赞分享文档教程后端【免费下载链接】CodeGuide:books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总旨在为大家提供一个清晰详细的学习教程侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助请给予支持(关注、点赞、分享)项目地址https://gitcode.com/gh_mirrors/code/CodeGuide点击查看免费下载相关推荐微服务架构设计模式从应用到扩展的终极指南微服务架构设计模式从应用到扩展的终极指南 微服务架构设计模式是现代软件开发中的关键技术它将应用程序拆分为独立的、可扩展的服务帮助开发者构建灵活且高效的系统示例工程教程ayu colors终极颜色主题调色板 - 如何提升你的开发体验ayu colors终极颜色主题调色板 如何提升你的开发体验 ayu colors 是一款专为开发者设计的终极颜色主题调色板提供三种精心调校的主题方案能够UI库/组件AtlasOS终极指南让你的Windows系统重获新生性能与隐私的完美平衡AtlasOS终极指南让你的Windows系统重获新生性能与隐私的完美平衡 在数字时代我们的电脑系统承载着工作、娱乐和生活的方方面面然而Windows系统操作系统隐私合规上一篇百度网盘直链提取技术突破文件传输瓶颈的完整解决方案下一篇当静态界面遇到动画困境Anime.js如何重新定义网页动态体验创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站