十年•杭研技术秀 | 构建高可用的PB级对象存储

社区编辑2018-05-15 15:56

2016年对于网易杭州研究院(以下简称“杭研”)而言是重要的 – 成立十周年之际,杭研正式推出了网易云产品。“十年•杭研技术秀”系列文章,由杭研研发团队倾情奉献,为您展示杭研那些有用、有趣的技术实践经验。正是这些宝贵的经验,造就了今天高品质的网易云产品。

在现代云计算体系结构中,对象存储是重要的组成部分。正如数据服务是互联网IT服务中的重要组成部分一样。对象存储可以帮助用户通过简单的REST API,在各种平台上很容易地上传、下载各种大小的文件,并且提供构建在存储服务上的图片外链,图片缩略等富媒体服务。云存储或者说对象存储的特点是内部具有海量数据的高可靠存储能力,具备极高的可扩展性;对外提供高速稳定的统一HTTP协议访问接口,支撑用户的高并发高带宽访问。

在网易杭州研究院的云计算体系中,也有这样一个提供海量数据存储的高可靠对象存储服务——NOS(网易对象存储):它提供多备份可扩展的PB级数据存储服务,以及图片缩略剪裁、水印与视频点播等丰富多彩的富媒体服务。NOS是杭研云计算体系中在网易公司使用最为广泛的子项目之一,为公司内部几乎所有互联网业务提供了稳定可靠的数据存储服务;并且随着2016年网易云产品化的浪潮,NOS已经开放了对外的公有云版本,公有云上线近半年也得到了外部用户的认可,已为多家企业级用户提供线上服务。

本文回顾NOS在架构体系上的成长之路,介绍这样一个最初只有6、7台服务器的小集群如何一步步发展,最终成长为一个为网易百余个项目提供数据服务的成熟平台。





NOS 1.0

图1:NOS最初的集群架构

图1是NOS最初上线的集群架构,层次简单、只有6、7台服务器,但是实质上已经实现了对象存储最核心的功能:基于HTTP协议的对象(文件)上传、下载功能。并且已经具备了基于桶的多租户命名空间隔离功能。上线之初的NOS主要由以下几个模块组成:
SDFS – 分布式文件系统;
DDB – 分布式数据库;
NOS服务器 – Http协议解析与封装、验权、元数据查询。

NOS最初的架构简单且易于理解,用户的文件读写请求以HTTP协议发送到NOS前端服务器,NOS前端服务器负责解析request请求,进行权限验证与元数据查找。元数据存储在分布式数据库DDB中,按照对象名的MD5进行hash分表存储,因此具备高并发与较高的存储容量。找到元数据后,用户可以与SDFS分布式文件系统交互,将实际文件的二进制流读取或写入到分布式文件系统中,并且将最终结果返回给用户。NOS最初的架构虽然简单,但是DDB和SDFS这两大核心组件却构成了NOS最基础的框架,并且一直沿用至今,他们直接保障了NOS的高效与稳定,下面我们就重点介绍下这两个模块:

SDFS是杭州研究院自研的分布式文件系统,结构类似于GFS,具备高可用、易扩容的特性,负责实际的文件存储与读写接口。SDFS早在2006年就研发上线,在NOS项目成立之前就已经作为一个独立的项目应用于网易相册、邮箱大附件等线上业务,NOS虽然对SDFS进行了一定的适配修改,但是基本是传承自杭研的历史积累。


图2:SDFS组织架构

SDFS主要是由SN与MDS两大模块组成,SN负责实际的文件存储与文件读写接口提供;MDS负责SN的资源管理、状态监控与故障恢复的任务分发。SN是多副本的架构,用户上传时同步并发写,读取时随机选择一个副本读取文件。任意SN故障或者SN上的磁盘损坏、SDFS的MDS可以自动将故障节点屏蔽,保障线上的正常使用。MDS是SDFS主控节点,负责新数据写入的资源分配;MDS可以根据SN的实时负载与剩余存储空间综合考量,决定新数据写入到哪个SN服务器。MDS另外一个重要的作用就是实时监控SN的状态,及时屏蔽故障节点,当MDS发现SN的心跳异常后,会通知所有客户端驱动,不要再向对应的SN发送数据读写请求。

由于MDS对整个SDFS分布式文件系统是如此重要,因此它自身也是具有高可用特性的。一个SDFS系统通常有2到3个MDS,它们通过Zookeeper进行选主。当主MDS异常,会自动触发基于Zookeeper的选主,而SN和客户端也可以通过服务端口是否可用来判断谁被选择成了新主,并且自动重连。这套高可用服务机制虽然简单,但是却被历史经验证明可靠而有效。

