一 前言

  本篇博客是JDFS系列博客的第四篇,从最初简单的上传、下载,到后来加入分布式功能,背后经历了大量的调试,尤其当实验的虚拟计算结点数目增加后,一些潜在的隐藏很深的bug就陆续爆发。在此之前笔者并没有网络编程的经验,大约半年之前读到unix环境高级编程的socket章节,然后就突然对网络编程产生了兴趣,于是后来就想着写一款http远程下载小工具(是笔者另外一篇博客,链接请点击我)。再到后来,由于笔者之前读研期间接触过map-reduce,知道HDFS这个东西,于是突发奇想,不如自己动手写一款类似于HDFS的小巧的分布式文件管理系统,这便是JDFS诞生的来历。笔者开发JDFS的目的,其一是想体验、巩固一下网络编程的知识;其二是想培养实现一个功能上较为完善有一定复杂性的系统;其三也许将来笔者会着手写一个小巧的map-reduce引擎,引擎就可以使用JDFS作为中间计算结果的存储。

  上一篇博客主要介绍了客户端如何把本地文件分片后流式、冗余地存储到虚拟集群里的结点里,本篇将会接着上一篇博客介绍如下几个话题:客户端向name node查询文件的元信息,并且显示在终端界面上;客户端查询完文件元信息后,向不同的data node请求下载原始文件的不同分片到本地,并且在本地合并所有分片,恢复原始文件的面貌;客户端向name node请求删除虚拟集群里面的某个文件。在前三篇博客提到的一些点,本文不会再重复赘述,因此如果读者朋友是第一次阅读本文,笔者建议最好先阅读前三篇博客,链接在下面。

  • JDFS:一款分布式文件管理实用程序第一篇(线程池、epoll、上传、下载)  点击我
  • JDFS:一款分布式文件管理实用程序第二篇(更新升级、解决一些bug)       点击我
  • JDFS:一款分布式文件管理系统,第三篇(流式云存储)                               点击我

代码已经更新到github上面,请点击我

  PS: 本篇博客是博客园用户“cs小学生”的原创作品,转载请注明原作者和原文链接,谢谢。

二   实验结果展示

  按照管理,先展示几张实验过程的截图

                                 

  如上图所示,左边是命令行,fileinfo.sh 是向name node查询文件元信息并显示出来,从图上可以看出,CRLS-en.pdf由5个block组成,每一个block分别被冗余地存储在data node 1,3,4上面(目前代码实现的时候简单地把每一个block存储于相同的几个结点上,后续会专门实现一个为每一个block挑选结点的函数)。接着./fetchfile.sh 是把存储在虚拟集群结点上的CRLS-en.pdf的各个block下载到本地并合并还原,还原后的截图如右边那种图显示。双击打开CRLS-en.pdf的截图如下:

三 获取并显示文件元信息

  在上一篇博客里,我们说过,文件的正文存储在data node上面,而描述文件元信息的文件存储在name node上。在JDFS的设计里,name node对每个将要存储到虚拟集群里的文件会在name node端创建一个同名的文件,文件里存储对应的元信息,按照存储的顺序包括如下信息:

  • 文件名。元信息文件的开头100个字节用来存储文件的名字
  • 文件的状态。一个int型的数据,值如果是0表示该文件还没有存储成功,1表示文件已经存储成功,2表示文件等待被删除(每一个data node删除自己的block后,name node才能最后删除元信息文件)
  • block数目。一个int型的数据,表示该文件由多少个block组成,比如在本文的实验中,CRLS-en.pdf由5个block组成
  • 每一个block的信息,加入block的数目是N,name接下来会有连续的N*max_num_of_nodes*sizeof(int)的存储空,其中max_num_of_nodes表示数据结点的最大数目,假设block 2 打算存储在第m个数据结点上,那么初始情况下(2-1)*max_num_of_nodes*sizeof(int)+(m-1)处的初始值应当被name node设置为1,表示期待存储在该结点上,如果后续data node成功接收到block 2后会告诉name node,然后name node会把该位置的值从1更新为2表示已经ok了。对于其他空闲的结点就初始化为0,表示block2不会存储在该node上。

 那么现在客户端想在终端上显示文件的元信息,就必须首先向name node请求上述的文件元信息,获取后解析出来,然后打印在终端上面,客户端实现了下面两个函数来支持该功能:

 int JDFS_cloud_query_file(char *file_name, JDFS_file_info *jfi,int flag);//flag, 0: query for reading ,1 :query for deleting
