v1.3.1 基于http协议的分布式文件系统。

1. 特性

curl命令上传 浏览器上传 断点续传(tus) 秒传
http下载 断点下载
小文件自动合并(减小incode占用)
配置自动生成 google认证码 自定义认证
自监控告警 跨域访问 一键迁移 并行体验
类fastdfs
多机自动同步 集群文件信息查看
高性能(使用leveldb作为kv库)
高可靠(设计极其简单,使用成熟组件)
无中心设计(所有节点都可以同时读写)
docker部署

2. 优点

无依赖(单一文件)
自动同步 失败自动修复
按天分目录
自动去重
目录自定义 保留原文件名 自动生成唯一文件名
token下载(token=md5(file_md5+timestamp))
单一角色(无Tracker Server,Storage Server,Client)
集群监控邮件告警
节点对等 节点同时读写

3. Tus

轻量级断点续传协议,服务端是用go编写,客户端也支持JavaScript、Andorid、Java、IOS,客户端在创建链接的时候上传必要的参数,服务端根据客户端传的参数寻找对应的文件,并返回上次上传的位置给客户端。客户端根据服务的返回的偏移量再进行上传。
go-fastdfs - 图1
Tus使用了文件名和大小作为文件的唯一性。如果文件名相同,文件大小也相同,那么服务端就认为是同一个文件。

4. LevelDB

LevelDB是Google的Jeff Dean和Sanjay Ghemawat设计开发的key-value存储引擎。LevelDB底层存储利用了LSM tree的思想,RocksDB是Facebook基于LevelDB开发的存储引擎,针对LevelDB做了很多优化,但是大部分模块的实现机制是一样的。
LevelDB是一个持久化存储的KV系统,和Redis这种内存型的KV系统不同,LevelDB不会像Redis一样狂吃内存,而是将大部分数据存储到磁盘上。LevleDB在存储数据时,是根据记录的key值有序存储的,就是说相邻的key值在存储文件中是依次顺序存储的,而应用可以自定义key大小比较函数,LevleDB会按照用户定义的比较函数依序存储这些记录。
LevelDB的操作接口简单,满足基本增删改查操作。另外,LevelDB支持数据快照(snapshot)功能,使得读取操作不受写操作影响,可以在读操作过程中始终看到一致的数据。LevelDB还支持数据压缩等操作,这对于减小存储空间以及增快IO效率都有直接的帮助。

4.1. Memtable

DB数据在内存中的存储方式,写操作会先写入memtable,memtable有最大限制(write_buffer_size)。LevelDB/RocksDB的memtable的默认实现是skiplist。当memtable的size达到阈值,会变成只读的memtable(immutable memtable)。后台compaction线程负责把immutable memtable dump成sstable文件。RocksDB增加了column family的概念,不同的column family不共享memtable,其他memtable机制与LevelDB一样。

4.2. sstable

DB数据持久化文件,内部key是有序的,文件内部前面是数据,后面是索引元数据。sstable文件之间逻辑上是分层的,LevelDB最大支持7层。

4.3. SequenceNumber

LevelDB中每次写操作(put/delete)都有一个版本,由sequence number来标识,整个DB有一个全局值保存当前使用的SequenceNumber,key的排序以及snapshot都要依赖它。

4.4. Version

将每次compact后的最新数据状态定义为一个version,也就是当前DB的元信息以及每层level的sstable的集合。跟version有关的一个数据结构是VersionEdit,记录了一次version的变化,包括删除了哪些sstable,新增了哪些sstable。old version + versionedit= new version。整个DB存在的所有version被VersionSet数据结构保存,这个数据结构包含:全局sequencenumber、filenumber、tablecache、每个level中下一次compact要选取的start_key。

4.5. FileNumber

DB创建文件时将FileNumber加上特定的后缀作为文件名,FileNumber在内部是一个uint64_t类型,并且全局递增。不同类型的文件的拓展名不同,例如sstable文件是.sst,wal日志文件是.log。LevelDB文件类型:

  1. enum FileType {
  2. kLogFile,
  3. kDBLockFile,
  4. kTableFile,
  5. kDescriptorFile,
  6. kCurrentFile,
  7. kTempFile,
  8. kInfoLogFile // Either the current one, or an old one
  9. };

4.6. Key

LevelDB对于用户输入的key做了不同的处理,user_key表示用户输入的key,internal_key是DB内部使用的key,在uers_key的基础上添加了sequencenumber和valuetype。

4.7. compact

DB有一个后台线程负责将memtable持久化成sstable,以及均衡整个DB各个level层的sstable。compact分为minor compaction和major compaction。memtable持久化成sstable称为minor compaction,level(n)和level(n+1)之间某些sstable的merge称为major compaction。
截屏2021-06-21 15.15.58.png
LevelDB的架构图,黄线上面是内存组件,黄线下面是磁盘组件。内存组件包括memtable、immutable memtable、log,磁盘组件包括:CURRENT文件、MANIFEST文件、.log文件、LOG文件、LOCK锁文件。
操作接口Put是写数据的接口,数据先写入log文件,然后写入memtable,如果memtable大小超过了设定的阈值,则memtable转成immutable memtable,immutable memtable只能读不能写。Immutable memtable会compact到磁盘上形成sstable文件。操作接口Get是读数据的接口。
读数据的顺序是:1.memtable 2.immutable memtable 3.sst file。
sstable文件是用户数据在磁盘上持久化存储的文件,逻辑上按层存储,内部按key排序,除了L0层外,其他层sstabel文件的key之间没有重叠。LevelDB支持多版本,MANIFEST文件记录了版本变化的信息,随着sstable文件增多,MANIFEST文件也是会增多的,所以CURRENT文件指向当前的MANIFEST文件。除了immutable memtable会compact成sstable文件,磁盘上相邻层之间也会发生compaction操作。

4.8. WAL

Write-ahead Log 现在关系型数据库几乎都提供了WAL机制,WAL机制即先写日志数据,后写用户数据,这样保证了用户数据持久化。在数据库意外宕机时,可以利用WAL恢复到宕机前的状态。LevelDB的日志格式:
截屏2021-06-21 15.21.20.png
Log相关的代码:

  1. db/log_format.h
  2. db/log_reader.h
  3. db/http://log_reader.cc
  4. db/log_writer.h
  5. db/http://log_writer.cc

value有可能太大,因此无法存放在一个block,会跨block存储,因此leveldb提供了RecordType枚举类型。
payload的格式:
截屏2021-06-21 15.24.28.png
LevelDB的删除操作是标记删除,并没有真正删除原来的数据,真正的删除操作通过compaction删除,为了区分写入的数据类型,LevelDB定义了ValueType枚举类型:

enum ValueType {
  kTypeDeletion = 0x0,
  kTypeValue = 0x1
}