首页/新闻资讯/正文详情

Redis缓存优化外卖平台店铺状态管理实践

发布时间:2026/11/3 7:32:58 来源:云帆数科 栏目:资讯中心
Redis缓存优化外卖平台店铺状态管理实践
1. 项目背景与核心需求最近在开发一个外卖平台项目苍穹外卖在Day05的开发中遇到了两个关键技术点Redis缓存的应用和店铺营业状态管理。这两个功能看似独立实则紧密关联——营业状态需要高频读取但低频修改正是Redis的典型应用场景。作为后端开发者我发现在实际业务中店铺营业状态这类基础数据会被订单系统、推荐系统、用户端展示等多个模块频繁查询。如果每次都走数据库不仅性能堪忧还会给数据库带来不必要的压力。而Redis作为内存数据库其读取速度是传统关系型数据库的100倍以上特别适合这种读多写少的场景。2. Redis技术选型与配置2.1 为什么选择Redis在技术选型时我们对比了几种缓存方案Memcached简单但功能单一缺乏持久化和丰富的数据结构Ehcache本地缓存集群环境下同步困难Redis支持持久化、多种数据结构、原子操作还有丰富的集群方案最终选择Redis 6.2版本主要基于以下考虑支持String/Hash/Set等多种数据结构营业状态适合用String类型存储提供原子性操作避免多线程下的状态不一致问题支持RDB和AOF两种持久化方式保证数据安全官方提供Cluster模式方便后续扩展2.2 Redis配置要点在application.yml中的关键配置spring: redis: host: 127.0.0.1 port: 6379 password: database: 0 lettuce: pool: max-active: 8 # 根据服务器核心数设置 max-wait: -1ms # 无限等待 max-idle: 8 min-idle: 0重要提示生产环境一定要配置密码和合理的连接池参数。我们曾经因为连接泄漏导致服务不可用后来通过max-active限制才解决。3. 营业状态功能实现3.1 数据库设计首先在MySQL创建店铺表CREATE TABLE shop ( id bigint NOT NULL AUTO_INCREMENT, name varchar(100) NOT NULL, status tinyint DEFAULT 0 COMMENT 0-休息中 1-营业中, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;3.2 双写一致性方案为了保证Redis和MySQL的数据一致我们采用先更新数据库再删除缓存的策略public void updateShopStatus(Long shopId, Integer status) { // 1. 更新数据库 shopMapper.updateStatus(shopId, status); // 2. 删除缓存 redisTemplate.delete(shop:status: shopId); // 3. 记录操作日志 logService.recordShopStatusChange(shopId, status); }踩坑记录曾经尝试先删缓存再更新数据库结果在高并发下出现了缓存击穿问题。现在的方案虽然可能有短暂不一致但对业务影响更小。3.3 缓存查询优化获取营业状态的典型代码public Integer getShopStatus(Long shopId) { // 1. 先查缓存 String cacheKey shop:status: shopId; Object status redisTemplate.opsForValue().get(cacheKey); if (status ! null) { return (Integer)status; } // 2. 缓存不存在则查数据库 Shop shop shopMapper.selectById(shopId); if (shop null) { throw new BusinessException(店铺不存在); } // 3. 写入缓存并设置TTL redisTemplate.opsForValue().set(cacheKey, shop.getStatus(), 1, TimeUnit.HOURS); return shop.getStatus(); }这里有几个优化点使用shop:status:作为key前缀避免与其他业务冲突设置1小时过期时间防止长期不更新使用opsForValue()简化String类型操作4. 高并发场景下的问题处理4.1 缓存击穿解决方案当某个店铺状态缓存过期同时有大量请求涌入时会导致所有请求都打到数据库。我们通过互斥锁解决public Integer getShopStatusWithLock(Long shopId) { String cacheKey shop:status: shopId; // 第一次尝试获取缓存 Object status redisTemplate.opsForValue().get(cacheKey); if (status ! null) { return (Integer)status; } // 获取锁 String lockKey lock:shop:status: shopId; boolean locked false; try { locked redisTemplate.opsForValue().setIfAbsent(lockKey, 1, 10, TimeUnit.SECONDS); if (locked) { // 二次检查缓存 status redisTemplate.opsForValue().get(cacheKey); if (status ! null) { return (Integer)status; } // 查询数据库 Shop shop shopMapper.selectById(shopId); if (shop null) { throw new BusinessException(店铺不存在); } // 写入缓存 redisTemplate.opsForValue().set(cacheKey, shop.getStatus(), 1, TimeUnit.HOURS); return shop.getStatus(); } else { // 未获取到锁短暂休眠后重试 Thread.sleep(50); return getShopStatusWithLock(shopId); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new BusinessException(获取店铺状态异常); } finally { if (locked) { redisTemplate.delete(lockKey); } } }4.2 批量查询优化在首页需要展示多个店铺状态时我们使用pipeline批量操作public MapLong, Integer batchGetShopStatus(ListLong shopIds) { // 1. 构建缓存key列表 ListString cacheKeys shopIds.stream() .map(id - shop:status: id) .collect(Collectors.toList()); // 2. 使用pipeline批量获取 ListObject statusList redisTemplate.executePipelined((RedisCallbackObject) connection - { for (String key : cacheKeys) { connection.stringCommands().get(key.getBytes()); } return null; }); // 3. 处理结果 MapLong, Integer result new HashMap(); ListLong missingIds new ArrayList(); for (int i 0; i shopIds.size(); i) { Long shopId shopIds.get(i); Object status statusList.get(i); if (status ! null) { result.put(shopId, (Integer)status); } else { missingIds.add(shopId); } } // 4. 处理缓存未命中的情况 if (!missingIds.isEmpty()) { ListShop shops shopMapper.selectBatchIds(missingIds); for (Shop shop : shops) { result.put(shop.getId(), shop.getStatus()); redisTemplate.opsForValue().set( shop:status: shop.getId(), shop.getStatus(), 1, TimeUnit.HOURS ); } } return result; }5. 监控与运维实践5.1 Redis监控指标我们使用PrometheusGrafana监控以下关键指标缓存命中率keyspace_hits / (keyspace_hits keyspace_misses)内存使用率used_memory / maxmemory命令延迟redis_command_latency_seconds连接数connected_clients5.2 常见问题排查问题1缓存命中率低可能原因TTL设置过短或缓存key设计不合理解决方案调整过期时间分析热点数据问题2Redis内存持续增长可能原因缓存无过期时间或内存泄漏解决方案检查所有key的TTL设置使用MEMORY USAGE命令分析大key问题3连接数过高可能原因连接未正确关闭或连接池配置不合理解决方案检查代码中的连接释放逻辑调整连接池参数6. 扩展思考与优化方向在实际项目中我们还考虑了以下优化点多级缓存在应用本地增加Caffeine缓存形成本地缓存RedisMySQL的三级架构热点数据预热在营业高峰前提前加载热门店铺的状态到缓存异步更新将状态变更事件发送到消息队列由消费者异步更新缓存分布式锁优化使用Redisson实现的分布式锁替代原生Redis命令这个项目让我深刻体会到看似简单的功能背后往往隐藏着复杂的技术考量。特别是缓存系统需要在一致性、可用性和性能之间找到平衡点。在实际开发中建议先实现基础功能再逐步引入缓存优化避免过早优化带来的复杂性。

