ceph的数据存储之路(11)----- cephfs 文件系统

cephfs 文件系统

cephfs 文件系统的使用:

1.首先你要搭建一个ceph集群。如何搭建ceph集群在前面已经介绍过了。若是要使用cephfs文件系统,则必需要有管理文件元数据的mds节点。node

2.在集群上建立文件系统,python

root@cephmon:~/ceph/ceph-0.94.2/src# ./ceph fs new cephfs2 cephfs_metadata cephfs_data
*** DEVELOPER MODE: setting PATH, PYTHONPATH and LD_LIBRARY_PATH ***
new fs with metadata pool 2 and data pool 1

fs new 表示须要建立一个新的文件系统。linux

cephfs2 表示新的文件系统的名字叫作cephfs2。c#

cephfs_metadata 表示文件系统元数据保存信息的存储pool。缓存

cephfs_data 表示文件系统的数据保存信息的存储pool。网络

若是我再新建一个文件系统cephfs3,则会出现以下提示:数据结构

root@cephmon:~/ceph/ceph-0.94.2/src# ./ceph fs new cephfs3 fsmeta fsdata
*** DEVELOPER MODE: setting PATH, PYTHONPATH and LD_LIBRARY_PATH ***
Error EINVAL: A filesystem already exists, use `ceph fs rm` if you wish to delete it

这就代表 ceph集群上只能建立一个文件系统。函数

 

3.客户端上的挂载:工具

说明:网络文件系统想要使用必需要在本地进行mount操做,mount操做后,便可 像本地目录同样操做。ceph的rbd 块设备在使用时提供了两种使用方式 librbd和kernel rbd,一样的cephfs也提供了两种使用方式,一种是基于用户空间的文件系统fuse使用,一个是基于内核空间的ceph 挂载使用,各有利弊,fuse使用和修改上更为方便,可是性能不得不说略差与kernel的使用方式,这尤为是表如今各个公司竞标pk时的表现。性能

须要得到secret key才能与集群进行对话。cat keyring文件

[mon.]
	key = AQCs8mxXxs5GNhAAUKCQuZ4XxBmeTfcEdIphCw==
	caps mon = "allow *"
[client.admin]
	key = AQCs8mxXrUwTNxAARQarCkQwsBYh7pyF4cUZsQ==
	auid = 0
	caps mds = "allow *"
	caps mon = "allow *"
	caps osd = "allow *"
得到admin用户的 key ,AQCs8mxXrUwTNxAARQarCkQwsBYh7pyF4cUZsQ==

在本地建立一个用于挂载的节点 mkdir  /mnt/cephfs

a、使用kernel形式进行挂载:在客户机上

mount   -t   ceph    mon_ipaddr:port:/    /mnt/cephfs   -o    name=admin,secret= AQCs8mxXrUwTNxAARQarCkQwsBYh7pyF4cUZsQ==

挂载后能够查询:直接输入mount命令
192.168.121.226:6789:/    on    /mnt/cephfs      type      ceph (rw, relatime  , name =  admin ,secret=<hidden>,nodcache)

b、使用fuse形式进行挂载:

使用ceph fuse须要先进行安装ceph fuse工具,收先先查找下安装包

root@cephmon:~/ceph/ceph-0.94.2/src# apt-cache search ceph-fuse
ceph-fuse - FUSE-based client for the Ceph distributed file system
ceph-fuse-dbg - debugging symbols for ceph-fuse

这里能够发现,能够直接安装ceph-fuse。
root@cephmon:~/ceph/ceph-0.94.2/src# apt-get install ceph-fuse 
Reading package lists... Done
Building dependency tree       
Reading state information... Done
………………..
update-initramfs: deferring update (trigger activated)
Processing triggers for initramfs-tools ...
update-initramfs: Generating /boot/initrd.img-3.10.36-openstack-amd64

