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. (5/9)*(f-32)与5*(f-32)/9

    今天在Linux下用c语言写个小程序玩玩,主要就是根据华氏温度计算摄氏温度.公式是:摄氏度=(5/9)*(华氏度-32) 代码很简单~ #include<stdio.h> main() { ...

  2. SRM 583 Div II Level Three:GameOnABoard,Dijkstra最短路径算法

    题目来源:http://community.topcoder.com/stat?c=problem_statement&pm=12556 用Dijkstra实现,之前用Floyd算法写了一个, ...

  3. 日本IT工作有感

    不知不觉,在日本关西已经呆了快一个月了. 除了饮食有点不是非常习惯.其他感觉都还好. 日本这边的文化还是非常偏向project师的,project师的社会地位非常高,公司里面也没有国内所谓35岁的焦虑 ...

  4. Hibernate持久化对象状态

    在Hibernate中,持久化对象再被操作过程中分为三个时期.这三个时期和session周期相关. 各自是瞬时(Transient),持久太(persistent)和游离态(Detached) 瞬时状 ...

  5. 浅C#中的装箱和拆箱

    1.什么是装箱和拆箱? 简单的来说: 装箱就是值类型转换为引用类型:拆箱就是引用类型转换为值类型 值类型,包括原类型(Sbyte.Byte.Short.Ushort.Int.Uint.Long.Ulo ...

  6. python 调用shell命令三种方法

    #!/usr/bin/python是告诉操作系统执行这个脚本的时候,调用/usr/bin下的python解释器: #!/usr/bin/env python这种用法是为了防止操作系统用户没有将pyth ...

  7. session对象和applicatione对象

    ASP.NET 的常用对象有:response对象.request对象.application对象.server对象.session对象.下面主要讨论session对象和cookie对象. sessi ...

  8. struts2对action中的方法进行输入校验---xml配置方式(3)

    上面两篇文章已经介绍了通过编码java代码的方式实现action方法校验,这里我们介绍第二种方式:xml配置文件 首先我们来看一个样例: ValidateAction.java: package co ...

  9. flask开发restful api

    flask开发restful api 如果有几个原因可以让你爱上flask这个极其灵活的库,我想蓝图绝对应该算上一个,部署蓝图以后,你会发现整个程序结构非常清晰,模块之间相互不影响.蓝图对restfu ...

  10. 关于Delphi XE2的FMX的一点点研究之消息篇

    Delphi XE2出来了一阵子了,里面比较抢眼的东西,除了VCLStyle这个换肤的东西之外,另外最让人眼亮的应该是FMX这个东西了.万一的博客上都连载了一票的关于FMX的使用心得了.我还是没咋去关 ...