fastdfs是一个针对互联网应用设计的分布式文件系统。具有架构简单。结构清晰。代码量小等特点。
详细的介绍及架构请參考分布式文件系统FastDFS架构剖析http://www.programmer.com.cn/4380/)。这篇文章是由fastdfs的作者撰写。

由于fastdfs的轻量级特点,所以也适合广大技术爱好者学习分布式文件系统的设计及实现技术。通过深入代码,了解内部细节。本文的fastdfs版本号为5.01。


服务交互场景
fastdfs採用了传统的C/S模型,服务分为client和server,之间採用私有协议通信。

系统的几种交互场景:

1)client ---->> track server
2)client ---->> storage server
3)storage server ---->> track server
4)storage server ---->> storage server

当中1)和2)是client(fastdfs的用户)使用fastdfs的情况,client先依据track server得到storage server地址。然后再storage server上做操作(如上传、下载文件等)。

由client发起操作。

3)是storage server向track server报告信息。由storage server主动发起。
4)storage server向同组内的其它storage server同步操作信息。同步的实现是系统中比較复杂的一块。


依据上面的交互图,storage server包含3部分功能:
1)接收并处理请求,来自client和storage,service threads
2)将自己的状态信息报告tracker server, report threads.
3)同步本地数据到同组内的其它storage server, sync threads

任务1)的启动及执行
主体实现代码。storage_service.c
依据配置文件里的定义。启动对应的service threads。线程入口storage_thread_entrance
storage_deal_task:解析协议,进行对应处理。


任务2)的启动与执行
主体实现代码,tracker_client_thread.c
针对每一个tracker创建一个线程(report线程),线程入口:tracker_report_thread_entrance。该任务启动过程中,storage的状态会经历一系列变化:


storage_server的状态转换图

这些状态是trackerserver上记录的对应的storage的状态,tracker依据storage的状态来决定其是否可用。
ACTIVE是终于状态,表示storage server能够提供服务;其余是中间状态。

INIT
storage server启动后,发送TRACKER_PROTO_CMD_STORAGE_JOIN到tracker,tracker将storage状态设置为FDFS_STORAGE_STATUS_INIT。

在tracker_report_join中实现。


推断是否须要同步
同步:是否须要同组的其它storage server向自己同步文件。对于组中的第一个storage server,不须要从其它storage同步,由于仅仅有一个storage;对于其它的storage server。依据g_sync_old_done推断,g_sync_old_done是全局变量。默认是false。storage第一次上线后。g_sync_old_done是false,所以会有其它storage server对自己进行同步,用来同步的源storage
server有tracker进行选择,同步完毕后g_sync_old_done设置为true,并被保存到文件系统中(storage_write_to_sync_ini_file)。第一次上线后的再次上线(比如系统关机维护后的又一次启动),g_sync_old_done是true,就不会从源服务器同步数据。

再次上线和第一次上线的差别是,再次上线的storage会有状态文件保存在本地,storage启动,会拿到这些持久化数据。


转换02,WAIT_SYNC
第一次上线的storage会经过该步骤,将状态变为FDFS_STORAGE_STATUS_WAIT_SYNC。发送TRACKER_PROTO_CMD_STORAGE_SYNC_DEST_REQ到tracker(tracker_sync_dest_req),假设tracker也决定该storage server须要从源storage进行同步,会返回源storageIP和时间戳:g_sync_src_id和g_sync_until_timestamp。

tracker端会将该storage状态设置为FDFS_STORAGE_STATUS_WAIT_SYNC。


转换03,SYNCING

该转换由源storage server的同步线程进行,任务3中实现。将storage状态改为FDFS_STORAGE_STATUS_SYNCING;


转换04。OFFLINE
源storage server完毕对该storage的同步后。将其状态改为OFFLINE,任务3中实现。storage的状态变为FDFS_STORAGE_STATUS_OFFLINE;


转换05。ACTIVE
该转换由tracker server完毕。storage向tracker发送heart beat(tracker_heart_beat),tracker收到storage的heart beat后,假设storage的状态是OFFLINE,就将其改动成ACTIVE。pTargetServer->status = FDFS_STORAGE_STATUS_ACTIVE;

转换06,ONLINE
假设不须要从其它storage进行同步(g_sync_old_done == true),调用tracker_sync_notify,发送TRACKER_PROTO_CMD_STORAGE_SYNC_NOTIFY到tracker。tracker将storage状态变为online,FDFS_STORAGE_STATUS_ONLINE。

转换07。ACTIVE
该转换由tracker server完毕。storage向tracker发送heart beat(tracker_heart_beat),tracker收到storage的heart beat后,假设storage的状态是ONLINE。就将其改动成ACTIVE。pTargetServer->status = FDFS_STORAGE_STATUS_ACTIVE;

storage状态变成ACTIVE,能够对外提供服务。

状态转换涉及3个角色。一个是trackerserver,一个是源storageserver的同步线程。一个是storage的report线程。


进入active状态后。report线程进入主循环运行以下几个任务:
  tracker_heart_beat
  tracker_report_sync_timestamp
  tracker_report_df_stat

