一、Binlog同步概述
FastDFS中为了维护文件的多个副本,会在同组的Storage之间互相同步文件,也就是一个备份过程,若一组有三台机器,那么互相备份后,一个文件就有三个副本。本篇将主要描述Binlog同步的相关概念,与同步逻辑,以及一些注意事项。
1、Binlog结构
1)目录结构
在Storage.conf配置文件中,有一个配置如下:base_path=/data/zcs/fdfs_Storage_base
在Storaged程序启动时会创建一个 base_path/data/sync 目录,该目录中的文件都是和Storaged之间的同步相关的,如:
10.0.1.1_23000.mark10.0.1.2_23000.mark binlog.000binlog.index
binlog.index ##记录当前使用的Binlog文件序号,如为1,则表示使用binlog.001
binlog.000##真实地Binlog文件
10.0.1.1_23000.mark##同步状态文件,记录本机到10.0.1.1的同步状态
2)Mark文件内容描述
对于10.0.1.1_23000.mark文件,本篇相关的内容有如下两项:
binlog_index=0##表示上次同步给10.0.1.1机器的最后一条binlog文件索引
binlog_offset=116##表示上次同步给10.0.1.1机器的最后一条binlog偏移量,若程序重启了,也只要从这个位置开始向后同步即可。
3)Binlog文件内容描述
对于binlog.000文件,是有一条条binlog日志组成的,如下:
1627025362 C M00/00/00/wKgDFGD6b9KALiDLAAYevEPlQIk376.jpg 1627025372 c M00/00/00/wKgDM2D6b9yAQJZxAAT4rd1P2iI703.jpg 1627025617 C M01/00/00/wKgDFGD6cNGAXGzwAAT4rd1P2iI215.jpg 1627025656 C M00/00/00/wKgDFGD6cPiAQED_AAT4rd1P2iI586.jpg 1627025654 c M01/00/00/wKgDM2D6cPaAC_vJAAT4rd1P2iI108.jpg 1627025657 c M00/00/00/wKgDM2D6cPmAZy_TAAT4rd1P2iI773.jpg 1627025658 C M01/00/00/wKgDFGD6cPqACGJNAAT4rd1P2iI332.jpg
其中的每一条记录都是使用空格符分成三个字段,分别为:
第一部分: 1627025362 表示文件upload时间戳
第二部分:表示文件创建方式
C表示源创建、c表示副本创建
A表示源追加、a表示副本追加
D表示源删除、d表示副本删除
T表示源Truncate、t表示副本Truncate
注:源表示客户端直接操作的那个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,其他几种操作同理。
第三部分:文件的FileID :M01/00/00/wKgDFGD6cPqACGJNAAT4rd1P2iI332.jpg 其中的M01为storepath索引,紧接着00/00/为路径,后面wKgDFGD6cPqACGJNAAT4rd1P2iI332.jpg为文件系统中实际的文件名(不采用合并存储时,若采用合并存储并不是一个实际的文件名)。
注:文件名组成:CgAHl1SJUR6AZqSHAAAF1vgN0rw59.conf,这个文件名中,除了conf 为文件后缀,CgAHl1SJUR6AZqSHAAAF1vgN0rw59 这部分是一个base64编码缓冲区,组成如下:
1、Storage_id(ip的数值型)
2、timestamp(创建时间)
3、file_size(若原始值为32位则前面加入一个随机值填充,最终为64位)
4、crc32(文件内容的检验码)
二、Binlog同步过程
在FastDFS之中,每个Storaged之间的同步都是由一个独立线程负责的,该线程中的所有操作都是以同步方式执行的。比如一组服务器有A、B、C三台机器,那么在每台机器上都有两个线程负责同步,如A机器,线程1负责同步数据到B,线程2负责同步数据到C。
1、获取组内的其他Storage信息,并启动同步线程
在Storage.conf配置文件中,只配置了Tracker的IP地址,并没有配置组内其他的Storage。因此同组的其他Storage必须从Tracker获取。具体过程如下:
1)Storage启动时为每一个配置的Tracker启动一个线程负责与该Tracker的通讯。
2)默认每间隔30秒,与Tracker发送一次心跳包,在心跳包的回复中,将会有该组内的其他Storage信息。
3)Storage获取到同组的其他Storage信息之后,为组内的每个其他Storage开启一个线程负责同步。
2、同步线程执行过程
每个同步线程负责到一台Storage的同步,以阻塞方式进行。
1)打开对应Storage的mark文件,如负责到10.0.1.1的同步则打开10.0.1.1_23000.mark文件,从中读取binlog_index、binlog_offset两个字段值,如取到值为:1、100,那么就打开binlog.001文件,seek到100这个位置。
2)进入一个while循环,尝试着读取一行,若读取不到则睡眠等待。若读取到一行,并且该行的操作方式为源操作,如C、A、D、T(大写的都是),则将该行指定的操作同步给对方(非源操作不需要同步),同步成功后更新binlog_offset标志,该值会定期写入到10.0.1.1_23000.mark文件之中。
3、同步前删除
假如同步较为缓慢,那么有可能在开始同步一个文件之前,该文件已经被客户端删除,此时同步线程将打印一条日志,然后直接接着处理后面的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也一样。
Storage会定期将每台机器同步给他的最后时间告诉给Tracker,Tracker在客户端要下载一个文件时,需要判断一个Storage是否有该文件,只要解析文件的创建时间,然后与该值作比较,若该值大于创建创建时间,说明该Storage存在这个文件,可以从其下载。
Tracker也会定期将该值写入到一个文件之中,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就是其最后最早被同步时间。
四、注意事项
1、由于到每台机器的同步都是有单线程负责的,因此即使主机上有很多个磁盘也不能加快同步速度,因此单线程并不能最大化磁盘IO,最大的速度也就是一个磁盘的速度。
2、对于重要文件,为了防止机器宕机或者坏磁盘的文件丢失,及时的同步备份是必须得。若同步太慢,还可能导致Tracker不能正确估计可用空间,而导致空间溢出。
3、同步性能,由于Linux系统的文件缓存机制,若一个刚写入的文件马上读,那么很可能就命中在系统缓存上,此时读数据几乎不耗费时间,若不能命中缓存,从磁盘读,将耗费很长时间。因此写入速度,最好与同步速度相当,这样可以保证及时同步。若写入速度超过同步速度,从某个时刻开始,将会使得所有的读无法命中缓存,同步性能将大幅下滑。