与SDFS类似,DDB也是继承自杭研2006年就研发上线的成熟项目。DDB是一个分布式数据库,或者更准确的说,是一个基于MySQL的分布式数据库代理。它提供了一套透明的数据切分方案,和完整的类JDBC数据库驱动,支持绝大多数的SQL语法。用户可以像使用单节点的关系型数据库那样方便的使用DDB进行数据的存储。由于NOS元数据访问多是简单的键值访问,但是并发大,数据量巨大,因此天然适合DDB这样的分布式数据库。


图3:DDB组织架构

DDB的组织架构如图3所示,DBN(MySQL)负责实际的数据存储与读写提供,管理服务器负责数据库表、用户权限、数据分布路由的维护以及DBN状态的监控与管理。除此之外DDB最核心的模块是被称之为DBI的数据库驱动,它是一个类JDBC驱动,一方面可以与管理服务器交互,获取分布式数据库的表结构与分布路由;另一方面可以解析用户发过来的SQL语句,转换成适用于分布式场景的SQL直接发送给DBN节点,并且将DBN返回的结果进行聚合或者排序并最终返回给应用程序。正是由于DBN这一系列的改写与聚合动作,才能使得应用程序可以像访问一个简单的关系型数据库那样去访问DDB这样一个分布式数据库。

DDB本身也具有极高的可靠性与可用性,DBN节点本质是一个MySQL,可以利用MySQL原生的Binlog复制建立实时镜像。我们通过一个外部程序实时的监控DBN的状态,当发现DBN不可用后,可以主动向DDB 管理服务器发送指令,将DBN切换到从库。与SDFS不同的是,DDB系统对于管理服务器不是强依赖的,用户驱动本身会缓存表结构与数据分布路由,正常的数据读写不需要访问管理服务器。因此DDB可以做到当管理服务器故障时,不影响正常的业务读写,只是不能进行相关管理操作。


NOS 2.0

虽然NOS在上线之初就已经具备了比较完备的基础框架,但是很快就经历了几次大的架构调整,原因有二:一是业务的推动,新增了图片缩略等富媒体处理集群;二是访问量迅猛增长,原有框架在前端WEB层的隔离性与可用性上暴露出了很大的弊端。伴随着几次血与泪的教训,NOS进行了架构上的细化与拆分,整体架构逐渐发展成了这个样子:


图4: NOS服务架构图

此时的NOS架构相较于最初的架构已经复杂了很多,一方面是对原有的模块进行了拆分和隔离,另一方面由于新功能的加入,引入了富媒体处理相关的多个模块。

首先介绍NOS在富媒体处理上的实现架构。所谓富媒体处理,是指对图片的缩略、剪裁、加水印等常见图片处理操作,已经视频截图、音频类型转换等功能。针对图片、视频存储在NOS上的文件,用户可以简单的通过在url请求中增加富媒体处理参数的方式获取到经过处理后的图片。

例如下面的请求可以获取一张经过旋转的图片:
http://nos.netease.com/img-sample/koala.jpg?imageView&rotate=45



NOS中负责处理富媒体操作的模块:
nosmedia:富媒体请求参数验证、一致性校验、用户权限校验;
ATS:图片缓存系统;
Tobie:图片缩略处理核心模块;
Nosfs:C语言实现的一个基于FUSE的用户态文件系统,通过Nosfs可以像操作本地文件一样操作云端的文件。

用户的一个富媒体请求大概要经历以下几个处理过程:首先经过nosmedia验证用户的请求是否合法以及是否有权限访问对应资源。通过验证后请求会发往ATS缓存,由于图片缩略或者视频截图都是比较消耗资源的操作,因此我们引入一个分布式的缓存层对处理后的图片进行缓存,缓解图片处理模块Tobie的压力。如果ATS缓存没有命中,请求会继续发往Tobie进行实际的图片缩略处理。Tobie通过基于用户态的文件系统Nosfs从NOS中到读取实际的文件,然后使用GraphicsMagick对图片文件进行相应的富媒体处理并将结果返回给ATS进行缓存,并最终返回给用户。

在NOS中,Tobie是一个很有特色的模块,它大量的考虑了并发控制与过载保护的问题。图片处理是一个CPU消耗型的场景,而一台服务器的线程数是有限的,因此Tobie引入了http层请求队列与Worker机制,可以根据服务器的CPU核数配置Tobie的Worker数量,合理控制并发。当用户的请求数量超过Tobie的处理能力后,Tobie可以通过限制http请求队列大小和Worker处理超时请求直接丢弃的方式进行过载保护,防止Tobie被超过自身处理能力的请求拖慢甚至卡死。Tobie的内部构造如下:


