背景
? ? ? ? Dubbo是阿里巴巴開源的一個(gè)高性能優(yōu)秀的服務(wù)框架現(xiàn)(已加入Apache項(xiàng)目中)然遏,使得應(yīng)用可通過高性能的 RPC 實(shí)現(xiàn)服務(wù)的輸出和輸入功能什湘,可以和 Spring框架無縫集成褐缠。京東也有一個(gè)基于這樣的框架做了定制和改進(jìn)的JSF,那我們?yōu)槭裁匆岢鲞@樣的一個(gè)RPC框架呢?
? ? ? ?孟子云:“頌其詩辐脖,讀其書狭莱,不知其人可乎僵娃,是以論其世也∫该睿”講的使我們要透徹的理解一篇文章默怨,就必須要知道作者的生平際遇』越祝互聯(lián)網(wǎng)架構(gòu)亦是如此先壕,經(jīng)歷了單一應(yīng)用架構(gòu)、垂直應(yīng)用架構(gòu)谆甜、分布式服務(wù)架構(gòu)和流動(dòng)計(jì)算架構(gòu)垃僚。服務(wù)的粒度越來越細(xì)化(比如以前一個(gè)網(wǎng)站后端只需要一個(gè)tomcat運(yùn)行一個(gè)Servlet程序,現(xiàn)在前端一個(gè)請(qǐng)求過來规辱,后端會(huì)有很多個(gè)tomcat容器分別運(yùn)行著不同的Servlet谆棺,他們之間相互調(diào)用,最后再由第一個(gè)Servlet返回給前端),服務(wù)治理的問題就越發(fā)的明顯改淑,所以優(yōu)秀的架構(gòu)師們就在思考可不可以有這么一個(gè)優(yōu)秀的架構(gòu)替我們解決服務(wù)之間的調(diào)用問題碍岔?當(dāng)然了,如果能高可用就更好了朵夏。如果有負(fù)載均衡就最好不過了蔼啦。因此,我們的Dubbo框架就呱呱墜地了仰猖。
Provider: 暴露服務(wù)的服務(wù)提供方
Consumer: 調(diào)用遠(yuǎn)程服務(wù)的服務(wù)消費(fèi)方
Registry: 服務(wù)注冊(cè)與發(fā)現(xiàn)的注冊(cè)中心
Monitor: 統(tǒng)計(jì)服務(wù)的調(diào)用次數(shù)和調(diào)用時(shí)間的監(jiān)控中心
Container: 服務(wù)運(yùn)行容器
Dubbo大體的流程是這樣的:先用容器Container(當(dāng)下以Docker為代表的應(yīng)用級(jí)虛擬化技術(shù)捏肢,為了容易理解可以粗糙的以為一個(gè)虛擬機(jī))啟動(dòng)我們的服務(wù)Provider。然后將其IP(192.169.0.1)注冊(cè)到注冊(cè)中心Registry去(通常我們會(huì)采用ZooKeeper這樣的分布式應(yīng)用服務(wù)協(xié)調(diào)程序)饥侵。接著我的服務(wù)調(diào)用方Comsumer就會(huì)去注冊(cè)中心去訂閱Subscribe相關(guān)服務(wù)鸵赫。注冊(cè)中心會(huì)異步的方式將你消費(fèi)者需要的服務(wù)的地址列表推送Notify給你。消費(fèi)者就會(huì)將整個(gè)地址列表緩存在本地躏升,當(dāng)業(yè)務(wù)需求到來時(shí)辩棒,就會(huì)使用地址列表里的地址去請(qǐng)求相關(guān)的服務(wù)程序。至于Monitor顧名思義就是監(jiān)視器的含義膨疏,消費(fèi)者和提供者會(huì)定時(shí)將服務(wù)的調(diào)用次數(shù)和被調(diào)用的次數(shù)發(fā)送給監(jiān)視器一睁。
配置與使用
Provider:
服務(wù)接口實(shí)現(xiàn)類就是我們真正Provider要執(zhí)行的邏輯,可能有人會(huì)問成肘,為什么我們要寫一個(gè)接口類卖局?不寫可不可以?這是一個(gè)好問題双霍。如果單純的看Provider確實(shí)沒有寫這么一個(gè)接口的必要砚偶,但是對(duì)于Consumer來講意義就大不相同了。RPC(Remote Procedure Cal)遠(yuǎn)程過程調(diào)用的目的就是要即便Consumer和Provider不是運(yùn)行在同一臺(tái)機(jī)子上洒闸,但是對(duì)于Consumer來講就是像調(diào)用本地方法一樣去調(diào)用Provider染坯,所以Consumer至少得有Provider的接口,這樣Comsumer才能知道Provider有哪些方法丘逸,至于具體怎么怎么做后面會(huì)解釋单鹿,請(qǐng)稍安勿躁。接著深纲,解釋一下配置文件的含義
<dubbo:application/>:用于配置當(dāng)前應(yīng)用信息仲锄,不管該應(yīng)用是提供者還是消費(fèi)者
<dubbo:registry/>:用于配置連接注冊(cè)中心相關(guān)信息
<dubbo:protocol/>:用于配置提供服務(wù)的協(xié)議信息,協(xié)議由提供方指定湃鹊,消費(fèi)方被動(dòng)接受
<dubbo:service/>:用于暴露一個(gè)服務(wù)儒喊,定義服務(wù)的元信息,一個(gè)服務(wù)可以用多個(gè)協(xié)議暴露币呵,一個(gè)服務(wù)也可以注冊(cè)到多個(gè)注冊(cè)中心
Consumer:
Consumer的使用也很簡(jiǎn)單怀愧,引入Provider的接口包,然后用配置文件生成Provider接口類的代理對(duì)象,再交給Spring來管理芯义,這樣Consumer的代碼中就可以很透明的使用demoService的對(duì)象去調(diào)用Provider中的DemoServiceImpl的具體函數(shù)哈垢。接著,解釋一下配置文件的含義
<dubbo:application/>:用于配置當(dāng)前應(yīng)用信息扛拨,不管該應(yīng)用是提供者還是消費(fèi)者
<dubbo:registry/>:用于配置連接注冊(cè)中心相關(guān)信息
<dubbo:reference/>:用于創(chuàng)建一個(gè)遠(yuǎn)程服務(wù)代理耘分,一個(gè)引用可以指向多個(gè)注冊(cè)中心
? ? ? ?Registry提了很多遍,這是一個(gè)抽象的概念鬼癣,但是要理解起來也很容易如下圖一般
模塊介紹
雖然我沒有看過Dubbo的源碼陶贼,但是我覺得作為一個(gè)RPC框架,它至少應(yīng)該有封裝TCP或者HTTP這類傳輸報(bào)文的協(xié)議功能待秃;消費(fèi)者端能生成代理對(duì)象去訪問提供者對(duì)象就應(yīng)該有一個(gè)生成代理的功能;消費(fèi)者在調(diào)用提供端函數(shù)時(shí)候會(huì)傳入一些參數(shù)痹屹,函數(shù)結(jié)果返回的時(shí)候又是對(duì)象章郁,那它就應(yīng)該有一個(gè)對(duì)象序列化和反序列化的功能;消費(fèi)者和提供者會(huì)將自己的IP地址發(fā)給注冊(cè)中心志衍,并且會(huì)在消費(fèi)者本地緩存服務(wù)列表暖庄,那它就應(yīng)該有一個(gè)配置中心;消費(fèi)者在調(diào)用的時(shí)候不用考慮訪問的到底是那個(gè)節(jié)點(diǎn)上的服務(wù)楼肪,那它就應(yīng)該有一個(gè)負(fù)載均衡的功能…..
?????? ?有了這些基本的想法以后我們就可以去Dubbo的構(gòu)成部分培廓,然后再根據(jù)自己想了解的部分進(jìn)行深入了解。那讓我看看它有哪些模塊
dubbo-config:
配置層春叫。解析dubbo中的xml文件生成config對(duì)象肩钠。
dubbo-proxy:
服務(wù)代理層。負(fù)責(zé)生產(chǎn)消費(fèi)端的代理對(duì)象暂殖。
dubbo-registry:
注冊(cè)中心層价匠。負(fù)責(zé)服務(wù)注冊(cè)與查詢服務(wù),以及注冊(cè)服務(wù)的本地緩存呛每。
dubbo-cluster:
路由層踩窖。負(fù)責(zé)消費(fèi)端的負(fù)載均衡策略,以及在訪問某個(gè)節(jié)點(diǎn)服務(wù)失敗以后的調(diào)整策略晨横。
dubbo-monitor:
監(jiān)控層洋腮。RPC服務(wù)端被調(diào)用次數(shù)還有消費(fèi)方調(diào)用時(shí)間的監(jiān)控。
dubbo-rpc:
遠(yuǎn)程調(diào)用層手形。封將RPC調(diào)用啥供、支持RMI 、Hessian叁幢、Http滤灯、Webservice、thrift等rpc調(diào)用方式。
dubbo-remoting:
信息交換層鳞骤。比較底層的模塊窒百,是封裝請(qǐng)求和響應(yīng),處理各種通信協(xié)議豫尽,支持netty篙梢,mina,http美旧。默認(rèn)采用netty通信渤滞。
dubbo-common:
序列化層。Common就是復(fù)用度很高的模塊榴嗅,主要是數(shù)據(jù)序列化和序列化線程池之類的工具妄呕。
????Dubbo的模塊大致如此,我個(gè)人覺得這些模塊中比較重要的是RPC模塊嗽测,RPC是介于應(yīng)用層和傳輸層之間的技術(shù)绪励,也是當(dāng)初設(shè)計(jì)RPC框架時(shí)候關(guān)注的地方,如果讓我自己去實(shí)現(xiàn)一個(gè)RPC框架的話唠粥,我會(huì)采用java中的ObjectInputStream和ObjectOutputStream流疏魏,這兩個(gè)流可以把java對(duì)象轉(zhuǎn)成字節(jié)流和把字節(jié)流還原成java對(duì)象,然后使用sockect編程晤愧,將字節(jié)流傳輸于客服端和服務(wù)端之間大莫。具體一點(diǎn)就是當(dāng)服務(wù)端接收到客戶端傳來的字節(jié)流,我們就可以在服務(wù)端反序列出接口名官份,方法名只厘,參數(shù)名。然后用反射的機(jī)制去調(diào)用贯吓,最后得到的返回值再序列化的方式發(fā)送給客戶端懈凹。
????好了Dubbo告一段下面將介紹一下JSF,因?yàn)槲以诰〇|實(shí)習(xí)悄谐,所以對(duì)于京東改進(jìn)Dubbo的原因比較好奇介评,下面我也將介紹京東的JSF相比于Dubbo的不同之處。
京東改進(jìn)之后的JSF
不難看出爬舰,JSF相比于Dubbo而言多了一個(gè)注冊(cè)中心尋址服務(wù)们陆,為什么會(huì)這樣呢?主要是因?yàn)?015年雙十一時(shí)候注冊(cè)中心掛了以后情屹,后端容器服務(wù)重啟以后之前緩存的服務(wù)地址列表丟失坪仇,服務(wù)無法調(diào)用。而且以Zookeeper為注冊(cè)中心的Dubbo垃你,會(huì)受制于Zookeeper的缺點(diǎn):在Zookeeper主節(jié)點(diǎn)掛了以后椅文,新的主節(jié)點(diǎn)被選出來之前喂很,Zookeeper集群不可用。而且Zookeeper沒有動(dòng)態(tài)水平擴(kuò)展的能力皆刺。由此可見注冊(cè)中心是瓶頸
?????? 所以京東在這一塊做了改進(jìn)少辣,我覺得就是拋棄Zookeeper集群,自己取長補(bǔ)短的去實(shí)現(xiàn)一個(gè)服務(wù)治理羡蛾。
1.? ? 引入了index概念漓帅,我的理解就是將注冊(cè)中心根據(jù)不同的業(yè)務(wù)分片,不同的業(yè)務(wù)模塊訪問不同的注冊(cè)中心以實(shí)現(xiàn)負(fù)載均衡痴怨,而不像以前的注冊(cè)中心邏輯上就是一個(gè)整體忙干。因此也需要注冊(cè)中心尋址服務(wù),在一開始定位到自己的注冊(cè)中心浪藻。
2.? ? 因?yàn)闆]了Zookeeper的主從架構(gòu)來保證分布式的數(shù)據(jù)一致性捐迫,所以就得自己去實(shí)現(xiàn)數(shù)據(jù)的一致性,京東則是采用的數(shù)據(jù)庫來實(shí)現(xiàn)數(shù)據(jù)的一致性爱葵。同時(shí)為了保障高可用弓乙,注冊(cè)中心內(nèi)有服務(wù)列表的緩存,所以即便數(shù)據(jù)庫掛了钧惧,注冊(cè)中心依舊可用
3.? ? 注冊(cè)中心服務(wù)既然通過數(shù)據(jù)庫解決了數(shù)據(jù)的一致性問題,自然可以實(shí)現(xiàn)水平擴(kuò)容勾习,監(jiān)控到壓力大即可進(jìn)行動(dòng)態(tài)水平擴(kuò)展
4.? ? Zookeeper優(yōu)點(diǎn)就是其有著訂閱推送的功能來實(shí)現(xiàn)服務(wù)列表更新的時(shí)候會(huì)推送給客戶端浓瞪,京東采用的是CallBack的方式,其實(shí)也能理解巧婶,只要注冊(cè)中心發(fā)現(xiàn)出現(xiàn)變化調(diào)用消費(fèi)者的回調(diào)函數(shù)乾颁,消費(fèi)者就可以知道服務(wù)列表的更新。
5.? ? 如果注冊(cè)中心尋址服務(wù)掛了艺栈,注冊(cè)中心也就成了斷線紙鳶英岭,所以只要在消費(fèi)端本地再緩存一個(gè)注冊(cè)中心地址即可。
? ? ? ?以上就是我對(duì)RPC框架Dubbo和京東改進(jìn)的JSF的理解湿右,其實(shí)這種理解是使用者角度層面诅妹,如果想要深入理解的話還是避不開閱讀源碼或者介紹的更加詳細(xì)的文檔。