Loading [MathJax]/jax/input/TeX/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >FastDFS不同步怎么破

FastDFS不同步怎么破

作者头像
心平气和
发布于 2020-09-11 03:36:02
发布于 2020-09-11 03:36:02
2.3K01
代码可运行
举报
运行总次数:1
代码可运行

一、背景说明

FastDFS是一款开源的分布式文件系统,具体介绍就不说了,有兴趣的可以自行百度下。

以下是官方的架构图:

一次完整的写交互过程如下:

1、Client向Tracker查询可用的Storage;

2、Tracker随机返回一个Storage;

3、Client向Storage发起写请求;

一次完整的读交互:

1、Client向Tracker查询可用的Storage;

2、Tracker随机返回一个Storage;

3、Client向Storage发起读请求;

可以看到每个Storage都是对等的,即每个Storage上存储的文件都是全量的。

最近一朋友线上FastDFS服务器老是报文件不存在的错误,版本为5.11:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[2020-08-12 23:16:37] WARNING - file: storage_service.c, line: 6899, client ip: xx.xx.xxx.xxx, logic file: 06/75/xxxx.jpg not exist

架构如下:

2台Tracker,2台Storage。

每台机器上都有上述报错。

二、FastDFS同步机制分析

我们先分析FastDFS如何实现文件在不同服务器的同步的,FastDFS是以binglog的格式同步各自上传/修改的文件的,具体位置在安装目录的data/sync目录下,文件一般叫binlog.000这样,以下为我开发机的截图:

具体内容如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1589182799 C M00/00/00/rBVrTV65AU-ACKi2AAARqXyG2io334.jpg
1589182885 C M00/00/00/rBVrTV65AaWAAYwKAAARqXyG2io765.jpg
1589427410 C M00/00/00/rBVrTV68vNKAbceuAAARqXyG2io657.jpg

第1列是时间戳,第2列是修改内容,示例中大部分是创建文件,所以是C,其它参考文件 storage/storage_sync.h:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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

有了binglog只是保证不同服务器可以同步数据了,真正实现还有很多东西要考虑:

1、每次是全量还是增量同步,如果是增量,如何记录最后同步的位置,同步的位置做持久化吗;

2、binlog如何保证可靠性,即FastDFS实现的时候是binlog刷磁盘即fsync后才返回给客户端吗;

关于第1点,FastDFS是实现增量同步的,最后位置保存在安装目录的data/sync目录下,扩展名是mark的文件,具体格式是这样的:

172.21.107.236_23000.mark

即 IP_端口.mark。

如果集群中有两个Storage,172.21.104.36, 172.21.104.35,则在36上有1个mark文件:172.21.104.35_23000.mark,而在35上mark文件也只有1个:

172.21.104.36_23000.mark。

mark文件具体内容如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
binlog_index=0
binlog_offset=3422
need_sync_old=1
sync_old_done=1
until_timestamp=1596511256
scan_row_count=118
sync_row_count=62

关键参数是binlog_offset,即binlog中最后同步成功的偏移量,每同步一个文件后,都会将偏移量更新。

