欢迎您光临本站,如有问题请及时联系我们。

专家观察 | 林尚泉:“小米结构化存储系统及融合云平台的设计与实践”

  由工业和信息化部指导,中国信息通信研究院主办,业界知名组织云计算开源产业联盟(OSCAR)承办的2017全球云计算开源大会于4月19日-20日在北京国家会议中心顺利召开。本文为本届大会嘉宾分享的大会演讲速记内容,敬请浏览。

  嘉宾介绍:林尚泉

  公司职务:小米科技开发工程师

  大会演讲速记

小米

  我是来自小米的云平台的工程师林尚泉,下面我来给大家介绍一下小米结构化存储系统以及融合云平台的设计和实践。

大纲

  这个是今天的演讲大纲,比较简单。

NoSQL数据库

  结构化存储是一个分布式NoSQL数据库服务,对标AWS DynamoDB,我们的目标是要把它做成一个弹性可扩展、高可用、低延时、稳定可靠的数据库服务。

  首先介绍一下项目的背景,HBase在小米用的比较好,但是用着就发现了一些问题,包括一些认证和环境配置比较复杂,还有多语言支持的不太好等等,到后面我们还要支持生态链公司的一些结构化数据的存储需求,所以我们需要在公网里面提供访问。

存储

  HBase在公网直接提供访问也不大方便,所以我们就做了这套服务,它是基于HBase的,对外提供无状态的公网访问,简化了客户的配置,支持多种主流语言的SDK,因为一个集群供多个用户一起使用,所以需要支持多租户的功能,包括访问控制和流量控制,并且我们还在原生的HBase上做了一些功能扩展,因为原生的HBase是只支持按主键索引,没有二级索引,也没有数据类型的概念。

存储

  我们在上面做了一些功能扩展,包括数据类型、二级索引、stream、还有软删除和数据冷备等等这些功能。现在这个服务不仅支持了小米内部业务,包括MIUI、小米网等等,还支持了十几家生态链公司的结构化存储的业务。

  看一下应用规模,我们在北京天津美国新加坡都有相应的集群,机器规模一百多台,支持的业务数二十几个,数据量一百多TB还有数千亿行,看起来不是很多,但是前段时间统计,现在的数据量是以每两个月翻倍的在增长,现在单集群的QPS大概是几十万级别。

  这是结构化存储一个典型的部署,分为主备结构、底层是Zookeeper/HDFS/HBase等系统,主集群使用ssd盘,备集群使用hdd盘,在HBase上面那层我们封了一层libsds,主要对HBase做了一些功能扩展,在libsds库上,我们是直接对外提供服务的ThriftServer,使用Thrift 的RPC框架,支持多种语言的SDK,还有流量控制等功能。主集群是直接供用户的线上访问,备集群除了充当主集群的热备之外还会给用户跑一些离线作业。

libsds库

  下面首先介绍一下libsds库,主要在HBase上做了以下的功能扩展,一个是规范化的数据模型,还有一些数据类型的支持,还有局部二级索引以及全局二级索引,下面分别介绍一下几个功能,规范化的数据模型意思是在libsds那层,表是有schema的,

  这个图就是对应HBase的一个KeyValue,还支持了多种数据类型,包括各种基本类型和集合类型。

编码

  我们采用了HBase8201和SQLite编码方案对RowKey进行编码,保证跟原来的数据类型的顺序是一致的,还可以支持逆序。

