TFS数据服务器(DS)通过在物理块的头部存放一个BlockPrefix结构来记录逻辑块与物理块的对应关系,在DS时,会读取每一个已经使用的block,并读取block头部的信息,汇报给NS,NS通过这些信息建立逻辑块到DS的映射关系。最初,TFS使用300G的小盘,按照每个主块64M,每个扩展块2M计算,物理块的总数接近1500个,即使这些块全部使用全部使用了(正常状态下扩展块的利用率不会太高),加载这些物理块也不到30s,这个时间是可以忍受的,但目前TFS多使用2T的盘,物理块总数会在7w左右,整个加载时间会随着块的个数线性扩大,当块全部使用时,加载过程应该会到十几分钟,对于服务器来说这是无法忍受的,必须对启动过程进行优化。

DS启动过程主要耗时在于BlockFileManager::bootstrap的过程,该过程执行如下任务:

  1. 加载超级块 load_super_blk

  2. 根据超级块信息加载数据块 load_block_file (主要时间耗在这里)

  • 遍历超级块normal_bitmap中位被设置的主块
  • 读取主块头部的BlockPrefix,并据此链式加载所有的扩展块
  • 加载逻辑块的index,加载过程中会读取index头部的BlockInfo,并与物理块头部的信息进行核对

load_block_file过程中,对于每个逻辑块,要先读取其对应物理块(一个主块,多个扩展块)的头部信息,建立逻辑块和物理块的对应关系,然后再mmap对应的index信息。

逻辑块的链式加载是根据block头部的BlockPrefix进行的,BlockPrefix结构如下:

struct BlockPrefix { uint32t logic_blockid; // 该物理块对应的逻辑块号 uint32t prev_physic_blockid; // 下一个物理块的块号 uint32t next_physic_blockid; // 上一个物理块的块号,为0代表最后一个 };

Index的加载包含open、mmap操作,并读取映射内存区头部的BlockInfo信息用于汇报给ns。

对比测试,物理块的加载和index的加载谁更耗时?

测试环境:2T的盘接近满,DS上逻辑块数22134个

  1. 正常启动DS,启动过程耗时约14min。 (假设每个物理块使用了一个扩展块,包含随机读的次数应该为逻辑块数的2倍
  2. 清页缓存,使用vmtouch将index的数据加载到内存,再启动DS,启动时间约13min。
  3. 修改代码,load_block_file中的循环改为两次,分别加载block和index;清页缓存,启动DS,启动时间约13min + 6s(6s为集中加载index的时间)。

从上面的测试可以看出,时间主要消耗在物理块的加载上,因物理块的空间是预先分配的,不断的读取各个block头部会引发磁盘随机读操作。

优化方案

将分散的BlockPrefix集中存储在一个文件中(因物理块数是确定的,文件大小也就确定了,文件的空间可预先分配好),在加载过程中只集中读取该文件来建立逻辑块与物理块的对应关系,从而减少大量的随机读。

Block的头部加载和更新通过接口load_block_prefix、dump_block_prefix完成,使用新的方案,需要修改这两个接口的实现,由从block**头部读取换成从单独的文件读取,**如果发现单独没有存储BlockPrefix的文件,则仍使用原来的方案启动。

配套工具改动

  1. 在format文件系统时创建好存储BlockPrefix的文件。
  2. 增加根据block头生成单独BlockPrefix文件的工具,用于支持已上线使用的DS采用新方案启动。

优化效果

采用集中存储BlockPrefix方案,分别对已运行的DS和使用新方案创建的DS两种情况进行了测试,DS启动时间在10s以内,且DS能正常的完成读写服务请求。


ref:
2013-04-19 14:13
blog.yunnotes.net

0 回复
需要 登录 后方可回复, 如果你还没有账号你可以 注册 一个帐号。