int JDFS_cloud_display_file_info(char *file_name);

  函数JDFS_cloud_query_file()便是用来具体向name node请求文件元信息用的,该函数还可以被删除功能调用,因此需要加一个参数flag来区分,不同的flag, name node做的事情不同。JDFS_cloud_display_file_info()调用前者来获取文件元信息,然后解析打印之,具体的代码逻辑也比较直接,请参考前言里给出的github代码链接。

  对应的name node端响应这个请求的函数如下,对应的http request_kind是13

 void *Http_server_callback_query_file_meta_info(void *arg);

四  从虚拟结点里下载文件到本地 

  截止到目前我们已经实现了把文件存储到虚拟集群里的结点上,也实现了查询特定文件元信息的功能,现在我们需要把文件下载到本地。

  想象一下,我们要把“云端”的数据下载到本地要经历哪些过程呢?首先客户端需要向name node查询元信息,元信息里包含了文件的block数目N,对于每个block客户端从元信息里解析出它冗余地存储在哪些结点里,然后挑选一个最优的结点将之下载到本地。在实际的场景中,挑选结点是有讲究的,如果同一个机柜里的结点有这个block,就从这个机柜里下载,否则需要从其他机柜里的某个结点下载。但是在JDFS中暂时把这个挑选的功能简化为直接指定某个结点,未来会细化这一块,目的是使得现在面临的问题不至于太复杂。文件元信息里面存储了包含这个block的结点串号,光是有串号还不行,客户端需要用这个串号向name node查询对应的ip地址和端口号(目前JDFS中简单地设置端口为8888),于是对于每一个block我就得到了<block num, ip, port>这组信息,有了这些信息我们就可以向对应的结点请求传送该block了,所有block传输到客户端后,客户端需要把这N个block合并成一个整体。

  在客户端我们实现了下面几个函数来支持该功能:

 int JDFS_cloud_query_file(char *file_name, JDFS_file_info *jfi,int flag);//flag, 0: query for reading ,1 :query for deleting
int JDFS_cloud_query_ip_from_node_serial(int serial_num, char *ip_str);
int JDFS_cloud_fetch_file(char *file_name);
int JDFS_cloud_merge_file(char *file_name, int num_of_blocks);

  如上述代码所示,JDFS_cloud_fetch_file()是该功能的入口,它先调用JDFS_cloud_query_file()来查询文件元信息,解析出存储该block的结点串号serial_num后调用JDFS_cloud_query_ip_from_node_serial()来查询它的ip地址,得到ip地址后紧接着调用JDFS_http_download()从data node上面下载该block,都下载完后调用JDFS_cloud_merge_file()合并block成为一个文件。

  name node端响应客户端查询文件元信息的过程请参见上一小节,此处不再赘述。

data node端响应客户端下载请求的逻辑在之前的博客里也详细介绍过,此处也不再赘述,感兴趣的读者可以翻看笔者之前写的博客。

五 从虚拟集群里删除文件

  最后我们还需要实现删除文件的功能。想象一下,一个文件被切分成了N份,N份文件正文被冗余地存储在不同的结点上面,我们需要通知所有存储有该文件block的数据结点去删除之,另外文件的元信息也需要删除。具体的流程是客户端向name node查询文件元信息,并通知它该文件要删除了,name node server不仅要把文件元信息发送给客户端,还有把文件元信息里的“文件状态”值改为2,表示等待被删除,以防止其他客户端来读它。客户端得到文件元信息后就会通知各个data node删除相应的数据。等隶属于该文件的所有冗余block都被删除后,客户端再一次请求name node server删除该文件的元信息文件,于是删除动作完成了。

  在客户端我们实现了如下几个函数来支持该功能:

 int JDFS_cloud_delete_file(char *file_name);
