从零实现一个分布式文件系统:HDFS的核心设计
前言在分布式存储中HDFSHadoop Distributed File System是处理海量数据的基石设计用于大文件的存储和处理。今天我们从零实现HDFS的核心功能· 元数据管理NameNode· 数据存储DataNode· 文件分块Block· 副本管理Replication· 心跳机制Heartbeat· 数据块复制与均衡· 文件读写流程---一、HDFS核心原理1. 架构图┌─────────────────────────────────────────────────────────────┐│ Client │└─────────────────────────────────────────────────────────────┘│ │▼ ▼┌─────────────────────────────────────────────────────────────┐│ NameNode ││ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ││ │ 文件元数据 │ │ 块位置 │ │ 操作日志 │ ││ │ 命名空间 │ │ (缓存) │ │ (WAL) │ ││ └─────────────┘ └─────────────┘ └─────────────┘ │└─────────────────────────────────────────────────────────────┘│ │▼ ▼┌─────────────────────────────────────────────────────────────┐│ DataNode集群 ││ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ││ │ DataNode1 │ │ DataNode2 │ │ DataNode3 │ ││ │ Block A │ │ Block A │ │ Block B │ ││ │ Block B │ │ Block C │ │ Block C │ ││ └─────────────┘ └─────────────┘ └─────────────┘ │└─────────────────────────────────────────────────────────────┘2. 核心概念概念 说明NameNode 元数据管理节点单点DataNode 数据存储节点Block 数据块默认128MBReplication 副本数默认3Heartbeat 心跳DataNode→NameNode---二、完整代码实现1. 基础数据结构c#include stdio.h#include stdlib.h#include string.h#include unistd.h#include pthread.h#include time.h#include errno.h#include sys/stat.h#include fcntl.h#include dirent.h#define MAX_FILENAME 256#define MAX_BLOCK_ID 64#define MAX_DATANODES 10#define BLOCK_SIZE (64 * 1024 * 1024) // 64MB#define REPLICATION_FACTOR 3// 数据块typedef struct block {char block_id[MAX_BLOCK_ID];long long size;long long offset;struct block *next;} block_t;// 文件元数据typedef struct hdfs_file {char filename[MAX_FILENAME];block_t *blocks;int block_count;long long file_size;time_t create_time;time_t modify_time;struct hdfs_file *next;} hdfs_file_t;// DataNode信息typedef struct datanode {char node_id[64];char host[32];int port;long long disk_free;long long disk_total;int status; // 0: offline, 1: online, 2: busytime_t last_heartbeat;char blocks[1024][64]; // 存储的块ID列表int block_count;struct datanode *next;} datanode_t;// NameNodetypedef struct hdfs_namenode {hdfs_file_t *files;datanode_t *datanodes;char block_dir[256];int block_id_counter;pthread_mutex_t mutex;int running;int port;pthread_t heartbeat_thread;} hdfs_namenode_t;// DataNodetypedef struct hdfs_datanode {char node_id[64];char data_dir[256];int port;pthread_mutex_t mutex;int running;int port_listen;pthread_t heartbeat_thread;char *blocks;} hdfs_datanode_t;// HDFS客户端typedef struct hdfs_client {char namenode_host[32];int namenode_port;} hdfs_client_t;2. NameNode实现c// 创建NameNodehdfs_namenode_t *namenode_create(int port) {hdfs_namenode_t *nn malloc(sizeof(hdfs_namenode_t));memset(nn, 0, sizeof(hdfs_namenode_t));nn-port port;nn-running 1;nn-block_id_counter 0;pthread_mutex_init(nn-mutex, NULL);mkdir(./blocks, 0755);printf([NameNode] 启动端口: %d\n, port);return nn;}// 注册DataNodeint namenode_register_datanode(hdfs_namenode_t *nn, const char *node_id,const char *host, int port, long long disk_free) {pthread_mutex_lock(nn-mutex);datanode_t *dn nn-datanodes;while (dn) {if (strcmp(dn-node_id, node_id) 0) {dn-status 1;dn-last_heartbeat time(NULL);dn-disk_free disk_free;pthread_mutex_unlock(nn-mutex);return 0;}dn dn-next;}dn malloc(sizeof(datanode_t));strcpy(dn-node_id, node_id);strcpy(dn-host, host);dn-port port;dn-disk_free disk_free;dn-disk_total disk_free;dn-status 1;dn-last_heartbeat time(NULL);dn-block_count 0;dn-next nn-datanodes;nn-datanodes dn;pthread_mutex_unlock(nn-mutex);printf([NameNode] DataNode注册: %s (%s:%d)\n, node_id, host, port);return 0;}// 心跳更新void namenode_heartbeat(hdfs_namenode_t *nn, const char *node_id,long long disk_free, char **blocks, int block_count) {pthread_mutex_lock(nn-mutex);datanode_t *dn nn-datanodes;while (dn) {if (strcmp(dn-node_id, node_id) 0) {dn-last_heartbeat time(NULL);dn-disk_free disk_free;dn-block_count block_count;for (int i 0; i block_count i 1024; i) {strcpy(dn-blocks[i], blocks[i]);}break;}dn dn-next;}pthread_mutex_unlock(nn-mutex);}// 选择DataNode存储块按磁盘空间datanode_t *namenode_select_datanode(hdfs_namenode_t *nn) {pthread_mutex_lock(nn-mutex);datanode_t *selected NULL;long long max_free -1;datanode_t *dn nn-datanodes;while (dn) {if (dn-status 1 dn-disk_free max_free) {max_free dn-disk_free;selected dn;}dn dn-next;}pthread_mutex_unlock(nn-mutex);return selected;}// 分配块IDchar *namenode_allocate_block(hdfs_namenode_t *nn) {pthread_mutex_lock(nn-mutex);nn-block_id_counter;char *block_id malloc(64);snprintf(block_id, 64, blk_%d_%ld, nn-block_id_counter, time(NULL));pthread_mutex_unlock(nn-mutex);return block_id;}3. DataNode实现c// 创建DataNodehdfs_datanode_t *datanode_create(const char *node_id, const char *data_dir, int port) {hdfs_datanode_t *dn malloc(sizeof(hdfs_datanode_t));strcpy(dn-node_id, node_id);strcpy(dn-data_dir, data_dir);dn-port port;dn-port_listen port;dn-running 1;pthread_mutex_init(dn-mutex, NULL);mkdir(data_dir, 0755);printf([DataNode] %s 启动数据目录: %s\n, node_id, data_dir);return dn;}// 存储块int datanode_store_block(hdfs_datanode_t *dn, const char *block_id,const char *data, int data_len) {pthread_mutex_lock(dn-mutex);char filepath[512];snprintf(filepath, sizeof(filepath), %s/%s.dat, dn-data_dir, block_id);FILE *fp fopen(filepath, wb);if (!fp) {pthread_mutex_unlock(dn-mutex);return -1;}fwrite(data, 1, data_len, fp);fclose(fp);pthread_mutex_unlock(dn-mutex);return 0;}// 读取块int datanode_read_block(hdfs_datanode_t *dn, const char *block_id,char *data, int *data_len) {pthread_mutex_lock(dn-mutex);char filepath[512];snprintf(filepath, sizeof(filepath), %s/%s.dat, dn-data_dir, block_id);FILE *fp fopen(filepath, rb);if (!fp) {pthread_mutex_unlock(dn-mutex);return -1;}fseek(fp, 0, SEEK_END);*data_len ftell(fp);fseek(fp, 0, SEEK_SET);fread(data, 1, *data_len, fp);fclose(fp);pthread_mutex_unlock(dn-mutex);return 0;}4. 文件操作c// 创建文件int namenode_create_file(hdfs_namenode_t *nn, const char *filename) {pthread_mutex_lock(nn-mutex);hdfs_file_t *f nn-files;while (f) {if (strcmp(f-filename, filename) 0) {pthread_mutex_unlock(nn-mutex);return -1;}f f-next;}f malloc(sizeof(hdfs_file_t));strcpy(f-filename, filename);f-blocks NULL;f-block_count 0;f-file_size 0;f-create_time time(NULL);f-modify_time time(NULL);f-next nn-files;nn-files f;pthread_mutex_unlock(nn-mutex);printf([NameNode] 创建文件: %s\n, filename);return 0;}// 写入文件分块int hdfs_write(hdfs_namenode_t *nn, const char *filename, const char *data, int data_len) {// 创建文件if (namenode_create_file(nn, filename) 0) {printf(文件已存在: %s\n, filename);return -1;}// 分块写入int offset 0;int block_num 0;int remaining data_len;while (remaining 0) {int chunk_size remaining BLOCK_SIZE ? BLOCK_SIZE : remaining;// 分配块IDchar *block_id namenode_allocate_block(nn);// 选择DataNodedatanode_t *dn namenode_select_datanode(nn);if (!dn) {printf(没有可用的DataNode\n);return -1;}// 写入数据到DataNode模拟// 实际通过RPC传输printf([写入] 块 %s 写入到 %s (大小: %d)\n, block_id, dn-node_id, chunk_size);// 更新元数据pthread_mutex_lock(nn-mutex);hdfs_file_t *f nn-files;while (f) {if (strcmp(f-filename, filename) 0) {block_t *b malloc(sizeof(block_t));strcpy(b-block_id, block_id);b-size chunk_size;b-offset offset;b-next f-blocks;f-blocks b;f-block_count;f-file_size chunk_size;break;}f f-next;}pthread_mutex_unlock(nn-mutex);offset chunk_size;remaining - chunk_size;block_num;free(block_id);}printf([HDFS] 文件 %s 写入完成共 %d 个块\n, filename, block_num);return 0;}// 读取文件int hdfs_read(hdfs_namenode_t *nn, const char *filename, char *data, int *data_len) {pthread_mutex_lock(nn-mutex);hdfs_file_t *f nn-files;while (f) {if (strcmp(f-filename, filename) 0) break;f f-next;}if (!f) {pthread_mutex_unlock(nn-mutex);return -1;}// 读取所有块block_t *b f-blocks;int total_len 0;while (b) {// 查找块所在的DataNode模拟printf([读取] 读取块: %s (大小: %lld)\n, b-block_id, b-size);// 实际需要从DataNode读取数据total_len b-size;b b-next;}*data_len total_len;pthread_mutex_unlock(nn-mutex);return 0;}5. 测试代码cvoid test_hdfs() {printf( HDFS分布式文件系统测试 \n\n);// 创建NameNodehdfs_namenode_t *nn namenode_create(9000);// 创建DataNodehdfs_datanode_t *dn1 datanode_create(dn-1, ./dn1_data, 9001);hdfs_datanode_t *dn2 datanode_create(dn-2, ./dn2_data, 9002);hdfs_datanode_t *dn3 datanode_create(dn-3, ./dn3_data, 9003);// 注册DataNodenamenode_register_datanode(nn, dn-1, 127.0.0.1, 9001, 1024*1024*1024);namenode_register_datanode(nn, dn-2, 127.0.0.1, 9002, 1024*1024*1024);namenode_register_datanode(nn, dn-3, 127.0.0.1, 9003, 1024*1024*1024);// 写入文件char test_data[1024 * 1024]; // 1MB数据for (int i 0; i 1024*1024; i) {test_data[i] A (i % 26);}printf(写入文件 /user/test.txt (1MB)...\n);hdfs_write(nn, /user/test.txt, test_data, 1024*1024);// 读取文件printf(\n读取文件 /user/test.txt...\n);char read_data[1024*1024];int read_len;hdfs_read(nn, /user/test.txt, read_data, read_len);printf(读取到 %d 字节\n, read_len);// 文件列表printf(\n文件列表:\n);hdfs_file_t *f nn-files;while (f) {printf( %s (大小: %lld, 块数: %d)\n,f-filename, f-file_size, f-block_count);f f-next;}printf(\nDataNode状态:\n);datanode_t *dn nn-datanodes;while (dn) {printf( %s: 状态%d, 块数%d\n,dn-node_id, dn-status, dn-block_count);dn dn-next;}free(nn);free(dn1);free(dn2);free(dn3);}int main() {test_hdfs();return 0;}---三、编译和运行bashgcc -o hdfs hdfs.c -lpthread./hdfs---四、HDFS vs 本实现特性 本实现 HDFSNameNode ✅ ✅DataNode ✅ ✅块存储 ✅ 64MB ✅ 128MB副本管理 ❌ ✅ 默认3心跳机制 ✅ ✅块均衡 ❌ ✅高可用 ❌ ✅ (HA)纠删码 ❌ ✅---五、总结通过这篇文章你学会了· HDFS的核心架构NameNode DataNode· 文件分块与元数据管理· DataNode注册与心跳· 文件写入流程分块存储· 文件读取流程块聚合HDFS是分布式存储的经典实现。掌握它你就理解了海量数据存储系统的核心设计。下一篇预告《从零实现一个分布式计算MapReduce的核心设计》---评论区分享一下你对HDFS的理解

