存储 频道

徐海峰:阅文集团自主分布式存储系统

  【IT168 现场报道】2016年10月27日-29日,2016中国系统架构师大会(SACC 2016)在北京万达索菲特大饭店举行。作为中国规模最大的架构师豪门盛会,本届大会以“架构创新之路”为主题,站在创新的风口上,与大家共同打造一场通过架构创新及各种IT新技术来带动企业转型增效,助力架构师们腾飞的技术盛会。在10月29日专场上,阅文集团首席架构师徐海峰对分布式存储系统做了精彩的演讲。

  徐海峰,主要负责内容中心的网站架构和分布式存储、分布式计算工作。10年互联网开发经验,为开源分布式文件系统fastdfs提交过代码。曾历任Ctrip国际机票引擎架构师、5173分布式存储和分布式计算架构师。多年来一直致力于网站架构和分布式计算的研究与实现,对大型网站架构和分布式计算有丰富的经验。

徐海峰:阅文集团自主分布式存储系统

  设计背景

  徐海峰指出,所谓分布式文件系统(以下简称DFS),它是基于linux的文件系统,并面向大规模数据存储、海量数据访问、具有良好可伸缩性的文件系统。DFS设计运行在廉价的linux系统中,但是它依然为数据提供良好的一致性和完整性。

  首先,我们的DFS不需要保存信息的元数据。在我们的整个系统中,文章的内容只是文章的一个属性,而并不是文章的 全部信息,所以在关系型数据库中保存文章的属性信息是在所难免的 。

  其次,和GFS一样,我们认为我们的磁盘是很容易毁坏的,所以数据的完整性和安全性是很重要的一个命题。

  第三,我们的DFS和传统的DFS一个很大的不同就是我们的数据将会面临经常被更改的情况。不仅仅只是尾部增加操作,而是不知 修改位置的增删改操作兼具。

  第四,放弃了系统级别的元信息导致内容自带自解析信息,所以对于我们来说,数据的一致性也是一个需要解决的问题。

  第五,DFS仅仅需要做好数据的存储、安全、唯一、备份功能就可以了。

  最后, 我们只需保证我们的DFS能在linux系统io接口的标准上安全而唯一的 存放、访问就可以了。

  架构

  为了达成目标,需要对DFS进行了最简化的设计。和目前的大家经常和使用的DFS不一样,我们的DFS去掉了元数据功能,但是保留了该服务器节点( 以下我们统称这个节点为tracker)。这点很像FastDFS。 简化 后的服务器只剩下了tracker和存储服务器(以下简称storage)。

  tracker的主要用途从存储元信息变成一个状态控制服务器和负载均衡服务器,或者说它成了一个类目录服务器。一方面它主要和系统中的storage配合,对storage进行健康检查和状态维护; 另一方面,tracker还需要对客户端的访问进行路由工作。这样的无元数据的设计不仅仅只是从根本上解决了元数据导致的单点问题, 而且还大大的减轻了数据的完整性在系统中的压力,从实现的角度,也大大减少了代码量, 使tracker节点变成一个可任意水平扩展的节点,从而解决了系统中最不稳定的一环.

徐海峰:阅文集团自主分布式存储系统

  相对tracker来说,storage的工作将会复杂很多,它不仅仅要做文件系统本身的“增删改查”工作,还需要肩负一个同步的工作。为了简单,我们把storage 的存储文件只做镜像同步,不做相对复杂的打散再存储工作。也为了尽量合理的利用机器并且可以快速的通过增加机器的方式来达到我们对于存储量和性能的提升, 我们对同组内的storage进行了分片处理,也就是逻辑集群。在同一个组内,分成一定量的syncgroup,每一个syncgroup内部的服务器是镜像的,不同的syncgroup内的storage之间是 平行的,在同步上不存在任何的关系。这一设计在维护的时候增加了一个人工的syncgroup工作,但是它简化了同步打散的算法,最重要的,增加机器不需要移动原先 的数据,使得几乎可以认为增加机器就是在增加DFS的存储量和吞吐能力。

