很多人可能都只知道,TFS需要配置一个特定的客户端才能访问。其实,如今通过一系列web_service的接口就可以轻松存储、获取TFS里面的数据,TFS在去年就已经实现了数据服务化。今天我们就来说说TFS的数据服务化之路。

在2012年以前,TFS有一个java和c++的客户端。最早只支持小文件的时候,TFS的客户端只需要在读写流程中和NameServer以及DataServer交互即可。后来在客户端实现了文件去重和大文件的支持。随着应用的增长、数据规模扩大以及跨机房容灾的需要,我们引入了RcServer来对应用、集群进行管理,并在客户端实现了相应逻辑,以达到集群选择、容灾功能都对应用透明的目的,大大简化了应用的配置,降低了应用使用TFS的成本。再后来,我们在原生文件的基础上开发了新的功能,允许应用使用自己定义的文件名来进行访问,拓展了TFS的用法。至此,客户端与后端Server的交互对象又增加了两个,逻辑复杂化的趋势愈演愈烈,需要bugfix的频率也越来越高。而每次新功能或bugfix都需要将新的客户端推到所有使用TFS的应用,这个过程异常的痛苦。不知不觉间,客户端已成为限制TFS前进的一个绊脚石,客户端改革势在必行。

在2012年的时候,我们和tengine团队合作开发了nginx-tfs模块,实现了当时TFS客户端的全部功能,发布了TFS 的RESTful API。在此基础上,我们开发了java、c++的RESTful客户端(此外还有一些应用根据我们的RESTful API贡献了php、python、ruby、nodejs等客户端),以替代对应原有客户端以帮助应用实现无缝迁移。这些RESTful客户端只需实现和TFS的nginx模块,也就是所谓TfsProxyServer的协议,因此逻辑简单,十分轻量。RESTful API基本不需改变,因此也不会有频繁的升级需求。至2013年上半年就已基本完成当时所有200多个应用的客户端替换,从此客户端升级这个TFS前进路上的绊脚石已被踢开,TFS进入数据服务化时代。

在统一了访问TFS数据的入口之后,我们就可以很方便的做一些原来做起来比较费劲的事,比如,访问统计分析等。另外,客户端升级成为可控,我们就可以大刀阔斧进行客户端和服务端改造、肆无忌惮地对他们之间的通信协议进行修改。

应用访问统计平台

我们搭建了一个访问日志收集和分析的平台,可以记录每个应用的每次访问相关信息,比如应用名、文件名、操作类型、数据大小、rt、来源ip等,并且提供了一些数据的图表输出以供开发和运维人员查看,大大提高了日常运维和定位、解决线上问题的效率。

自定义文件名服务的迁移

这期间,我们改造了原来支持自定义文件名服务的系统,实现了Amazon S3兼容的对象存储系统,并将原有的自定义文件名服务迁移至新的系统。

erasure code的支持以及通信协议的优化

后续,我们出于降低存储成本的考虑,为TFS增加了erasure code的支持,并对客户端和服务端的通信协议进行了一系列优化,以及文件名长度的升级(从18位升级至27位)。在以前的架构中,写流程必须要经过NameServer。NameServer是集群中的单点节点,我们一直致力于减少它的负担以提高整个系统的可用性。在之前我们已经通过元数据cache(包括本地和远程)使得绝大多数读请求可以绕过NameServer。接下来,我们要让写请求也不经过NameServer。这个功能已经开发完成,目前正在测试中。

imgsrc的改造

imgsrc是CDN回源TFS的入口,主要作用是获取原图或对原图做一些图像处理如缩放、质量变换等工作。在此之前,imgsrc是由一个apache模块,通过调用原有的TFS的C++客户端来从TFS中读取数据的。众所周知,Apache由于自身设计的缘故,在高并发的情况下,性能不如Nginx,对系统资源的使用上也不如nginx来得节俭和稳定。因此我们在nginx-tfs的基础上,结合nginx的lua模块,很方便的开发出了nginx-imgsrc,成功替换了服役数年之久的apache。
此后还完成了mediasrc业务的整合,这都得力于nginx-tfs模块以及可以很方便地实现各种业务逻辑的nginx-lua模块,相信在未来,这种模式还会有很多可想象的空间。

lifecycle和用户自定义元信息功能

最近,我们又开发了两个TFS的新功能:lifecycle和用户自定义元信息。前者可以让用户指定文件的生命周期,实现文件按期(支持绝对和相对过期时间)自动删除的功能;后者可以允许用户对自定义文件进行自定义元信息的存储。这两个功能都已开发完成,即将上线,敬请期待!

未来的工作

从原来的客户端直连后端server到现在的经过TfsProxyServer这一层中间层转发,对rt会造成一定影响,特别是网卡的流量变大的时候,目前我们通过部署万兆网卡来暂时避免了这个问题,并开发了一个自适应的流控模块来对流量进行控制,接下来会着手对rt进行优化。

另外,我们正在进行nginx-tfs的重构工作。众所周知,nginx之所以具备较高的性能,这得力于它的异步事件驱动框架。因此,nginx-tfs的代码自然也全是异步的。之前已经提过,TFS的客户端具备相对比较复杂的业务逻辑,要在异步框架下实现复杂的业务逻辑。从这大半年的开发和维护经验来看,在现有的nginx-tfs的框架下,新功能的增加以及bugfix已经开始遇到一些阻力,代码维护和新人学习的成本较高。因此目前我们正着手进行nginx-tfs重构工作,目的是通过封装底层的异步框架,争取能够使用同步的方式来编写业务逻辑。