文件布局

文件布局可控制如何把文件内容映射到各 Ceph RADOS 对象,你可以用虚拟扩展属性或 xattrs 来读、写某一文件的布局。

布局 xattrs 的名字取决于此文件是常规文件还是目录,常规文件的布局 xattrs 叫作 ceph.file.layout 、目录的布局 xattrs 叫作 ceph.dir.layout 。因此后续实例中若用的是 ceph.file.layout ,处理目录时就要替换为 dir

Tip

你的 Linux 发行版也许默认没提供操作 xattrs 的命令,所需软件包通常是 attr

布局字段

pool

字符串,可指定 ID 或名字。它是文件的数据对象所在的 RADOS 存储池。

pool_namespace

字符串。在数据存储池内,对象应该写入哪个 RADOS 命名空间,默认为空(即默认命名空间)。

stripe_unit

字节数、整数。一个文件的数据块按照此尺寸(字节)像 RAID 0 一样分布。一文件所有条带单元的尺寸一样,最后一个条带单元通常不完整——即它包含文件末尾的数据、还有数据末端到固定条带单元尺寸之间的未使用“空间”。

stripe_count

整数。组成 RAID 0 “条带”数据的连续条带单元数量。

object_size

整数个字节。文件数据按此尺寸分块为 RADOS 对象。

Tip

RADOS 会确保对象的尺寸是个可配置的限量:如果你自行增大 CephFS 对象尺寸,超过了那个限量,那么写入可能不会成功。对应的 OSD 选项是 osd_max_object_size ,默认值是 128MB 。 RADOS 对象过于大可能会影响集群的平稳运行,所以不建议对象尺寸限量超过默认值。

getfattr 读取布局

读出的布局信息表示为单个字符串:

$ touch file
$ getfattr -n ceph.file.layout file
# file: file
ceph.file.layout="stripe_unit=4194304 stripe_count=1 object_size=4194304 pool=cephfs_data"

读取单个布局字段:

$ getfattr -n ceph.file.layout.pool file
# file: file
ceph.file.layout.pool="cephfs_data"
$ getfattr -n ceph.file.layout.stripe_unit file
# file: file
ceph.file.layout.stripe_unit="4194304"
$ getfattr -n ceph.file.layout.stripe_count file
# file: file
ceph.file.layout.stripe_count="1"
$ getfattr -n ceph.file.layout.object_size file
# file: file
ceph.file.layout.object_size="4194304"

Note

读取布局时,存储池通常是以名字标识的。然而在极少数情况下,如存储池刚创建时,可能会输出 ID 。

目录只有经过定制才会有显式的布局,如果从没更改过,那么读取其布局时就会失败:这表明它会继承父目录的显式布局设置。

$ mkdir dir
$ getfattr -n ceph.dir.layout dir
dir: ceph.dir.layout: No such attribute
$ setfattr -n ceph.dir.layout.stripe_count -v 2 dir
$ getfattr -n ceph.dir.layout dir
# file: dir
ceph.dir.layout="stripe_unit=4194304 stripe_count=2 object_size=4194304 pool=cephfs_data"

setfattr 设置布局

布局字段可用 setfattr 修改:

$ ceph osd lspools
0 rbd
1 cephfs_data
2 cephfs_metadata

$ setfattr -n ceph.file.layout.stripe_unit -v 1048576 file2
$ setfattr -n ceph.file.layout.stripe_count -v 8 file2
$ setfattr -n ceph.file.layout.object_size -v 10485760 file2
$ setfattr -n ceph.file.layout.pool -v 1 file2  # Setting pool by ID
$ setfattr -n ceph.file.layout.pool -v cephfs_data file2  # Setting pool by name

Note

setfattr 命令修改文件的布局字段时,此文件必须是空的,否则会报错。

# 创建空文件
$ touch file1
# 可如愿修改布局字段
$ setfattr -n ceph.file.layout.stripe_count -v 3 file1

