FastDFS之Storage程序框架

FastDFSStorage程序框架

 

基于FastDFS 5.03/5.04


2014-12-19

 

一、概述

      FastDFS分布式文件系统中有TrackerStorage两个角色,其中绝大多数功能都是在Storage中实现,包括网络处理、文件上传、下载、同步、磁盘恢复等众多功能,本篇将讲述Storage程序的启动过程,网络处理,磁盘处理,与Tracker通讯,文件同步等过程。

 

二、启动过程

      源码在fdfs_storaged.c/main,也是程序的主线程。此处将列举启动的主要过程,并非一个完整的操作列表。

1)首先从配置文件中读取base_path配置,初始化日志,响应stoprestart命令;

2)读取完整的配置文件内容,包括日志目录,各种线程个数,TrackerIP地址等各种信息,记录在各个全局变量之中;

3)执行创建或检查各store_path/data目录

对于首次启动则依据配置创建data下面的二级子目录(默认256个二级子目录)

对于非首次启动则检查各store_path/data/下面的子目录是否存在,若不存在则进入磁盘恢复操作(磁盘恢复具体过程详见我另一篇博文)。

4)连接Tracker,向其查询各种配置(主要是合并存储的配置),若有多个Tracker则只要从其中一个查询成功即可,因此Tracker的配置应该是一样的。

5)启动服务的监听端口,默认为23000,并设置该socket的超时时间。

6)写pid文件,将程序转入后台(在此时才转入后台,可见磁盘恢复过程还是一个控制台程序)。

7)文件同步的初始化(主要是创建 /base/data/sync/目录,读取binlog.index文件,打开对应的binlog.xxx文件,并seekEND)。

8)初始化网络操作,预先分配一些客户端的缓冲区,创建网络线程,线程个数在配置文件中配置,默认为4个。

9)处理各种信号,包括SIGPIPE

10)根据storage.confTracker-Server的配置,为每个Tracker启动一个线程处理与其的通讯。

11)设置定期执行的任务,并启动执行这些任务的线程,主要有如下这些任务:

log_sync_func	10秒	执行log的fsync操作
fdfs_binlog_sync_func	60秒	执行binlog的fsync操作
fdfs_stat_file_sync_func300秒	执行将统计信息写入到stat文之中
trunk_binlog_sync_func 	1秒	开启trunk-file时启动 g_if_use_trunk_file
log_sync_func	10秒	开启记录访问日志时g_use_access_log
log_notify_rotate	每天	开启记录访问日志g_use_access_log,与访问日志自动轮换g_rotate_access_log
log_notify_rotate	每天	开启记录错误日志轮换g_rotate_error_log

12)进入网络监听的大循环,也就是Accept线程,如果配置了多个Accept线程,那么会开启N-1个线程执行同样地操作,因为主线程也执行该操作:

13)此时监听大循环已经退出,进行程序的清理操作,包括把fsync日志,停掉各种线程,删除日志文件等操作。

 

三、网络处理

      Storage之中有两种处理网络的线程,分别为Accept线程与NIO线程,前者专门处理客户端的连接操作,并为每个Socket连接创建一个任务,将该任务提交到NIO线程,处理网络数据的读写。这两种线程的个数都可以独立配置。

accept_threads=1##配置的是Accept线程个数,若为1则直接在主线程上进行

work_threads=4##配置的是NIO线程,也就是网络线程数

      Accept线程源代码在 storage_service.c,而网络线程源码在 storage_nio.c 

1、最大连接数支持

      Storage之中为每个连接分配一个fast_task_info任务对象。连接关闭后,该任务对象会被回收再利用。fast_task_info任务对象的分配是在一个队列之中,该队列根据配置的最大连接数设置了可分配的最大任务数,当客户端有一个新的连接,Accept线程就从该队列中获取一个任务指针,当获取不到时表示已经达到最大连接数,将打印malloc task buff failed日志,并关闭连接。