root@cephmon:~/ceph/ceph-0.94.2/src#c eph-fuse    –k    ./keyring   -m 192.168.121.226:6789   /mnt/cephfs
ceph-fuse[4743]: starting ceph client 
ceph-fuse[4743]: starting fuse
root@cephmon:~/ceph/ceph-0.94.2/src# df
Filesystem                                             1K-blocks     Used Available Use% Mounted on
rootfs                                                 101016992 16514904  79347684  18% /
udev                                                       10240        0     10240   0% /dev
tmpfs                                                    1002252      328   1001924   1% /run
/dev/disk/by-uuid/6a5b4c32-fd65-4e62-a953-102b0a3fe9ea 101016992 16514904  79347684  18% /
tmpfs                                                       5120        0      5120   0% /run/lock
tmpfs                                                    2423300        0   2423300   0% /run/shm
ceph-fuse                                              303050752 65007616 238043136  22% /mnt/cephfs
root@cephmon:~/ceph/ceph-0.94.2/src#

这里能够看到已经mount成功了,能够正常使用/mnt/cephfs目录进行存储。

 

卸载:

umount    /mnt/cephfs

cephfs的两种使用方法已经交代完毕,下面就来具体说说文件系统那点事儿吧

文件系统从何提及呢?

linux文件系统简介

cephfs的 新建立一个文件系统 过程

cephfs的mount流程

cephfs的 建立目录或者文件的流程。

这里我想结合linux文件系统来聊一聊cephfs,因此在接下来的介绍中也都使用了linux kernel的方式对cephfs进行挂载使用。固然这里面设计到了一些kernel的知识,参考的linux kernel代码为4.1.4 ceph 代码0.94.2。

 

linux 文件系统简介:

在linux系统中有着很重要的一句话就是,一切皆是文件,可见文件的重要性,因此文件系统是重要中的重要了。这里存在一个重要的角色那就是文件系统的tree。

全部的文件系统都有一个tree,tree从一个主干开始(也叫作root根),而后能够在这个上长出叶子(文件file)或者枝条(目录dir)。而后枝条上还能够继续长出叶子或者枝条。

在linux启动之初,系统还未发现可用的磁盘,这时会先建立一个叫作rootfs的内存文件系统,这个文件系统伴随内存的生而生,死而死。这个rootfs建立了linux文件的第一个根 “\”目录。

可是为何在系统启动以后,咱们去查看mount状况时,却没有发现任何关于rootfs的信息呢?

咱们使用mount命令查看,发现mount的并非rootfs信息。这个后面看完天然会明白

 

好了,这时有了这个rootfs的根目录了,这样就能够加载其余的文件系统了。

这里先说明下,磁盘在使用以前会进行分区,每一个分区都须要创建一个文件系统,这些文件系统能够type相同也能够不一样,在每个磁盘分区创建独立的文件系统来管理这部分空间,可是他们是各自独立的孤岛,由于还没加入到内存中进行管理,因此他们这些文件系统还不能使用。

 

当磁盘上线后,会使用工具对磁盘进行分区,在分区上创建文件系统,而后对分区sda(这里假设该分区叫作sda)进行mount 到 “/“目录, 什么是mount? 哈哈能够自行百度。

mount操做以后,对于“/“目录的操做都转化为对sda的操做。

而且能够在“/“ 中建立其余的目录,而后把磁盘的剩余分区进行mount操做。

如上图,把分区1mount在“/“目录上,在”/“目录中建立几个目录 /home,/var,/tmp,/usr,/bin,/boot,/sbin等目录。而后分区2挂载到/home目录,这样使用/home目录存储文件时,数据所有都保存在分区2上,同理挂载分区3到/var目录,挂载分区4到/tmp目录。剩余的目录/usr,/bin,/boot,/sbin没有被挂载其余的磁盘,因此他们继续使用分区1的空间

固然除了须要理解上面这部份内容,你还须要去看看 linux vfs系统,linux系统调用,linux的某种本机文件系统(好比简单的ext2文件系统原理)。

固然假设上面举例的这几部分你都了解过,能够继续下面的内容。

 

ceph文件系统

在monitor节点上会时刻的mds节点发送过来心跳信息 ,当接收到心跳信息后,在monitor上会对mdsmap进行比较,可是因为尚未创建文件系统,因此mds仍然再也不mdsmap中,这样monitor每次收到mds发送的心跳信息后都暂不作任何处理。

