FastDFS合并存储的一个深层次bug排查

Stella981
• 阅读 623

FastDFS V3引入合并存储(trunk file)特性后,有用户反馈上传文件提示trunk空间被占用的问题。我在测试环境中经过一通测试,在极其偶然的情况下也能重现这个问题。然后就开始排查这个问题。

    FastDFS一个group(存储分组)内有一台storage server被选举为trunk server,用于管理和分配该组的trunk可用空间。为了高效管理trunk file的可用空间,我们使用了平衡二叉树 AVL。我们很自然地怀疑trunk空间管理和分配出了bug。于是对管理和分配trunk空间的代码前前后后做了不下10遍的代码review,直到看花眼了,也没有发现任何问题。也怀疑过AVL实现有bug,于是写单元测试对AVL进行了大量测试,也没有发现任何问题。

    这个问题很难复现,尝试通过代码review解决,但多次无功而返。合并存储这个潜在bug一直存在,导致合并存储存在风险,我心里很忐忑。

    到了2017年初,我再次尝试解决这个困扰多年的bug。既然代码排查没有任何效果,那就想办法重现吧。于是我开始通过小规模压力测试试图复现这个问题,通过上传和删除文件并行,问题终于得到复现,并且多次压测可以大概率复现。这次我盯住trunk空间分配的binlog,写脚本进行分析和排查,发现binlog记录本身是正确的。但在发生trunk空间冲突的时间点,从binlog中发现一个trunk空间被回收后几乎立即就被分配出去了,我凭直觉抓住了这条关键线索。

    继续review代码,然并卵,依然一无所获。业界有个说法我比较认可:问题能够稳定复现,就等于解决了一大半。在这么明显的线索的指引下,我终于转变了思路,开始思考这个成精的bug是否是多机环境导致的。然后。。。,经过反复推敲,我终于终于想明白了这个bug是如何被触发的了:

多机环境下操作时序问题。

    以前的排查重心在trunk空间管理,经反复验证,这块是没问题的。问题在于一个group的多台storage server均可执行文件上传操作,而FastDFS对文件操作分发(复制)到其他存储节点采用异步方式,一个trunk空间的回收和再利用机制本身没有问题,但storage server在其trunk file上存放用户上传的文件时,就可能会因时序问题而导致冲突(trunk server返回该空间可用,但因文件同步延迟导致实际还在被其他文件占用)。具体如何引起乱序和冲突的,留给各位读者去思考。

    问题的现象和原因找到后,解决方法就很容易了:指定group中的一台storage server上传文件即可。FastDFS默认配置是轮流(round robin)上传到各台storage server的,通过tracker.conf配置文件中的store_server这个参数来设置。贴一下配置示例:

# which storage server to upload file

# 0: round robin (default)

# 1: the first server order by ip address

# 2: the first server order by priority (the minimal)

# Note: if use_trunk_file set to true, must set store_server to 1 or 2

store_server=0

千万不要小看Note这一句话,其背后是满满的辛酸和血泪啊!

补充说明一下,在开启合并存储,即use_trunk_file设置为true的情况下,为了避免上述乱序问题,若store_server设置为0的话,程序将强制调整为1。

V3最后一个版本是V3.11,通过查看HISTORY文件,其发布日期为 2012-08-04。直到2017-03-29,终于修复了trunk文件空间偶发冲突的问题。贴出HISTORY文件中的changelog为证(git log也可以查到):

Version 5.10  2017-03-29

* adjust parameter store_server when use_trunk_file is true

一个修复了约5年的bug,必须记录在案。

本文分享自微信公众号 - FastDFS分享与交流(fastdfs100)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
FastDFS tracker leader机制介绍
FastDFStrackerserver不保存文件索引,只保存集群拓扑信息。按照原始设计,FastDFS多台trackerserver是完全对等的,不存在主从关系。FastDFSv3.0开始支持文件合并存储,而trunk空间管理由一个group的一台storageserver兼任,我们把这一角色称作trunkserver。trunkserv
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
mysql用户
1\.学会能按着需求创建一个帐号2\.知道连接字符串是什么样3\.密码密码怎么恢复mysql用户权限介绍mysql用户管理 !(https://oscimg.oschina.net/oscnet/368d3c1e00a0a9515545c2962660a27a080.png)!(https://oscimg.oschin
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
京东云开发者 京东云开发者
6个月前
Java服务总在半夜挂,背后的真相竟然是... | 京东云技术团队
最近有用户反馈测试环境Java服务总在凌晨00:00左右挂掉,用户反馈Java服务没有定时任务,也没有流量突增的情况,Jvm配置也合理,莫名其妙就挂了
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这