任务3)的启动与执行
主体代码,storage_sync.c

针对本组中的每一个storage server创建一个线程(sync线程,同步线程)。线程入口:storage_sync_thread_entrance。storage server列表由tracker提供。在tracker_report_join中返回。任务3的主循环就是读取binlog,然后将binlog记录的内容。同步到组内的其它storage上去。


sync线程将自己本地保存的数据(源数据而不是副本)同步给本组的其它storage:
有两种同步模式:
1)正常同步
指同步本地的源数据。代码逻辑是读binlog记录,然后依据记录运行同步操作:
storage_sync_data(&reader, &storage_server, &record))

2)追加同步
同步本地的源数据和副本数据。

该模式就是上述状态转换中须要同步的情况,运行转换03和04。

sync线程会依据被同步的storage和tracker分配给他的源storage,来决定是否由自己对storage进行同步。


转换03代码
  if (pStorage->status == FDFS_STORAGE_STATUS_WAIT_SYNC)
  {
   pStorage->status = FDFS_STORAGE_STATUS_SYNCING;
   storage_report_storage_status(pStorage->id, \
    pStorage->ip_addr, pStorage->status);
  }
推断是否须要同步副本代码:
STARAGE_CHECK_IF_NEED_SYNC_OLD(pReader, pRecord)
仅仅有针对副本(REPLICA)数据,才须要推断是否须要同步给其它storage。

转换04代码
当binlog中没有数据后(read_result == ENOENT),改动storage状态
    if (pStorage->status == \
     FDFS_STORAGE_STATUS_SYNCING)
    {
     pStorage->status = \
      FDFS_STORAGE_STATUS_OFFLINE;
     storage_report_storage_status( \
      pStorage->id, \
      pStorage->ip_addr, \
      pStorage->status);
    }
    }

binlog文件

任务1中的service线程会把对本地的文件改动(upload, delete,改动metadata等)记录在binlog文件里。


binglog格式:

文件改动时间戳
文件操作类型
  STORAGE_OP_TYPE_SOURCE_CREATE_FILE
  STORAGE_OP_TYPE_SOURCE_APPEND_FILE
  。

。。

定义在storage_sync.h

文件名称字

storage_binlog_write:写记录


binlog缓存
binglog的读写通过buffer进行。buffer SYNC_BINLOG_WRITE_BUFF_SIZE。到超过buffer容量,写入磁盘。


binlog文件大小
每一个binglog的大小是SYNC_BINLOG_FILE_MAX_SIZE,超过这个值,会创建新的binlog文件。


binlog文件名称的最后由binlog_index确定。binlog_index从0開始递增。binlog_index是全局变量。会被持久化保存到index文件里。
#define SYNC_BINLOG_INDEX_FILENAME SYNC_BINLOG_FILE_PREFIX".index"
每次又一次启动时,会依据这个index文件取到binlog_index。然后定位到须要对应的binlog文件。

binlog文件会持续添加。


static char *get_writable_binlog_filename1(char *full_filename, \
  const int binlog_index)
{
 snprintf(full_filename, MAX_PATH_SIZE, \
   "%s/data/"SYNC_DIR_NAME"/"SYNC_BINLOG_FILE_PREFIX"" \
   SYNC_BINLOG_FILE_EXT_FMT, \
   g_fdfs_base_path, binlog_index);
 return full_filename;
}


怎样使用binlog进行同步
sync线程会真对每一个storage。将本地binlog文件里的内容所有应用到对应的storage中。

针对每一个storage,synn线程会保存一份mark文件。get_mark_filename_by_reader
mark文件后缀名:#define SYNC_MARK_FILE_EXT ".mark"
mark文件里会保存上次同步到的状态(storage_write_to_mark_file):
  MARK_ITEM_BINLOG_FILE_INDEX, pReader->binlog_index, \
  MARK_ITEM_BINLOG_FILE_OFFSET, pReader->binlog_offset, \
  MARK_ITEM_NEED_SYNC_OLD, pReader->need_sync_old, \
  MARK_ITEM_SYNC_OLD_DONE, pReader->sync_old_done, \
  MARK_ITEM_UNTIL_TIMESTAMP, (int)pReader->until_timestamp, \
  MARK_ITEM_SCAN_ROW_COUNT, pReader->scan_row_count, \
  MARK_ITEM_SYNC_ROW_COUNT, pReader->sync_row_count);

后面sync thread又一次启动后,能够依据上次记录的位置。继续開始同步。


storage_reader_init
用来读取该mark文件(第一次上线的系统,没有该文件),载入上次同步状态。

其它状态文件
storage中还有另外2个保存持久化状态的文件
#define DATA_DIR_INITED_FILENAME ".data_init_flag"
#define STORAGE_STAT_FILENAME "storage_stat.dat"
每次启动时,都会从这些文件载入信息,已恢复上次的执行状态。


STORAGE_STAT_FILENAME用来记录本storage的同步信息,如是否须要从其它源storage进行同步等。通过storage_write_to_sync_ini_file写入。