mds节点上运行这ceph_mds程序,这个程序目前负责收发心跳和信息传递等。当ceph_mds接受到monitor节点的回应后,会查是否mdsmap会发生改变。若是mds发生变化则调用handle_mds_map进行处理。

 

在ceph集群上建立文件系统:

运行命令 ceph   fs   new   cephfs   metadatapool  datapool

命令被发送到了mdsmonitor上,在这里进行处理。MDSMonitor::management_command,该函数用来处理文件系统的建立和删除

首先是prefix==fs new,建立一个新的文件系统。

建立一个新的文件系统固然要有不少的检查了。

a、metedata_pool 是否存在。固然对这些pool仍是有要求的,不能是tier类型的pool。

b、data_pool是否存在。固然对这些pool仍是有要求的,不能是tier类型的pool。

c、fs name是否与已经存在的文件系统重名。

d、若是已经存在了文件系统,在建立第二个文件系统时,失败处理。

1232:看的出,这里就是表明全部前面的检查都经过了。

1233:新建立一个MDSMap。

1235:用这个MDSMap去更新 pending_mdsmap。

1236:增长版本号

1238:create_new_fs,这里开始建立新的fs,可是仅仅是更新这个pending_mdsmap。

0085:建立一个文件系统开始。

0087:mdsmap.enable 表示文件系统正式生效。

0088:mdsmap.fs_name 表示文件系统的名字。

剩余的见名知意。再也不多说。

这个时候新创建了一个pending_map 而且对pending_mdsmap的epoch作了更新。

那么MDSMonitor会对这个pending_mdsmap与MDSMap进行检查,版本出现了更新,会推送新的MDSmap到mds上。这里会发生了一些mdsmap提议选举投票之类的操做,将mds加入到MDSMap中,将pending_mdsmap的信息替换到MDSMap上,而后将MDSMap推向相应的mds上。这里再也不细讲这个过程(由于我也不是特别了解),首先在mds上线后向mon发送消息,而且验证mds的权限。而后mon回复mds,告知mds拥有这个集群的权限。mds启动后开始发送mon_subscribe消息给mon,mon将mdsmap,monmap,osdmap等map信息回复给mds。mds拥有这些信息开始处理,好比handle_mds_map就是专门用来处理mdsmap的流程。mds发现了mdsmap中没有本身,开始尝试加入mdsmap中,开始发送消息请求mdsbeacon,交给mon处理,而后在发还给mds信息,则mds开始了本身的状态转化 boot -> standby -> creating -> active.这些状态都在handle_mds_map中找到踪影。

 

在handle_mds_map中有一个重要的步骤—建立root目录。以前也讲过一个文件系统的根本就是这个root目录。root是全部目录的基础。

 

MDS::handle_mds_map(MMDSMap *m) – >boot_create();

1877:若是文件系统的根目录保存在 我本身的mds上,则建立根目录。因为mds集群的扩展,根目录会主要的保存在一个primary mds上和其余几个stary mds上。因此建立时须要判断是不是属于本mds的。

1880:这里开始建立一个根目录,因为根目录的名字是“\”因此使用create_empty_hierarchy()。

1884:这里还须要建立一个个人目录,由于不是全部的目录都会保存在本mds上,因此本地要管理本身的目录。create_mydir_hierarchy()。

 

create_empty_hierarchy 和 create_mydir_hierarchy之间的区别不大,无非是一个建立“/”目录,另一个建立“mds%s”。来看看empty_hierarchy()函数。

0405:建立root,这里的类型的CInode。文件系统中全部的文件或者目录都有两个最重要的东西inode和dentry。inode中定义了文件的操做相关处理和数据管理,dentry是为了表达目录层级关系,可用于路径的搜索。

0408:这里用于获取目录分片CDir的,可能一个目录过于庞大或者成为热点目录的时候,就要对这个目录进行切片,分散到不一样的mds上面去。这个就是获取固然mds上的分片。

 