相关新闻

IT采购必备指南:有实力的知识库系统五大核心评判维度

IT采购必备指南:有实力的知识库系统五大核心评判维度

知识库系统实力评判的核心逻辑企业数智化转型进程中,知识库作为承载内部知识资产的核心载体,选型结果直接影响组织协作效率与数据安全。当前多数企业在知识库选型阶段缺乏统一评判标准,常陷入参数模糊、资质掺水、案例空泛的决策陷阱&#xf…

2026/10/2 12:41:03 阅读更多 →
LVS负载调度

LVS负载调度

一、LVS全称 Linux Virtual Server,四种模式,十三种算法二、什么是集群集群(Cluster)是指将多台独立的计算机(服务器)通过网络连接在一起,协同工作,对外表现为一个统一的系统。同一个…

2026/10/13 23:49:41 阅读更多 →
OpenClaw客户端分发教程,Windows 与 Mac 安装包获取

OpenClaw客户端分发教程,Windows 与 Mac 安装包获取

🦞教程适配:OpenClaw v2.7.9 | 适配 Windows10/11、macOS 双系统 核心亮点:提供全程可视化图形操作界面,自动补齐全套运行依赖,数据独立存储于本地设备,兼容多款主流大模型,并采用轻量化的 45.7…

2026/10/14 4:00:54 阅读更多 →

