微服務(wù)架構(gòu)之RPC-client序列化細(xì)節(jié)
第一章聊了【“為什么要進(jìn)行服務(wù)化纵柿,服務(wù)化究竟解決什么問題”】
第二章聊了【“微服務(wù)的服務(wù)粒度選型”】
上一篇聊了【“為什么說要搞定微服務(wù)架構(gòu),先搞定RPC框架凤瘦?”】
通過上篇文章的介紹,知道了要實(shí)施微服務(wù)荆几,首先要搞定RPC框架杨箭,RPC框架的職責(zé)要向【調(diào)用方】和【服務(wù)提供方】屏蔽各種復(fù)雜性:
(1)讓調(diào)用方感覺就像調(diào)用本地函數(shù)一樣
(2)讓服務(wù)提供方感覺就像實(shí)現(xiàn)一個(gè)本地函數(shù)一樣來實(shí)現(xiàn)服務(wù)
整個(gè)RPC框架又分為client部分與server部分:
RPC-client的部分流程如上圖,要進(jìn)行序列化反序列化(上圖中的1锅移、4),要進(jìn)行發(fā)送字節(jié)流與接收字節(jié)流(上圖中的2饱搏、3)非剃。
通過上一篇文章的用戶調(diào)研:
78%讀者 -> 繼續(xù)聊RPC框架技術(shù)細(xì)節(jié)
14%讀者 -> 聊微服務(wù)其他實(shí)踐
7%讀者 -> 不聊微服務(wù)了,聊最終一致性
那么按照多數(shù)讀者的意見推沸,今天深入聊RPC的技術(shù)細(xì)節(jié)备绽,本文先討論RPC-client部分的【序列化反序列化】實(shí)施細(xì)節(jié)(筆者不是這方面的專家,有不對(duì)之處鬓催,歡迎大家指正肺素,任何具有建設(shè)性意見的留言,將在下一章share給更多的小伙伴)宇驾。
一压怠、為什么要進(jìn)行序列化
工程師通常使用“對(duì)象”來進(jìn)行數(shù)據(jù)的操縱:
class User{
std::Stringuser_name;
uint64_tuser_id;
uint32_tuser_age;
};
User u = new User(“shenjian”);
u.setUid(123);
u.setAge(35);
但當(dāng)需要對(duì)數(shù)據(jù)進(jìn)行存儲(chǔ)(固化存儲(chǔ),緩存存儲(chǔ))或者傳輸(跨進(jìn)程網(wǎng)絡(luò)傳輸)時(shí)飞苇,“對(duì)象”就不這么好用了菌瘫,往往需要把數(shù)據(jù)轉(zhuǎn)化成連續(xù)空間的二進(jìn)制字節(jié)流蜗顽,一些典型的場(chǎng)景是:
(1)數(shù)據(jù)庫索引的磁盤存儲(chǔ):數(shù)據(jù)庫的索引在內(nèi)存里是b+樹或者h(yuǎn)ash的格式,但這個(gè)格式是不能夠直接存儲(chǔ)到磁盤上的雨让,所以需要把b+樹或者h(yuǎn)ash轉(zhuǎn)化為連續(xù)空間的二進(jìn)制字節(jié)流雇盖,才能存儲(chǔ)到磁盤上
(2)緩存的KV存儲(chǔ):redis/memcache是KV類型的緩存,緩存存儲(chǔ)的value必須是連續(xù)空間的二進(jìn)制字節(jié)流栖忠,而不能夠是User對(duì)象
(3)數(shù)據(jù)的網(wǎng)絡(luò)傳輸:socket發(fā)送的數(shù)據(jù)必須是連續(xù)空間的二進(jìn)制字節(jié)流崔挖,也不能是對(duì)象
所謂序列化(Serialization),就是將“對(duì)象”形態(tài)的數(shù)據(jù)轉(zhuǎn)化為“連續(xù)空間二進(jìn)制字節(jié)流”形態(tài)數(shù)據(jù)的過程庵寞,以方便存儲(chǔ)與傳輸狸相。這個(gè)過程的逆過程叫做反序列化。
二捐川、怎么進(jìn)行序列化
這是一個(gè)非常細(xì)節(jié)的問題脓鹃,要是讓你來把“對(duì)象”轉(zhuǎn)化為字節(jié)流,你會(huì)怎么做古沥?很容易想到的一個(gè)方法是xml(或者json)這類具有自描述特性的標(biāo)記性語言:
規(guī)定好轉(zhuǎn)換規(guī)則瘸右,發(fā)送方很容易把User類的一個(gè)對(duì)象序列化為xml,服務(wù)方收到xml二進(jìn)制流之后岩齿,也很容易將其范序列化為User對(duì)象(特別是語言支持反射的時(shí)候太颤,就更easy了)。
第二個(gè)方法是自己實(shí)現(xiàn)二進(jìn)制協(xié)議來進(jìn)行序列化盹沈,還是以上面的User對(duì)象為例龄章,可以設(shè)計(jì)一個(gè)這樣的通用協(xié)議:
(1)頭4個(gè)字節(jié)表示序號(hào)
(2)序號(hào)后面的4個(gè)字節(jié)表示key的長(zhǎng)度m
(3)接下來的m個(gè)字節(jié)表示key的值
(4)接下來的4個(gè)字節(jié)表示value的長(zhǎng)度n
(5)接下來的n個(gè)字節(jié)表示value的值
(6)像xml一樣遞歸下去,直到描述完整個(gè)對(duì)象
上面的User對(duì)象乞封,用這個(gè)協(xié)議描述出來可能是這樣的:
(1)第一行:序號(hào)4個(gè)字節(jié)(設(shè)0表示類名)瓦堵,類名長(zhǎng)度4個(gè)字節(jié)(長(zhǎng)度為4),接下來4個(gè)字節(jié)是類名(”User”)歌亲,共12字節(jié)
(2)第二行:序號(hào)4個(gè)字節(jié)(1表示第一個(gè)屬性),屬性長(zhǎng)度4個(gè)字節(jié)(長(zhǎng)度為9)澜驮,接下來9個(gè)字節(jié)是屬性名(”user_name”)陷揪,屬性值長(zhǎng)度4個(gè)字節(jié)(長(zhǎng)度為8),屬性值8個(gè)字節(jié)(值為”shenjian”)杂穷,共29字節(jié)
(3)第三行:序號(hào)4個(gè)字節(jié)(2表示第二個(gè)屬性)悍缠,屬性長(zhǎng)度4個(gè)字節(jié)(長(zhǎng)度為7),接下來7個(gè)字節(jié)是屬性名(”user_id”)耐量,屬性值長(zhǎng)度4個(gè)字節(jié)(長(zhǎng)度為8)飞蚓,屬性值8個(gè)字節(jié)(值為123),共27字節(jié)
(3)第四行:序號(hào)4個(gè)字節(jié)(3表示第三個(gè)屬性)廊蜒,屬性長(zhǎng)度4個(gè)字節(jié)(長(zhǎng)度為8)趴拧,接下來8個(gè)字節(jié)是屬性名(”user_name”)溅漾,屬性值長(zhǎng)度4個(gè)字節(jié)(長(zhǎng)度為4),屬性值4個(gè)字節(jié)(值為35)著榴,共24字節(jié)
整個(gè)二進(jìn)制字節(jié)流共12+29+27+24=92字節(jié)
實(shí)際的序列化協(xié)議要考慮的細(xì)節(jié)遠(yuǎn)比這個(gè)多添履,例如:強(qiáng)類型的語言不僅要還原屬性名,屬性值脑又,還要還原屬性類型暮胧;復(fù)雜的對(duì)象不僅要考慮普通類型,還要考慮對(duì)象嵌套類型等问麸。however往衷,序列化的思路都是類似的。
三严卖、序列化協(xié)議要考慮什么因素
不管使用成熟協(xié)議xml/json席舍,還是自定義二進(jìn)制協(xié)議來序列化對(duì)象,序列化協(xié)議設(shè)計(jì)時(shí)要考慮哪些因素呢妄田?
(1)解析效率:這個(gè)應(yīng)該是序列化協(xié)議應(yīng)該首要考慮的因素俺亮,像xml/json解析起來比較耗時(shí),需要解析doom樹疟呐,二進(jìn)制自定義協(xié)議解析起來效率就很高
(2)壓縮率脚曾,傳輸有效性:同樣一個(gè)對(duì)象,xml/json傳輸起來有大量的xml標(biāo)簽启具,信息有效性低本讥,二進(jìn)制自定義協(xié)議占用的空間相對(duì)來說就小多了
(3)擴(kuò)展性與兼容性:是否能夠方便的增加字段,增加字段后舊版客戶端是否需要強(qiáng)制升級(jí)鲁冯,都是需要考慮的問題拷沸,xml/json和上面的二進(jìn)制協(xié)議都能夠方便的擴(kuò)展
(4)可讀性與可調(diào)試性:這個(gè)很好理解,xml/json的可讀性就比二進(jìn)制協(xié)議好很多
(5)跨語言:上面的兩個(gè)協(xié)議都是跨語言的薯演,有些序列化協(xié)議是與開發(fā)語言緊密相關(guān)的撞芍,例如dubbo的序列化協(xié)議就只能支持Java的RPC調(diào)用
(6)通用性:xml/json非常通用,都有很好的第三方解析庫跨扮,各個(gè)語言解析起來都十分方便序无,上面自定義的二進(jìn)制協(xié)議雖然能夠跨語言,但每個(gè)語言都要寫一個(gè)簡(jiǎn)易的協(xié)議客戶端
(7)歡迎大家補(bǔ)充…
四衡创、業(yè)內(nèi)常見的序列化方式
(1)xml/json:解析效率帝嗡,壓縮率都較差;擴(kuò)展性璃氢、可讀性哟玷、通用性較好
(2)thrift:沒有用過,歡迎大家補(bǔ)充
(3)protobuf:Google出品一也,必屬精品巢寡,各方面都不錯(cuò)喉脖,強(qiáng)烈推薦,屬于二進(jìn)制協(xié)議讼渊,可讀性差了點(diǎn)动看,但也有類似的to-string協(xié)議幫助調(diào)試問題
(4)Avro:沒有用過,歡迎大家補(bǔ)充
(5)CORBA:沒有用過爪幻,歡迎大家補(bǔ)充
(6)mc_pack:懂的同學(xué)就懂菱皆,不懂的就不懂了,09年用過挨稿,傳說各方面都超越protobuf仇轻,懂行的同學(xué)可以說一下現(xiàn)狀
(7)…
五、后文預(yù)告
RPC-client的部分奶甘,除了要進(jìn)行序列化反序列化篷店,還要進(jìn)行發(fā)送字節(jié)流與接收字節(jié)流,下一篇文章會(huì)介紹這一部分內(nèi)容臭家。
RPC-client中數(shù)據(jù)的發(fā)送與接收遠(yuǎn)比序列化反序列化復(fù)雜疲陕,其涉及“連接池、負(fù)載均衡钉赁、故障轉(zhuǎn)移蹄殃、隊(duì)列、超時(shí)你踩、異步诅岩、上下文回調(diào)管理”等技術(shù),具體細(xì)節(jié)带膜,下篇再溝通吩谦。
==【完】==
回【sed】一分鐘sed入門(一分鐘系列)
回【廣告】一分鐘讀懂互聯(lián)網(wǎng)廣告競(jìng)價(jià)策略(一分鐘系列)
回【陣列】一張“神圖”看懂單機(jī)/集群/熱備/磁盤陣列(一分鐘系列)
回【awk】一分鐘學(xué)awk夠用(一分鐘系列)
回【perl】十分鐘學(xué)perl夠用(一分鐘系列)
回【mongo】一分鐘了解mongodb(一分鐘系列)
回【2pc】一分鐘了解兩階段提交2PC(一分鐘系列)
回【join】30秒懂SQL中的join(一分鐘系列)