索引

  局部二级索引,这种二级索引是实体组内部的索引,索引数据是和原数据存在同一张表上的不同Column Family,我们实现了个基于正则表达式的前缀分割策略,确认保证同一个实体组键里面的数据是在同一个Hbase region上面,并且不能被split的,这两个图刚才介绍过,一个是原数据的,我们建了局部索引,除了写原数据还会加一行索引数据,就是下面这个图。

  RowKey的排列是实体组键到索引键再到主键,可以看到原数据和索引数据的实体组键是一样的,然后根据我们实现的前缀分割策略就可以保证原数据和索引数据在同一台机器上,就可以比较简单的去保证这两个数据写入的原子性。

  我们是通过HBase Coprocessor来实现了indexObserver,也就是客户发送Put或Delete请求后我们会拦截这个操作,然后再计算要上出来索引,再把它放到原来的数据里,最后再同一台机器上一起落地,就可以保证原数据和索引数据的原子性。

  还支持了多种类型的局部二级索引,其中包括EAGER类型,也就是更新删除时同时删除失效索引,是适合写少读多的场景,而LAZY索引是读取判断索引有效性,更新时不做额外操作,适合写多读少,还有IMMUTABLE是需要用户保证数据的只读性,就适合以只读数据的一次性写入,读写都不需要做额外的判断,这种比较高效。

  还支持了全局二级索引,和局部二级索引不一样的地方是它的索引数据是单独的存在一个HBase表里,我们采用了谷歌的percolator方案实现的,我们在hbase上实现了这套算法叫Themis,这个已经开源,这个算法可以保证跨表更新的原子性,Chronos为全局单调递增时间戳。

  全局二级索引数据对应的HBase的KeyValue跟局部二级索引不大一样,是以索引键排在最前面,再到实体组键和主键,我们对局部二级索引和全局二级索引做了一下性能对比。这个图是对某一张表建立了一个全局二级索引和局部二级索引,然后再写,红色是局部二级索引,蓝色是全局二级索引

  可以看到因为全局二级索引会涉及到分布式的事务,可以看到性能损耗比较大,局部二级索引比它有好个四倍左右,而读的话同样局部二级索引好个两倍。

  另外我们实现了stream功能,如果开了这个功能,用户对表的修改除了在原来的数据CF上写,还会封装成一条消息在另一个CF里再写一份,另外起一个MR job定期扫那个额外的CF,再把那个消息打到流式消息队列里,用户就会拿到流式消息队列来消费这些数据。

  其中包括两种类型,一个是RECORD IMAGE,得到的消息是这行数据被修改以后最后的视图,用户拿着这种类型的消息就可以做一些最终一致的增量备份,另外是MUTATE LOG,就是每一行的修改日志,这种类型再结合一个定期打快照的功能,就可以把指定某一个表恢复到历史任意一个时间点。

  我们采用了facebook 的Thrift框架,对外屏蔽了一些复杂的配置,由于是使用了Thrift框架,很方便的可以支持多种语言的SDK。

  ThriftServer主要对外提供一个无公网的http服务,对外屏蔽了HBase,用户只需要拿到一个域名就可以直接访问,简化了认证和配置,支持了多种语言的SDK,多租户包括访问控制和流量控制。

  ACL功能,我们是在HBase那里存了一份元数据表,它的格式是某一个表有哪些ACL信息,并且每一个节点会对元数据做本地缓存,假如有用户发了一个修改ACL的请求,这个ThriftServer不仅要更新元数据表,还要在Zookeeper修改一个节点,因为所有的ThriftServer节点都监听了Zookeeper的那个节点,就会收到一个通知进行更新,通过访问元数据表更新本地缓存。

  流量控制,SDS支持用户每一个表进行预设置的读写配额,设置读写配额的时候SDS会检查一下集群的能力,集群的能力是根据我们的一些性能测试得到的,做限流的时候是基于token bucket算法进行限流的,集群能力使用到80%的时候会提醒我们进行集群扩容。还实现了软删除的功能,因为要保证数据安全,

  软删除就是用户发一个删表请求,要删除一张表的时候,SDS后台会先对这个表打一个快照,然后再去删除这个表,这个时候会存一堆snapshot文件,在经过TTL 的时间后删除,在删除之前用户可以通过restoretable通过clonesnapshot把表恢复出来。

  而数据冷备我们实现了一个工具,是可以把HBase一些snapshot推到AWS S3,需要的时候再拉下来。结构化数据存储系统暂时介绍到这里。

  我们来看一下融合云平台。这个是小米融合云平台的控制台的首页,可以看到它除了刚才介绍的结构化存储之外,还包括的文件存储,团队管理,流式消息队列和深度学习等等的一些服务,我们的愿景是把它打造成一个闭环的集计算和存储于一体的云服务平台,更好的给小米的用户和生态链公司进行服务。然后用户要访问上面的任何一个服务都要通过团队管理,自己去申请一些team等等。

  这个是我们融合云平台的架构图,中间主要的服务是Zookeeper、HDFS、HBase等等服务,在上面有SDS、FDS、EMQ,还有其他服务等等,外围有一些公用的组件就是部署服务,我们为了方便我们集群的管理还有一些升级部署,我们开发了一套公用的部署系统,所有的部署都是通过融合云的部署系统。

  还有一套公用的报警系统,并且用户访问的时候都要通过团队认证管理提供一个统一的认证入口。下面来简单介绍一下三模块,融合云通过一个CloudManager进行了团队认证管理,用户可以对CloudManager发一些团队管理请求,添加或删除team等,这个模块就会把这些信息存在MySql,比如用户要访问我们的结构化存储或者文件存储的服务,如果前端过来的请求,前端首先会把这个请求转发到CloudManager这个模块,CloudManager经过验证以后会从MySQL读出团队信息,再放到http header里面再转发到后端service。

  如果通过SDK直接访问service,要通过签名进行认证才的,具体是service调CloudManager的RestfulAPI,这个Restful API会返回用户的团队信息,service再把这个解密,算一个签名出来,再做对比。

  融合云的部署系统是使用了我们小米发的Minos2.0,1.0已经开源,2.0实际上是在1.0的基础上增加了一些认证授权的模块,主要包括Tank管理服务器,集群每一个节点都用supervisor监控,提供了工具来给用户做集群的升级等等,这些操作都需要经过CloudManager进行认证,主要是为了保证只有集群的owner或者对这个集群有相应的权限的用户才可以进行相应的操作。

  提供了一套统一的监控告警系统,小米其实在运维团队也开发了一套open-falcon的告警系统,为什么自己还要再搞一套?因为那套在公网访问是不太方便,因为我们这一套系统需要供很多的用户一起用,需要数据隔离,并且那套是使用RRD来存储数据,不保存原始数据,我们的很多用户是有这个需求的。更重要的一个原因就是我们需要为用户来监控其他服务的资源上面的一些指标提供一个统一的入口,例如用户用了结构化存储还有文件存储等等,这些服务上面的资源的指标都可以通过我们统一的监控告警系统来进行统一的监控。

  它的主要架构是这样的,用户是可以直接往我们的监控告警系统的ThriftServer发请求,包括两种,一个是推送指标或者查询指标,这种请求在ThriftServer直接转发到OpenTSDB,再对这些指标进行保存,OpenTSDB支持数据的下采样和聚合。

  另外一种就是对指标监控要定制一些告警规则,用户可以把这个告警规则的请求发到service,ThriftServer把这个规则存到SDS,告警用户模块是对用户每一个指标都要过一遍,根据用户定制的告警规则看有没有触发告警,因为需要有一些指标的内存状态,所以就需要保证同一个指标必须发到模块的同一个节点上。

  另外还有一个Collector模块,把我们所有小米融合云里面的子服务的指标,就是用户关注的指标统一收集然后推送到我们的监控告警系统给用户做统一监控。我今天的分享就到这里,谢谢。


来源:本文由E8运维原创撰写,欢迎分享本文,转载请保留出处和链接!