相关推荐

SuperCapture+Excel截图导入全流程避坑指南
SuperCapture+Excel截图导入全流程避坑指南

简介:本资源是一份面向办公人员与数据处理初学者的Excel高效截图整合指南,解决日常工作中频繁将截图批量导入指定Excel表格的效率痛点。文档详细讲解如何借助超级屏捕专业版(SuperCapture)与Excel工具箱实现“一键截图→自动命名→… · 2026/11/3 7:31:58

从大语言模型到组织化AI代理:架构范式转变与工程实践
从大语言模型到组织化AI代理:架构范式转变与工程实践

1. 从单模型到多代理:为什么“组织化”是必然一步大语言模型(LLM)这两年从实验室走到大众视野,速度之快让很多做传统软件的人措手不及。但如果你真正拿它做过稍微复杂一点的事情,就会发现一个尴尬的现实:单… · 2026/11/3 7:31:58

雅思词汇真经:语义网络+真题词频驱动的高效背词法
雅思词汇真经:语义网络+真题词频驱动的高效背词法

简介:本资源是专为雅思备考者打造的词汇核心学习资料——《雅思词汇真经》,由雅思培训界权威名师刘洪波编写,系统覆盖雅思考试高频、常考及易混淆词汇,兼顾词义辨析、搭配用法与真题语境应用,有效解决考生词汇记忆碎片… · 2026/11/3 7:31:58