# 向文件写入些东西
$ echo "hello world" > file1
$ setfattr -n ceph.file.layout.stripe_count -v 4 file1
setfattr: file1: Directory not empty

清除布局

如果你想删除某一目录的布局,还继承上级的布局,可以这样:

setfattr -x ceph.dir.layout mydir

类似地,如果你已经设置了 pool_namespace 属性,又想让布局改回默认命名空间:

# 创建个目录,并给它设置命名空间
mkdir mydir
setfattr -n ceph.dir.layout.pool_namespace -v foons mydir
getfattr -n ceph.dir.layout mydir
ceph.dir.layout="stripe_unit=4194304 stripe_count=1 object_size=4194304 pool=cephfs_data_a pool_namespace=foons"

# 清除目录布局的命名空间
setfattr -x ceph.dir.layout.pool_namespace mydir
getfattr -n ceph.dir.layout mydir
ceph.dir.layout="stripe_unit=4194304 stripe_count=1 object_size=4194304 pool=cephfs_data_a"

布局的继承

文件会在创建时继承其父目录的布局,然而之后对父目录布局的更改不会影响其子孙。

$ getfattr -n ceph.dir.layout dir
# file: dir
ceph.dir.layout="stripe_unit=4194304 stripe_count=2 object_size=4194304 pool=cephfs_data"

# 证实 file1 继承了其父的布局
$ touch dir/file1
$ getfattr -n ceph.file.layout dir/file1
# file: dir/file1
ceph.file.layout="stripe_unit=4194304 stripe_count=2 object_size=4194304 pool=cephfs_data"

# 现在更改目录布局,然后再创建第二个文件
$ setfattr -n ceph.dir.layout.stripe_count -v 4 dir
$ touch dir/file2

# 证实 file1 的布局未变
$ getfattr -n ceph.file.layout dir/file1
# file: dir/file1
ceph.file.layout="stripe_unit=4194304 stripe_count=2 object_size=4194304 pool=cephfs_data"

# 但 file2 继承了父目录的新布局
$ getfattr -n ceph.file.layout dir/file2
# file: dir/file2
ceph.file.layout="stripe_unit=4194304 stripe_count=4 object_size=4194304 pool=cephfs_data"

如果中层目录没有设置布局,那么内层目录中创建的文件也会继承此目录的布局:

$ getfattr -n ceph.dir.layout dir
# file: dir
ceph.dir.layout="stripe_unit=4194304 stripe_count=4 object_size=4194304 pool=cephfs_data"
$ mkdir dir/childdir
$ getfattr -n ceph.dir.layout dir/childdir
dir/childdir: ceph.dir.layout: No such attribute
$ touch dir/childdir/grandchild
$ getfattr -n ceph.file.layout dir/childdir/grandchild
# file: dir/childdir/grandchild
ceph.file.layout="stripe_unit=4194304 stripe_count=4 object_size=4194304 pool=cephfs_data"

把数据存储池加入 MDS

要通过 CephFS 使用一个存储池,你必须把它加入元数据服务器。

$ ceph fs add_data_pool cephfs cephfs_data_ssd
$ ceph fs ls  # Pool should now show up
.... data pools: [cephfs_data cephfs_data_ssd ]

确保你的 cephx 密钥允许客户端访问这个新存储池。

然后就能在 CephFS 内更新一个目录的布局了,以使用刚加上的存储池:

$ mkdir /mnt/cephfs/myssddir
$ setfattr -n ceph.dir.layout.pool -v cephfs_data_ssd /mnt/cephfs/myssddir

此后,在那个目录内新创建的文件都会继承它的布局、并把它们的数据放入你新加的存储池。

你也许注意到了,主数据存储池(传递给 fs new 的那个)内的对象计数仍在继续增加,即使创建的文件位于你后加的存储池内。这很正常:文件的数据存储于由布局指定的存储池内,但是所有文件的元数据还都存储在主数据存储池内,数量很小。