小米何亮亮——HBase服务化实践,DCon2015文字实录

image001.png

主持人:好我们现在开始下一场,下面是来自小米的何亮亮,何亮亮是09年毕业于中国科学院,2013加入小米基础架构组,先后负责小米结构化存储服务设计与开发,Hadoop和HBase开发与维护等工作。他带来的报告主题是,HBase服务化实践,我们掌声欢迎何亮亮。
何亮亮:各位朋友大家好,我来自小米云平台存储组,我们组主要负责小米公共存储服务的开发与支持,小米是HBase的一个重度用户,我今天主要分享一下我们在使用HBase过程中遇到的一些问题,以及我们的一些实战经验。这也是今天的主要内容,因为时间关系我可能会加快速度,如果有什么问题我们可以线下交流。

image003.png

首先我们回顾一下HBase的架构,HBase是基于谷歌的Bigtable论文,它主要是由HMaster和Regionserver这两个组件组成。它底层的数据存储在HDFS上边,Zookeeper负责各个组建之间的协调工作。

image005.png

接下来讲一下HBase在小米的应用现状,HBase在小米主要是用在OLTP的场合,以及相关的一些离线分析,典型的应用包括小米云服务,包括大家常用的通话记录、短信、云相册等。这些服务的结构化数据存储在HBase上面。第二个应用就是小米消息推送服务,主要面向移动应用开发者。其他还有多看阅读以及小米各种设备的数据。

image007.png

这是现在的一个应用规模,我们现在大概有10多个在线集群5个离线集群还有若干个测试集群,分布在5个数据中心,目前有几百台机器,典型的数据结点是12*2T配制,目前服务了公司内外的数十个业务,最大集群QPS大概在的百万级别。

image009.png

这是我们一个典型的部署情况,在线集群主要服务线上业务,然后它的数据通过日志的方式,同步到离线集群和冷备集群,其中离线集群是用来做一些离线的分析。冷被集群主要考虑到数据安全,所以我们做了一个数据的备份。考虑到存储成本我们是采用了HDFS RAID,这样可以大大减少存储上面的成本,目前RAID的配制是6+3。同时我们增加了细粒度的同步设置支持,这样可以支持表级别和CF级别同步设置,这样只需要同步必要的一些数据,节省空间和带宽成本。

image011.png

这是我们一个典型的部署,除了Zookeeper、HBase、HDFS这三个必备的模块之外,我们还在HBase原生接口基础上,开发了结构化存储库libsds,以及结构化存储服务。除此之外,我们还开发的自己的部署运营系统Minos,接下来我会分别介绍一下这三方面的工作。

image013.png

前面百度马老师也吐槽了Hadoop,Hadoop的默认部署是非常难用的,不太适合大规模的生产环境。我们就开发了我们自己的Hadoop集群管理系统,可以实现Hadoop系列软件的部署与管理。Minos内建监控的支持,对于HBase我们增加了一些表级别的监控数据的聚合。这是Minos的一个整体架构,主要包含了四个组件,包管理服务,统计监控服务、结点上面的Agent负责进程的生命周期管理,配制管理等,以及运维工具,目前这个项目已经开源,如果大家有兴趣,可以在Github上面下载试用。

image015.png

这是我们的一个上线的流程,我们发布新版本的时候,大概经过单元测试、压力测试和Staging集群的测试。除了3个测试之外,我们还有Longhaul测试和Failover测试,这样可以帮助我们尽快发现问题。

image017.png

除此以外我们还做了一些其他的辅助工作,包括HBase的Nameservice支持,Snapshot管理,HBase错误日志统计分析,Kerberos帐号管理等工具。

image019.png

这是我们遇到一些典型故障,首先最常见的是坏盘,这是个问题是在HDFS层面解决。
    第二个问题是相对影响比较大的,就是慢盘的问题,我们在HDFS层面开发了一个叫Hedged  Read的特性,就是在第一次读取超时的时候,同时向第二个Datanode发请求,从而降低整个请求的延时。
    第三个就是用JVM问题,HBase、HDFS这些都是里Java实现的,所以说GC问题是难以避免的,我们主要是做两方面个工作,一个是调节JVM参数,另外一个就是我们在采用单机多实例的部署方式,这样就是减少JVM堆的大小,这样可以缓解GC的影响。
    第四个问题是程序Bug,在我们使用的过程中,也遇到过一些包括(Zookeeper、HBase、HDFS)的Bug,这个是比较难避免的。所以我们做了两方面工作,一个是可用性监控,另外一个就是刚才提到的错误日志的统计分析,这样我们可以尽早的发现一些异常的情况,然后去排查。最后一类问题节是网络故障,网络故障发生的比较少,但是影响比较严重,会导致集群整体宕机,需要重视。