int JDFS_cloud_delete_file_internal(char *file_name, char *ip_str, int port);
int JDFS_cloud_delete_meta_file(char *file_name, char *ip_str, int port); int JDFS_cloud_query_file(char *file_name, JDFS_file_info *jfi,int flag);//flag, 0: query for reading ,1 :query for deleting
int JDFS_cloud_query_ip_from_node_serial(int serial_num, char *ip_str);

  JDFS_cloud_delete_file()是该功能的入口点函数,它会首先调用第5,6行的函数来获得文件元信息、以及结点ip地址,然后对于文件的每一个block,查询所有存储有该block的data node,向该data node server发送删除请求,具体是通过调用JDFS_cloud_delete_file_internal()来做的,等所有的都删除完毕后,再调用JDFS_cloud_delete_meta_file()向name node server发送删除元信息文件的请求。

  对于data node端,实现了一下几个函数来支持该功能

 void *Http_server_callback_delete_file(void *arg);

  对于name node server实现了如下函数来支持该功能:

 void *Http_server_callback_delete_meta_file(void *arg);

六 结束语

  到此为止,JDFS的全部功能已经介绍完毕,当前还剩下两件事情要做,其一是继续调试JDFS隐藏很深的潜在bug,使得系统能够稳定的运行,稳定运行之后,需要把data node server和name node server做成守护进程,这样server启动后就不会因为用户关闭终端而终止了,也不会因为用户按下Crtl+C等而终止,诸如此类,关于守护进程请参见《Unix环境高级编程》;其二,在下一篇博客笔者会配以流程图、结构图的方式从总体上勾画出JDFS的架构,工作流程等,还会详细介绍如何在虚拟集群里把JDFS跑起来,也有读者反应能否简化安装,一键部署等,等JDFS稳定运行后,我在来研究一下简化安装,一键部署的问题。

  另外因为笔者研究生期间曾接触过一个单机多核平台的map-reduce系统,因此萌生了自己动手写一个模仿hdoop的小巧的map-reduce引擎的想法,如果未来真去做的话,正好可以用JDFS来作为中间结果的存储管理系统。

  联系方式:https://github.com/junhuster/

JDFS:一款分布式文件管理系统,第四篇(流式云存储续篇)的更多相关文章

  1. JDFS:一款分布式文件管理系统,第五篇(整体架构描述)

    一 前言 截止到目前为止,虽然并不完美,但是JDFS已经初步具备了完整的分布式文件管理功能了,包括:文件的冗余存储.文件元信息的查询.文件的下载.文件的删除等.本文将对JDFS做一个总体的介绍,主要是 ...

  2. JDFS:一款分布式文件管理系统,第三篇(流式云存储)

    一 前言 看了一下,距离上一篇博客的发表已经过去了4个月,时间过得好快啊.本篇博客是JDFS系列的第三篇博客,JDFS的目的是为了实现一个分布式的文件管理系统,前两篇实现了基本的上传.下载功能,但是那 ...

  3. 手把手教你用 FastDFS 构建分布式文件管理系统

    说起分布式文件管理系统,大家可能很容易想到 HDFS.GFS 等系统,前者是 Hadoop 的一部分,后者则是 Google 提供的分布式文件管理系统.除了这些之外,国内淘宝和腾讯也有自己的分布式文件 ...

  4. JDFS:一款分布式文件管理实用程序第二篇(更新升级、解决一些bug)

    一 前言 本文是<JDFS:一款分布式文件管理实用程序>系列博客的第二篇,在上一篇博客中,笔者向读者展示了JDFS的核心功能部分,包括:服务端与客户端部分的上传.下载功能的实现,epoll ...

  5. Hadoop HDFS概念学习系列之分布式文件管理系统(二十五)

    数据量越来越多,在一个操作系统管辖的范围存在不了,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,因此迫切需要一种系统来 管理多台机器上的文件,这就是分布式文件管理系统. 是一种允许文件 ...

  6. 分布式文件管理系统HDFS

    Hadoop 分布式文件管理系统HDFS可以部署在廉价硬件之上,能够高容错. 可靠地存储海量数据(可以达到TB甚至PB级),它还可以和Yam中的MapReduce 编程模型很好地结合,为应用程序提供高 ...

  7. 20190827 On Java8 第十四章 流式编程

    第十四章 流式编程 流的一个核心好处是,它使得程序更加短小并且更易理解.当 Lambda 表达式和方法引用(method references)和流一起使用的时候会让人感觉自成一体.流使得 Java ...

  8. JDFS:一款分布式文件管理实用程序第一篇(线程池、epoll、上传、下载)

    一 前言 截止目前,笔者在博客园上面已经发表了3篇关于网络下载的文章,这三篇博客实现了基于socket的http多线程远程断点下载实用程序.笔者打算在此基础上开发出一款分布式文件管理实用程序,截止目前 ...

  9. 分布式文件管理系统_FastDFS集群

    简单介绍 1,client storage tracker的关系 先用一幅图来解释用户如何访问一个通过DFS管理的文件 一般来说,一台服务器只有一个storage server,多个storage s ...

