为高吞吐量时间序列存储设计可伸缩、成本效益高的访问模式
发布: (2025年12月4日 GMT+8 17:39)
6 min read
原文: Dev.to
Source: Dev.to
表结构 & 主键
| 属性 | 类型 | 角色 |
|---|---|---|
deviceId | String | 分区键 |
timestamp | String (ISO‑8601,例如 2025-12-04T12:34:56Z) | 排序键 |
temperature, humidity, pressure | Number | 负载 |
metadata | String (JSON) | 可选负载 |
ttl | Number (epoch 秒) | 用于过期的 TTL 属性 |
为什么使用这个主键?
同一设备的所有读数会被存放在一起,便于高效的范围查询(deviceId = X AND timestamp BETWEEN …)。通过 ScanIndexForward=false 并设置 Limit=1,可以对最新读数执行单项查询。
索引策略
| 索引 | 分区键 | 排序键 | 使用场景 |
|---|---|---|---|
| 主表 | deviceId | timestamp | 按设备的点查询 & 范围查询 |
全局二级索引 (GSI) – DeviceLatestGSI | deviceId | timestamp(投影为 DESC) | 直接查询最新读数,无需扫描整个分区(Limit=1, ScanIndexForward=false) |
可选 GSI – MetricGSI | metricType(例如 "temperature" 常量) | timestamp | 跨设备的单一指标时间范围查询(较少使用) |
注意: 主表已经支持最新读数查询;该 GSI 为可选,仅在预期大量并发“最新”读取可能导致同一 deviceId 热分区时才考虑。大多数情况下,使用 Limit=1 的主表查询即可。
容量模式 & 扩展
| 模式 | 适用场景 | 配置 |
|---|---|---|
| 按需 (On‑Demand) | 不可预测的流量峰值,快速启动,无需管理容量 | 自动处理 10 k 写入/秒;按请求付费 |
| 预置 + 自动扩展 | 流量可预测,想要控制成本 | 初始 15,000 RCUs 与 5,000 WCUs(每写入 ≤ 1 KB 消耗 1 WCU)。开启自动扩展,目标 70 % 利用率 |
成本对比(约算,US East 1,2025 年 12 月):
- 按需写入:$1.25 每百万写请求单元 → 约 $12.5 k/月(10 k 写入/秒 ≈ 26 M 写入/天)。
- 预置 5,000 WCUs ≈ $0.65 每 WCU‑小时 → $2.3 k/月,加上自动扩展缓冲。
按需模式更简单;如果流量稳定,预置模式可能更便宜。
缓解热点分区风险
- 均匀的
deviceId分布: 确保设备 ID 随机(如 UUID 或哈希)。 - 若少数设备占据大部分流量: 使用 分片——在
deviceId前加随机分片后缀(如deviceId#shard01)。在一个小配置表中保存分片数量;应用查询所有分片并合并结果。这样可以将写容量分摊到多个分区。
数据保留 (TTL)
新增数值属性 ttl = timestampEpoch + 30 days。
在该属性上启用 DynamoDB TTL,DynamoDB 会自动删除过期项(通常在过期后 48 小时内完成)。
- 无需额外 Lambda,成本保持低。
读取性能优化
- 投影: 在 GSI 中仅保留需要的属性(如
temperature,humidity,pressure,timestamp),降低读取大小和费用。 - 强一致 vs. 最终一致读取: 大多数查询使用 最终一致(更便宜,4 KB 读取消耗 0.5 RCU)。对“最新读数”且对新鲜度要求高的场景使用 强一致 读取(4 KB 读取消耗 1 RCU)。
- BatchGetItem:一次调用获取多个设备的最新读数。
辅助服务(可选)
| 服务 | 目的 |
|---|---|
| AWS Kinesis Data Streams | 缓冲入站传感器数据,平滑突发写入,并通过 Lambda 消费写入 DynamoDB。 |
| AWS Lambda (TTL 清理) | 若需在恰好 30 天时删除,可使用计划 Lambda 查询即将过期的 ttl 项并删除,但 DynamoDB TTL 通常已足够。 |
| Amazon CloudWatch 警报 | 监控 ConsumedWriteCapacityUnits, ThrottledRequests, SystemErrors,触发扩容或告警。 |
| AWS Glue / Athena | 对导出到 S3 的历史数据(通过 DynamoDB Streams → Lambda → S3)进行即席分析。 |
权衡总结
| 权衡点 | 影响 |
|---|---|
| 按需 vs. 预置 | 按需简化运维,但在稳定 10 k 写入/秒时可能贵约 30 %。预置需要容量规划,但配合自动扩展可更省钱。 |
| 分片 vs. 简单性 | 分片消除热点分区风险,但查询逻辑更复杂(每个设备可能涉及多个分片)。 |
| TTL vs. Lambda 清理 | TTL 成本低,删除有延迟(最多 48 小时)。Lambda 可实现精确删除,但会产生计算费用。 |
| GSI 用于最新读数 | 在高负载下保证 O(1) 读取延迟,但会增加写入成本(每次写入都要更新 GSI)。若 Limit=1 的主表查询已足够,通常不必使用。 |
| 强一致 vs. 最终一致 | 强一致读取费用翻倍;仅在必须立即获取最新数据时使用。 |
结论
采用本方案可实现:
- 快速点查询(
Query+deviceId+Limit=1,ScanIndexForward=false)。 - 高效时间范围查询(
Query+deviceId+timestamp BETWEEN …)。 - 通过 DynamoDB TTL 自动 30 天过期。
- 成本效益高的高吞吐写入,可选按需或预置并自动扩展,必要时使用分片避免热点分区。