若依微服务消息中心架构设计与优化实践
1. 项目背景与需求分析在若依(RuoYi)微服务架构中消息通知模块最初采用SysNotice表结构进行设计随着业务复杂度提升这种单一表结构的设计逐渐暴露出以下问题扩展性不足SysNotice表结构固定难以支持多种消息类型系统通知、待办提醒、预警消息等渠道耦合严重消息发送逻辑与业务代码深度耦合新增短信、邮件等渠道需要修改多处代码状态管理混乱消息的已读/未读状态、处理状态等缺乏统一管理机制性能瓶颈高并发场景下频繁操作数据库表容易成为系统瓶颈2. 架构设计与技术选型2.1 整体架构设计统一消息中心采用分层架构设计[接入层] ├── REST API ├── RPC接口 └── 消息队列监听 [核心服务层] ├── 消息路由引擎 ├── 模板管理 ├── 渠道适配器 └── 状态机管理 [存储层] ├── MySQL结构化数据 ├── MongoDB非结构化内容 └── Redis缓存与队列2.2 关键技术选型Spring Cloud Stream用于解耦消息生产与消费支持RabbitMQ/Kafka等消息中间件状态模式实现消息生命周期管理创建→发送→接收→处理→归档模板引擎采用Freemarker实现消息内容动态渲染分布式事务使用Seata保证消息创建与业务操作的一致性3. 核心实现细节3.1 数据模型重构// 消息主体 Entity Table(name sys_message) public class SysMessage { Id GeneratedValue(strategy IDENTITY) private Long id; Enumerated(STRING) private MessageType type; // 消息类型 private String templateCode; // 模板编码 private String title; private String content; Enumerated(STRING) private MessageStatus status; Column(updatable false) private LocalDateTime createTime; } // 消息接收者 Entity Table(name sys_message_receiver) public class MessageReceiver { Id GeneratedValue(strategy IDENTITY) private Long id; private Long messageId; private Long userId; Enumerated(STRING) private ReadStatus readStatus; private LocalDateTime readTime; }3.2 消息发送流程优化public interface MessageSender { SendResult send(MessageDTO message); } Service public class MessageSendService { Autowired private ListMessageSender senders; Transactional public void sendMessage(MessageDTO message) { // 1. 持久化消息 SysMessage entity convertToEntity(message); messageRepository.save(entity); // 2. 选择发送渠道 MessageSender sender senders.stream() .filter(s - s.support(message.getChannel())) .findFirst() .orElseThrow(); // 3. 异步发送 messageQueue.push(() - { SendResult result sender.send(message); updateMessageStatus(entity.getId(), result); }); } }3.3 消息模板管理采用模板与内容分离的设计# 消息模板示例 (yaml配置) templates: - code: TASK_ASSIGN title: 任务分配提醒 content: | 您有新的任务待处理 任务名称${taskName} 优先级${priority} 截止时间${deadline?string(yyyy-MM-dd)} channels: [WEB,EMAIL]4. 与原有系统集成方案4.1 兼容性处理数据迁移编写Flyway迁移脚本将SysNotice数据转换到新结构INSERT INTO sys_message (id, type, title, content, status, create_time) SELECT id, SYSTEM, title, content, CASE status WHEN 1 THEN UNREAD ELSE READ END, create_time FROM sys_notice;API适配层提供兼容原有接口的FacadeDeprecated RestController RequestMapping(/notice) public class NoticeCompatController { Autowired private MessageService messageService; GetMapping(/list) public R list(SysNotice notice) { // 将旧参数转换为新参数 MessageQuery query convertQuery(notice); return R.ok(messageService.queryList(query)); } }4.2 灰度发布策略通过Nacos配置中心控制新旧系统切换RestController RequestMapping(/api/notice) public class NoticeRouterController { Value(${notice.new.enabled:false}) private boolean useNewSystem; Autowired private OldNoticeService oldService; Autowired private MessageService newService; GetMapping(/{id}) public R detail(PathVariable Long id) { return useNewSystem ? newService.getDetail(id) : oldService.getNotice(id); } }5. 性能优化实践5.1 读写分离设计Repository public class MessageRepositoryImpl implements MessageRepository { Autowired Qualifier(messageWriteMapper) private MessageMapper writeMapper; Autowired Qualifier(messageReadMapper) private MessageMapper readMapper; Override Transactional(readOnly true) public PageMessageVO queryPage(MessageQuery query) { return readMapper.selectPage(query); } Override Transactional public void save(SysMessage message) { if (message.getId() null) { writeMapper.insert(message); } else { writeMapper.update(message); } } }5.2 缓存策略采用多级缓存架构热点数据Caffeine本地缓存有效期5分钟普通数据Redis集群过期时间30分钟持久层MySQL分库分表Service CacheConfig(cacheNames message) public class MessageServiceImpl implements MessageService { Cacheable(key detail: #id, unless #result null) Override public MessageDetail getDetail(Long id) { return mapper.selectDetailById(id); } Caching(evict { CacheEvict(key detail: #message.id), CacheEvict(key list: #message.userId) }) Override public void updateStatus(MessageStatusUpdateDTO dto) { // 更新逻辑 } }6. 监控与运维方案6.1 监控指标埋点Aspect Component RequiredArgsConstructor public class MessageMonitorAspect { private final MeterRegistry meterRegistry; Around(execution(* com.ruoyi.message..*.*(..))) public Object monitor(ProceedingJoinPoint pjp) throws Throwable { String method pjp.getSignature().getName(); Timer.Sample sample Timer.start(meterRegistry); try { Object result pjp.proceed(); sample.stop(meterRegistry.timer(message.process, method, method, status, success)); return result; } catch (Exception e) { sample.stop(meterRegistry.timer(message.process, method, method, status, fail)); throw e; } } }6.2 告警规则配置在Prometheus中配置关键指标告警groups: - name: message-center rules: - alert: HighFailureRate expr: rate(message_process_fail_total[1m]) / rate(message_process_total[1m]) 0.05 for: 5m labels: severity: warning annotations: summary: 消息处理失败率过高 description: 当前失败率 {{ $value }}7. 迁移实施经验在实际迁移过程中我们总结了以下关键经验双写过渡期新旧系统并行运行2周通过对比日志确保数据一致性批量处理优化使用MyBatis的批量插入代替单条插入性能提升8倍动态开关在Nacos中配置功能开关出现问题时快速回滚补偿机制编写定时任务修复状态不一致的消息记录Scheduled(cron 0 0/5 * * * ?) public void fixInconsistentStatus() { // 查询处理中超时的消息 ListLong timeoutMessages mapper.selectTimeoutMessages( LocalDateTime.now().minusMinutes(30)); timeoutMessages.forEach(id - { try { MessageDetail detail getDetail(id); if (detail.getStatus() SENDING) { log.warn(Fix timeout message: {}, id); updateStatus(id, FAILED); } } catch (Exception e) { log.error(Fix message failed: id, e); } }); }

