可扩展的健康数据:使用 CQRS 模式构建更快的健康仪表盘
Source: Dev.to
在健康与养生应用的世界里,数据为王。用户不断记录锻炼、饮食和睡眠,同时也期望看到美观、几乎即时的仪表盘,以跟踪他们随时间的进展。
同时满足 频繁写入 与 复杂分析读取 这两大需求,往往会在传统数据库中导致性能瓶颈。这种架构暗示需要一种更为专业的方案,以确保应用在扩展时仍保持响应迅速。
如果你想深入了解构建这些系统的技术细节,可在我们的 understanding your results 指南中找到完整 walkthrough。
问题:单一数据库不足以应对
典型的养生应用处理两种截然不同的流量。首先是简单的 写入,比如记录一次 10 km 跑步。其次是 读取,比如计算用户在过去一年中按星期几划分的 平均跑速。
当单一数据库同时承担这两类工作时,必然会触及瓶颈。为快速写入而优化的模型(规范化)往往对需要 连接和聚合 的复杂分析效率低下。
随着用户规模的增长,这些高强度的分析查询会让应用陷入停滞。这也是许多工程师转向 命令查询职责分离(CQRS) 模式的原因。
解决方案:职责分离
CQRS 是一种将 写入 与 读取 数据模型分离的架构模式。系统不再由单一模型处理所有请求,而是拆分为两个独立的侧面:
- 命令侧 – 处理状态变更,如写入、更新和删除。
- 查询侧 – 仅针对数据检索和展示进行优化。
通过使用事务型数据库 PostgreSQL 进行日志记录,配合列式数据库 ClickHouse 进行分析,你既能实现快速写入,又能拥有闪电般的仪表盘。
命令 vs. 查询:快速对比
| 特性 | 命令端(写) | 查询端(读) |
|---|---|---|
| 主要目标 | 数据完整性与一致性 | 速度与分析性能 |
| 数据库示例 | PostgreSQL | ClickHouse |
| 数据结构 | 规范化(干净的表) | 反规范化(扁平、快速的表) |
| 优化对象 | LogWorkout, AddMeal | MonthlyTrends, YearlyAverages |
使用 Kafka 连接系统
为了保持两侧同步,我们使用 Kafka 之类的 事件总线。当用户记录一次锻炼时,记录会先保存到 PostgreSQL 数据库,并立即向 Kafka 发布一个事件。
读取 侧随后监听这些事件并更新自己的表。这种架构属于 最终一致性,意味着在仪表盘上显示已记录的锻炼可能会有亚秒级的延迟。
这种小幅的权衡让系统的每个部分都能 独立扩展,确保大量用户查询统计数据时不会导致负责记录健康数据的那一部分崩溃。
扩展分析的关键要点
- 专精取胜 – 使用 PostgreSQL 保证事务完整性,使用 ClickHouse 进行高速数据计算。
- 通过事件解耦 – 使用 Kafka 在写入模型与读取模型之间搭桥,而不拖慢用户体验。
- 以用户为中心 – 在读取侧进行数据反规范化,使得复杂聚合在毫秒级完成,而非分钟。
想获取使用 Node.js 与 Docker 实现该技术栈的完整分步教程,请查看 WellAlly 的完整指南。