# 儒猿分布式小文件系统
**Repository Path**: java-core-test/ruyuan-dfs
## Basic Information
- **Project Name**: 儒猿分布式小文件系统
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 898
- **Created**: 2021-10-20
- **Last Updated**: 2023-06-08
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 介绍
本项目是使用Java开发的一个分布式海量小文件存储系统,功能包括文件上传、文件下载、文件存储等,解决了海量小文件在存储和访问过程中遇到的各种性能问题。
## 加微信获取更多免费资料

## 项目特性&设计
- 网络升级
- 核心逻辑优化
- BackupNode+NameNode主备模式高可用架构
- NameNode联邦架构
## 生产级技术架构

## 网络升级
小文件系统的网络部分原本实现比较杂乱,这是由于讲课的时候需要讲解各种技术的使用方式和演示最底层的开发是使用那些API。所以在课程中的网络分别使用了原生NIO和gRpc
但是我们做技术选型的时候选择统一网络请求方式,统一采用Netty作为网络通讯框架,改造前后对比如图:

## 文件传输协议
在集群中会有几种场景需要进行文件传输,比如上传、下载文件是客户端和DataNode之间进行文件传输,BackupNode和NameNode之间也要进行FsImage的文件传输。所以设计了一套文件传输的协议。文件传输的网络包包括包类型、文件元数据、文件内容二进制数据,如图:

## 分块传输设计
如图所示,当发送一个请求的时候,假如服务端写回的响应较大(超过最大消息长度),此时可以根据请求是否支持分块传输来决定是否需要拆包传输,可以将1个包拆分为n个包,然后传输给NetClient, NetClient收到包的时候,会根据一定的机制判断整个包是否传输完整,当收到了所有的响应包之后,再将所有的响应包合并成一个包,然后返回给用户。

## NameNode联邦架构
为了解决大规模海量小文件带来的内存增长压力,开发了NameNode的联邦架构,简单来说,就是通过多个NameNode节点组成集群,每个NameNode节点保存整个内存目录树的一部分数据。

## 线上性能参数回放


## 生产环境下的问题盘点
- OOMKiller杀死spring boot发压程序
- 带宽打满导致请求响应超时问题
- DataNode流量不均匀问题
- 线程数过多导致的 CPU 100% 问题
- NameNode上传文件请求在吞吐量和一致性之间的抉择
- 刷磁盘导致吞吐量大幅下降如何优化
## 项目配套学习视频
[https://space.bilibili.com/478364560/channel/seriesdetail?sid=453116](https://space.bilibili.com/478364560/channel/seriesdetail?sid=453116)
## 版权声明
本仓库存放的是儒猿【自研分布式小文件系统】,版权归儒猿技术窝所有,侵权将追究法律责任
## 官网
[www.ruyuan2020.com](www.ruyuan2020.com)
## 编译&运行
由于源码使用了protobuf作为序列化框架,所以下载代码之后需要执行以下命令,生成protobuf序列化文件
```
cd ruyuan-dfs/ruyuan-dfs-common
mvn protobuf:compile && mvn install
```
>
>
> 温馨提示:如果你的电脑是Apple M1芯片的,Protobuf编译可能会报错,这个问题可以通过配置指定使用x86架构解决,具体方式如下:
- 方式一:在ruyuan-dfs-common的pom.xml 中添加如下代码
```
osx-x86_64
```
- 方式二:全局配置Maven,不用修改代码,在你的Maven的settings.xml(通常在~/.m2/settings.xml)文件下添加如下代码
```
apple-silicon
osx-x86_64
default
apple-silicon
...你其他的profile
```
## 启动NameNode
打开配置NameNode的配置文件,在项目根目录下conf目录存在一个namenode.properties文件,打开此文件,修改以下内容:
```
base.dir=/srv/ruyuan-dfs/namenode # 修改为你本机的一个路径
```
启动类为ruyuan-dfs-namenode模块下的类:com.ruyuan.dfs.namenode.NameNode。我们可以运行他的main方法,
但是通常第一次运行是不成功的,会提示异常。
我们需要对启动程序进行一些配置,点击IDEA右上角运行按钮左边的下拉框。 选择 Edit Configurations...,在弹出框中,我们需要配置几个参数:

主要看下面两个红框,需要配置一个JVM参数-Dlogback.configurationFile=conf/logback-namenode.xml 用于指定Logback的配置文件,
接着添加一个Program arguments为 conf/namenode.properties 用于指定NameNode的配置文件,接着就可以运行起来了。
## 启动BackupNode
BackupNode机器已经和NameNode集成在同一个module中了,启动类为com.ruyuan.dfs.backup.BackupNode
同样的,BackupNode也需要修改配置文件和启动参数:

同样需要修改base.dir属性为你本机的一个路径,其他属性不变即可。启动参数配置如下:

## 启动DataNode
修改conf/datanode.properties文件中的base.dir参数值为你本机电脑的一个路径

>
>
> 另外需要注意的是,如果你要启动多个DataNode节点,需要改为配置文件的值,其中datanode.id需要改成不同的数值,每个节点不一样,
base.dir需要改为不同的文件夹, 避免文件存储冲突,datanode.http.server和datanode.transpot.server的端口都需要改成不同的,避免端口冲突,
主机名也需要换成不同的,不然会造成DataNode注册混乱。因为NameNode是通过hostname来标识一个DataNode节点的。可以通过配置hosts文件
```
127.0.0.1 datanode01
127.0.0.1 datanode02
127.0.0.1 datanode03
```
配置启动参数:

## 运行客户端单元测试
如果上面几个节点都启动了,则可以开始进行单元测试看看效果了,但是在进行单元测试之前,需要先创建一个用户。
运行以下命令创建用户:
```
curl -H "Content-Type: application/json" -X POST -d '{"username": "admin","secret": "admin"}' "http://localhost:8081/api/user"
```
### 运行单元测试
接着就可以运行单元测试,打开ruyuan-dfs-client模块的test文件夹,查看测试类: com.ruyuan.dfs.client .FileSystemTest,直接执行:

通过这个按钮则会将所有流程都测试一遍,包括上传文件、下载文件、创建文件夹等场景。