NPC三电平逆变器同步载波调制原理与Simulink实现
NPC三电平逆变器同步载波调制原理与Simulink实现

简介:本资源是一份面向电力电子方向毕业设计与课程实践的三电平逆变器调制算法仿真方案,聚焦NPC型拓扑下的同步载波调制技术改进,适用于电气工程、自动化专业本科生及研究生开展电能变换系统建模与谐波分析。压缩包共16个文件,含7… · 2026/11/3 8:01:03

SQLAlchemy ORM实战技巧与性能优化指南
SQLAlchemy ORM实战技巧与性能优化指南

1. Python开发者必看:SQLAlchemy ORM实战避坑指南作为一名长期使用Python进行Web开发的工程师,我见证了无数项目因为ORM使用不当而导致的性能问题和维护噩梦。SQLAlchemy作为Python生态中最强大的ORM工具,其灵活性和复杂性并存。今天我将分享… · 2026/11/3 8:01:03

网络安全工程师职业发展:从入门到高薪的实战路径
网络安全工程师职业发展:从入门到高薪的实战路径

1. 28岁网络安全工程师的职场困境与破局之道28岁,对于很多职场人来说是个关键的分水岭。蔡少的故事在网络安全行业颇具代表性——从土木工程转行到网络安全,月薪1万出头,面临结婚成家的压力却苦于经济基础薄弱。这种困境在北上广深等一线城市… · 2026/11/3 8:01:03

H³混合内存架构:LLM长序列推理的分层调度方案
H³混合内存架构:LLM长序列推理的分层调度方案

1. 项目概述:H不是电路里的H桥,而是长序列推理的“内存调度中枢”H混合架构——这个标题里藏着三个H,但和电赛H题、H桥驱动电路、HBM显存带宽、甚至网络热词里那些乱码混搭的“h1.006tw(25011.86t)”完全无关。它是一个专为大语言模型&#x… · 2026/11/3 8:01:03

H³混合架构:大模型长文本推理的内存协同调度方案
H³混合架构:大模型长文本推理的内存协同调度方案

1. 项目概述:H不是电路里的H桥,而是长序列推理的“内存减压阀”你搜“H混合架构”时,页面里蹦出一堆“h桥驱动电路原理图”“2024电赛H题”“男秘书被C摁办公H跪趴”——这根本不是一回事。H(Triple-H)在这里是Hierarc… · 2026/11/3 8:01:03

Docker镜像分层架构与全生命周期管理实战
Docker镜像分层架构与全生命周期管理实战

1. Docker镜像核心概念解析1.1 镜像的本质与分层架构Docker镜像本质上是一个只读的模板文件系统,采用分层存储的设计理念。每个镜像由多个只读层(Layer)叠加组成,这种架构带来了三个显著优势:资源共享:不同… · 2026/11/3 8:00:03

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

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

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

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

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

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

STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战

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

ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题

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

基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践

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

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

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

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

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

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

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

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码