1、故事的起源
还是很多很多年前,做过一个小系统,是一个和支付相关的小系统。因为是一个小系统,所以一切都那么简单。一台应用服务器,一台数据库服务器;文件、图片都放在应用服务器上,一切都是那么的平淡,一切都是那么的理所当然。
突然有一天,支付成为一个时髦的话题;突然有一天,这个平台居然要孕育成为一个新的支付公司的核心系统;于是,系统的访问就要暴涨了。这一切都很突然……
2、调整后的系统简易架构
前端使用负载均衡设备统一进行调度,中端对应于服务器进行横向扩展,后端把数据库升级。后端文件存储用了多层NFS架构,但是还是不够,分布式文件系统成为了必然的选择。采用分布式文件系统后,服务器之间的数据访问不再是一对多的关系,而是多对多的关系,这样一来,性能大幅提升毫无问题。
3、分布式文件系统介绍
使用分布式文件系统可以轻松定位和管理网络中的共享资源、使用统一的命名路径完成对所需资源院的访问、提供可靠的负载平衡、与FRS(文件复制服务)联合在多台服务器之间提供冗余、与系统权限集成以保证安全。
在分布式环境中,有太多的意外,数据随时传输错误,服务器时刻准备牺牲,很多平常称为异常的现象,在这里都需要按照平常事来对待。因此,对于分布式文件系统而言,仅仅是满足了正常状况下文件系统各项服务还不够,还需要保证分布式各种意外场景下健康持续的服务,否则,将一无是处。
1、服务器的错误恢复
在分布式环境中,哪台服务器牺牲都是常见的事情,牺牲不可怕,可怕的是你都没有时刻准备好它们会牺牲。作为一个合格的分布式系统,应用服务器当然时刻准备好了前赴后继奋勇向前。每一台应用服务器出错了,都要有相应的应急策略和处理方法;
客户端
在分布式文件系统中,最不重要的应用服务器,应该就是客户端了。毕竟,做为一个文件系统的使用者,在整个文件系统中的地位,难免不高。而作为客户端,大部分时候,牺牲了就牺牲了,没人哀悼,无人同情,只有在在辛勤写入的时候,不幸辞世(机器挂了,或者网络断了,诸如此类...),才会引起些恐慌。因为,此时此刻,在主控服务器上对应的文件,正作为可能被构造的节点活着,仅仅为占有它的那个客户端服务者,做为一个专一的文件,它不允许别的客户端染指。这样的话,一旦占有它的客户端服务者牺牲了,此客户端会依然占着资源不释放。这种事情,必须要有办法解决这个问题,这就是:租约。。。
租约,顾名思义,就是当客户端需要占用某文件的时候,与主控服务器签订的一个短期合同。这个合同有一个期限,在这个期限内,客户端可以延长合同期限,一旦超过期限,主控服务器会强行终止此租约,将这个文件的享用权,分配给他人。。。
在打开或创建一个文件,准备追加写之前,与主控服务器在指定的路径下与此客户端签订一份租约。客户端会定时轮询续签租约。在主控服务器一端,始终在轮询检查所有租约,查看是否有到期未续的租约。如果一切正常,该客户端完成写操作,会关闭文件,停止租约,一旦有所意外,比如文件被删除了,客户端牺牲了,主控服务器都会剥夺此租约,如此,来避免由于客户端停机带来的资源被长期霸占的问题。。。
文件服务器
海量的文件服务器是一个更不稳定的因素。一旦某文件服务器挂掉,并且主控服务器还不知道,主控服务器就会变相的欺骗客户端,给它们无法连接的读写服务器列表,导致它们处处碰壁无法工作。因此,为了整个系统的稳定,数据服务器必须时刻向主控服务器汇报,保持主控服务器对其的完全了解,这个机制就是心跳消息。文件服务器必须要不断向主控服务器汇报自身的状况。比如:有多少可用空间、用了多大的空间,等等之类。主控服务器会将文件服务器汇报的状况,作为新的数据块分配或是负载均衡的依据。
主控服务器
主控服务器是整个分布式文件系统的核心,作为整个系统的核心和单点,主控服务器一旦当机,整个分布式文件服务集群将彻底瘫痪罢工。如何在主控服务器牺牲后,提拔新的主控服务器并迅速使其进入工作角色,就成了系统必须考虑的问题。解决策略是事物日志。
熟悉数据库的同学一看就知道是从数据库那里山寨来的。在主控服务器上,所有对文件目录操作的关键步骤(具体文件内容所处的数据服务器,是不会被写入日志的,因为这些内容是动态建立的...),都会被写入日志。另外,主控服务器会在某些时刻,将当下的文件目录完整的序列化到本地,这称为镜像。一旦存有镜像,镜像前期所写的日志和其他镜像,都纯属冗余,其历史使命已经完成,可以报废删除了。在主控服务器不幸牺牲,或者是战略性的停机修整结束,并重新启动后,主控服务器会根据最近的镜像 镜像之后的所有日志,重建整个文件目录,迅速将服务能力恢复到牺牲前的水准。。。
2、数据的正确性保证
在复杂纷繁的分布式环境中,我们坚定的相信,万事皆有可能。哪怕各个服务器都在认认真真工作,也可能有各种各样的情况导致网络传输中的数据丢失或者错误。并且在分布式文件系统中,同一份文件的数据,是存在大量冗余备份的,系统必须要维护所有的数据块内容完全同步,否则,不同客户端读同一个文件读出不同数据,用户非得疯了不可。
事实上,在没有用分布式系统之前,我们的系统就出现过多次数据不一致的情况,严重的时候公司领导都亲自关注,但是尘归尘,土归土,该怎样还怎么样,不从整体的视野上权衡,问题就不能彻底解决….
为了保证数据的正确性和同一份数据的一致性,分布式文件系统必须要做大量的工作。首先,每一个数据块,都有一个版本标识,一旦数据块上的数据有所变化,此版本号将向前增加。在主控服务器上,保存有此时每个数据块的版本,一旦出现数据服务器上相关数据块版本与其不一致,将会触发相关的恢复流程。这样的机制保证了各个数据服务器器上的数据块,在基本大方向上都是一致的。但是,由于网络的复杂性,简单的版本信息无法保证具体内容的一致性(因为此版本信息与内容无关,可能会出现版本相同,但内容不同的状况)。因此,为了保证数据内容上的一致,必须要依照内容,作出签名。。。
当客户端向数据服务器追加写入数据包时,每一个数据包的数据,都会切分成段,作为签名验证的基本单位,当数据包传输到流水线的最后一级,数据服务器会对其进行验证,一旦发现当前的传输块签名与在客户端中的签名不一致,整个数据包的写入被视为无效,整个流程需要重来;
3、分布式文件系统的内部负载均衡
这里说的负载均衡,是宽泛意义上的均衡过程,主要涵盖两个阶段的事务,一个是在任务初始分配的时候尽可能合理分配,另一个是在事后时刻监督及时调整
负载均衡,是分布式系统中一个永恒的话题,要让大家各尽其力齐心干活,发挥各自独特的优势,不能忙得忙死闲得闲死,影响战斗力。而且,负载均衡也是一个复杂的问题,什么是均衡,是一个很模糊的概念。比如,在分布式文件系统中,总共三百个数据块,平均分配到十个数据服务器上,就算均衡了么?其实不一定,因为每一个数据块需要若干个备份,各个备份的分布应该充分考虑到机架的位置,同一个机架的服务器间通信速度更快,而分布在不同机架让安全性有了进一步提升;而分布在不同机房的服务器,安全性更加高,但是响应速度,更加难以控制。
4、垃圾回收
丢垃圾,丢是一件简单的事情,但是什么东西能丢,不是一件容易的事情。我在家搞卫生的时候,总有很多的东西感觉从此以后不再使用,但是我和我媳妇(主控服务器)并不是每次都能达成一致,很多东西我想丢,我媳妇说要放一放,等几天看看,很多的时候,几天的几天又过去了,也许就这样放了几年,只能等下次大扫除或者家里没地方放东西了才行。
在分布式文件系统而言,没有利用价值的数据块备份,就是垃圾。基本上,所有的垃圾都可以视为两类,一类是由系统正常逻辑产生的,比如某个文件被删除了,所有相关的数据块都沦为垃圾了,某个数据块被负载均衡器移动了,原始数据块也不幸成了垃圾了。此类垃圾最大的特点,就是主控服务器是生成垃圾的罪魁祸首,也就是说主控服务器完全了解有哪些垃圾需要处理。另外还有一类垃圾,是由于系统的一些异常症状产生的,比如某个文件服务器停机了一段,重启之后发现其上的某个数据块已经在其他服务器上重新增加了此数据块的备份,它上面的那个备份过期了失去价值了,需要被当作垃圾来处理了。此类垃圾的特点恰恰相反,主控服务器无法直接了解到垃圾状况,这个时候就需要一些额外的策略来进行处理,比如将出现故障的文件服务器的数据都作为垃圾进行处理,然后按照规则同步这台文件服务器的全部数据。有可以先缓存起来,过几天没人想恢复它了再删除。
4.、总结
整个分布式文件系统。三类服务器、作为单点存在的核心主控制服务器、基于日志的恢复机制、基于租约的保持联系机制等等,在分布式计算系统和分布式数据库中都可以看到类似的影子,分布式文件系统中最大特点,就是文件块的冗余存储,它直接导致了较为复杂的写入流程。
写了这么多,看了这么多激动人心的概念,自己做一个分布式文件系统,是一个好主意,但是也是一个挑战,如果不能下大决心和花费无数的银子和时间,那么,就在诸多的分布式文件系统中,选择一个吧。