最新新闻

光子晶体光纤仿真降维实操:笔记本搞定模式干涉建模

光子晶体光纤仿真降维实操:笔记本搞定模式干涉建模

最近有个朋友跟我诉苦:他接手了一个光子晶体光纤传感器的项目,领导开口就问“你这个仿真要多大内存,是不是得租台服务器”,他按照常规三维时域软件一估算,发现模型随便就是几十亿网格,当场就自闭了。我跟他…

2026/10/15 7:41:00 阅读更多 →
Zotero本地增强方案:可视化+AI问答+全文翻译

Zotero本地增强方案:可视化+AI问答+全文翻译

1. 这不是“又一个Zotero插件”,而是一套可落地的学术工作流增强方案你有没有过这样的时刻:文献库攒了八百篇PDF,点开Zotero主界面却像面对一座没有索引的图书馆——知道里面有东西,但找不到入口;读到关键段落想查证原…

2026/10/15 7:41:00 阅读更多 →
一人公司的商业价值与运营策略解析

一人公司的商业价值与运营策略解析

1. 一人公司的产业定位解析在商业生态系统中,一人公司正以独特的组织形式填补着传统企业难以触及的市场缝隙。这种微型企业形态不同于自由职业者或个体工商户,其核心特征在于以公司法人身份运作,却保持极简的组织架构。我观察到近年来在软件开…

