前言
在宽表领域,Cassandra和Hbase都是排名前两的数据库,本文主要介绍Cassandra的一些基本概念和特性,
并与Hbase进行对比
去中心化
Cassandra使用了去中心化设计,相比于Hbase的主从架构,更易于扩展,且
无单点故障风险,但这点比较难理解,Hbase有一个主节点可以协调各从节点一起干活,
相当于一个公司有一个领导可以协调公司内部各个部门,比较符合我们日常的认知
但Cassandra每个节点都是对等的,没有主从之分,那当一个数据到来时,谁来存储?
而当我想获取这个数据时,又去哪个节点找?
这就好比一个公司多个人,没有领导,那活来了谁干,一定会打起来,如何解决这个问题呢?
解决方案很简单,定一个规则,大家都按照这个规则进行任务分配,这样即使没有一个主,各个
节点也能协调工作,前提是要保证各个节点之间的通信畅通,这就是去中心化,以一个协定好的规则
来取代主从关系
那么Cassandra有哪些提前定好的规则,各节点又如何进行通信
一致性哈希
关于一致性哈希算法,可以参考这篇文章分布式寻址算法,
这里不在多做介绍
Cassandra 使用 Murmur3 哈希算法(默认情况下),其哈希空间为 2^64(即 0 到 2^64 - 1)。
这个巨大的哈希环确保了即使在大规模集群中也能均匀分布数据
为了避免数据倾斜,Cassandra 使用了虚拟节点(vnodes),默认情况下,每个节点有 256 个vnodes
Cassandra会为每个vnodes计算一个大小为 64 位的哈希值,然后将这个哈希值映射到哈希环上,64位的哈希值刚好
对应哈希环上的一个点,这样其实就可以不用做取模运算,直接找到对应的节点,且基本不会出现冲突
对于每个数据项,Cassandra 计算其哈希值,并将其放置在哈希环上的相应位置,根据一致性hash算法就找到了对应存
储的节点
Gossip协议
Gossip协议是Cassandra的通信协议,Cassandra的节点之间通过Gossip协议进行通信
通过 Gossip 协议,每个节点不仅可以知道自己的令牌,还可以知道其他节点的令牌及其负责的范围
每个节点会维护两个表
- system.local 表,用来保存节点自己的信息,包括节点的令牌和负责的令牌范围
- system.peers 表,用来保存其他节点的信息,包括节点的令牌和负责的令牌范围
通过 Gossip 协议,每个节点会定期向其他节点发送自己的信息,同时也会接收其他节点的信息,这样
每个节点都能知道其他节点的信息
协调节点
当客户端发起读写请求时,请求首先到达一个任意一个节点,这个节点充当协调节点(coordinator)。协调节点根据哈希环和令牌信
息确定哪些节点负责该请求的数据,然后进行请求分发,请求分发到相应的节点上,然后返回结果给协调节点,
协调节点再返回给客户端
故障检测与恢复
- 故障检测:通过 Gossip 协议,节点可以快速检测到其他节点的故障情况,并相应调整数据分布。
- 自动修复:Cassandra 提供了自动修复机制(如 Hinted Handoff、Read Repair 等),以确保在节点故障恢复后数据的一致性和完整性
数据模型
Cassandra和Hbase一样都是列簇数据库,但hbase一个表可以有多个列族
而Cassandra一个表就是一个列簇,实际上最早Cassandra没有表的概念,只有列簇的概念
列族就相当于传统数据库中的表,新版本Cassandra表概念,列簇的概念被简化为表
但但底层仍然保留了列簇的特性如稀疏存储,动态列,按列存储等
其它相关概念于传统数据库差不多,表下是行和列,其中行由主键(Primary Key)和列(Column)组成
主键又包括分区键(Partition Key)和聚簇键(Clustering Key),分区键好理解,就是主键么,决定
数据如何分布,聚簇键决定同一分区下数据如何排序,以方便范围查找等
存储结构
下面通过一个例子来说明Cassandra的存储结构,为了清晰,会忽略部分细节,并不完全严谨
逻辑结构
假设现在有个用户表,包含三个列id name age
此时有三条数据,他们的逻辑结构如下:
id | name | age |
---|---|---|
1 | 张三 | 18 |
2 | 李四 | 19 |
3 | 王五 |
物理结构
相比于hbase按列簇存储,Cassandra按列存储,相同的列数据会连续存储在一起,
继续上一个例子,假设按id按奇偶分区,Cassandra的物理结构可简单的描述如下:
总结
通过上图可以很直观的看清Cassandra是如何存储数据的,简单概括如下
- 通过分区键进行水平分区,将数据存储在不同的Region中
- 在一个Region中,Cassandra按列存储,相同列的数据会连续存储在一起
- 同一个分区中数据按聚簇键排序,上图没有表示出来
CQL
相比于Hbase使用各种api操作数据库,Cassandra提供查询语言
CQL(Cassandra Query Language)与SQL类似,但有一些不同之处
Cassandra对比Hbase
一致性
Cassandra是AP系统,即可用性和分区容忍性优先,而不是一致性,所以Cassandra不支持事务
Cassandra实现最终一致性,即在一段时间内,所有节点的数据最终会达到一致,但是在这段时间内,数据可能不一致
而Hbase是CP系统,即一致性优先,Hbase支持事务
可用性
Cassandra是去中心化设计,无单点故障风险,而Hbase有一个主节点,是一个潜在的瓶颈,即使某些节点失效,其他
节点仍然可以继续处理请求,确保系统的高可用性和持续运行,相比之下,Hbase依赖 Master 节点来管理元数据和协
调负载。如果 Master 节点发生故障,虽然有备用 Master,但切换过程会导致短暂的服务中断
Cassandra 采用完全对等的节点架构,所有节点都是平等的,没有主从之分。这种设计使得它可以更容易地扩展到多个数据中心,
相比之下,HBase 严重依赖 Hadoop 分布式文件系统(HDFS),而 HDFS 主要设计为单数据中心环境。HDFS 的 NameNode
是单点故障点,并且其复制机制默认在同一数据中心内进行
性能
一般情况下,Cassandra高并发写入性能更高,主要原因如下:
- 去中心化:写入操作可以直接发送到任意节点,写入请求可以并行处理,而Hbase依赖 Master 节点来管理元数据和协调负载。
虽然实际写入发生在RegionServer上,但Master节点的存在仍然是一个潜在的瓶颈,尤其是在高并发写入场景下 - 高效的写路径:Cassandra的写路径非常高效,写入数据时,先写入内存中的 Memtable,并同时追加到 Commit Log 中,然后异步刷盘到磁盘中的 SSTable
而Hbase的写路径是先写Write-Ahead Log,然后写 MemStore,最后异步刷盘到磁盘中的 HFile,表面看基本一致,但虽然WAL 的写入也是顺序的,但依赖于
HDFS 的三副本机制, 增加了额外的网络和磁盘 I/O 开销 - 异步副本复制:在 Cassandra 中,客户端发起写请求时,数据首先写入本地,然后异步地将写请求发送到其他副本节点。
客户端可以在不等待所有副本确认的情况下立即返回写入成功的响应。Hbase也有类似的涉及,但底层使用HDFS进行数据存储,
默认情况下,HDFS 的写入是同步的,即需要等待主副本和至少一个副本写入成功后才返回确认
其实这些原因也只是表象原因,根本上讲Hbase是CP系统,而Cassandra是AP系统,所以Cassandra更适合高并发写入场景
分析总结
- Cassandra与Hbase使用场景基本很像,都擅长大宽表和稀疏数据的存储
- Cassandra是AP系统,适合高可用、高并发写入场景,而Hbase是CP系统,适合强一致性场景
- Cassandra是去中心化设计,无单点故障风险,而Hbase有一个主节点,是一个潜在的瓶颈
- HBase 更适合已经使用 Hadoop 生态系统并且需要强一致性和事务支持的场景
- Cassandra 提供CQL查询语言,使用更方便,Hbase 则使用API操作数据库