徐海峰:阅文集团自主分布式存储系统

  storage的改变不会迁移数据,也会导致性能的热点问题。新加的storage负载可能不够,但是老的数据被频繁的访问。对于我们来说,老的数据基本上都是被用来做读取之用, 业务的服务可以规避掉这个问题。对于写来说,本身就不会有太多的请求,所以这样的设计是我们所能接受的,对于我们这种特殊的需求,这并不是一个问题。

  不管是tracker还是storage,它们在linux中都是一个用户层面的进程,并未涉及到系统的内核,它们也都有自己的api,并没有为了兼容poixs等接口带来复杂度。 这样的设计方便了以后的维护和管理,也方便了实现的时候,只要考虑DFS本身的问题即可,无需为一些“杂事”而分心。

  进程内部结构模型

  在DFS内部,除了storage的sync模块和storage的心跳模块发起请求的部分之外,余下所有的功能全部依赖于一种线程模型,我们把它称之为module。

  module模型主要是把进程分成逻辑上隔离的3个部分,mainsocket module、network module和task module。

  为了socket accept的简单,DFS把mainsocket module设计成单线程module,该module只负责接收main socket的连接,然后获取DFS中的jobcontext对象, 将请求通过负载均衡算法发送到network module。

  network module为线程池设计,但是在mainsocket module中,经过负载均衡算法的发送,它保证了一个socket只会被一个network module的线程处理, 所以这里的处理是线程安全的。DFS会根据socket buffer的实际大小和服务器设置来决定读取数据,并且把数据依附在taskcontext对象上,和jobcontext一起 通过负载均衡算法发送到task module。

  task module和network module一样也是线程池设计,同样发送到task module后的处理也是线程安全的,task module是整个任务真正被处理的地方。不管任务 是否执行的正确,task module都会装配好回复client使用的response信息,然后按照原路返回给network module,network负责将response信息发送给client。

  存储模型

  在我们整个系统中,文章只是一个对象。但是在DFS中,文章的内容虽然也是对象,但是它还是被分成了2种:一种是大文件,一种是小文件。 对于文件的区分,我们会通过配置设定一个阀值决定。

  大文件将会作为sinalefile单独存储。它不会有带有别的信息,唯一需要使用的信息是lastmodifytime,这部分会在访问和同步中涉及。

  对于小文件,DFS会把这些零零散散的内容合并成一个chunkfile,在合并内容的同时,也把零零散散的随机IO变成了顺序IO。这样不仅仅解决了海量小文件 对于系统压力的问题,也解决了随机IO导致的性能低下的问题,一举两得。相对于singlefile,chunkfile内的内容存储就不一样了。DFS无法简单的只存储 内容,所以我们在内容前面给每一个需要存储的内容加了一个metadata。metedata主要存储了文件的存储日期、是否被删除、最后更新时间,总长度,实际使用长度 ,等等一序列的数据元信息。但是这些属性里面最重要的是一个类似于MVCC的值,在DFS中是opver,操作版本,它解决了版本问题。

徐海峰:阅文集团自主分布式存储系统

  对于DFS来说,它关心是文件的名字,不管是singlefile还是chunkfile,DFS只会受限于名字不能产生冲突。所以文件名必须带上storage的machineid。machineid是在 group内部唯一的。文件名带上machineid后,首先,它能确保文件的归属问题,可以把唯一范围缩小到单机,但是在单机内部还不能保证文件的唯一性,所以,我们给文件名带上另外的 一些信息,包括但不限于创建时间、顺序数、线程ID号。至少由这4部分组成的文件名才能确保该文件在DFS系统内唯一。

  对于storage,我们首选使用的是多而小的磁盘,这样可以让系统的并发达到最大化。而对于整个系统来说,我们又必须要支持磁盘的大容量。所以我们增加了多挂载点的功能, 原则上,每台storage机器最多可支持256个挂载点,这些挂载点会根据一定的规则进行数据的平衡策略。通常采用的是轮询的策略,也支持最大剩余空间等等策略,这部分 可以根据自己的需要自己来决定。对于多挂载点的支持,唯一的要求是同一逻辑集群内,必须做到镜像。

  数据一致性问题

  在分布式系统中,数据的一致性问题是被比较多的提及和难以解决的点。一般数据一致性出现问题的地方在于数据的版本控制和数据同步上。一旦在数据的版本控制上 出现纰漏,几乎数据的同步是肯定会发生一致性问题的。所以要解决数据一致性的问题,主要的工作还是在数据的版本控制上。

  对于DFS,刚刚上面讲到我们使用类似于MVCC的opver来解决这个问题。那么我们到底怎么解决这个问题?和为什么要这样解决这个问题呢?

     对于singlefile来说,它不需要版本控制,它是一个单独的实体,有就有,没有就没有,不会存在对于它的版本。 版本的冲突一般发生在modify的情况下, 只有执行modify,数据才会对同一个文件块进行覆盖。但是对于singlefile来说,它被更改就是先上传一个新的singlefile,然后把原来的siglefile删除掉,所以在这种情况下不存在问题。那么还有 一种情况,如果原来是一个singlefile,然后需要更新的是一个小文件阀值定义的内容,这时候DFS还是先上传一个新的chunkfile内容,然后把老的删除,以后的版本控制就会 按照chunkfile的版本控制来进行,所以singlefile是不需要做版本控制的,只要在同步的时候检测一下该文件是否还存在,然后根据实际的需要进行同步。

徐海峰:阅文集团自主分布式存储系统
 http://www.it168.com/redian/sacc2016/

1
相关文章