2026/10/15 7:41:00 阅读更多 →
考虑源荷不确定性的两阶段鲁棒机组调度:Yalmip+Gurobi实现

考虑源荷不确定性的两阶段鲁棒机组调度:Yalmip+Gurobi实现

1. 项目概述:源荷不确定性下的机组调度为何需要重做模型电力系统的机组调度问题,如果只在确定性场景下做,说实话已经不算难事了。常规的经济调度加机组启停约束,用线性规划或者混合整数线性规划就能收敛得很漂亮。真正让调度模型从…

2026/10/15 7:41:00 阅读更多 →
AI热点背后的认知校准:GPT-6、世界模型与术语通胀解析

AI热点背后的认知校准:GPT-6、世界模型与术语通胀解析

1. 标题背后的三重信号:一场被误读的“AI纪年”重构看到这个标题,我第一反应不是点开看内容,而是下意识翻了翻日历——2026年10月?再确认一遍手机系统时间:2024年9月。没错,这根本不是一份“新闻简报”&…

2026/10/15 7:41:00 阅读更多 →
2026年10月北京市联通宽带实测办理避坑全攻略

2026年10月北京市联通宽带实测办理避坑全攻略

上个月我翻了一下家里的宽带账单,一年算下来花了快两千块。很多人有个反常识的误区,觉得宽带资费越贵,网速就绝对越快。其实我拿着四家运营商的账单横向对比后发现,花双倍钱办的千兆宽带,实际体验甚至不如邻居办的五百…

2026/10/15 7:40:00 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →