从MySQL到HBase:数据存储方案转型演进
根据主键查询,可以快速定位到数据所在磁盘块,只需要极少的磁盘IO即可拿到数据:通过缓存高层节点,主健查询只需要一次磁盘IO就可拿到数据;MySQL单表行数一般建议不会超过2千万,千万行以下的大表,B+树只需2~3层即可; 辅助索引,提供快速定位能力:辅助索引B+树,可以快速定位到最终所需的主键ID,根据主键ID可以快速拿到所需信息。 HBase只有局部信息,没有辅助索引 查询会优先查找memstore,如果没有会查找Hfile(存储结构类似B+树)。如果第一个Hfile中没有所需的信息,则需要去第二、第三个Hfile中查询;如果查询的数据恰好在memstore,第一个Hfile,HBase会优于MySQL;平均下来,HBase读性能一般。减少Hfile数据以提速,小的HFile合并成大的HFile文件。这种存储结构叫LSM树(Log-structured merge-tree); 如果需要检索特定的列,可能需要遍历所有Hfile,成本巨高。 MySQL成也B+,败也B+;HBase成也LSM,败也LSM。 4、附录 B+ 树 查询“值为25”的节点,只需要2次定位即可。 LSM树 查询“值为25”的节点,只需要4次定位即可。 三、优化思路 1、HBase优化点 (主要是读) 异步化 后台线程将memstore写入Hfile; 后台线程完成Hfile合并; wal异步写入(数据有丢失的风险)。 数据就近 blockcache,缓存常用数据块:读请求先到memstore中查数据,查不到就到blockcache中查,再查不到就会到磁盘上读,把最近读的信息放入blockcache,基于LRU淘汰,可以减少磁盘读写,提高性能; 本地化,如果Region Server恰好是HDFS的data node,Hfile会将其中一个副本放在本地; 就近原则,如果数据没在本地,Region Server会取最近的data node中数据。 快速检索 基于bloomfilter过滤: 正常检索,RegionServer会遍历所有Hfile查询所需数据。其中,需要遍历Hfile的索引块才能判断Hfile中是否有所需数据; BloomFiler存储HFile的摘要,可以通过极少磁盘IO,快速判断当前HFile是否有所需数据: 行缓存:快速判断Hflie是否有所需要的行,粒度较粗,存储占用少,磁盘IO少,数据较快; 列缓存:快速判断Hfile是否有所需的列,粒度较细,但存储占用较多。 基于timestamp过滤: HFile基于日志追加、合并,维护了版本信息; 当查询1小时内提交的信息时,可以跳过只包含1小时前数据的文件。 HFile存储结构: HFile存储格式 参考链接: https://link.zhihu.com/?target=https%3A//blog.csdn.net/yangbutao/article/details/8394149 Trailer存储整个Hfile的定位信息; DataIndex存储Data块的索引信息:Data存储为一组磁盘块,存储数据信息;DataIndex功能类似于B+树的非叶子节点;Data每个磁盘块中的数据按key有序,加载到内存后可以用二分查找定位;Key按行 + 列族 + 列 + 时间戳生成,按字典序排序(最佳查询方式:最左匹配); MetaIndex存储Meta的索引信息,Meta存储一系列元信息;MetaIndex功能类似于B+树的非叶子节点;Meta存储bloomfiler等辅助信息。 2、MySQL优化点(主要是写) 查询缓存 将SQL执行结果放入缓存。 缓存B+高层节点 一千万行的大表,一般只需要一棵3层的B+树,其中索引节点 (非叶子节点) 的大小约20MB。完全可以考虑将大部叶子节点缓存,基于主键查询只需要一次IO。 减少随机写——缓冲:延迟写/批量写 上节提到,B+树通过自增主键大量减少随机插入。由于辅助索引的存在,插入、修改、删除操作,辅助索引可能引起大量的随机IO。 插入缓冲:只是将被插入数据写入insert buffer;定期将其merge到B+树; 修改缓冲:类似于insert buffer的思路。 减少随机读——MRR SELECT * FROM t WHERE key_part1 >= 1000 AND key_part1 < 2000 AND key_part2 = 10000; # 普通操作分解: key_part1= 1000, key_part2=1000, id = 1 select * from t where id=1 key_part1= 1001, key_part2=1000, id = 10 select * from t where id=10 ... # MRR 操作分解: SELECT * FROM t WHERE key_part1 >= 1000 AND key_part1 < 2000 AND key_part2 = 10000; key_part1= 1000, key_part2=1000, id = 1 buffer.append(1) key_part1= 1000, key_part2=1000, id = 10 buffer.append(10) ... sort(buffer) select * from t where id in (buffer) 索引下推 MySQL的server处理完索引后,会将索引其它部分传给引擎层; 引擎层根据过滤条件过滤掉无用的行,减少数据量,进而优化server的性能。 3、集群化数据库的辅助索引 InnoDB的辅助索引 B+树全局有序,叶子节点存储的是主键。基于辅助索引定位主键,再用主键定位数据。MySQL水平切分后,没办法跨库维持建立全局有序索引: 单实例维护索引,丧失了全局有序性; 再做一个基于新索引分库方案,丧失了辅助索引维护的事务性。 HBase相同问题 仿照InnoDB实现辅助索引,辅助索引可以做成单独的key,其value是被索引行的key; 可以做到全局信息的维护,但没法保证事务性。 4、HBase异步合并带来的好处 TTL:基于后台合并,TTL很容易做; 数据多版本支持:基于“追加”,HBase天然的可以支持多版本; 版本数量:基于后台合并,可以将太旧版本干掉。 四、总结 (编辑:晋中站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |