面试题答案
一键面试高并发写入时 HBase 的 MemStore 数据一致性挑战
- 内存溢出:高并发写入会使 MemStore 快速增长,一旦达到阈值(如 region 级别设定的
hbase.hregion.memstore.flush.size
)仍未及时刷写,可能导致内存溢出,部分数据丢失,破坏数据一致性。 - 写入顺序不一致:多个并发写入线程可能导致数据写入 MemStore 的顺序与期望顺序不符。如果依赖写入顺序保证某些业务逻辑一致性(如按时间戳顺序写入的日志数据),则会出现问题。
- 节点故障:在高并发写入期间,若 RegionServer 节点发生故障,MemStore 中尚未刷写到磁盘的数据可能丢失,影响数据一致性。
MemStore 应对数据一致性挑战的设计和算法
- 内部结构设计
- 数据结构:MemStore 本质上是一个 LSM - Tree(Log - Structured Merge Tree)的内存部分。它使用跳表(SkipList)来存储KeyValue 对。跳表是一种基于链表的数据结构,通过多层索引来加速查找、插入和删除操作。这种结构在高并发环境下能高效地进行写入操作,并且通过索引能快速定位数据,保证数据存储的有序性,一定程度上应对写入顺序不一致问题。
- 分段存储:为了管理方便和提高并发性能,MemStore 会进行分段存储。每个 MemStore 被划分为多个
MemStoreLAB
(MemStore Local Allocation Buffer),不同的写入线程可以并行地向不同的MemStoreLAB
写入数据,减少锁竞争,提高写入并发度的同时保证各段数据的一致性。
- 算法
- 刷写算法:当 MemStore 达到预设的刷写阈值时,会触发刷写操作。HBase 使用一种写前日志(Write - Ahead Log,WAL)机制。在数据写入 MemStore 之前,先将数据写入 WAL 日志。当 MemStore 需要刷写时,会将 MemStore 中的数据以 HFile 的格式刷写到 HDFS 上。如果在刷写过程中 RegionServer 发生故障,重启后可以根据 WAL 日志进行数据恢复,从而保证数据一致性。
- 并发控制算法:为了应对高并发写入,MemStore 使用了乐观锁机制。在写入数据时,并不立即加锁,而是在数据更新前检查数据的版本号等标识。如果版本号一致,则认为更新成功;如果不一致,则说明数据已被其他线程修改,需要重新读取数据并再次尝试更新。这种机制减少了锁的使用,提高了并发性能,同时保证数据一致性。