九她渴、最佳實踐
分布式應(yīng)用和單體應(yīng)用的主要區(qū)別是本地調(diào)用和遠程調(diào)用,解決的主要問題都是和遠程調(diào)用相關(guān)躲因。首先早敬,遠程調(diào)用的性能差于本地調(diào)用;其次大脉,遠程調(diào)用受網(wǎng)絡(luò)狀況影響搞监,有一定的失敗率,框架和應(yīng)用需要對失敗進行處理镰矿;再次琐驴,分布式場景下,事務(wù)控制會變得及其復(fù)雜;第四绝淡,分布式調(diào)用和調(diào)用本地API的不同宙刘。
遠程調(diào)用的性能:遠程調(diào)用的復(fù)雜性和流程遠超本地調(diào)用,包括序列化反序列化牢酵,網(wǎng)絡(luò)傳輸荐类,反射調(diào)用等重量級開銷。要保證高性能茁帽,除了框架自身之外,應(yīng)用的實現(xiàn)也應(yīng)該盡可能高性能話屈嗤,最佳實踐包括:1潘拨、盡可能異步或并行化服務(wù)調(diào)用,提高服務(wù)吞吐量饶号,降低服務(wù)調(diào)用時延铁追,或者使次要事件不影響響應(yīng)時間;2茫船、減小調(diào)用傳輸量琅束,包括dubbo在內(nèi)的很多分部式服務(wù)框架在服務(wù)的消費者和提供者之間使用單一長連接,傳輸量大會嚴重降低服務(wù)吞吐量算谈,增大調(diào)用時延涩禀;3、在消費者端控制超時時延然眼,避免慢響應(yīng)的服務(wù)引起故障擴散艾船;4、做好服務(wù)隔離高每,避免次要服務(wù)消耗過多資源屿岂,影響重要服務(wù)的吞吐量或性能。
容災(zāi)容錯:在分布式服務(wù)框架和應(yīng)用中需要做好被調(diào)用服務(wù)出錯或不可用的準備鲸匿,并進行兼容爷怀,避免次要服務(wù)引起整個業(yè)務(wù)無法進行的狀況。前面在服務(wù)降級中進行過詳細描述带欢,此處不再細講运授。
分布式事務(wù)的一致性:單體應(yīng)用中,事務(wù)是個極其簡單的控制洪囤,spring的聲明式事務(wù)提供了很多事務(wù)控制策略徒坡,代碼中幾乎不需要考慮事務(wù)一致性問題。服務(wù)分布化之后瘤缩,每個服務(wù)都擁有自己的數(shù)據(jù)庫喇完,服務(wù)之間的調(diào)用也變成了遠程調(diào)用,事務(wù)一致性幾乎無法通過框架來保證剥啤,事務(wù)一致性控制可能是分布式應(yīng)用和單體應(yīng)用的最大區(qū)別锦溪。通常不脯,兩階段提交時企業(yè)應(yīng)用保證分布式事務(wù)的常規(guī)策略,然而刻诊,兩階段提交采用悲觀鎖策略策略所表現(xiàn)出的低吞吐量和在出現(xiàn)故障時的脆弱性防楷,幾乎不被互聯(lián)網(wǎng)應(yīng)用所采納≡蜓模回到問題的本質(zhì)复局,我們之所以采用事務(wù),是為了數(shù)據(jù)的一致性粟判,而為了達到數(shù)據(jù)一致性亿昏,不一定只有事務(wù)一種方式,尤其是在分布式場景下档礁,采用分布式事務(wù)帶來的吞吐量下降是無法接受的角钩。我們考慮在整個業(yè)務(wù)處理過程中,保證數(shù)據(jù)在任何時間內(nèi)強一致的必要性呻澜,在很多業(yè)務(wù)場景下用戶對短暫的數(shù)據(jù)不一致是可以理解和容忍的递礼,只要最終數(shù)據(jù)是一致的即可。使用最終一致性羹幸,就不需要使用強一致的兩階段提交型分布式事務(wù)脊髓,從而使得系統(tǒng)的吞吐量得到保證。常用的最終一致性方案睹欲,要么在整個業(yè)務(wù)過程中記錄每個調(diào)用其他服務(wù)事務(wù)性操作的結(jié)果供炼,對失敗的操作進行重試,如果某個關(guān)鍵性服務(wù)返回失敗窘疮,例如支付時余額不足袋哼,則對每個成功的事務(wù)性操作進行補償性操作調(diào)用,以達到事務(wù)回滾的效果闸衫;要么使用帶有事務(wù)功能的MQ做中間人角色涛贯,做本地事務(wù)之前向MQ發(fā)送prepare消息,然后執(zhí)行本地事務(wù)蔚出,執(zhí)行成功的話向MQ發(fā)送commit消息弟翘,執(zhí)行失敗則發(fā)送rollback消息。對于最終一致性骄酗,一個很關(guān)鍵的點就是:對于網(wǎng)絡(luò)超時的事務(wù)性請求稀余,不能假設(shè)為失敗,必須查詢后趋翻,根據(jù)查詢結(jié)果決定下一步的操作睛琳,如果成功則進行下一步操作,失敗則重試。
分布式調(diào)用與本地調(diào)用的不同:遠程調(diào)用比本地調(diào)用復(fù)雜师骗,所以有一些通用的最佳實踐历等。
分包:建議將服務(wù)接口,服務(wù)模型辟癌,服務(wù)異常等放在api包中寒屯;
粒度:服務(wù)接口盡可能大粒度,每個服務(wù)方法應(yīng)代表一個功能黍少,而不是某功能的一個步驟寡夹,否則將面臨分布式事務(wù)問題;
序列化:服務(wù)參數(shù)及返回值建議使用POJO對象厂置,即通過set,get方法表示屬性的對象要出,服務(wù)參數(shù)及返回值都必需是byValue的,而不能是byRef的农渊,遠程調(diào)用出現(xiàn)byRef可能出現(xiàn)難以預(yù)料的問題;
異常:建議使用異常匯報錯誤或颊,而不是返回錯誤碼砸紊,異常信息能攜帶更多信息,以及語義更友好囱挑。
作為本系列的終結(jié)篇醉顽,強調(diào)最后一次,在分布式應(yīng)用中平挑,一定要處理好異常游添,處理好調(diào)用失敗,處理好網(wǎng)絡(luò)超時等各種非正常的場景通熄。