分布式FastDFS存储原理2
框架
数据流程
FastDFS文件同步
连接tracker有独立的线程(tracker_report_thread_entrance),连接n个tracker就有n个线程;一个group里面又n个storage,每个storage都有n-1个线程(storage_sync_thread_entrance)用来给同group的storage做同步。
storage的状态:
#define FDFS_STORAGE_STATUS_INIT 0
#define FDFS_STORAGE_STATUS_WAIT_SYNC 1
#define FDFS_STORAGE_STATUS_SYNCING 2
#define FDFS_STORAGE_STATUS_IP_CHANGED 3
#define FDFS_STORAGE_STATUS_DELETED 4
#define FDFS_STORAGE_STATUS_OFFLINE 5
#define FDFS_STORAGE_STATUS_ONLINE 6
#define FDFS_STORAGE_STATUS_ACTIVE 7
#define FDFS_STORAGE_STATUS_RECOVERY 9同步命令:
#define STORAGE_PROTO_CMD_SYNC_CREATE_FILE 16 //新增文件
#define STORAGE_PROTO_CMD_SYNC_DELETE_FILE 17 // 删除文件
#define STORAGE_PROTO_CMD_SYNC_UPDATE_FILE 18 // 更新文件
#define STORAGE_PROTO_CMD_SYNC_CREATE_LINK 19 // 创建链接
同步日志所在目录
例如在192.168.221.152服务器上的sync log:
在 192.168.221.157服务器上看到的sync log:
192.168.221.152_23000.mark
binlog.000
binlog_index.dat
192.168.221.157_23000.mark
同步状态文件,记录本机(192.168.221.152)到192.168.221.157的同步状态,文件名由同步源IP_Port组成。mark文件可以有多份,group里面如果有N个storage,就有N-1个mark文件;文件内容如下:
mark文件内容解释如下:
binlog_index=0 //binlog索引id 表示上次同步给192.168.221.157机器的最后一条binlog文件索引
binlog_offset=232 //表示上次同步给192.168.221.157机器的最后一条binlog偏移量,//若程序重启了,也只要从这个位置开始向后同步即可。
need_sync_old=0 //是否需要同步老数据
sync_old_done=0 //是否同步完成
until_timestamp=0 //同步已有数据文件的截至时间
scan_row_count=4 //扫描记录数
sync_row_count=3 //同步记录数
binlog.000
binlog文件,大小最大1G,超过1G,会重写下个文件,如binlog.001,binlog.002,...,同时更新binlog_index.dat文件中索引值。文件内容如下:
FastDFS文件同步采用binlog异步复制方式。storage server使用binlog文件记录文件上传、删除等操作,根据binlog进行文件同步。binlog中只记录文件ID和操作,不记录文件内容。
从上面可以看到,binlog文件有三列,依次为:
(1)1685368794表示文件upload时间戳
(2)C表示文件操作类型
(3)文件的FileID
例如:M00/00/00/wKjdmGR0r9qADDWgAAAoIvD4yLo41.conf,其中M00为stragepath索引;00/00/为路径;wKjdmGR0r9qADDWgAAAoIvD4yLo41.conf为文件系统中实际的文件名(若采用合并存储并不是一个实际的文件名)。
wKjdmGR0r9qADDWgAAAoIvD4yLo41是经过base64编码后的值,由下面几个部分组成:
- Storage_id(ip的数值型)
- timestamp(创建时间)
- file_size(若原始值为32位则前面加入一个随机值填充,最终为64位)
- crc32(文件内容的检验码)
文件操作类型采用单个字母编码,其中源头操作用大写字母表示,被同步的操作为对应的小写字母。文件操作字母含义如下:
源 |
副本 |
C :上传文件(upload) |
c:副本创建 |
D:删除文件(delete) |
d:副本删除 |
A:追加文件(append) |
a:副本追加 |
M:部分文件更新(modify) |
m:副本部分文件更新(modify) |
U:整个文件更新(set metadata) |
u:副本整个文件更新(set metadata) |
T:截断文件(truncate) |
t:副本截断文件(truncate) |
L:创建符号链接(文件去重功能,相同内容只保存一份) |
l:副本创建符号链接(文件去重功能,相同内容只保存一份) |
注:源表示客户端直接操作的那个Storage即为源,其他的Storage都为副本。如客户端向10.0.1.1主机Upload一个文件,那么在10.0.1.1机器上记录的就是C,当10.0.1.1机器将该条binlog的操作同步给10.0.1.2时,在10.0.1.2上记录的binlog就是c,其他几种操作同理。
binlog_index.dat
记录了当前写binlog的索引id。
同步机制
storage同步规则
- 文件同步采用增量方式,记录已同步的位置到mark文件中;
- 文件同步只在同组内的storage server之间进行,采用push方式;
- 源头数据才需要同步,备份数据不需要再次同步,否则就构成环路了。源数据和备份数据是根据binlog的操作类型来区分:操作类型是大写字母表示源数据,小写字母表示备份数据;
- 当新增加一台storage server时,由已有的一台storage server将已有的所有数据(包括源头数据和备份数据)同步给该新增服务器。
- 可以通过增加group,来扩展存储能力;
- 如果一个group由N个storage,则每个storage需要创建N-1个线程,每个线程中的所有操作都是以同步方式执行的。(例如:一组服务器有A、B、C三台机器,那么在每台机器上都有两个线程负责同步,如A机器,线程A1负责同步数据到B,线程A2负责同步数据到C。)
storage获取组内的其他storage信息,并启动同步线程
tracker_report_thread_entrance 线程负责向tracker上报信息。
在storage.conf配置文件中,只配置了Tracker的IP和Port,并没有配置组内其他的Storage:
tracker_server=192.168.221.152:22122
tracker_server=192.168.221.152:22123
因此同组的其他Storage必须从Tracker获取。具体过程如下:
1)Storage启动时为每一个配置的Tracker启动一个线程负责与该Tracker的通讯。
2)默认每间隔30秒,与Tracker发送一次心跳包,在心跳包的回复中,将会有该组内的其他storage信息。
3)Storage获取到同组的其他Storage信息之后,为组内的每个其他Storage开启一个线程负责同步。
同步线程执行过程
storage_sync_thread_entrance是storage同步线程
每个同步线程负责一台Storage的同步,以阻塞方式进行。
1)打开对应storage的mark文件,如负责到192.168.221.157的同步则打开192.168.221.157_23000.mark文件,从中读取binlog_index、binlog_offset两个字段值,如取到值为:0、100,那么就打开binlog.000文件,seek到100这个位置。
2)进入一个while循环,尝试着读取一行,若读取不到则睡眠等待。若读取到一行,并且该行的操作方式为源操作,如C、A、D、T(大写的都是),则将该行指定的操作同步给对方(非源操作,如c、a、d、t则不需要同步),同步成功后更新binlog_offset标志,该值会定期写入到192.168.221.157_23000.mark文件之中。
同步前删除
假如同步较为缓慢,那么有可能在开始同步一个文件之前,该文件已经被客户端删除,此时同步线程将打印一条日志,然后直接接着处理后面的Binlog记录。
storage的最后最早被同步时间
这个标题有点拗口,先举个例子:一组内有Storage-A、Storage-B、Storage-C三台机器。对于A这台机器来说,B与C机器都会同步Binlog(包括文件)给他,A在接收同步时会记录每台机器同步给他的最后时间(也就是Binlog中的第一个字段timpstamp)。比如B最后同步给A的Binlog-timestamp为100,C最后同步给A的Binlog-timestamp为200,那么A机器的最后最早被同步时间就为100.
这个值的意义在于判断一个文件是否存在某个Storage上。比如这里A机器的最后最早被同步时间为100,那么如果一个文件的创建时间为99,就可以肯定这个文件在A上肯定有。为什呢?一个文件会Upload到组内三台机器的任何一台上:
1)若这个文件是直接Upload到A上,那么A肯定有。
2)若这个文件是Upload到B上,由于B同步给A的最后时间为100,也就是说在100之前的文件都已经同步A了,那么A肯定有。
3)同理C也一样。
Tracker也会定期将每个storage的最后最早时间写入到一个文件storage_sync_timestamp.dat之中,内容如下:
group1,10.0.0.1,0,1408524351,1408524352
group1,10.0.0.2,1408524353,0,1408524354
group1,10.0.0.3,1408524355,1408524356,0
每一行记录了,对应Storage同步给其他Storage的最后时间,如第一行表示10.0.0.1同步给10.0.0.2的最后时间为1408524351,同步给10.0.0.3的最后时间为1408524352;同理可以知道后面两行的含义了。每行中间都有一个0,这个零表示自己同步给自己,没有记录。按照纵列看,取非零最小值就是最后最早同步时间了,如第三纵列为10.0.0.1被同步的时间,其中1408524353就是其最后最早被同步时间。
新增storage节点同步流程
1、新节点storage C 启动的时候会创建线程tracker_report_thread_entrance,调⽤ tracker_report_join向tracker 发送命令TRACKER_PROTO_CMD_STORAGE_JOIN(81),报告⾃⼰的group名称,ip,端⼝,版本号,存储⽬录数,⼦⽬录数,启动时间,⽼数据是否同步完成,当前连接的 tracker信息,当前状态信息(FDFS_STORAGE_STATUS_INIT)等信息
2、tracker收到TRACKER_PROTO_CMD_STORAGE_JOIN命令后,将上报的信息和已有 (tracker数据⽂件中保存的信息)的信息进⾏⽐较,如果有则更新,没有的话,将节点及状态信息写⼊缓 存和数据⽂件中,并查找同group的其他节点做为同步源,如果有返回给stroage C
3、新节点stroage C 收到tracker响应继续流程。发送 TRACKER_PROTO_CMD_STORAGE_SYNC_DEST_REQ (87)查询同步⽬的
4、tracker收到TRACKER_PROTO_CMD_STORAGE_SYNC_DEST_REQ 请求后, 查找同group 的其他节点做为同步⽬标,及时间戳返回给新storage节点
5、新storage节点收到响应后,保存同步源及同步时间戳。继续流程,发送 TRACKER_PROTO_CMD_STORAGE_BEAT(83) 给tracker
6、tracker收到⼼跳报告后,leader trakcer(⾮leader不返回数据),把最新的group的 storagelist返回给新的stroaged
7、stroage C 收到 tracker storage list后,启动2个同步线程,准备将binlog同步到节点 A和 B(此时还不能同步,因为stroage C 还是WAIT_SYNC 状态)
8、这时候,其他的已在线的storage 节点 A 、B会发送⼼跳给tracker ,tracker 把会收到最新的 stroagelist,A、B、C返回给Storage A,B
9、storage A,B 收到tracker响应后,会发现本地缓存中没有stroage C,会启动binlog同步线 程,将数据同步给 stroage C
10、storage A 、B分别启动storage_sync_thread_entrance 同步线程,先向 tracker 发送 TRACKER_PROTO_CMD_STORAGE_SYNC_SRC_REQ(86)命令,请求同步源,tracker会把同步源 IP及同步时间戳返回
11、stroage A 、B节点的同步线程收到TRACKER_PROTO_CMD_STORAGE_SYNC_SRC_REQ 响应后,会检查返回的同步源IP是否和⾃⼰本地ip⼀致,如果⼀致置need_sync_old=1表示将做为源数据 将⽼的数据,同步给新节点C,如果不⼀致置need_sync_old=0,则等待节点C状态为Active时,再同步 (增量同步)。因为,如果A、 B同时作为同步源,同步数据给C的话,C数据会重复。这⾥假设节点A, 判断tracker返回的是同步源和⾃⼰的iP⼀致,A做为同步源,将数据同步给storage C节点。
12、Storage A同步线程继续同步流程,⽤同步⽬的的ip和端⼝,为⽂件名,.mark为后缀,如 192.168.1.3_23000.mark,将同步信息写⼊此⽂件。将Storage C的状态置为 FDFS_STORAGE_STATUS_SYNCING 上报给tracker,开始同步:
A)、从data/sync⽬录下,读取binlog.index 中的,binlog⽂件Id,binlog.000读取逐⾏读取,进 ⾏解析 具体格式 如下: 1490251373 C M02/52/CB/CtAqWVjTbm2AIqTkAAACd_nIZ7M797.jpg 1490251373 表示时间戳 C 表示操作类型 M02/52/CB/CtAqWVjTbm2AIqTkAAACd_nIZ7M797.jpg ⽂件名 因为storage C是新增节点,这⾥需要全部同步给storage C服务 B)、根据操作类型,将数据同步给storage C,具体有如下类型
#define STORAGE_OP_TYPE_SOURCE_CREATE_FILE 'C' //upload file
#define STORAGE_OP_TYPE_SOURCE_APPEND_FILE 'A' //append file
#define STORAGE_OP_TYPE_SOURCE_DELETE_FILE 'D' //delete file
#define STORAGE_OP_TYPE_SOURCE_UPDATE_FILE 'U' //for whole file update such as metadata file
#define STORAGE_OP_TYPE_SOURCE_MODIFY_FILE 'M' //for part modify
#define STORAGE_OP_TYPE_SOURCE_TRUNCATE_FILE 'T' //truncate file
#define STORAGE_OP_TYPE_SOURCE_CREATE_LINK 'L' //create symbol link
#define STORAGE_OP_TYPE_REPLICA_CREATE_FILE 'c'
#define STORAGE_OP_TYPE_REPLICA_APPEND_FILE 'a'
#define STORAGE_OP_TYPE_REPLICA_DELETE_FILE 'd'
#define STORAGE_OP_TYPE_REPLICA_UPDATE_FILE 'u'
#define STORAGE_OP_TYPE_REPLICA_MODIFY_FILE 'm'
#define STORAGE_OP_TYPE_REPLICA_TRUNCATE_FILE 't'
#define STORAGE_OP_TYPE_REPLICA_CREATE_LINK 'l'
具体同步函数storage_sync_data
C)、 发送数据给Stroage C,StroageC 收数据并保存
D)、binlog⽂件读完之后,会将Stroage C 状态 置为FDFS_STORAGE_STATUS_OFFLINE,向 tracker 报告,同时更新同步状态到本地⽂件mark⽂件
E)、同步完成后调⽤ tracker_sync_notify 发送 TRACKER_PROTO_CMD_STORAGE_SYNC_NOTIFY通知tracker同步完成,将storage C的 状态置为 FDFS_STORAGE_STATUS_ONLINE
F) 当storage server C向tracker server发起heart beat时,tracker server将其状态更改为 FDFS_STORAGE_STATUS_ACTIVE。
tracker处理机制
tracker下载文件过程
storage会定期将每台机器同步给他的最后时间告诉给Tracker,Tracker在客户端要下载一个文件时,需要判断一个Storage是否有该文件,只要解析文件的创建时间,然后与该值作比较,若该值大于创建创建时间,说明该Storage存在这个文件,可以从其下载。
tracker持久化storage信息
查看持久化的storage信息:
tracker持久化storage信息是为了下次tracker启动时,可以加载该文件,快速获取storage信息。
如何选择tracker
当集群中有多个tracker server时,由于tracker之间是对等的关系,客户端在upload文件时可以任意选择一个tracker。
同步总结
1、为了避免循环推送,当发现binlog中的文件操作类型是大写的,才推送给其他storage;如果是小写的,则不用推送给其他storage.
2、
分布式FastDFS存储原理2相关推荐
- fastdfs存储原理
本文主要介绍fastdfs客户端的上传下载原理以及以及服务端的网络io模型:主要介绍storage,不涉及tracker:storage和tracker使用的网络io模型是一样的. 协议格式 Fast ...
- RADOS分布式对象存储原理简介
Ceph是一个开源的PB级文件系统,最早是加州大学Santa Cruz分校的一个研究项目,项目创始人sage weil是该校的一名博士.ceph包括一个兼容POSIX的分布式文件CephFS,一个分布 ...
- 如何从零起步搭建一个分布式对象存储的架构
早在几年前,云存储还只是存在于业界大佬们口中的一个概念,其应用场景仅供大公司使用.突飞猛进的网络技术似乎在一瞬间就把这个概念普及到千家万户,现在云存储已经是大家司空见惯的一个网络服务了.比如大家用的百 ...
- 分布式对象存储 读书笔记(一) 开始
这是 <分布式对象存储 原理架构及Go语言实现>的学习笔记的第一篇 我们简单的实现一个REST(表述性状态传递,英文:Representational State Transfer)服务接 ...
- 分布式文件存储FASTDFS
分布式文件存储FASTDFS 目录 概 述 小结 参考资料和推荐阅读 LD is tigger forever,CG are not brothers forever, throw the pot a ...
- 分布式文件存储FastDFS介绍安装部署及相关Java代码编写
分布式文件存储FastDFS 一.FastDFS简介 1.1 FastDFS体系结构 FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传 ...
- Redis如何实现分布式锁延时队列以及限流应用丨Redis源码原理|跳表|B+树|分布式锁|中间件|主从同步|存储原理
Redis如何实现分布式锁延时队列以及限流应用 视频讲解如下,点击观看: Redis如何实现分布式锁延时队列以及限流应用丨Redis源码原理|跳表|B+树|分布式锁|中间件|主从同步|存储原理|数据模 ...
- 分布式文件存储——FastDFS
FastDFS FastDFS 是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等,解决了大容量存储和负载均衡的问题. 特别适合以文件为 ...
- FastDFS合并存储原理分析
FastDFS合并存储原理分析 基于FastDFS 5.03/5.04 2014-12-03 一.合并存储简介 在处理海量小文件问题上,文件系统处理性能会受到显著的影响,在读写次数与吞吐量这两个指标上 ...
最新文章
- HTML5 — 让拖放变的流行起来
- vim编写python_用vim写python代码
- 有趣,机器人吵架视频!
- android-x86 镜像iso下载_Windows 10(1909)最新12月更新版MSDN官方简体中文原版ISO镜像下载+激huo工ju...
- 麻省理工学院给研究生的文献阅读方法,简单高效!
- (4)ISE14.7 ChipScope使用流程(FPGA不积跬步101)
- Scanner、String(java基础知识十二)
- synchronized的作用以及不足
- iOS import,include和class的区别
- Redis实战篇(视频学习来自黑马程序员)
- ssm毕设项目疫情防控管理系统02vsf(java+VUE+Mybatis+Maven+Mysql+sprnig)
- 校园导游系统(C++实现,VC6.0编译,使用EasyX图形库)
- 如何刷一些网站的阅读量
- 【替罪羊树及其应用】替罪羊树总结
- 【连载】从单片机到操作系统⑥——FreeRTOS任务切换机制详解
- 【转】db_domain参数设置影响dblink迁移问题
- 磊科路由器信号按键_磊科路由器按了后面的默认设置按钮后,怎么配置路由上网?...
- 快速傅里叶变换功率谱密度matlab_[转载]Matlab实例:频谱、功率谱和功率谱密度计算...
- 【避坑指南】Python12个坑爹的陷阱,再不看坑的就是你
- EGL, GLX/WGL/AGL 和GL之间的关系
热门文章
- RTK+GPS提高定位精度原理解析(一个小白写给另一个小白系列)
- java继承的优缺点分析
- 妖怪宝可萌html5游戏,妖怪宝可萌h5斗宠棋玩法规则以及技巧分析
- osg bullet
- 谈C中scanf陷阱
- xftp传输文件失败的解决方法
- http参数 libcurl_LibCurl HTTP部分详细介绍
- 今日5点起床时,悟到一条街道,恍然觉悟。随机分享给大家,相信大家看了都有用。不急,不求,功到自然成。图片1、定得住心,自然不气。苏东坡和好友佛印之间的故事,很多人应该听过。
- 如何实现一个京东自定义流式ViewGroup?
- 热更新报错 log.error('[WDS] Errors while compiling. Reload prevented.');