继续来看create_root_inode();用于建立root目录的CInode节点。

create_root_inode()  - >  create_system_inode(MDS_INO_ROOT, S_IFDIR|0755); MDS_INO_ROOT是一个宏,表明这个inode的编号,值为1。

0385:参数ino就是上面说的MDS_INO_ROOT=1,mode就是目录的权限。

0388:建立一个新的CInode。这个CInode与当前的MDCache相关。

0389:CInode与ino、mode等进行初始化操做。绑定。

0390:在mds上,不少的文件节点inode都保存在内存中,这些inode由MDCache进行管理。在MDCache中有个inode_map用于保存全部的inode。若是这个inode是root或者mydir 在MDCache中会有指针特别指出这些inode,方便用于查找。

如今已经在mds上建立了cephfs的根目录了,就等待客户端的mount操做。

客户端的mount操做,这里客户端mount操做采用直接mount形式,采用kernel mount的方式,fuse mount的操做原理差很少相同。为了简化描述,采用kernel mount的形式。

在cephfs kernel mount使用前,你要确保你的内核有cephfs模块。ceph模块的代码再也不ceph源码包里,并且在linux kernel的源码包里,因此你能够去下载完成kernel包(https://www.kernel.org/)   有 了kernel源码包就能够分析下面的代码了

来看下 ceph 内核模块加载的过程。

1041:ceph内核模块加载的初始化函数。

1043:申请和初始化须要用到的cache。这个cache是用于分配inode\file\cap\dentry的高速缓存。

1047:初始文件锁之类的。

1048:初始化cephfs系统的 文件和目录的 attr属性的操做方法。

1049:文件系统快照初始化。

1052:这里是将文件系统ceph_fs_type进行注册。linux内核中全部的文件系统type结构都会经过一个链表file_systems链接起来。查找时遍历链表file_systems便可。那么接下来看看 ceph_fs_type中都定义了什么?

1032:定义ceph_fs_type类型。

1033:模块的全部者。

1034:文件系统的名字。后续在mount时  -t参数指定的名字。

1035:定义这个ceph文件系统进行mount时的操做。 那是若是调用到这里的呢?

 

来看看cephfs是怎么进行kernel mount的。

mount –t ceph mon_ip_addr:port:\   \mnt\cephfs  -o name=admin,secret=key

mount 命令 经过系统调用系统调用sys_mount 带着参数来到内核,解析-t 参数是叫作ceph,因此在内核的file_systems链表中查找名字叫作ceph类型的文件系统,而后能够找到结构ceph_fs_type。在这个type中找到能够ceph_mount操做。而后进入ceph_mount中,对ceph文件系统进行真正的mount操做。

接下来看看ceph_mount中作了什么

0944:开始对参数进行解析,解析出fsopt用于mount的基本信息,具体能够查看数据结构。opt是ceph集群的相关信息。dev_name用于mount的目录名字,path用于mount到客户端本机的路径名(能够是客户端机器中的绝对路径或者相对路径)。

0952:建立fs客户端,这里面包括与mon通讯的monclient 与osd通讯的osdclient信息。

0960:建立fsc中的mdsclient。与mds进行通讯的结构,这里叫作mdsc。

 

创建了与集群通讯相关的操做,接下来就是本地初始化了。在本地创建superblock。啥是superblock?能够自行百度。。。。superblock是文件系统中最高的管理者。保存了不少重要的信息。看看superblock的建立。

0971:试图获取sb,若是获取sb失败,则建立新的sb。这里对sb的初始化等操做放在ceph_set_super这个参数中。最重要的是全部的文件系统sb数据结构都是同样的,可是sb->data是能够保存本身私有的数据。ceph_fs的sb->data 保存的就是上面介绍的与ceph集群通讯fsc结构。

0978:查看sb中保存的fsc与当前的fsc是否相同。

 

那么看看ceph_set_super中作了什么,他要对sb负责。

0843:从sb->data中恢复出fsc的结构。

0848:设置flags的相关信息。

0849:设置sb的最大字节数

0851:设置这个xattr的操做方法。  这个很是重要

0855:设置了s_op的操做方法。该方法由ceph_super_ops实现。 这个很是重要,很是重要。很是重要。

0856:设置其余的操做方法,该方法又ceph_export_ops实现。很是重要。

这时咱们先看看ceph_super_ops的定义吧。

0693:定义操做方法ceph_super_ops

0694:定义ceph如何申请一个inode。

0695:定义ceph如何销毁一个inode。

其余的以此类推咯,就是该文件系统想要和inode的相关操做从这查找就能够。

 

sb 掌握了这些信息之后,咱们再回到ceph_mount中继续下面的操做。

接下来进行,ceph_real_mount操做,这个适合本地文件系统mount操做的处理,让ceph文件系统无缝的链接在客户端本地的文件系统上。

 

看一看,瞧一瞧 ceph_real_mount作了哪些见不得人的事儿。

ceph_real_mount内部实现。

0784:创建与mon、osd的集群链接。保证req的发送。

0789:在本地打开ceph的root目录,返回值为这个目录 dentry类型的root目录。

这里由客户端打开root目录就算是mount结束了。那主要的流程是要看看如何打开这个root目录。

0720:这里建立一个请求mds的req。操做码是CEPH_MDS_OP_GETATTR,能够发给任意一个mds。

0724:设置这个req请求的路径。这个路径就是“/”根目录。

0730~0735:设置req,初始化一系列的值。

0736:向mds发送这个req。这是一个同步的下发的接口,会在里面等待命令的完成。

0739:在mds返回的消息中可知,这个已经打开inode。

0745:建立一个dentry 与这个inode匹配。而后返回这个root。

以后会将这个fsc->sb->s_root = root; 便于下次查找。

 

好的,如今算是这个文件系统建立完成,而且mount成功。来看看相关的信息

查看mount信息:

查看空间信息:

这里还要说明下请求是怎么来处理的,又是怎么 回到客户端的。这个中间经历了不少过程。

 

咱们在打开root目录时,发送这样的一个请求,请求的操做码是CEPH_MDS_OP_GETATTR ,以下图

该请求通过客户端的封装,经过ceph_mdsc_do_request统一发送到mds上。这个消息发送传递这一块 就不细说了,能够了解这一块,理解ceph的通讯协议模式,数据包格式等信息。可是这个不是本文的重点,因此很少说,想了解的能够研究下这部分代码。

再来看mds上的处理(ceph代码),固然前面有一些消息解析的动做,可是这些先不讲,只来看看消息被解析后的处理。mds上处理消息的接口为dispatch_client_request。在该函数里查找对的CEPH_MDS_OP_GETATTR处理。

1473:这里对应处理CEPH_MDS_OP_GETATTR的函数为handle_client_getattr();在这个函数里天然就是怎么来解决打开root目录的操做了。最终的目标就是返回root目录的Inode的相关信息。而后调用respond_to_request() -> reply_client_request() -> client_con->send_message(reply); 将消息回复给客户端。在respond_to_request()函数中声明这样一条消息MClientReply,该消息继承与Message,并且这个Message中使用了CEPH_MSG_CLIENT_REPLY进行构造。因此在客户端中使用该操做码解析。

 

客户端用于处理消息应答的接口handle_reply()(linux内核代码)。该接口适用于CEPH_MSG_CLIENT_REPLY 操做码,即客户端向mds发送消息,而后mds使用该操做码回复消息。最后经过接口handle_reply()处理消息。

 

在handle_reply()中,须要对打开的节点inode进行处理。首先就是要根据你的返回信息,而后在客户端本地进行缓存。调用 handle_reply() -> ceph_fill_trace() -> fill_inode()  

0787:在fill_node中解析节点的类型。

0823:若是节点是S_IFDIR类型,也就是目录类型的文件。

0824:对Inode的i_op 项赋值为 ceph_dir_iops;

0825:对Inode的i_fop项赋值为ceph_dir_fops;

0829~0833 :对其目录文件的其余信息进行解读,包括文件,目录数量等。

 

这几步很是的重要。一个是拿到了目录中已经包含的全部信息。另外一个是该步定义了这个目录操做的方法 i_op 和 i_fop。

 

i_op 的原型为inode_operations。表示inode节点的定义操做列表。

i_fop的原型为file_operations。表示inode节点的 默认定义操做列表。

 

简单的看下i_op中定义了什么?

1393:定义ceph_dir_iops的操做方法。

1394:定义目录中子节点的查找方法。若是要调用该节点的lookup方法会转嫁到ceph_lookup上进行处理。同理 一下的其余方法也会被转嫁。

1395:定义该目录的权限处理方法----ceph_permission。

1396:定义该目录的属性获取方法----ceph_getattr

1397:定义该目录的属性设置方法----ceph_setattr

1398:定义该目录的拓展属性获取方法----ceph_getxattr。xattr用于存储inode以外的信息,通常使用key/value 形式。

1399:定义该目录的拓展属性设置方法----ceph_setxattr

1400:定义该目录的拓展属性列举方法----ceph_listxattr

1401:定义该目录的拓展属性移除方法----ceph_removexattr

1402:定义该目录的acl属性获取方法----ceph_getacl

1403:定义该目录的acl属性设置方法----ceph_setacl

1404:定义该目录中建立子节点的方法----ceph_mknod

1405:定义该目录建立符号链接的方法----ceph_symlink

1406:定义该目录建立子目录的方法----ceph_mkdir

1407:定义该目录建立硬连接的方法----ceph_link

1408:定义该目录解除硬连接的方法----ceph_unlink

1409:定义该目录删除rmdir的方法 ----ceph_unlink

1410:定义该目录重命名的方法----ceph_rename

1411:定义该目录建立文件的方法 ----ceph_create

1412:定义该目录原子打开的方法 ----ceph_atomic_open

 

这样打开这个root的inode后,这个inode上携带者这么多的操做方法。而后inode返回到open的操做open_root_dentry()中。

总结:

前面叙述的东西有点多。在这里简单复述下:

一、在monitor上先运行了cephfs的建立命令,cephfs 建立文件系统,建立文件系统后。而后mds加入mdsmap中,将新的mdsmap发送给mds处理。而后在mds上建立文件系统的根root目录。

二、保证客户端的机器上有加载ceph的内核模块。在ceph内核模块加载的时候,就将cephfs文件系统注册到系统中。

三、在客户端进行mount操做。在客户端上首先根据ceph关键字在系统中找到这个cephfs文件系统。在cephfs文件系统中定义文件的方法。尝试打开这个root目录,组织msd_request。发送给mds进程。在mds上对root目录进行查找打开,将获取到的结果经过消息回复给client。client在对回复的解析中,根据inode->mode形式对inode赋予操做方法。

四、根据inode的操做方法,就能够对inode进行操做了。上面举例子是目录文件,那么普通文件呢,inode->i_op = &ceph_file_iops;  inode->i_fop = &ceph_file_fops;,具体的细节你能够去查看这两个操做的定义ceph_file_iops、ceph_file_fops.定义的这些操做 好比建立目录、建立文件、操做文件、读写文件、修改文件属性等。可是这些操做只是客户端上的操做,这些操做的背后都是须要与mds进行通讯,将请求传递到mds上。简单的流程图以下:

五、若是要操做一个普通文件则必须先打开这个文件,若是要操做一个目录文件则也必需要打开这个目录文件,因此无论是目录文件仍是普通文件都必须先打开这个文件,打开操做会得到这个文件的inode,这个inode中i_op或者i_fop包含了文件的操做方法,全部的文件操做都会本身去这里面查到方法。而这些方法必须与mds进行通讯才能操做元数据。mds的进程上一样定义相同操做的实现方法,最后在mds上操做元数据。后面的建立文件、建立子目录同窗们能够自行的去了解了。

六、固然 还有人喜欢使用fuse的方法mount目录,对于fuse中的实现也是相似的,有兴趣能够本身看下ceph_fuse的代码。

相关文章
相关标签/搜索