时序数据存储实战

知识库
知识库文档
/tech-stacks/cassandra/tutorial/时序数据存储实战.md

文档

Apache Cassandra 从零到实战

1. 背景与概念

1.1 为什么需要 Cassandra?

传统关系型数据库(如 MySQL)面临单点瓶颈:读写压力集中在主库。Cassandra 采用去中心化设计——所有节点对等,无主从之分。Google BigTable 的宽列模型 + Amazon Dynamo 的分布式哈希 = Cassandra。

1.2 核心概念速查

概念 类比 SQL 说明
Keyspace Database 数据容器,定义复制策略
Table Table 列族,实际存储结构
Partition Key 无直接类比 决定数据在哪个节点上
Clustering Key ORDER BY 字段 分区内排序
TTL 无直接类比 数据自动过期时间

1.3 数据模型设计原则

Cassandra 建模不是"范式化",而是"查询驱动"。

❌ SQL 思维:先设计实体关系图
✅ CQL 思维:先列出所有查询,反推表结构

规则:

  • 一个查询 = 一张表(允许数据冗余)
  • WHERE 条件必须命中 Partition Key
  • 不使用 JOIN(数据预聚合)

2. 分步实战:构建时序传感器数据平台

场景

某物联网平台需要存储每台设备每分钟的温度读数,需支持:

  1. 查询某设备最近 N 条记录
  2. 查询某设备某天的所有读数
  3. 自动清理 30 天前的旧数据

步骤一:设计表结构

CREATE KEYSPACE iot_data
WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};

USE iot_data;

CREATE TABLE sensor_readings (
    device_id UUID,
    date TEXT,          -- '2024-09-01'
    timestamp TIMESTAMP,
    temperature DOUBLE,
    humidity DOUBLE,
    status TEXT,
    PRIMARY KEY ((device_id, date), timestamp)
) WITH CLUSTERING ORDER BY (timestamp DESC)
   AND default_time_to_live = 2592000; -- 30天自动过期

设计分析:

  • (device_id, date) 复合分区键——同一设备同一天的数据在同一分区
  • timestamp DESC——最新数据先返回
  • TTL = 30天——自动清理旧数据

步骤二:模拟数据写入

from cassandra.cluster import Cluster
import uuid, random, time
from datetime import datetime

cluster = Cluster(['127.0.0.1'])
session = cluster.connect('iot_data')

insert_stmt = session.prepare("""
    INSERT INTO sensor_readings (device_id, date, timestamp, temperature, humidity, status)
    VALUES (?, ?, ?, ?, ?, ?)
""")

device_id = uuid.uuid4()
for i in range(100):
    now = datetime.now()
    date = now.strftime('%Y-%m-%d')
    
    session.execute(insert_stmt, [
        device_id,
        date,
        now,
        round(random.uniform(20, 30), 2),
        round(random.uniform(40, 60), 2),
        'normal'
    ])
    time.sleep(0.1)

print("写入 100 条数据完成")

步骤三:常见查询

-- 查询某设备最新 10 条记录
SELECT * FROM sensor_readings 
WHERE device_id = <UUID> AND date = '2024-09-01' 
LIMIT 10;

-- 范围查询(timestamp 是聚簇键,支持范围)
SELECT * FROM sensor_readings 
WHERE device_id = <UUID> 
  AND date = '2024-09-01'
  AND timestamp > '2024-09-01T08:00:00'
  AND timestamp < '2024-09-01T18:00:00';

-- 跨日期查询(需要查两个分区)
-- 查询某设备最近 3 天的数据(3次查询或使用 IN,但不推荐 IN 跨分区)

3. 思考题

  1. 为什么 Cassandra 不推荐 ALLOW FILTERING?在什么场景下可以接受?
  2. 如果设备数量暴增至 100 万台,分区键设计需要如何调整?提示:考虑热点问题。
  3. TTL 设置为 30 天后,数据是精确在 30 天后删除还是近似?为什么?

信息

路径
/tech-stacks/cassandra/tutorial/时序数据存储实战.md
更新时间
2026/5/31