简易分布式系统初步设计|青训营笔记

85 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的第5天

此篇笔记是对结营项目-简易分布式系统 所进行的初步设计。

技术选型

  1. 基础的调用方式 鉴于启动时必须通过命令行的方式来启动,所以应该至少保证一个终端命令的调用方式,对终端命令的配置采用库github.com/urfave/cli
  2. 通信协议 Client、NN、DN之间都需要通信,使用RPC协议进行各个节点之间的通信。RPC协议选用grpc和protobuf,这套协议使用方式比较简单,并且跨平台的支持也不错。一个简单的grpc使用教程
  3. 配置方式 通过yaml文件进行配置,并通过yaml的方式存储一些元数据等,基于gopkg.in/yaml.v3

整体结构

结合项目要求,整个项目将主要包含Client、Name Node、Data Node三个组件,这三个组件主要包含如下的交互关系:

graph TD
    nn[Name Node]
    c[Client]
    dn[Data Node]

    c <-- 元数据读写 --> nn
    dn <-- 存储节点维护 --> nn
    c <-- 数据读写 --> dn

读数据主要流程如下:

graph TD
    nn[Name Node]
    c[Client]
    dn[Data Node]

    c -- 1.读文件请求 --> nn
    nn -- 2.返回dn BlockId FileId --> c
    c -- 3.请求文件 --> dn
    dn -- 4.返回文件内容 --> c

写数据主要流程如下:

graph TD
    nn[Name Node]
    c[Client]
    dn1[Data Node 1]
    dn2[Data Node 2]
    dn3[Data Node 3]

    c -- 1.上传文件请求 --> nn
    nn -- 2.返回BlockId和DNList --> c
    c -- 3.发送数据 --> dn1
    dn1 -- 4.返回BlockId和FileId --> c
    dn1 -- 5.a.转发数据进行存储 --> dn2
    dn1 -- 5.a.转发数据进行存储 --> dn3
    dn2 -- 5.b.返回结果 --> dn1
    dn3 -- 5.b.返回结果 --> dn1
    dn1 -- 6.上报数据落盘 --> nn
    dn2 -- 6.上报数据落盘 --> nn
    dn3 -- 6.上报数据落盘 --> nn

主要RPC接口

Client To NameNode

  1. 文件操作接口(GET\PUT)
  2. 获取文件接口
  3. 创建文件接口
  4. 元数据操作接口
  5. 重命名元数据
  6. 获取文件元数据
  7. 获取目录元数据
  8. 传输完成

DataNode To NameNode

  1. 心跳(定时)
  2. Block Report(定时)
  3. 注册DataNode

NameNode To DataNode

  1. 请求DataNode进行Block Report(主动执行)

Client To DataNode

  1. 从块读数据
  2. 向块写数据

各模块主要功能及特性

Client

  1. 能够访问Name Node和Data Node
  2. 通过终端命令的方式调用各API
  3. 通过HTTP的方式或RPC的方式进行调用
API功能备注
Put存数据Overwrite、Not Found、Parent Not Found、一致性
Get读数据选择哪个读、遇到异常如何切换
Delete删数据删除结果是否有意义、删除成功如何定义
Stat获取文件信息参考Linux文件系统
Mkdir建目录
Rename重命名
Listls参考ls命令

Name Node

  1. 至少2个Name Node,Active和Standby
  2. Active挂掉Standby能顶上
  3. 元数据的存储
  4. Active和Standby之间的一致性:Raft协议

接口:

  1. 接收自Client的请求
    1. 读数据
    2. 写数据
    3. 目录操作
    4. 元信息
  2. 接收自Data Node的请求
    1. Data Node登录的请求
    2. Data Node数据落盘的结果
  3. 接收自Name Node的请求
    1. 元数据更新

Data Node

  1. 至少3个Name Node,1主2从
  2. DN之间的数据交换
  3. 单点故障问题
  4. 存储引擎的组织方式

接口

  1. 接收自Client的请求
    1. 读数据
    2. 写数据的内容
  2. 接收自Data Node的请求
    1. 写数据的内容
    2. 写数据完成的返回
  3. 接收自Name Node的请求
    1. 创建块
    2. 更新块

目录结构

├─client        客户端逻辑实现
│  └─service    客户端RPC服务提供
├─command       命令行解析
├─config        配置文件目录
│  └─items      配置信息实体类
├─datanode      DataNode实现逻辑
│  └─service    DataNode RPC服务
├─DirTree       存放NameNode目录树
│  ├─dir        存放目录信息
│  └─meta       存放meta信息
├─DNData        存放DataNode数据,目录下按照node名再细分目录
├─log
├─namenode      namenode实现逻辑
│  └─service    NameNode RPC服务
├─NNData        NameNode数据存放,按副本集分类
├─proto         rpc协议
├─utils         组件存放,如日志、配置等
└─values        项目所需常量及全局变量定义

调用方式

初步计划是采用命令行的方式启用

启动服务

在配置文件中填写需要的地址等配置信息后,使用配置文件启动datanode服务和namenode服务

./CrazyDFS nn --config ./config/namenode.1.yaml
./CrazyDFS dn --config ./config/datanode.1.yaml

Client操作

首先初始化Client操作环境

./CrazyDFS client --config ./config/client.yaml

然后进行相关api的操作

./CrazyDFS client get /a/b/c.txt ./c.txt
./CrazyDFS client put ./c.txt /a/b/c.txt
./CrazyDFS client rm /a/b/c.txt
./CrazyDFS client ls /a/b