接下来我讲一下我们在开发工具方面所做的一些工作。

image021.png

首先小米这边的数据模型相对来说是比较统一的,因为它有两个特点,一个是它的数据是由底大量的独立用户产生,另外一个就是业务一般就是需要在用户实体范围内支持跨行原子性和二级索引。同时一般没有全局事务和全局索引的需求。对上面的特点我们对HBase做了两个改进,一个就是基于正则表达式的前缀分割策略,这样就能保证相同前缀向记录能够分在同一个Region上。第二个改进就是实现Region内部的跨行原子性的支持,对于batch操作,保证修改在同一条WALEdit落地,并按照Rowkey顺序加锁的方式保证原子性。顺序加锁能够避免死锁的问题。

image023.png

   最开始我们的应用都是通过HBase原生Client来开发的,当中也遇到了一些问题,就比如说学习成本,还有就是用户需要自己实现数据类型,实现的时候,会有一些额外的开销。另外是从客户端实现索引,通过checkndPut这种方式,开销比较大,另外实现起来也比较复杂,功能也不是完备。最后最重要的一点,业务层的代码大量冗余,这样一方面开发效率低,另一方面很难保证代码质量。我们解决的方案就是,在HBase Client基础上开发了一个结构化存储库,提供了内建的数据类型支持和局部二级索引支持(Region内部)。
我们提供了三种索引,第一种是Eager索引,这种索引在更新和删除数据的时候,就清除失效索引,读取时无需额外操作,索引一定是有效的。第二种是Lazy索引,这种索引在读取的时候判断是不是有效的,在数据更新时不做额外操作。第三种Immutable索引是结合了上面两种索引特点,适合只读性数据一次性写入的情景,这样读取和写入都没有额外的开销。

image025.png

接下来简单介绍一下数据类型的支持。我们参考了HBase的实现和SQLite的编码方案,对于数值类型,采取符号位反转方案,对于二进制类型,采取的方案是,由8比特编码转换成7比特变长编码,最高位为标志位。1表示是否是有效的编码数据,0表述编码结束。同时编码方案还支持逆序编码,采用的方案是按位取反,可用于逆序索引等场合。这种编码方案的优点就是保持编码后的二进制数据,跟原来的值大小关系是不变的,这样可以兼容HBase的存储格式和访问接口。

image027.png

     这是libsds的整体结构。其中索引通过HBase的Coprocessor来实现。除基本的访问接口之外,还提供了 Object-KeyValue Mapping,可实现业务层Java对象到HBase KeyValue的自动映射。下面的例子演示了通过libsds Annotation方式定义Schema和访问数据的方式。


image029.png


image031.png


image033.png


image035.png


image037.png

通过这个例子看到,业务层做开发的时候,需要写的代码是非常少的,所以无论是开发效率,还是开发质量上来讲,都可以得到很好的保证。

image039.png

最后一个我简单介绍一下小米开放平台,我们前面讲了,就是我们前面讲了两种使用方式,一种是使用HBase原生Client,另一种是使用libsds。存在一些问题,第一Zookeeper,Kerberos等环境配置比较复杂,第二是只支持Java语言(HBase的Thrift跨语言方案不是特别完备)。第三点,小米的应用大多数都是移动的应用,目前的一个趋势是手机端App直接访问后端通用数据服务,免去后端业务层服务器的开发。基于这些考虑,我们就在HBase的基础上,提供的结构化存储存储服务。
 

image041.png

这是整体的一个架构,架构也是非常简单的,在HBase以上,提供了安全控制和Quota管理模块,在这之上是接入层以及多语言SDK。目前已经接入了一些业务,包括MIUI的部分应用,小米智能家居设备的数据,小米手环等生态链公司的数据,目前可以在小米开放平台试用。
 
请点击下载

colincheng - 大数据工程师@易宝支付

赞同来自:

总结的非常好,能再给些干货吗?小米的hbase还是很厉害的。

fish - Hadooper

赞同来自:

文中提到HBase备份时使用hdfs raid。 但HBase的hdfs存储由于不断compact/split的缘故会不断的变化,hdfs raid并不擅长处理在持续变化中的数据,请问这里怎么处理这个矛盾的?  或者说,这里的hdfs raid并不是直接存的HBase的Hfile数据?

hufei1204

赞同来自:

不错

fish - Hadooper

赞同来自:

咦,怎么没有可下载的pdf?

要回复问题请先登录注册