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系统中有着很重要的一句话就是,一切皆是文件,可见文件的重要性,因此文件系统是重要中的重要了。这里存在一个重要的角色那就是文件系统的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文件系统原理)。
固然假设上面举例的这几部分你都了解过,能够继续下面的内容。
在monitor节点上会时刻的mds节点发送过来心跳信息 ,当接收到心跳信息后,在monitor上会对mdsmap进行比较,可是因为尚未创建文件系统,因此mds仍然再也不mdsmap中,这样monitor每次收到mds发送的心跳信息后都暂不作任何处理。
mds节点上运行这ceph_mds程序,这个程序目前负责收发心跳和信息传递等。当ceph_mds接受到monitor节点的回应后,会查是否mdsmap会发生改变。若是mds发生变化则调用handle_mds_map进行处理。
运行命令 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时的操做。 那是若是调用到这里的呢?
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的代码。