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. Java的LockSupport.park()实现分析

    LockSupport类是Java6(JSR166-JUC)引入的一个类,提供了主要的线程同步原语.LockSupport实际上是调用了Unsafe类里的函数,归结到Unsafe里,仅仅有两个函数: ...

  2. Javascript 生成指定范围数值随机数

    JavaScript对随机数的介绍比较少,所以今天分享一下有关随机数的一些事儿.希望能对大家有点小帮助. 主要的公式就是parseInt(Math.random()*(上限-下限+1)+下限); Ma ...

  3. 原码、反码、补码和移码事实上非常easy

    近期在备战软考,复习到计算机组成原理的时候,看到书中关于原码.反码.补码和移码的定义例如以下(n是机器字长): 原码: 反码: 补码: 移码: 看完这些定义以后,我的脑袋瞬间膨胀到原来的二倍!这样变态 ...

  4. C#超级有用的一种类型—匿名类型

    顾名思义 匿名类型就是没有名字的类型.当一个新的匿名对象定义与前面已经存在的类型定义的内部变量类型同样时,编译器就会仅仅生成一个类定义,而不是各一个. 匿名类型对象中仍然能够再包括匿名对象. 在C#3 ...

  5. Endnote X6 如何修改输出格式(output style)成为自己想要的输出格式:

    Endnote X6 如何修改输出格式(output style)成为自己想要的输出格式: (1)首先尝试在endnote output style 网站中查找: http://www.endnote ...

  6. linux shell脚本:在脚本中实现读取键盘输入,根据输入判断下一步的分支

    echo please input “runbip” to run bip. variableName="null" while [ $variableName != " ...

  7. ACM POJ 2192 Zipper

    题目大意:输入字符串a,b,c 要求推断c是否有a,b中的个字符保持原有顺序组合而成. 算法思想: DP 用dp[i][j]表示a的前0~i-1共i个字符和b的前0~j-1共j个字符是否构成c[i+j ...

  8. python实现刷博器(适用于新浪、搜狐)

    本文总结于智普教育: 做点小东西,有成就感,才会有动力学下去哈! 先上代码: 1: import webbrowser as web 2: import time 3: import os 4: co ...

  9. 浅谈MySQL 数据库性能优化

    MySQL数据库是 IO 密集型的程序,和其他数据库一样,主要功能就是数据的持久化以及数据的管理工作.本文侧重通过优化MySQL 数据库缓存参数如查询缓存,表缓存,日志缓存,索引缓存,innodb缓存 ...

  10. 慎得慌二u赫然共和任务i个屁

    http://www.huihui.cn/share/8424421 http://www.huihui.cn/share/8424375 http://www.huihui.cn/share/842 ...