Ceph中的序列化
2019獨角獸企業重金招聘Python工程師標準>>>
??作為主要和磁盤、網絡打交道的分布式存儲系統,序列化是最基礎的功能之一,今天我們來看一下Ceph中序列化的設計與實現。
1. Ceph序列化的方式
??序列化(ceph稱之為encode)的目的是將數據結構表示為二進制流的方式,以便通過網絡傳輸或保存在磁盤等存儲介質上,其逆過程稱之為反序列化(ceph稱之為decode)。例如對于字符串“abc”,其序列化結果為7個字節(bytes):
??03 00 00 00 61 62 63
??其中頭四個字節(03 00 00 00)表示字符串的長度為3個字符,后3個字節(61 62 63)分別是字符“abc”的ASCII碼的16進制表示。Ceph采用little-endian的序列化方式,即低地址存放最低有效字節,所以32位整數0x12345678的序列化結果為78 56 34 12。
??由于序列化在整個系統中是非常基本,非常常用的功能,Ceph將其序列化方式設計為一個同一的結構,即任意支持序列化的數據結構,都必須提供一對定義在全局命名空間上的序列化/反序列化(encode/decode)函數。例如,如果我們定義了一個結構體inode,就必須在全局命名空間中定義以下兩個方法:
??在此基礎上,序列化的使用就變得非常容易 。 即對于任意可序列化的類型T的實例instance_T,都可以通過以下語句:
::encode(instance_T, instance_bufferlist);將instance_T序列化并保存到bufferlist類的實例instance_bufferlist中。
??以下代碼演示了將一個時間戳以及一個inode序列化到一個bufferlist中。
??bufferlist類(定義于include/buffer.h)是ceph核心的緩存類,用于保存序列化結果、數據緩存、網絡通訊等,可以將bufferlist理解為一個可變長度的char數組。關于bufferlist的設計與實現,可以參考《Ceph中Bufferlist》。
??序列化后的數據可以通過反序列化方法讀取,例如以下代碼片段從一個bufferlist中反序列化一個時間戳和一個inode(前提是該bl中已經被序列化了一個utime_t和一個inode,否則會報錯)。
2 數據結構的序列化
??Ceph為其所有用到數據類型提供了序列化方法或反序列化方法,這些數據類型包括了絕大部分基礎數據類型(int、bool等)、結構體類型的序列化(ceph_mds_request_head等)、集合類型(vector、list、set、map等)、以及自定義的復雜數據類型(例如表示inode的inode_t等),以下分別介紹不同數據類型的序列化實現方式。
2.1 基本數據類型的序列化
??基本數據類型的序列化結果基本就是該類型在內存中的表示形式。基本數據類型的序列化方法使用手工編寫,定義在include/encoding.h中,包括以下類型:
在手工編寫encode方法過程中,為了避免重復代碼,借助了WRITE_RAW_ENCODER和WRITE_INTTYPE_ENCODER兩個宏。
2.2 結構體類型的序列化
??結構體類型的序列化方法與基本數據類型的序列化方法一致,即使用結構體的內存布局作為序列化的形式。在結構體定義完成后,通過調用WRITE_RAW_ENCODER宏函數生成結構體的全局encode方法,例如結構體ceph_mds_request_head相關結構實現如下。
WRITE_RAW_ENCODER(ceph_mds_request_head)
其中:
ceph_mds_request_head結構體定義在include/ceph_fs.h . WRITE_RAW_ENCODER(ceph_mds_request_head)語句位于include/types.h WRITE_RAW_ENCODER宏函數定義在include/encoding.h WRITE_RAW_ENCODER宏函數實際上是通過調用encode_raw實現的,而encode_raw調用bufferlist的append的方法,通過內存拷貝,將數據結構放入到bufferlist中。相關代碼為:
2.3 集合數據類型的序列化
??集合數據類型序列化的基本思路包括兩步:
??1) 序列化集合大小,
??2) 序列化集合內的所有元素
??例如vector<T>& v的序列化方法:
其中元素的序列化通過調用該元素的encode方法實現。
??常用集合數據類型的序列化已經由Ceph實現,位于include/encoding.h中,包括以下集合類型:
??集合類型的序列化方法皆為基于泛型(模板類)的實現方式,適用于所有泛型派生類
2.4 復雜數據類型的序列化
??除以上兩種業務無關的數據類型外,其它數據類型的序列化實現包括兩部分: 在類型內部現實encode方法,將類型內部的encode方法重定義為全局方法。
??以下以utime_t類為例:
??utime_t內部實現了encode和decode兩個方法,WRITE_CLASS_ENCODER宏函數將這兩個方法轉化為全局方法。
??WRITE_CLASS_ENCODER宏函數定義于include/encoding.h中,其定義如下:
??復雜數據結構內部的encode方法的實現方式通常是調用其內部主要數據結構的encode方法,例如utime_t類的encode方法實際上是序列化內部的tv.tv_sec和tv.tv_nsec兩個成員。
轉載于:https://my.oschina.net/u/3011935/blog/979200
總結
- 上一篇: 关于开源软件的思考
- 下一篇: hdu2089 不要62 数位dp