DATA_DIR_INITED_FILENAME用来保存storage上的文件状态信息,如上传文件数等。通过storage_write_to_stat_file写入。

last_sync_update用来记录storage上次被同步到的时间,这个字段在tracker选择download storageserver的时候非常重要。


fastdfs storage server的设计与实现的更多相关文章

  1. 配置nginx为FastDFS的storage server提供http访问接口

    1.拉取模块代码 # git clone https://github.com/happyfish100/fastdfs-nginx-module.git 2.编译安装nginx,添加支持fastdf ...

  2. fastdfs之同一台storage server下包含多个store path

    一,查看本地centos的版本 [root@localhost lib]# cat /etc/redhat-release CentOS Linux release 8.1.1911 (Core) 说 ...

  3. WSS存储服务器(Windows Storage Server) 2012新功能解析

    虽然最近一段时间有关微软的新闻大多数集中在Windows 8以及Surface平板设备身上,但数周之前Windows Server 2012新版本中所包含的Windows Storage Server ...

  4. Vmware ESX5i 环境下部署Windows Storage Server 2008 R2

    ESX5i 环境下部署Windows Storage Server 2008 R2       Windows Storage Server 2008 这款产品微软早已发布,WSS2008是基于Win ...

  5. 【学习记录】第一章 数据库设计-《SQL Server数据库设计和开发基础篇视频课程》

    一.课程笔记 1.1  软件开发周期 (1)需求分析阶段 分析客户的业务和数据处理需求. (2)概要设计阶段 设计数据库的E-R模型图,确认需求信息的正确和完整. /* E-R图:实体-关系图(Ent ...

  6. 《SQL Server 2000设计与T-SQL编程》

    <SQL Server 2000设计与T-SQL编程> <SQL Server 2000设计与T-SQL编程>笔记1 http://dukedingding.blog.sohu ...

  7. SQL Server 数据库设计、命名、编码规范

    https://blog.csdn.net/songguozhi/article/details/5858159 SQL Server 数据库设计.命名.编码规范

  8. 转载:SQL Server高效 -- 设计(ITPUT 讨论汇总

    http://blog.csdn.net/zjcxc/article/details/8979756 认为在设计SQL Server对象时,主要会考虑哪些因素来避免出现性能问题? 讨论汇总——总体设计 ...

  9. SQL Server索引设计 <第五篇>

    SQL Server索引的设计主要考虑因素如下: 检查WHERE条件和连接条件列: 使用窄索引: 检查列的选择性: 检查列的数据类型: 考虑列顺序: 考虑索引类型(聚集索引OR非聚集索引): 一.检查 ...

随机推荐

  1. POJ 2187 Beauty Contest 凸包

    Beauty Contest Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 27276   Accepted: 8432 D ...

  2. 14.18.1 The InnoDB Recovery Process InnoDB 恢复进程:

    14.18.1 The InnoDB Recovery Process InnoDB 恢复进程: InnoDB crash recovery 有几个步骤组成: 1.应用redo log,Redo lo ...

  3. python 站点爬虫 下载在线盗墓笔记小说到本地的脚本

    近期闲着没事想看小说,找到一个全是南派三叔的小说的站点,决定都下载下来看看,于是动手,在非常多QQ群里高手的帮助下(本人正則表達式非常烂.程序复杂的正则都是一些高手指导的),花了三四天写了一个脚本 须 ...

  4. Swift - UIView的常用属性和常用方法总结

    1,UIView常用的一些属性如下: frame:相对父视图的坐标和大小(x,y,w,h) bounds:相对自身的坐标和大小,所以bounds的x和y永远为0(0,0,w,h) center:相对父 ...

  5. 进程、线程、轻量级进程、协程和go中的Goroutine

    进程.线程.轻量级进程.协程和go中的Goroutine 那些事儿电话面试被问到go的协程,曾经的军伟也问到过我协程.虽然用python时候在Eurasia和eventlet里了解过协程,但自己对协程 ...

  6. c vs c++ in strcut and class

    c vs c++ in strcut and class 总习惯用c的用法,现在学习C++,老爱拿来比较.声明我用的是g++4.2.1 SUSE Linux.看例子吧 #include <ios ...

  7. Phpcms V9 所有的中文变量

    $LANG['start_update_category'] = '开始更新栏目页 ...'; $LANG['start_to_end_id'] = '" 第{page} - {endpag ...

  8. Atitit.jquery 版本号新特性attilax总结

    Atitit.jquery 版本号新特性attilax总结 1. Jq1.4 1 2. 1.5 1 3. 1.6 3 4. Jq1.7 3 ⒉提升了事件委派时的性能有了大幅度的提升.尤其是在ie7下: ...

  9. T-SQL 操作文件 具体解释

    /*******  导出到excel EXEC master..xp_cmdshell 'bcp SettleDB.dbo.shanghu out c:\temp1.xls -c -q -S" ...

  10. hdu 4706 Children's Day 2013年ICPC热身赛A题 模拟

    题意:按字母顺序排列成n型,简单的模拟题. 当字母排到z时从a开始重新排起. 代码: /* * Author: illuz <iilluzen[at]gmail.com> * Blog: ...