2、将客户端连接分配给NIO线程

      Accept获取一个客户端的Socket之后,会初始化一个fast_task_info指针,并且根据NIO线程数对socket进行取模,该值就是该Socket分配给的NIO线程索引,该Socket后续的所有操作都在该NIO线程中进行。

      在获取处理某个SocketNIO线程索引之后,是如何将该fast_task_info传递给NIO线程呢。过程是这样的,每个NIO线程都有一个epoll实例,在NIO线程启动时使用pipe创建两个Socket,然后在pipe[0]上监听读事件。当Accept要将一个任务(Socket)传给指定的NIO线程时,只要向该线程对应的pipe[1]上写入该任务的指针总共8个字节。NIO线程中对pipe[0]的处理函数就是,一次读取8个字节,就可以获取到该fast_task_info的指针,接着开始该任务。


3NIO网络处理线程

      在配置文件中有一个buff_size=256KB的配置,这个是在fast_task_info中预分配的一个网络读写缓冲区。由于缓冲区大小是固定的,因此假如客户端的请求内容大于该缓冲区,就需要在网络线程与磁盘线程之间多次切换处理。比如客户端要Upload一个1MB的文件,那么网络线程读取256KB内容后,就要将该任务提交给磁盘线程将数据写入到文件中,然后磁盘线程再次通知网络线程读取数据,当读取到256KB之后,再次通知磁盘线程,如此反复直到数据处理完成。对于下载整个过程是类似的。

      在NIO接收到一个Socket之后,该Socket也会被加入到其自己的Epoll中进行监听。NIO线程为每个任务fast_task_info设置当前状态,根据不同的状态执行不同的操作,目前有如下四种状态:

#define FDFS_STORAGE_STAGE_NIO_INIT   0

#define FDFS_STORAGE_STAGE_NIO_RECV   1

#define FDFS_STORAGE_STAGE_NIO_SEND   2

#define FDFS_STORAGE_STAGE_NIO_CLOSE  4  //close socket

 

四、磁盘处理

      磁盘处理也是由独立的线程来完成的,默认读写分离,为每个磁盘(store_path),配置一个读线程,一个写线程。通常这样配置已经足够,通常来说对于一个磁盘配置更多地线程并不能提高IO性能。

      该部分源代码为 storage_dio.c


1、磁盘线程接收任务

      磁盘线程与网络线程接收任务的方式不一样,NIO线程通过在pipe套接字上监听来得到通知有任务要处理,而磁盘线程是通过同步队列与每个线程自带的条件变量进行的。具体如下:网络线程接收到足够的数据后,要交给磁盘线程处理,此时只要将任务fast_task_info指针添加到对应磁盘处理线程的同步队列(依然根据Socket的取摸来决定由那个磁盘线程处理),然后使用对应的条件变量通知其处理即可。

      同样地磁盘线程处理完成后,通知网络线程处理方式与Accept通知网络线程处理方式一样。

 

五、Tracker通讯

      Storage内部与每个Tracker的通讯都是由独立的线程负责,该线程是在初始化的时候启动的。(详见,启动过程的第10步)。该部分代码在tracker_client_thread.c之中。

      Tracker处理线程执行操作如下:

1)连接对应的Tracker服务器

2)是否需要进行源同步判断(该步骤请详细参考我另一篇讲述源同步的文章)。

3)接着进入一个大循环

定期向Tracker发送心跳报告,从心跳回复消息中可以知道该组内的其他Storage变动,若有新的Storage加入,则创建一个与其的同步线程,该线程在《文件同步》中详细说明;

定期向Tracker查询,一些重要的变更,如Storage被删除,与StorageIP变更信息;

定期向Trakcer汇报,其他Storage到自己的最后同步时间;

定期向Tracker汇报,本地的磁盘可用空间;

若为Trunk-Server则向Tracker汇报trunk-fileidtrunk-free-space

 

六、文件同步

      文件同步也是由独立的线程负责的,每个Storage都有到同组中其他Storage的同步线程,如一组三个Storage,那么每个Storage都有两个线程负责到其他两个Storage的同步。同步线程由Tracker通讯线程启动,因为只有Tracker才知道一组中有哪些Storage

      同步线程的执行过程,主要有两部分,分别是源同步与Binlog同步,这两部分内容我分别在另外两篇文章中详细讲述,此处就不在重复。

      该部分源代码为 storage_sync.c

 

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值