图5:Tobie内部处理流程

除了富媒体处理集群的引入,NOS在架构上还对原有的NOS服务器进行了隔离与拆分,拆分成了两个模块:
nos proxy:解析用户请求,从DDB中获取元数据,并且将文件读取或写入到分布式文件系统。
auth:用户权限认证,根据用户header中携带的签名信息判断用户是否有对应资源的访问权限。

NOS将权限验证功能拆分成独立的模块,主要原因是可以作为一个独立的服务供富媒体缩略等其他集群使用,另一方面,还可以进行一些认证服务降级等可靠性保障工作。针对原有的核心文件读写业务处理模块nos proxy,我们也进行了物理上拆分,针对普通的文件读写、富媒体集群的图片读写、视频帧截图的视频读写,都建立的对应的nos proxy集群。这是因为NOS中所有的请求都会经过nos proxy,合理的拆分可以防止某一类操作过载导致nos proxy的连接数飙升,影响了其他的所有请求。例如,用户图片缩略请求过载,导致Tobie并发请求增高可能会导致nos proxy的线程数达到上线,如果没有隔离,对于普通的用户文件上传下载也会产生相应的影响。

nos proxy和auth模块进行了大量的拆分隔离后,还面临了负载均衡与高可用的问题,由于NOS中的请求都是http协议的,我们采用在应用模块前增加一个nginx的方式进行反向代理。Nginx的upstream支持后端自动的failover与负载均衡,很适合无状态服务的转发代理。针对nos proxy这类无状态的前端服务,NOS采取设置合理的超时时间与重试机制来提高系统整体的可用性,降低系统中各模块之间的依赖。


NOS 3.0

经过了一系列的内部架构改造,NOS逐步成型了一套完整稳定的对象存储技术解决方案。但是这套架构只是单机房的解决方案,很快NOS就面临了两个问题,一是部分用户对数据可靠性有更高的要求,要求多机房数据备份与高可用;另一个是上传加速的需求,NOS的用户遍布全球各地,下载文件可以用传统的CDN进行加速,但是上传文件尤其是移动端的上传文件,需要专门的上传加速系统。针对这两个问题,NOS对原有的架构进行了进一步的扩展,给出了自己的解决方案。


图6: NOS多机房部署架构

上传加速方面,NOS引入了LBS与NOSUP模块,一次完整的上传加速流程如下:
客户端访问LBS获取边缘加速节点ip,LBS根据用户的ip返回距离用户最近的上传代理节点。
客户端使用SDK将文件以64KB为一个chunk发送给边缘节点,边缘节点再转发到中心机房的NOSUP。所有边缘节点都做过一些针对广域网的TCP优化,如设置tcp_slow_start_after_idle=0,维持数据收发使用高速通道。
NOSUP部署在中心机房,负责接收用户上传的分块文件,并且维护分块信息以支持断点续传。边缘节点将数据写入到NOSUP的内存中就会直接返回,NOSUP再以1M为单位异步的将数据写入到NOS中。

通过整个这样一套加速上传机制,NOS可以大大的加速广域网用户上传文件的速度,此外上传加速还在sdk中提供加速效果汇报的功能,因此可以评估整体的加速效果,并且定期的更新边缘节点的布点情况。经过我们的评估,NOS的上传加速的加速比在25%左右。

多机房方面,NOS在杭州、北京都部署了分区,然后通过Nossyncer做机房间的数据同步,Nossyncer可以通过消息队列获取用户桶的数据变化,然后将相应的新增或者删除操作应用到从分区。用户的桶只能在一个分区提供用户使用,称之为主分区,当主分区出现故障后,管理员可以人工设置切换到从分区。用户上传可以通过切换LBS使用户连接到从分区的NOSUP,从而把数据上传切换到从分区。下载可以通过切换域名DNS指向新的分区前端机。


结语

NOS 1.0时代,重点实现的是基础的存储与底层的高可用与自动切换;NOS 2.0时代,对于前端进行了拆分与细化,提升并发处理与隔离不同操作的相互影响;NOS 3.0时代,实现了基本的多分区部署与广域网的上传加速框架。软件系统的体系架构总是随着业务场景和访问规模的不断变化而随时调整,近年来随着网易各项业务的迅猛发展和蜂巢公有云的对外发布,更多新的挑战等待NOS去完成。下一个阶段,NOS会开发基于万兆网络的第二代高密度分布式文件系统;更精细的权限管理与租户隔离;基于消息队列的数据消费分发平台等。相信下一个十年NOS会更好、下一个十年网易杭研会更好。
——潘威
网易杭州研究院运维部NOS运维负责人