Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4022330
  • 博文数量: 251
  • 博客积分: 11197
  • 博客等级: 上将
  • 技术积分: 6862
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-05 14:41
个人简介

@HUST张友东 work@taobao zyd_com@126.com

文章分类

全部博文(251)

文章存档

2014年(10)

2013年(20)

2012年(22)

2011年(74)

2010年(98)

2009年(27)

分类: 服务器与存储

2013-10-08 15:15:59

TFS新版本完成开发、测试人员能做的基本测试工作后,前段时间已经上线跑beta测试了,至今已运行近三个月。分布式系统的很多问题在上线前由于规模限制,是很难在功能测试、系统测试阶段发现的,这些问题只有当节点数达到一定规模,事件序列足够随机的时候才能暴露出来,在线上beta测试的这段时间里,由于规模效应暴露出了不少问题,当然也有些问题是系统测试不完备造成的。

均衡线程不工作

Nameserver(NS)上有单独的后台线程检测block分布情况是否均衡,如果发现不均衡的情况,就会将block从负载高的Dataserver(DS)迁移到负载低的DS(负载主要由DS容量使用情况决定)。在检测是否需要做均衡任务时,会先检查下汇报队列里是否有DS存在(汇报包括启动时的汇报和每日的定时汇报),如果有DS尚未汇报完成,就会暂时停止均衡任务(只有所有的节点都启动并且汇报block后,均衡才是有意义的,不然只有局部信息的情况下的均衡通常是不合理的);线上运行的过程中,发现有时均衡任务会停掉,调查后发现是因为有DS还在汇报队列里,而在队列里的DS早已经宕机下线,原因是有些场景下队列里元素由于状态设置错误没有被正确的移除。

问题影响及解决:偶尔需要人工干预,不影响数据可靠性。通过修改代码修复,在后台超时线程里加上定期检测汇报队列的功能,如果汇报队列里的元素超过汇报超时,则直接将其移除。

版本兼容问题

新版本的系统在过渡期,要能兼容老版本客户端的请求,包括面向应用的读写删接口,以及面向内部运维工具的各种接口(比如获取block的副本信息、获取DS上的block列表、获取block的元数据信息、修改服务器配置项等)。面向应用的基本读写删接口比较简单,而且数量少,兼容工作比较好做,测试起来也简单;但为内部运维工具提供的各种接口兼容起来就比较麻烦了,接口比较多,用的地方也多,在初期我们只对常用的工具做了兼容,上线后发现有部分接口还是存在兼容性问题。

问题影响及解决:影响内部运维工作,不影响数据可靠性。通过修改代码修复,有时候如果运维工具需求比较急,要对整个集群做紧急升级。

汇报block一致性问题

DS收到NS要求汇报block的请求时,会将拥有的block信息汇报给NS,具体做法是,先获取当前block数(加读锁访问),然后根据这个数量分配内存用于存放block元信息(不加锁),然后获取每个block的元信息(加读锁),汇报给NS;线上观察到有未初始化的block信息汇报到NS,原因是DS汇报时,获取到block数后,block列表发生了变化,有block被删除或者创建了新的block,如果是前者,则会出现有未初始化的block信息汇报到NS。

问题影响及解决:NS上会出现一些无效的block信息,不影响数据可靠性。通过修改代码,将获取block数、分配内存、获取元信息都加读锁访问解决问题,代价就是分配内存也加锁了,但从线上运行情况来看,影响并不大。

内存数据一致性问题

NS上每个block的信息里有一个server_size字段用于表示block当前副本数;一个servers的指针,用于指向副本列表,列表的内存是动态申请的,如果内存里的值不为0,说明是一个有效的副本。有一个block,其server_size为1,而实际上servers里有两个有效副本(所有集群有且仅有一例),副本信息的更新都是加锁访问的,「理论上」是不应该出现的,而且至今我们也没有出现的原因。

问题影响及解决:后台复制线程发现server_size为1,就准备复制block,而实际上block已经有足够多的副本;运维工具获取block副本信息时,NS在编码数据时,先编码server_size字段,然后就是servers里所有不为0的副本,由于这两个信息本身不一致,导致工具在解码数据时出现问题。通过重启NS让内存信息重建解决,但尚未找到直接产生的原因,也没有再出现过。

压缩block问题

TFS在删除文件时,只是给文件设置一个删除标记,具体删除由后台线程来做,当block里删除文件数超过一定比例时,就会对block进行压缩(compact),回收删除文件的存储空间。compact实际上是个「高危」的操作,因为他会改变已经存储数据的内容,一旦代码写的不正确,可能就会把block的数据搞得「面目全非」,造成无法挽回的损失。compact简单的说,就是把block里的文件重新整理一下,写到新的block里,只不过整理时,会忽略掉设置了删除标记的文件,逻辑非常简单;但由于block里文件数通常成百上千,如果逐个文件的处理,可能引起上千次磁盘IO操作,导致compact时DS负载非常高;为了解决该问题,compact时每次会从block里读取一大块数据出来(比如8M),然后整理后写到内存缓冲区,当缓冲区满时就刷新先刷到新block里,对于比较大的文件(超出缓冲区默认大小的文件),会直接读取出来写到新block里。正是由于这层优化工作,导致实际简单的逻辑变得稍复杂了些,为了能尽早发现compact的问题,在compact时会检查每个文件的完整性(通过crc校验),一旦发现有数据不完整的情况直接让DS coredump,通过这个策略,在早期就发现了一个比较严重的bug—有个代码路径上,缓冲区没被刷到磁盘就被清空了,导致数据错乱。

问题影响及修复:影响数据可靠性,甚至可能造成数据丢失。问题应尽早发现,发现有问题时,从备份集群里恢复正确的数据,并对集群内所有数据重新做校验已验证数据的可靠性。TFS存储的数据都是多机房部署的,新版本系统上线通常会先升级一个辅集群,等稳定跑一段时间后再升级主集群,即使新版本里出现严重的bug,也可以从其他机房的集群恢复数据,机房容灾对数据存储至关重要。

index文件被复用

每个block对应一个index文件,index文件是一个hash表,用于快速根据文件fileid定位文件在block内部的偏移位置。index文件的开始部分包含一个Header,Header中有一个blockid的字段,用于标识与这个index关联的block,线上发现有少量index文件里的blockid与超级块里存在不一致的情况,从而导致有部分文件访问不到的情况;而出现这种情况的DS所在的机器都有一个共同特征就是所在机器出现过异常重启的情况。在block创建时,会先根据超级块里的信息,选出一个空闲的物理块,将物理块标记为已使用,然后为block创建index文件,而在刷新超级块和index文件时msync调用使用了MS_ASYNC的标记,导致宕机时超级块和index文件刷新的顺序是不确定的(而实际语义要求超级块必须先刷到磁盘),如果index文件刷盘了,而超级块没有刷盘,则可能出现index被复用的情况。

问题影响及解决:少量文件访问不到,影响到数据可靠性。首先人工修复线上数据(量不大,用脚本很快解决),然后修改代码(msync改用MS_SYNC标记),保证超级块一定先刷盘,同时在出现index复用的情况时直接assert失败,让DS退出以尽早发现问题。

阅读(3292) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~