4、Cassandra深度解析:Cassandra特性、分布式架构原理、在ThingsBoard中的角色、安装与集群部署
好,咱们进入第四讲。这一章我打算好好聊聊Cassandra。说实话,在ThingsBoard的整个数据链路里,Cassandra是我个人觉得最「硬核」的一环。很多朋友刚开始接触TB时,看到默认数据库是Cassandra,心里会犯嘀咕:这玩意儿到底好在哪?为什么不用MySQL?
嗯,别急。咱们今天就把Cassandra的底裤扒干净。从它的核心特性,到分布式架构原理,再到它在ThingsBoard里具体扮演什么角色,最后我会手把手带你装一个集群。你跟着走一遍,心里就有底了。
4.1 Cassandra的核心特性
Cassandra是什么?说白了,它是一个去中心化的、分布式的NoSQL数据库。它最初由Facebook开发,后来捐给了Apache基金会。我最早接触它是在2015年,当时一个物联网项目的数据量暴涨,MySQL扛不住了,我们被迫换库。那会儿踩了不少坑,但也积累了一些经验。
它的核心特性,我归纳为四点:
- 线性扩展能力:加节点就能提升性能,不需要停机。我在项目中见过从3个节点扩展到30个节点,吞吐量几乎线性增长。
- 无单点故障:每个节点地位平等,没有主从之分。你挂掉一个节点,集群照样提供服务。
- 最终一致性:Cassandra不追求强一致性,而是追求高可用。你想想看,物联网设备每秒上报成千上万条数据,如果每条都要等所有节点确认,那延迟得多高?
- 列族存储模型:它不像关系型数据库那样有行有列,而是基于列族(Column Family)来组织数据。这个模型对时序数据特别友好。
重要提示:Cassandra的写入性能极强,单节点每秒可以处理数万次写入。但它的读取性能相对弱一些,尤其是范围查询。这一点在ThingsBoard中体现得很明显——写入遥测数据飞快,但查询历史数据时,如果没建好索引,可能会慢得让你怀疑人生。
4.2 分布式架构原理
Cassandra的分布式架构,我习惯用「环」来理解。所有节点组成一个环,数据按照分区键(Partition Key)的哈希值,均匀分布到各个节点上。
这里有几个关键概念:
- 分区器(Partitioner):决定数据放在哪个节点。默认是Murmur3Partitioner,一致性哈希算法。
- 副本因子(Replication Factor):一份数据存几份。比如RF=3,意味着每条数据存3个副本。
- 一致性级别(Consistency Level):读写操作需要多少个节点确认才算成功。常用的有ONE、QUORUM、ALL。
举个例子。假设你有6个节点,RF=3。当你写入一条数据时,Cassandra会计算这条数据的主副本位置,然后自动把数据复制到环上接下来的两个节点。这样,即使你挂掉两个节点,数据依然完整。
我记得有一次线上事故,一个节点磁盘满了,直接宕机。但集群照常运行,用户完全没感知。这就是无单点故障的魅力。
避坑指南:我曾经犯过一个错误——把RF设成了1,觉得省空间。结果一个节点挂了,数据直接丢了一部分。后来我学乖了,生产环境RF至少设3,一致性级别用QUORUM。虽然写入慢一点,但数据安全第一。
4.3 在ThingsBoard中的角色
ThingsBoard为什么选Cassandra?说白了,物联网场景下,数据写入是海量的、持续的,但读取往往是最近的数据。Cassandra的写入性能正好匹配这个需求。
在ThingsBoard中,Cassandra主要存储以下几类数据:
| 数据类型 | 说明 | Cassandra表名 |
|---|---|---|
| 遥测数据(Telemetry) | 设备上报的传感器值,如温度、湿度 | ts_kv_cf |
| 最新遥测值 | 每个设备每个属性的最新值 | ts_kv_latest_cf |
| 事件数据 | 告警、生命周期事件等 | event_storage |
| 审计日志 | 用户操作记录 | audit_log |
其中,ts_kv_cf 是核心表。它的设计很有意思:
CREATE TABLE thingsboard.ts_kv_cf (
entity_id timeuuid,
key int,
partition int,
ts bigint,
bool_v boolean,
str_v text,
long_v bigint,
dbl_v double,
PRIMARY KEY ((entity_id, key, partition), ts)
) WITH CLUSTERING ORDER BY (ts DESC);
注意这个主键设计。分区键是 (entity_id, key, partition),排序键是 ts。这意味着同一个设备、同一个属性键的数据,会按照时间戳倒序排列。查询最近100条数据时,效率极高。
嗯,这里要注意。如果你要查询某个设备一整天的数据,Cassandra可能就不太擅长了。因为数据分散在不同的分区里,需要扫描多个分区。我一般建议在ThingsBoard中配置数据保留策略,比如只保留7天的原始数据,超过的自动清理。
4.4 安装与集群部署
好,咱们动手。我以Ubuntu 20.04为例,部署一个3节点的Cassandra集群。
4.4.1 单节点安装
先装Java。Cassandra依赖Java 8或11:
sudo apt update
sudo apt install openjdk-11-jdk -y
java -version
然后下载Cassandra。我习惯用4.0版本,稳定且性能好:
wget https://dlcdn.apache.org/cassandra/4.0.7/apache-cassandra-4.0.7-bin.tar.gz
tar -xzf apache-cassandra-4.0.7-bin.tar.gz
sudo mv apache-cassandra-4.0.7 /opt/cassandra
配置环境变量:
echo 'export CASSANDRA_HOME=/opt/cassandra' >> ~/.bashrc
echo 'export PATH=$PATH:$CASSANDRA_HOME/bin' >> ~/.bashrc
source ~/.bashrc
启动Cassandra:
sudo /opt/cassandra/bin/cassandra -R
用 nodetool status 检查状态。看到 UN 表示节点正常。
警告:Cassandra默认会占用大量内存。如果你是在开发机上测试,建议修改 conf/jvm.options 文件,把 -Xms 和 -Xmx 调小,比如设为2G。否则你的机器可能会卡死。我曾经在2G内存的云服务器上直接跑默认配置,结果SSH都连不上了。
4.4.2 集群部署
假设你有三台机器:
- node1: 192.168.1.101
- node2: 192.168.1.102
- node3: 192.168.1.103
每台机器都按上面的步骤安装好Cassandra。然后修改 conf/cassandra.yaml 文件:
cluster_name: 'ThingsBoard Cluster'
seed_provider:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
- seeds: "192.168.1.101,192.168.1.102"
listen_address: 192.168.1.101 # 每台机器填自己的IP
rpc_address: 0.0.0.0
endpoint_snitch: GossipingPropertyFileSnitch
注意,种子节点(seeds)只需要配置2-3个,不需要把所有节点都列进去。我一般选前两个节点作为种子。
然后修改 conf/cassandra-rackdc.properties:
dc=DC1
rack=RAC1
如果你有多个数据中心,可以在这里配置。不过咱们先简单点,所有节点都在同一个数据中心。
配置完成后,依次启动每个节点。启动顺序无所谓,Cassandra会自动发现彼此。
启动后,用 nodetool status 查看集群状态。你应该能看到三个节点都是 UN 状态。
4.4.3 配置ThingsBoard连接Cassandra
最后一步,让ThingsBoard连上你的Cassandra集群。修改ThingsBoard的 conf/thingsboard.yml 文件:
cassandra:
cluster_name: "ThingsBoard Cluster"
contact_points: "192.168.1.101,192.168.1.102,192.168.1.103"
keyspace: "thingsboard"
replication_factor: 3
重启ThingsBoard服务。如果一切正常,ThingsBoard会自动创建所需的表结构。
个人经验:我第一次部署集群时,忘了改 listen_address,结果节点之间互相找不到。排查了半天才发现是IP没改。你配置的时候,一定记得每台机器的 listen_address 要填自己的IP,不要照抄我的示例。
好了,这一章的内容就到这里。Cassandra的深度解析,咱们从特性讲到了架构,再到ThingsBoard中的角色,最后动手部署了集群。下一章,我会带你看看PostgreSQL在ThingsBoard中的用法,以及它和Cassandra如何配合。咱们到时候见。