相关新闻

日化行业新零售模式系统开发

日化行业新零售模式系统开发

日化行业新零售模式系统开发的关键要素编辑:araolin(私域邦网络土土哥)日化行业新零售模式系统开发需要结合线上线下融合、数据驱动、用户运营等核心能力。以下是关键开发方向与实施要点:全渠道整合系统构建统一的线上线下库存管理…

2026/10/5 12:48:13 阅读更多 →
我在WAIC 2026看见的十大趋势

我在WAIC 2026看见的十大趋势

如果你没能肉身前往,或者来不及看完一场又一场发布和展出,欢迎通过我们这份言简意赅的总结,快速了解今年WAIC上呈现的趋势。人实在太多了。高温、雷暴,挡不住;黄牛票,炒上天,却依然一票难求&…

2026/9/26 7:39:52 阅读更多 →
轻度体验了一下 腾讯的workbuddy

轻度体验了一下 腾讯的workbuddy

以前本地部署 小龙虾openclaw的时候感觉好复杂 现在部署Hermes agent可方便了哈哈哈,直接让workbuddy给我部署成功了遇到了一点小插曲, 但是解决的很快!!

2026/10/1 14:23:34 阅读更多 →

最新新闻

SpringBoot+Vue+MyBatis+MySQL多媒体共享平台源码解析