随机推荐

  1. Python | 多种编码文件(中文)乱码问题解决

    问题线索   1 可以知道的是,文本文件的默认编码并不是utf8. 我们打开一个文本文件,并点击另存为 2 我们在新窗口的编码一栏看到默认编码是ANSI.先不管这个编码是什么编码,但是通过下拉列表我们 ...

  2. hr用法

    定义和用法 <hr> 标签在 HTML 页面中创建一条水平线. 水平分隔线(horizontal rule)可以在视觉上将文档分隔成各个部分. HTML 与 XHTML 之间的差异 在 H ...

  3. c89和c99中/运算符和%运算符为负数时的区别

    运算式 -8 / 5 = -1.6,在C89中取值为 -1 或 -2,C99的出现,CPU对除法的结果向零取整,上述运算式结果为 -1. 在C89和C99中都要确保 (a / b) * b + a % ...

  4. 【Java并发编程】之六:Runnable和Thread实现多线程的区别(含代码)

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17161237 Java中实现多线程有两种方法:继承Thread类.实现Runnable接口 ...

  5. 【Alpha阶段】第一次Scrum Meeting!

    每日任务 1.本次会议为第一次 Meeting会议: 2.本次会议在中午12:30,在第五社区5号楼楼下,召开本次会议为30分钟讨论接下来的任务: 一.今日站立式会议照片 二.每个人的工作 (有wor ...

  6. 201521123059 《Java程序设计》第五周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 1.2 可选:使用常规方法总结其他上课内容. 1.Comparable与Arrays.sort,其功能是对指定对象数组按升序进 ...

  7. 201521123079《java程序设计》第5周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 2. 书面作业 1.代码阅读:Child压缩包内源代码 1.1 com.parent包中Child.java文件能否编译通过? ...

  8. 201521123029《java程序设计》第2周学习总结

    1. 本周学习总结 (1)完成了课后习题,对所学知识进一步巩固. (2)学会了JAVA中的选择结构,循环结构,其中条件必须为布尔表达式,与C++非0即真不同. (3)学会java中的break和con ...

  9. 201521123039 《java程序设计》第十周学习总结

    1. 本周学习总结 2. 书面作业 本次PTA作业题集异常.多线程 finally 题目4-2 1.1 截图你的提交结果(出现学号) 1.2 4-2中finally中捕获异常需要注意什么? 总结:需要 ...

  10. java第十周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 2. 书面作业 1.finally 题目4-2 1.1 截图你的提交结果(出现学号) 1.2 4-2中fin ...