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的代碼。

相關文章
相關標籤/搜索