Netty 实战之如何设计一个大文件存储系统
逅弈 转载请注明原创出处,谢谢!
我们知道随着系统的发展,以往单机的存储系统已经无法满足日益增长的文件存储需求了。急需一种可以存储大量文件、低成本、高扩展、高可用的分布式存储系统。Google的GFS就是这样的一种分布式文件系统。Google File System、Map Reduce、Big Table是Google的三大论文,他们是奠定Google伟大帝国的重要基石。今天我们主要来了解下分布式文件系统,与GFS类似的还有:HDFS、Ceph 、GridFS 、TFS等等。这些文件系统各有各的优点,适用的场景也各不相同,他们的特点不是本文要讨论的重点。今天我要来说的是,怎样设计一个简单的大文件
存储系统。
分布式、集群部署
首先分布式系统,我想大家都不陌生。说到分布式
,肯定要说下集群
。
分布式是将不同的业务分布在不同的地方,简单来说就是一个业务分拆多个子业务,部署在不同的服务器上。
集群是将同一个业务,部署在多个服务器上。
为了保证系统的高可用性,肯定要通过集群部署;为了保证系统的可扩展性,则要通过分布式部署。
分块存储
为了保证一个大文件能快速的存储,可以将文件分块,通过多线程进行并发的存储。读取的时候,也可以通过多线程并发的读取文件块,快速的下载。
基于以上两点的分析,初步可以得出一个系统的架构:
[ node ] <--sync--> [ node ] <--sync--> [ node ]
其中每一个node都是集群中的一个节点,主要有以下职责:
[ node ] ---store---> disk
[ node ] <--restore-- disk
节点之间通过p2p通讯的方式进行数据的同步,保证数据的一致性。这里同步的是文件的元数据metaData。文件的实际数据不需要在每一个node中保存,为了容灾,一般对数据在不同磁盘、不同机架、不同机房保存3个副本。
除此之外,该系统还需要有以下特点:
- node是无状态的,每一个node都知道每个文件有多少个文件块,每个文件块存储在哪些node上
- 当一个node接收到存储请求时,会根据自身情况,确定这些文件块是自己存储还是委托其他node存储
- 每一个文件块都需要至少保存3个副本
- 每一个文件的metaData会在所有node上保存
- node之间需要同步文件块,以保证至少有3个副本
- 每个node负责文件块的存储的读取
有了node之后,就有了一个集群,对外一个集群肯定是一个单独的系统,是一个整体。因此,还需要有一个单独的节点来管理所有的node。所以,在系统中增加一个proxy
节点。该节点对外充当整个系统的入口,对内则管理所有的node,并给node下发store和restore的指令。调整后的系统架构如下:
+--------------[ proxy ]---------------+
| | |
v v v
[ node ] <--sync--> [ node ] <--sync--> [ node ]
proxy和node之间通过zk进行连接。
系统启动的流程如下:
- proxy通过netty开启一个http服务
- proxy启动后监听zk的/node节点
- node将自己的ip和port注册到/node节点下,并获知/node节点下其他的node,将其他node的信息保存在内存中
- proxy收到node上线的通知后,通过netty与node维持一个heartbeat,当node挂掉之后,能够迅速将其移除
存储文件的流程如下:
- proxy接收到存储请求后,通过RandomAccessFile的方式将文件分成若干个文件块,并根据文件分成一个唯一的fid,返回给客户端
- proxy将文件块封装成数据后转发给node,然后给node下发store指令,该过程将轮询转发到不同的node,将文件块分散存储到不同的node中去,在此过程中proxy将在metaData中纪录每个文件块存储在哪些node中
- node存储完文件块之后,找到其他合适的两个node,将文件块同步过去,保证一个文件块有3个副本
- node存储完文件块之后,告知proxy,该文件块是由该node自己存储的还是委托其他node存储的,如果是其他node存储的,proxy将要修改metaData
- metaData准备完毕之后,proxy将广播给所有的node,并下发存储metaData的指令
下载文件的流程如下:
- proxy接收到下载文件的请求,得到文件的fid
- proxy将请求转发给任意一个node
- node根据fid得到文件的metaData
- node从metaData中找到文件块存储的位置
- node将存储文件块的所有位置返回给proxy
- proxy根据位置到具体的node中并发的请求文件块,返回给客户端
至此一个简单的大文件分布式存储系统设计完成了,还有许多其他需要考虑的,如:
- 当某个节点挂了之后,该节点中存储的文件块应该要同步到其他节点中
- 节点恢复后其他节点备份的该节点的文件块该如何处理
- 每个节点应该要监控磁盘的容量,当容量小于某个阈值时,不能再进行写入操作
以上是我的一点思考,肯定有不到位的地方,欢迎大家批评指正,如果您有更好的方法或建议,欢迎分享。
更多原创好文,请关注「逅弈逐码」