技术开发 频道

Hypertable数据库应用实践:比肩HBase

  2.据与日志存储分离

  挑战:Hypertable集群中某些Range Server发生故障(Range Server进程故障退出)时,需要重新启动该Range Server并恢复服务,这依赖于Range Server记录的操作日志(CommitLog和SplitLog等)。BigTable系统(Hypertable/HBase)最重要的功能之一是自动恢复,自动恢复依赖操作日志(Commit Log)能够真正写入HDFS(Sync),故障发生后,系统通过重放日志构建故障前的一致性状态。

  在我们早期使用Hypertable和Hadoop系统时,Hadoop 0.18版本尚不支持Append Sync功能。即使当前版本的Hadoop支持了Append Sync功能,频繁使用Sync也会影响系统的写吞吐能力。另外,Hadoop的稳定性在当时还不能得到保证,存在写入失败的情况。如果Hadoop出现问题,那么Hypertable刚写入的数据可能丢失。如果是日志,那么重启时无法恢复系统状态。

  解决:一般情况下,Hypertable系统的存储基于Hadoop文件系统,数据和日志都写入HDFS。而在改进后的Hypertable系统中我们采用了不同的存储方式:数据写HDFS,日志写Local FS。

  较之本地文件系统Ext2等,HDFS的稳定性还是略逊一些,在Hypertable的实际运维过程中,我们也遇到过Hypertable向Hadoop写入数据失败的情况。鉴于日志的重要性,我们选择将日志写入可靠性更高的本地文件系统,这样即使Hadoop写文件时出现问题,也可以通过重放本地日志来恢复Hypertable系统状态。

  改进后的Hypertable集群发生故障时,有以下几种处理场景。

  写日志故障:Range Server在写日志时(CommitLog等)发生错误,可能是本地磁盘故障。此时日志的完整性不能得到保证,需要在Range Server写日志的相关操作上附加额外的例外处理。日志写例外将触发Range Server执行一次OFFLINE操作,即在日志完整性不能保证的前提下,尽快保证数据的完整性和一致性,之后再人工参与后续的恢复处理。

  写数据故障:Range Server故障非日志操作引起的,可能由系统Bug导致,也可能是Hadoop写数据文件失败。此时日志的完整性有保障,可以直接执行SHUTDOWN操作,关闭各个Range Server。待Bug解决或Hadoop恢复后,重启Hypertable重放日志即可恢复集群状态和数据。

  以上提到半自动容错机制的两条路线分别保证了“日志- | 数据+”和“日志+ | 数据-”两种故障情况下集群数据的完整性和一致性。那么有没有“日志- | 数据-”的情况,极端情况下可能出现Hadoop写数据文件失败和某Data Node(Range Server)硬盘故障同时发生,此时系统将不可避免地丢失数据,我们只能通过上层应用回滚重放的方式来恢复系统数据。

  3.分裂日志策略

  挑战:Hypertable系统涉及的日志为CommitLog和SplitLog等,日志写本地文件系统的策略约束了SplitLog的故障恢复。

  Hypertable系统设计SplitLog的初衷在于保证导入数据的速率。Range Server上的Range在分裂时,数据可以无阻塞地写入SplitLog(它必须写到分布式文件系统上,因为它保存的是实际数据),Range分裂完成后SplitLog文件可能被其他的Range Server重放。CommitLog中记录了SplitLog的位置,系统恢复时日志重放会涉及SplitLog日志的重放,如果SplitLog写在本地,那么故障恢复时就无法读取该日志。

  HBase系统中并未涉及SplitLog机制,在Range分裂时数据不能继续导入。

  解决:解决方案有两种,一种是本着稳定性和可靠性优先于性能的原则,为了保证日志的可靠性和使得自动恢复机制更简单,取消SplitLog机制,修改后的Hypertable系统在Range分裂过程不涉及SplitLog相关操作;另一种是将SplitLog写入更加可靠的共享存储中,能够让Range Server远程访问,这相当于引入了第三方系统。

  4.安全停机策略

  挑战:kill/run操作可以完成任意时刻Hypertable系统的关闭和启动,无论当前是否正在导入数据,因为Range Server启动后会重放日志。但由于当时的Hypertable缺乏自动迁移(负载均衡)机制,这组操作并不适用于集群的变更,例如更替或添加节点。

  解决:offline/online操作方式的提出是为了辅助kill/run操作,增加Hypertable集群的可扩展性。执行这组操作,可以保证offline执行时内存数据都写入文件系统,online执行时Range能够均匀分布加载,易于集群节点更换。系统管理员通过Hypertable命令行工具执行offline向各个Range Server发出命令,Range Server进程收到offline命令后,等待其上执行的Maintenance任务执行完成,并卸载其上加载的Range后退出。Range卸载成功时,所有系统数据被成功写入分布式文件系统,本地文件系统的日志被删除;卸载失败时,日志保留。系统管理员通过Hypertable命令行工具执行online命令,Master收到online命令后,将METADATA记录的Ranges均匀分配给各个Range Server加载,这就做到了半自动的负载均衡。

  性能优化

  1.内存优化

  挑战:在Hypertable系统的运维中,我们发现,Hypertable在内存使用效率上存在严重问题。在数据插入过程中,Range Server内存用量一直飙升,而且持久不下,很容易造成内存溢出并最终崩溃,严重威胁Hypertable的稳定性。

  为了定位内存占用过量问题,我们使用valgrind和TCMalloc库的Heap Profiling工具对Hypertable进行了测试,发现Hypertable内存飙升的原因是Cell Cache代码中存在频繁分配、释放小片内存(从十几字节到几千字节不等)的情况,从而产生了大量内存碎片,致使内存效率存在严重问题。如图4所示,Range Server中的大量内存分配集中于Cell Cache为和Cell Map进行空间分配的时候。

Hypertable应用实践:比肩HBase(2)
▲图4 改进前Range Server内存使用情况统计

  解决:我们决定对Cell Cache相关的内存实施独立管理,即采用自定义的内存分配回收方式管理和Cell Map,使其产生的内存碎片最小化。

  图5显示了Hypertable数据服务器上的数据更新过程。Client向Range Server发送数据(形式),Range Server首先将数据缓存在Cell Cache中,并使用Cell Map结构建立树形索引。当需要进行Compaction时,会新开一个Cell Cache,并把当前Cell Cache冻结,新写入的数据会进入新开的Cell Cache,而冻结的Cell Cache则在后台写到文件系统中形成Cell Store文件,Compaction完成后,冻结了的Cell Cache会被统一释放。此过程中,Cell Cache涉及的内存分配释放操作主要有:分配空间(new)容纳要写入的key/value;分配空间维护Cell Map(本质上是一个std::map,使用默认的STL allocator分配空间)索引结构;释放数据和索引占用的全部空间。可见,问题主要出在内存分配太过细碎。

Hypertable应用实践:比肩HBase(2)
▲图5 Hypertable插入数据时Cell Cache内存分配示意图

0
相关文章