那binlog是异步还是同步将binlog同步给其它的Storage呢,答案是异步,具体可以参考函数:storage_sync_thread_entrance,这个函数是线程的入口,FastDFS在启动时会启动这个线程用来同步:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int storage_sync_thread_start(const FDFSStorageBrief *pStorage)
{
  int result;
  pthread_attr_t pattr;
  pthread_t tid;

 //省略非关键代码

  /*
  //printf("start storage ip_addr: %s, g_storage_sync_thread_count=%d\n", 
      pStorage->ip_addr, g_storage_sync_thread_count);
  */

  if ((result=pthread_create(&tid, &pattr, storage_sync_thread_entrance, \
    (void *)pStorage)) != 0)
  {
    logError("file: "__FILE__", line: %d, " \
      "create thread failed, errno: %d, " \
      "error info: %s", \
      __LINE__, result, STRERROR(result));

    pthread_attr_destroy(&pattr);
    return result;
  }

在这个线程中,会周期地读取binlog,然后同步给其它的Storage:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  while (g_continue_flag && (!g_sync_part_time || \
      (current_time >= start_time && \
      current_time <= end_time)) && \
      (pStorage->status == FDFS_STORAGE_STATUS_ACTIVE || \
      pStorage->status == FDFS_STORAGE_STATUS_SYNCING))
    {
      //读取binlog
      read_result = storage_binlog_read(&reader, \
          &record, &record_len);
      //省略非关键代码
      }

      if (read_result != 0)
      {
        //省略非关键代码
      }
      else if ((sync_result=storage_sync_data(&reader, \
        &storage_server, &record)) != 0)
      {
        //上面就是就binlog同步到其它Storage
        logDebug("file: "__FILE__", line: %d, " \
          "binlog index: %d, current record " \
          "offset: %"PRId64", next " \
          "record offset: %"PRId64, \
          __LINE__, reader.binlog_index, \
          reader.binlog_offset, \
          reader.binlog_offset + record_len);
        if (rewind_to_prev_rec_end(&reader) != 0)
        {
          logCrit("file: "__FILE__", line: %d, " \
            "rewind_to_prev_rec_end fail, "\
            "program exit!", __LINE__);
          g_continue_flag = false;
        }

        break;
      }
      
    if (reader.last_scan_rows != reader.scan_row_count)
    {
      //定稿mark文件
      if (storage_write_to_mark_file(&reader) != 0)
      {
        logCrit("file: "__FILE__", line: %d, " \
          "storage_write_to_mark_file fail, " \
          "program exit!", __LINE__);
        g_continue_flag = false;
        break;
      }
    }

可以看到,这个线程周期性地调用storage_binlog_read 读取binlog,然后调用storage_sync_data同步给其它Storage,然后调用storage_write_to_mark_file 将mark文件写入到磁盘持久化。

通过上面的分析,可以判断FastDFS在异步情况下是会丢数据的,因为同步binlog给其它Storage是异步的,所以还没同步之前这台机器挂了并且起不来,数据是会丢失的;

另外binlog不是每1次都刷磁盘的,有参数设置,单位为秒:

sync_binlog_buff_interval

即保证多久将将mark文件刷新到磁盘中,果设置大于0,也是会容易丢失数据的。

三、解决方案

回到问题本身,为什么出现数据不同步呢,是因为在搭建 FastDFS的时候,运维的同学直接从其它服务器上拷过来的,包括整个data目录,也包括data下面的sync目录,这样就容易出现mark文件的偏移量不准的问题。

如何解决呢,手动修改mark文件,将binlog_offset设为0,这样FastDFS就会从头同步文件,碰到已经存在的文件,系统会略过的,这是我开发机上的日志:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[2020-08-11 20:27:36] DEBUG - file: storage_sync.c, line: 143, sync data file, logic file: M00/00/00/rBVrTV8yZl6ATOQyAAAJTMk6Vgo7337.md on dest server xx.xx.xx.xx:23000 already exists, and same as mine, ignore it

当然前提是日志级别开到DEBUG级别。

PS:

源代码中同步文件成功是没有日志的,写mark文件成功也是没有日志的,为了调试方便,我们都加上相关的调试日志了。

保存mark文件加日志可以在函数storage_write_to_mark_file中加入一条info日志。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

  if ((result=storage_write_to_fd(pReader->mark_fd, \
    get_mark_filename_by_reader, pReader, buff, len)) == 0)
  {
    pReader->last_scan_rows = pReader->scan_row_count;
    pReader->last_sync_rows = pReader->sync_row_count;

    logInfo("file: "__FILE__", line: %d, " \
              "write server:%s mark file success, offset:%d", \
              __LINE__, pReader->storage_id, pReader->binlog_offset);
        
  }
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-08-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员升级之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
最强大的 CSS 布局 —— Grid 布局
Grid 布局即网格布局,是一种新的 CSS 布局模型,比较擅长将一个页面划分为几个主要区域,以及定义这些区域的大小、位置、层次等关系。号称是最强大的的 CSS 布局方案,是目前唯一一种 CSS 二维布局。利用 Grid 布局,我们可以轻松实现类似下图布局,演示地址[1]
GopalFeng
2020/09/24
16.3K0
最强大的 CSS 布局 —— Grid 布局
Grid网格布局入门
它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局。以前,只能通过复杂的 CSS 框架达到的效果,现在浏览器内置了。
javascript.shop
2019/09/04
2.3K1
Grid网格布局入门
【CSS】最强大的布局之grid布局精讲
轮播图swiper框架的基本使用 【Transform3D】转换详解(看完就会) 【css动画】移动的小车
坚毅的小解同志的前端社区
2022/11/28
3.1K0
【CSS】最强大的布局之grid布局精讲
【图片版】CSS网格布局(Grid)完全教程
CSS网格布局(Grid)是一套二维的页面布局系统,它的出现将完全颠覆页面布局的传统方式。传统的CSS页面布局 一直不够理想。包括table布局、浮动、定位及内联块等方式,从本质上都是Hack的方式,并且遗漏了一些重要的功能(比如:垂直居中)。Flexbox的出现部分解决了上述问题,但Flex布局是为了解决简单的一维布局,适用于页面局部布局。而Grid天然就是为了解决复杂的二维布局而出现的,适用页面的整体布局。在实际工作中,Grid和Flexbox不但不矛盾,而且还能很好的结合使用。做为WEB程序员,我们在页面布局问题上都付出过努力,也将不断探索新的方案。而Grid是第一个专门为布局问题而生的CSS模块,我们有理由对Grid充满期待。
毛瑞
2018/05/02
5.3K0
【图片版】CSS网格布局(Grid)完全教程
[译]二维布局:Grid Layout
CSS Grid Layout 是 CSS 中最强大的布局系统。不像 flexbox 那样的一维系统,它是一个二维系统,可以同时处理列和行。您可以通过将规则应用到父元素来使用 Grid Layout。
码农小余
2022/06/16
4.7K0
[译]二维布局:Grid Layout
CSS(七)
Grid 布局是 CSS 中最强大的布局系统。 Grid 布局是一个二维布局系统,意味着它可以处理列和行,不像 Flexbox 主要是一维布局系统。通过将 CSS 规则应用于父元素(称为 grid container)和子元素(称为 grid items),我们就可以使用网格布局。
1ess
2021/10/29
5430
CSS(七)
图解CSS布局(一)- Grid布局
Grid 布局是将容器划分成"行"和"列",产生单元格,然后指定"项目所在"的单元格,可以看作是二维布局,也是唯一的二维布局方案,利用grid布局可以很轻松的实现很多的网页布局
小丞同学
2021/08/16
2.1K0
万字总结 CSS 布局
本文总结了主流的几种 CSS 的布局方法,无论你是一个想要学习 CSS 布局的新手,还是一个比较有经验但想要进一步巩固与了解最新CSS布局知识的前端开发者,这篇指南都能帮你全面了解如今CSS布局发展的现状。
用户8921923
2022/10/24
6.1K0
万字总结 CSS 布局
grid网格布局
​ 距今来看已经十多年了,确确实实占据了前端布局中很大的地位,相比大家对flex都很熟悉,所以今天我们的主角就是-------> Grid
Snine
2022/02/11
2.1K0
grid网格布局
Web前端学习 第2章 网页重构16 grid布局
grid容器的水平区域成为行(row),垂直区域成为列(column),行与列之间的较差与是单元格(cell),划分网格的线成为网格线(gird line),了解了这些基本概念之后,就可以开始用相应的css属性设置grid容器中的项目了。
学习猿地
2020/06/15
1K0
Web前端学习 第2章 网页重构16 grid布局
Grid布局详解:打造完美的网页布局
随着Web技术的不断发展,网页布局也在不断地改进和完善,其中Grid布局是最受欢迎的一种布局方式。它是一种基于网格线的布局方式,可以轻松地实现复杂的网页布局,而且还具有很强的可读性和可维护性。
Front_Yue
2023/12/22
1.7K0
Grid布局详解:打造完美的网页布局
CSS 中的 Grid 布局 完全指南
Grid 是一个基于二维网格布局的系统,有了它我们可以非常方便的实现过去很复杂布局,无需再使用float, inline-block, position 这些本质上是 hack 的方法。
羽月
2022/10/08
4.2K0
CSS 中的 Grid 布局 完全指南
10分钟理解CSS3 Grid
上一篇文章我们介绍了 css3 flexbox,今天我们再来说说css3的另外一个强大的功能:Grid。 Grid做前端的同学应该都很熟悉了,翻译成中文为“栅格”,用过bootstrap、semantic ui、ant design的同学肯定都了解grid layout(删格布局),以往css框架中的grid布局一般是通过float和百分比的宽度实现的,这种实现有几种缺点:
MudOnTire
2019/05/26
7910
CSS Flexbox与Grid:构建响应式布局的艺术
开启Flex布局模式。将一个元素设置为Flex容器,其直接子元素将成为Flex项目。
天涯学馆
2024/05/22
5370
CSS Flexbox与Grid:构建响应式布局的艺术
grid布局—让css变得更简单
通过将属性display的值设为grid,使 HTML 元素变为网格容器。在 CSS 网格中,父元素称为容器(container),它的子元素称为项(items)。
_kyle
2020/08/24
5.7K0
grid布局—让css变得更简单
grid 布局的使用
grid 布局的使用    css 网格布局,是一种二维布局系统。    浏览器支持情况:老旧浏览器不支持,    概念: 网格容器。元素应用dispalay:grid,它是所有网格项的父元素。       <div class="container">          <div class="item item-1"></div>         <div class="item item-2"></div>         <div class="item item-3"></div>       
用户1197315
2018/01/22
1.7K0
[CSS] 栅格化布局
栅格化布局帮助你更容易构建复杂的网页设计。它会将HTML元素转换为网格的容器(有行有列)。你可以在网格里面添加你想要的子元素。
Jimmy_is_jimmy
2020/10/29
1.3K0
CSS Grid 新手入门
另外,下面一段话摘自A Complete Guide to Grid,对于CSS Grid会有更加清楚地释义
糊糊糊糊糊了
2018/09/28
2.3K0
CSS Grid 新手入门
grid布局了解一下
首先,看一张图,了解一下容器和项目(不难理解,容器就是包在外层的元素,项目就是内部的元素)
用户4793865
2023/01/12
5200
grid布局了解一下
GRID布局
目前CSS布局方案中,网格布局可以算得上是最强大的布局方案了。它可以将网页分为一个个网格,然后利用这些网格组合做出各种各样的布局。Grid布局与Flex布局有一定的相似性,都可以指定容器内部多个成员的位置。不同之处在于,Flex布局是轴线布局,只能指定成员针对轴线的位置,可以看作是一维布局。Grid布局则是将容器划分成行和列,产生单元格,然后指定成员所在的单元格,可以看作是二维布局。
WindRunnerMax
2020/08/27
1.5K0
相关推荐
最强大的 CSS 布局 —— Grid 布局
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验