SpringBoot+Vue+MyBatis+MySQL多媒体共享平台源码解析

“企业级武理多媒体信息共享平台管理系统源码”这个标题,乍一看像是那种烂大街的毕设项目,但如果你正好在准备毕业设计、或者刚入行想找一套能完整跑通前后端的项目练手,会发现这类项目反而是最实在的参考样板。先说清楚,“武理”…

2026/10/6 17:14:11 阅读更多 →
Java三大易错点:时间日期、包装类与正则表达式实战全解

Java三大易错点:时间日期、包装类与正则表达式实战全解

不绕弯子,直接说结论。这三个东西——时间与日期、包装类、正则表达式——是Java进阶路上特别容易“看着会了、一用就废”的三块内容。很多自学的朋友学到集合、IO之后就觉得基础差不多结束了,结果一去面试,或者一接手老项目,立刻…

2026/10/6 17:14:10 阅读更多 →
村级行政边界矢量数据:代码、坐标系与离线处理全解析

村级行政边界矢量数据:代码、坐标系与离线处理全解析

做了好几年GIS数据和基层落地项目,我发现最容易被低估但又特别关键的一类数据,就是村级行政边界矢量数据。省市县三级边界大家手里多少都有,可真到村、社区、居委会、街坊这个层级,想找一套字段规范、边界准确、坐标统一的数据&am…

2026/10/6 17:14:09 阅读更多 →
OpenShell 深度解析:Windows 开始菜单定制与效率优化实战

OpenShell 深度解析:Windows 开始菜单定制与效率优化实战

1. 从零认识 OpenShell:它到底解决什么问题 第一次听到 OpenShell 这个名字,很多人会下意识以为它又是一个新的命令行工具或者某种终端增强器。实际上,OpenShell 是一个面向 Windows 平台的开始菜单替代与外壳定制工具,它的核心使…

2026/10/6 17:13:09 阅读更多 →
基于Python与Flask的超市采购管理系统实现与设计

基于Python与Flask的超市采购管理系统实现与设计

一个项目从标题命名为“基于Python基于flaskWeb的超市员工供应采购管理系统_dlhtj29a”,再结合“Python、flask、Web”这三个关键词,基本就能猜到它的定位:一个面向高校课程设计、毕业设计,或中小型超市信息化改造的Web管理系统。…

2026/10/6 17:13:09 阅读更多 →
ESD防静电烘箱:电子制造中静电隐患的识别与防护

ESD防静电烘箱:电子制造中静电隐患的识别与防护

1. 从这台烘箱说起:电子制造里被忽视的静电隐患 今天下午打包发走一台ESD防静电烘箱,木箱已经打好带、贴上标识,物流车在门口等着。这台设备发往一家做精密传感器的客户那边,现场调试约在下周二。打包前我照习惯拍了几张照片发给这…

2026/10/6 17:13:08 阅读更多 →

日新闻

杰理AC7916A硬件设计全指南:电源、时钟与射频三大关键

杰理AC7916A硬件设计全指南:电源、时钟与射频三大关键

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

2026/10/6 1:01:12 阅读更多 →
探针座选型指南:从需求梳理到验收避坑,稳稳解决半导体测试难题

探针座选型指南:从需求梳理到验收避坑,稳稳解决半导体测试难题

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

2026/10/6 1:01:36 阅读更多 →
SO-DIMM内存设计指南:DDR3与DDR4引脚、拓扑、布线及调试

SO-DIMM内存设计指南:DDR3与DDR4引脚、拓扑、布线及调试

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

2026/10/6 1:01:44 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/6 7:15:40 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/6 5:29:09 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/6 6:26:51 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/6 8:21:32 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/6 4:21:51 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/6 1:18:13 阅读更多 →