想象一座没有“总部”的城市咖啡馆网络:每家店独立经营,没有主店与分店之分;客人走进任意一家都能点单,订单按一套数学规则自动分派给某几家店;店主们靠口口相传了解“谁开着、谁歇业”;每笔订单都会在便签、白板和账本之间有序流转。这套体系不需要关店维护,想扩张就在地图上多开一家店——这就是 Apache Cassandra 的设计哲学。 Cassandra 是 Apache 基金会的分布式宽列存储数据库,被全球互联网公司用作海量数据的高可用存储底座。本文将用“无总部咖啡馆网络”这个比喻,拆解它的去中心化架构、一致性哈希、Gossip 协议、LSM-Tree 写入路径、压缩合并等核心机制。你不需要任何前置知识,跟着故事走,就能对 Cassandra 建立完整直觉。
对 AI 从业者来说,理解 Cassandra 架构能帮你在海量数据场景中正确选型与排障——无论是为推荐系统构建特征库,还是为 AI 训练搭建数据管道,你都能判断它是否合适、瓶颈在哪、如何扩展。
可视化演示
动态演示Cassandra架构的核心机制,通过架构/数据/状态/性能四种模式展示关键概念与交互流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
Cassandra架构:去中心化 去中心化架构与一致性哈希 Gossip协议与节点发现 核心机制可视化 Cassandra架构整体架构与关键组件
去中心化架构
设想一个遍布全城的咖啡馆网络,但没有任何“总部大楼”。每家店主独立进货、独立招聘,没有老板发号施令;服务规则靠大家约定俗成。客人走进任何一家店都能点单,因为每一家店都掌握完整的服务章程。如果某一家停业,其他店照常运转,客人们几乎感觉不到变化。
Cassandra 的架构与这个“无总部咖啡馆网络”如出一辙。集群中每个节点(node)地位完全平等,没有主从之分——这就是去中心化(decentralized)。客户端可以连接任意节点发起读写,此时这个节点自动扮演“协调者”(coordinator),负责把请求路由到正确的数据节点,就像客人找任何一位店员点单都可以,店员自己会去后厨协调。
逻辑上,所有节点构成一个“令牌环”(token ring),每个节点负责环上的一段连续区间。存数据时,先计算分区键的哈希值,找到负责该区间的节点,再落地写入。因为不存在主节点,任何一个节点宕机,其他节点照常服务,从设计上就消除了“单点故障”。这正是分布式存储最看重的基础能力。
回看咖啡馆比喻:单店再精致也可能临时关门,但“无总部网络 + 订单分派到多家店”的设计,让整个网络不会因为任何一家店的意外而停摆。去中心化架构就是这样把“单点故障”从系统基因里抹掉了。
- 单点可用率a 表示一台机器一年中正常工作的比例,比如 99%。
- 单点不可用率1 - a 是这台机器可能在某一时刻宕机的概率。
- 所有副本同时不可用N 个副本同时失效的概率是 (1-a)^N,副本数越多这个值越小。
- 集群整体可用率1 减去这个极小概率,就是整个集群仍能对外服务的概率。
一致性哈希
无总部不代表无秩序。“订单该给哪家店”必须有一套自动规则,不能靠人肉分配。咖啡馆网络的约定是:每位店主在入职时把自己的店名哈希成一个数字,对应到地图环上的一个坐标;同样,每张订单的订单号也哈希成环上的坐标。订单从自己的坐标出发,顺时针沿着环走,遇到的第一家店就是它的“归属店”。这套规则就是一致性哈希(consistent hashing)。
在 Cassandra 中,这个“地图环”的取值空间是 0 到 2^127-1 的超大数字环。每个节点通过自己的 ID 算出环上的位置;每条数据通过分区键(partition key)算出环上的位置。数据顺时针遇到的第一个节点,就是它的 owner(归属节点)。如果 owner 宕机,数据由下一个节点继续负责,不会出现“不知道该找谁”的窘境。
虚拟节点(vnode)是工程上的重要优化:每家店可以把自己的地盘拆成多个不连续的小区间,而不是只占一个点。这样环被切得更碎,数据分布更均匀,能有效避免“某家店恰好处在热门区间而忙死”的热点问题。节点增删时,也只需要迁移相邻小区间的数据,影响面非常小。
回到咖啡馆:新店开张,不用重新培训所有人、不用把所有订单重新分一遍——只要在环上“插队”占一段地盘,把相邻分店的一部分订单接过来即可。一致性哈希让“加店”和“关店”都变成局部操作,这正是水平扩展能日常化的关键。
- 哈希函数 h任意字符串(订单号、用户 ID)经过哈希运算变成一个很大的整数。
- 模 2^127把大整数压缩到环的地址范围 [0, 2^127)。
- 节点同样定位每个节点 ID 用相同公式算出自己在环上的位置。
- 顺时针寻找 owner从数据坐标出发,找第一个 token 不小于自己的节点。
Gossip协议
无中心的网络里,店主们怎么知道“谁还在营业、谁出去旅游了”?靠的不是公告栏(没有中心),而是“小圈子口口相传”。每隔一秒,每个店主在小群里发一句“我这里一切正常”,顺便转发自己听到的别人的消息。消息一传十、十传百,很快全网络都知道每家的最新状态。这就是 Gossip 协议(八卦协议)的直觉——像八卦一样,消息在人群里快速扩散。
Cassandra 中每个节点每秒向随机选择的节点发送心跳消息,消息里带着自己知道的其他节点状态,并附一个版本号。收到消息的节点如果发现版本号更新,就更新自己的记录,并继续向其他节点传播。最终,所有节点在几秒内都能收敛到一致的集群状态视图。这个过程只传输元数据(谁活着、谁死了、谁的数据范围是什么),不搬运真正的用户数据。
新节点加入时,通过种子节点(seed node)进入集群。种子节点就像“引路人”,帮新店长加入聊天圈、认识第一批邻居。故障检测则依赖心跳超时:如果超过一段时间收不到某个节点的心跳,就用统计方法计算一个“存疑指数” phi,phi 越大说明该节点越可能真的宕机,而不是网络偶发抖动。
咖啡馆里,店主们聊的是“谁开门谁休息”这类状态信息,而不是在群里直接搬运整本菜单。Gossip 协议同样只传递“状态八卦”,真正的大块数据走的是哈希环决定的专属通道。这样既保证了全集群信息流通,又不让通信流量压垮网络。
- 当前时刻T_now 是现在的时间戳。
- 上次心跳时刻T_last 是该节点最后一次广播心跳的时间。
- 沉默时长归一化两者相减得到“多久没说话了”,再除以历史平均间隔,消除不同网络环境的差异。
- 判定阈值phi 超过阈值(如 8)才判定节点不可用,避免网络抖动造成误杀。
数据复制一致性
单靠哈希环分配,数据还缺一道保险:如果归属店突然关门,订单就丢了。于是咖啡馆网络规定:每笔订单抄送多份,抄几份由“副本因子”(Replication Factor,RF)决定。RF=3 意味着每个订单同时抄给 3 家分店保管,任何一家关门,另外两家依然能提供完整订单。
写入时,协调者把数据同时发给所有副本节点,等足够多的副本确认后才向客户端报告“写入成功”。这个“足够多”就是一致性级别(consistency level)。最常用的 QUORUM 级别要求“超过半数副本确认”;ONE 级别只要求一个副本确认,延迟更低但一致性更弱;ALL 级别要求所有副本确认,最安全但最慢。用户可以按业务需求在读写两端分别选择。
还有一个巧妙机制叫 Hinted Handoff(提示移交):如果某个副本节点刚好离线,协调者会把数据暂时保存在自己这里,附上一张“小纸条”指向目标节点。等目标节点恢复后,协调者再补发数据。就像吧台帮请假同事记了一笔账,等同事回来照单补录,让系统不因短暂故障而阻塞写入。
想想咖啡店的抄送制度:多数店对得上账,就确认订单有效,不必等所有店都回话。这种“折中”正是分布式系统的艺术——在延迟、可用性和一致性之间,用可调参数找到最适合业务的平衡点。
- 副本因子一份数据复制到 RF 个节点,比如 RF=3。
- 半数向下取整3 ÷ 2 = 1.5,向下取整为 1。
- 超过半数再加 1,得到 QUORUM = 2,即至少 2 个副本确认。
写路径与LSM树
顾客点单时,服务员先用最快速度把订单记在便签(Commit Log)上,防止丢单;这步是顺序追加写入磁盘,速度极快。接着把订单内容写到吧台的白板(Memtable)上——白板在内存里,读写都快。当白板写满,后台线程就把白板内容誊写成一个新的正式账本 SSTable,换一块新白板继续接单。整个过程不用改旧账本,因为新订单永远先进新白板。
这套“便签 → 白板 → 账本”的流程,就是 LSM-Tree(Log-Structured Merge-Tree,日志结构合并树)的思想:写入全部走顺序追加,先在内存聚合,再批量落盘。相比传统 B+ 树每次写入都要随机修改磁盘页面,LSM-Tree 把随机写转化成了顺序写,写入吞吐量能高出数倍。这也是 Cassandra 被誉为“写性能怪兽”的根本原因。
SSTable 是一个不可变的(immutable)数据文件:一旦誊写完成就永远不再修改。这意味着没有“原地更新”的操作,所有更新都是产生新版本数据。旧的账本虽然不再被引用,但物理上还占着磁盘,需要后续的合并压缩(compaction)来收拾——这是第 7 节的主题。不可变性也带来一个好处:SSTable 可以被安全地缓存、压缩和并行读取,无需加锁。
再回到咖啡馆:便签防丢失,白板提速度,账本做沉淀,三层各司其职。订单从来不会被“就地修改”,只会被更新版本覆盖逻辑状态。这套流水线的代价是磁盘写得多一点,但换来的是简单、高效、并发友好的写入模型。
- 应用写入量S_app 是客户端程序提交的数据字节数。
- 磁盘写入量S_disk 包括 Commit Log、SSTable 落盘、后台压缩合并等全部写盘流量。
- 比值含义理想值是 1,但 LSM-Tree 因为多次合并,实际通常在 10~30 之间。
读路径机制
顾客来取订单,服务员怎么快速找到它?先看吧台白板(Memtable),那里是最新的订单;如果白板没有,再去翻正式账本(SSTable)。但账本越积越多,一本本翻太慢了。于是每本账本封面都贴了一个“快速索引”——Bloom Filter(布隆过滤器),它能直接告诉你“这本账本里肯定没有这个订单”或“可能有”。大多数账本在第一步就被跳过,只有少数账本需要真正翻开查找。
读请求同样由协调者发起:它会向拥有该数据的所有副本节点并发发出请求,各副本返回自己保存的版本。协调者比较时间戳,把最新版本返回给客户端。如果发现某些副本的版本陈旧,还可以触发“读修复”(read repair),用最新版本纠正过期副本——相当于取餐时顺便帮店主把抄错的账本改过来。
删除操作在 Cassandra 中很有意思:数据不会立即被抹掉,而是写入一个“删除标记”(tombstone,墓碑)。读取时看到墓碑,就视该数据为不存在。墓碑本身仍然占用磁盘空间,要等到压缩阶段才会被真正清除。这也是 Cassandra 中“DELETE 后磁盘不释放”现象的来源。
回想取餐场景:白板最先被看,账本靠目录索引快速跳过,多本账本之间比版本号取最新,被取消的订单靠标记过滤。读路径的所有设计都围绕一个目标——用最小的成本,找到最新版本的答案。
- 位数组长度m 是 Bloom Filter 底层位数组的比特数。
- 元素个数n 是已经插入过滤器的 key 数量。
- 哈希函数个数k 表示每个 key 会被 k 个哈希函数映射到位数组的 k 个位置。
- 误判概率查询时这 k 个位置恰好都被其他元素置 1 的概率,就是假阳性率。
压缩与清理
账本日积月累,吧台后面的架子越来越挤,找一本账本越来越慢。于是每周打烊后,店员做一次“账本合订”:把许多小账本合并成一册大账本,合并过程中顺手把标着“已取消”的订单页撕掉。这个过程就是 compaction(压缩合并)。
Cassandra 提供了多种压缩策略。最常见的是 STCS(SizeTiered Compaction Strategy,大小分层压缩):把大小相近的 SSTable 归为一组,合并成更大的文件。它的优点是实现简单、写放大相对低,适合写多读少的场景。另一种是 LCS(Leveled Compaction Strategy,分层压缩):把 SSTable 按层级组织,每层内 key 范围不重叠,读取时最多查少数几个文件,读性能更好,但后台合并更频繁、写放大更高。选择哪种策略,本质是在“读放大”和“写放大”之间做取舍。
压缩在后台自动运行,会占用一部分磁盘 IO 和 CPU。如果压缩跟不上写入速度,SSTable 数量会无限增长,读性能就会劣化。因此存储工程师的日常运维中,监控 SSTable 数量、压缩停顿时间和磁盘吞吐是必做功课。
账本不整理,终将堆满库房;数据不压缩,磁盘终将被墓碑和冗余文件占满。压缩虽然有后台开销,但它是 LSM-Tree 模型保持读性能、回收磁盘空间的“清道夫”,必不可少。
- 参与合并集合S_1 到 S_k 是这次压缩选中的 k 个小文件。
- 合并结果S_merged 是新产生的大 SSTable 的大小。
- 查询成本变化合并前读一条数据最坏要查 k 个文件,合并后只需要查 1 个。
高可用扩缩容
生意火了,想开新店。流程并不复杂:新店长先通过种子节点进入“聊天圈”(Gossip),在哈希环上选一个位置宣布自己的地盘,然后相邻的老店把属于这段区间的数据迁移过来。整个过程中所有老店照常营业,客人完全无感知——这就是 Cassandra 引以为傲的在线水平扩展。
缩容同理:要关掉一家店,先把它的数据迁移给相邻节点,再让它退出环。由于一致性哈希的特性,数据迁移只影响环上的相邻区间,比例大约是新节点数分之一。相比许多数据库“扩容要停机重建”的重流程,Cassandra 把扩缩容变成了日常运维操作,这也是它能支撑千万级 QPS 规模的原因。
更进一步,Cassandra 支持多数据中心部署:可以在北京、上海、深圳各建一个“分店群”,每个数据中心内部用一致性哈希和 Gossip 管理,数据中心之间通过跨 DC 复制同步数据。即使整个机房断电,另一个数据中心的副本依然可以继续提供读取服务,真正做到“可用性优先”。
咖啡馆网络开新店,不需要关掉整条街重新规划;Cassandra 加节点,也不需要停服重建索引。这套“插队占位 + 邻店让渡”的机制,让水平扩展从“年度大项目”变成了“随手加一台机器”的日常操作。
- 原有节点数N 是当前集群的节点总数。
- 加入新节点后总数N+1,环被多切一段,每个节点平均区间变小。
- 影响范围只有新节点抢占的那段区间对应的旧 owner 需要迁出数据,比例约 1/(N+1)。
AI 应用场景
AI 训练日志采集管道
阶段:数据接入与预处理
解决的问题:训练推荐模型需要海量用户行为日志(点击、滑动、购买),每天数十亿条。传统关系型数据库随机写入很快成为瓶颈,且扩展困难。Cassandra 的 LSM-Tree 顺序写模型能承担每秒百万级写入,同时天然支持按时间和用户 ID 分区,为下游 AI 训练提供稳定数据源。
具体案例:一家游戏公司的埋点系统,用 Cassandra 存储玩家行为事件,按 (日期, 玩家ID) 作为分区键。数据先进入 Kafka 清洗,再由流处理程序批量写入 Cassandra。训练团队既可以用 SELECT ... WHERE player_id=? 查询单个用户的完整行为序列,也可以按日期范围扫描做批量特征统计。
物联网设备状态存储
阶段:实时数据存储与特征提取
解决的问题:智能工厂中每台设备每秒上报状态,百万设备意味着每秒百万级写入。设备状态天然按设备 ID 聚合,Cassandra 的宽列模型正好把一个设备的所有传感器数据放在同一行(或邻近列),读取连续高效;AI 异常检测模型可以低延迟获取设备状态序列。
具体案例:某新能源电池工厂在每条产线上部署传感器,采集温度、电压、电流等指标。Cassandra 以设备 ID 为分区键,每分钟一个时间桶,AI 模型实时读取最近 N 分钟数据,预测设备故障概率,提前触发维护工单。
推荐系统在线特征库
阶段:在线推理特征读取
解决的问题:推荐系统在线推理需要在毫秒级内读取用户最新行为特征。传统缓存系统(如 Redis)内存成本高,且扩展受内存上限约束。Cassandra 高可用、可水平扩展的特性,使其成为特征存储的流行选择:用户特征按用户 ID 分区,热点用户天然落在同一节点区间,读延迟稳定。
具体案例:某短视频推荐平台把用户最近 100 条交互行为存放在 Cassandra 中,线上推理服务每次请求读取特征向量。大促高峰期通过临时加节点水平扩展,不需要停机,整个集群在分钟级完成扩容。
Python 演示
import hashlibfrom collections import defaultdict class SimpleCassandraRing: """极简实现:用一致性哈希环模拟Cassandra数据分布与副本复制""" def __init__(self, nodes=None, rf=3): self.ring = [] # [(token, node_id), ...],按token升序 self.rf = rf self.node_data_map = defaultdict(dict) for node in nodes or []: self.add_node(node) def _hash(self, key): return int(hashlib.md5(key.encode()).hexdigest(), 16) def add_node(self, node_id): token = self._hash(node_id) self.ring.append((token, node_id)) self.ring.sort() def remove_node(self, node_id): self.ring = [(t, n) for t, n in self.ring if n != node_id] def find_owner(self, key): pos = self._hash(key) for token, node_id in self.ring: if token >= pos: return node_id return self.ring[0][1] if self.ring else None def write(self, key, value): owner = self.find_owner(key) idx = next(i for i, (t, n) in enumerate(self.ring) if n == owner) for k in range(self.rf): node = self.ring[(idx + k) % len(self.ring)][1] self.node_data_map[node][key] = value def read(self, key): owner = self.find_owner(key) idx = next(i for i, (t, n) in enumerate(self.ring) if n == owner) for k in range(self.rf): node = self.ring[(idx + k) % len(self.ring)][1] if key in self.node_data_map[node]: return self.node_data_map[node][key] return None def status(self): return {n: len(self.node_data_map[n]) for n, _ in self.ring} if __name__ == "__main__": cluster = SimpleCassandraRing(["node-a", "node-b", "node-c", "node-d"], rf=3) cluster.write("user:1001", {"name": "Alice", "level": 5}) cluster.write("user:1002", {"name": "Bob", "level": 3}) print("读取 user:1001 ->", cluster.read("user:1001")) print("当前各节点数据量:", cluster.status()) cluster.add_node("node-e") print("水平扩展后各节点数据量:", cluster.status())
self.ring.append((token, node_id))把节点的哈希 token 放入环数组并排序,保证“顺时针查找”从低到高有序if token >= pos: return node_id从数据哈希位置出发,顺时针找第一个 token 不小于它的节点;若走完一圈都没有,就回到第一个节点for k in range(self.rf)指定副本因子 rf,让数据同时复制到 owner 以及后面 rf-1 个节点self.node_data_map[node][key] = value把数据写入节点对应的字典,模拟每个节点的本地存储cluster.add_node("node-e")演示水平扩展:新增节点后,环自动重新排序,新数据会分布到新节点上
常见误区
误区很多初学者以为 Cassandra 和 MySQL 一样,写入成功后立刻就能读到最新数据,把它当作强一致性数据库来设计业务。
正解Cassandra 提供的是“可调一致性”(tunable consistency)。默认常用级别(如 ONE、QUORUM)下,不同副本之间可能存在短暂延迟,属于最终一致模型。只有选择 LINEARIZABLE 等高级别时才近似强一致,但代价是性能下降。就像咖啡馆网络:多数店对得上账就告诉顾客“订单已确认”,但个别分店可能还没抄完账本。
为何常见:Cassandra 的官方文档常强调“high availability“和”no single point of failure”,新手容易把高可用等同于强一致,忽略了二者是分布式系统中互相权衡的两端。
误区听到“宽列存储”就以为是列式数据库,觉得它和 ClickHouse、BigQuery 一样适合大规模聚合分析。
正解Cassandra 是“宽列存储”(wide-column),数据仍按行组织,一行可以有海量列,但物理存储布局是行优先的;它擅长按行键(分区键)做点查和范围查,不擅长跨行聚合和复杂 JOIN。想用一条 SQL 做数亿行分组统计,Cassandra 会让你失望。它就像咖啡馆的订单账本:按“哪桌点了什么”记录,而不是按“所有订单的咖啡种类”汇总记录。
为何常见:术语中的“列”字极具迷惑性,加上 NoSQL 概念普及不够系统,很容易和列式 OLAP 引擎混为一谈。
误区执行 DELETE 删除大量数据后,发现磁盘空间并没有明显减少,于是怀疑是 bug。
正解Cassandra 的删除只是写入一条 tombstone(墓碑)标记,数据本身仍然存在磁盘上,读取时会被过滤掉;物理空间要等到 compaction 阶段才会真正回收。如果长时间不触发压缩,墓碑会占用大量空间,甚至拖慢读性能。这是 LSM-Tree 存储模型的固有特性,不是故障。
为何常见:传统关系型数据库的 DELETE 会立即释放页空间,用户把这份直觉迁移到 Cassandra 上,自然产生误解。
误区以为只要节点足够多,真实数据的哈希值自然会均匀落在每个节点上,虚拟节点只是锦上添花。
正解哈希函数的输出在统计上是均匀的,但真实世界的 key 集合是有限的、有偏的,样本量不大时分布可能严重倾斜。没有 vnode,节点少时几台机器可能扛着绝大多数数据。虚拟节点把环切分成数千个微小区间,让每台物理节点承担许多分散的小段,数据分布才会接近均匀,热点概率大幅下降。
为何常见:教科书上“哈希随机分布”的理想假设,让初学者忽略了工程中样本偏斜与节点粒度对均衡性的实际影响。
面试题
Q1. Cassandra 的整体架构属于以下哪种模式?
- A.主从复制模式
- B.无中心对等模式← 正确答案
- C.共享存储模式
- D.单机单库模式
答案:B。Cassandra 是去中心化的对等架构,所有节点地位平等,客户端可连接任意节点读写。A 是 MySQL 主从复制;C 是 Oracle RAC 等共享存储方案;D 是单机数据库,都不符合 Cassandra 的设计。
Q2. Cassandra 决定一条数据存储在哪个节点的核心策略是什么?
- A.轮流分配请求
- B.一致性哈希分配← 正确答案
- C.主节点指派存储
- D.随机选择存储节点
答案:B。Cassandra 使用一致性哈希,把数据 key 和节点 ID 都哈希到环上,数据顺时针归到第一个遇到的节点。A/B/C/D 都不是 Cassandra 的数据分布机制,其中“主节点指派”完全不成立,因为 Cassandra 没有主节点。
Q3. Cassandra 属于以下哪类数据库?
- A.关系型事务数据库
- B.宽列族存储数据库← 正确答案
- C.图数据库存储系统
- D.内存键值缓存系统
答案:B。Cassandra 是宽列(列族)存储数据库,按行键组织数据,每行可包含海量列。它不是关系型数据库(无 JOIN、无 ACID 事务),不是图数据库,也不是纯内存缓存(数据持久化在磁盘)。
Q4. 当副本因子 RF=3 时,QUORUM 一致性级别要求几个副本确认写入成功?
- A.需要 1 个副本确认
- B.需要 2 个副本确认← 正确答案
- C.需要 3 个副本确认
- D.需要 0 个副本确认
答案:B。QUORUM 的计算公式是 floor(RF/2)+1,RF=3 时 floor(3/2)+1=2,因此至少 2 个副本确认即可报告写入成功。这既保证了多数派的一致性,又不需要等待所有副本,是延迟与可靠性的折中。
Q5. 下列哪些组件属于 Cassandra 的写入路径?
- A.提交日志 Commit Log← 正确答案
- B.内存表 Memtable← 正确答案
- C.字符串表 SSTable← 正确答案
- D.二进制日志 Binlog
答案:ABC。Cassandra 写路径是“Commit Log → Memtable → 刷盘为 SSTable”。Commit Log 保证崩溃恢复,Memtable 在内存中缓存,SSTable 是不可变的磁盘文件。Binlog 是 MySQL 的二进制日志,Cassandra 没有该概念。
Q6. Gossip 协议在 Cassandra 中的主要作用有哪些?
- A.传播节点状态与元数据← 正确答案
- B.直接服务客户端读写
- C.发现故障节点并通知← 正确答案
- D.承担用户数据全量复制
答案:AC。Gossip 每秒交换节点心跳与元数据,让集群快速感知节点存活状态。服务客户端读写是协调者的职责;用户数据的复制走的是哈希环协调后的写路径,不依赖 Gossip 承担数据流量。
Q7. 在 Cassandra 中执行 DELETE 删除数据,最初发生的是什么?
- A.立即物理清除数据
- B.写入墓碑标记删除← 正确答案
- C.覆盖旧数据并同步
- D.触发整表重建索引
答案:B。Cassandra 的删除是“逻辑删除”,写入一条 tombstone 墓碑记录,读取时自动过滤;物理空间要等 compaction 才会回收。A 是关系型数据库行为;C 不是 SSTable 的不可变语义;D 不存在此操作。
Q8. 某节点短暂离线,写操作被协调者暂时保存、等该节点恢复后再补发,这个机制叫什么?
- A.读修复机制
- B.提示移交机制← 正确答案
- C.幂等重做机制
- D.热数据迁移机制
答案:B。Hinted Handoff(提示移交)在副本节点短暂不可达时,把写数据暂时保存在协调者本地并记录目标节点,恢复后补发。读修复发生在读取路径上纠正过期副本;幂等重做与热迁移都不是 Cassandra 的标准术语。
Q9. 为什么 Cassandra 选用 LSM-Tree 而不是 B+ 树作为存储结构?
- A.顺序写为主写吞吐更高← 正确答案
- B.完全不需要读取操作
- C.后台合并平衡读写放大← 正确答案
- D.完全不需要内存即可运行
答案:AC。LSM-Tree 把随机写改成顺序追加写,大量写入在内存聚合后批量落盘,写吞吐远高于 B+ 树;后台 compaction 在后台合并文件,用额外的写放大换取持续稳定的写性能。LSM 仍然需要读操作,也必须依赖内存缓冲 Memtable。
Q10. 关于一致性哈希中的虚拟节点(vnode),下列说法最准确的是?
- A.环被切分更细分布更均匀← 正确答案
- B.数据不再需要复制到多个节点
- C.节点数量必须保持偶数幂
- D.哈希函数碰撞概率完全消失
答案:A。vnode 把每个物理节点拆成多个虚拟区间,让环被切得更碎,数据分布更均匀,减少热点。vnode 不改变副本因子,节点数量也无需是偶数幂,更不会消除哈希碰撞——它只解决“样本偏斜导致负载不均”的工程问题。