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