架构设计:远程调用服务架构设计及zookeeper技术详解(上篇)
一、序言
? ? ?Hadoop是一個技術(shù)生態(tài)圈,zookeeper是hadoop生態(tài)圈里一個非常重要的技術(shù),當(dāng)我研究學(xué)習(xí)hadoop的相關(guān)技術(shù)時候,有兩塊知識曾經(jīng)讓我十分的困惑,一個是hbase,一個就是zookeeper,hbase的困惑源自于它在顛覆了我對數(shù)據(jù)庫建模的理解,而zookeeper的困惑卻是我無法理解它到底是干嘛的。
? ? 前不久我結(jié)合我了解的一種遠(yuǎn)程調(diào)用服務(wù)的設(shè)計來幫助我理解zookeeper在實際的生產(chǎn)中運(yùn)用,該文章的地址是:
? ??http://www.cnblogs.com/sharpxiajun/p/3297852.html
? ?其實這篇文章寫完后,我自己感覺并不是太好,因為寫本文的時候,對遠(yuǎn)程調(diào)用服務(wù)的設(shè)計以及zookeeper的理解都不是很到位,但是這篇文章還是受到了大家很大的關(guān)注,被博客園作為了推薦文章,還有很多網(wǎng)友希望我寫一篇更加詳盡的文章,還有童鞋留言說這個設(shè)計方案和淘寶開源的dubbo和hsf類似。我相信大家的關(guān)注就是意味著這個主題是當(dāng)下技術(shù)的熱點,所以今天我要寫一篇主題和上篇文章一樣的博文,這是上篇文章的升級版,不管是遠(yuǎn)程調(diào)用服務(wù)還是zookeeper我都會給出更加詳盡的講解。不過這里還是要說明下,這篇文章里遠(yuǎn)程服務(wù)的設(shè)計我還是沒有參照dubbo,因為最近實在太忙,沒有時間研究淘寶的dubbo,但是我希望學(xué)習(xí)過dubbo的童鞋可以幫我對比下我的方案和dubbo的區(qū)別,區(qū)別就會產(chǎn)生新的問題,也會有新的知識需要研究。
? ?本文是該主題的上篇,主要是講解遠(yuǎn)程調(diào)用服務(wù)的相關(guān)知識,下篇則是根據(jù)遠(yuǎn)程調(diào)用服務(wù)架構(gòu)設(shè)計中zookeeper的相關(guān)應(yīng)用方法詳細(xì)講解關(guān)于zookeeper的知識。
?
二、遠(yuǎn)程調(diào)用服務(wù)的架構(gòu)設(shè)計總述
? ? 首先我們要再深入理解下為什么應(yīng)用軟件服務(wù)里需要一個遠(yuǎn)程調(diào)用服務(wù),遠(yuǎn)程調(diào)用服務(wù)解決了軟件設(shè)計中的什么問題,它的架構(gòu)設(shè)計又有什么理論根據(jù)了?
? ? 我曾寫了一篇關(guān)于分布式網(wǎng)站架構(gòu)設(shè)計的文章,文章地址是:
? ??http://www.cnblogs.com/sharpxiajun/archive/2013/05/11/3072798.html
? ? 在文章開頭我就把這個新的網(wǎng)站架構(gòu)方案和傳統(tǒng)的企業(yè)軟件的B/S架構(gòu)作了對比,我將一個網(wǎng)站里提供業(yè)務(wù)服務(wù)的組件抽象為獨(dú)立的服務(wù)系統(tǒng),接收用戶信息的邏輯部分抽象為前端系統(tǒng),服務(wù)系統(tǒng)和前端系統(tǒng)使用netty這樣的通訊組件進(jìn)行通訊,而到了講解遠(yuǎn)程調(diào)用服務(wù)的框架設(shè)計時候我將netty通訊組件進(jìn)一步抽象為一個通訊獨(dú)立系統(tǒng)及遠(yuǎn)程調(diào)用服務(wù),這就是為什么要設(shè)計遠(yuǎn)程調(diào)用服務(wù)的緣起了,遠(yuǎn)程調(diào)用服務(wù)又會帶來了網(wǎng)站架構(gòu)的升級,如果傳統(tǒng)的企業(yè)B/S架構(gòu)為1.0版,我將前端和業(yè)務(wù)服務(wù)端分離為獨(dú)立系統(tǒng)則是2.0版,那么引入了遠(yuǎn)程調(diào)用服務(wù)網(wǎng)站就是3.0版了,3.0版的架構(gòu)帶來的好處就是可以將N多的前端系統(tǒng)和N多的業(yè)務(wù)服務(wù)端系統(tǒng)融為一個整體,網(wǎng)站的規(guī)模會越來越大,提供的服務(wù)也會越來越多,這既避免重復(fù)造輪子的問題還使得網(wǎng)站規(guī)模越來越大。
? ?3.0版本的網(wǎng)站架構(gòu)帶來了新的網(wǎng)站架構(gòu)總圖,如下所示:
?
? ? ?有了遠(yuǎn)程調(diào)用服務(wù),我們可以做到業(yè)務(wù)級別的集群,例如:一個制造企業(yè),一般都會有采購業(yè)務(wù),生產(chǎn)業(yè)務(wù)、銷售業(yè)務(wù)以及財務(wù)業(yè)務(wù),按照傳統(tǒng)的思路我們都會給每個業(yè)務(wù)獨(dú)立開發(fā)一個系統(tǒng),如果引用了遠(yuǎn)程調(diào)用服務(wù),我們可以將這些業(yè)務(wù)都做成獨(dú)立的服務(wù),這些服務(wù)組成業(yè)務(wù)集群,而這些服務(wù)都是用統(tǒng)一的遠(yuǎn)程調(diào)用服務(wù)作為操作的入口,換句話說不管什么樣的服務(wù)對于調(diào)用者來說都是統(tǒng)一的,這樣前端的調(diào)用者可以做到應(yīng)用的統(tǒng)一,所謂的應(yīng)用的統(tǒng)一淘寶網(wǎng)站是最典型的代表,我們在一個同一的網(wǎng)站里可以操作各種不同的應(yīng)用,而不會發(fā)生因為應(yīng)用的不同我們就得重新訪問新的地址或者重新登錄到另外一個系統(tǒng)里做其他業(yè)務(wù)的操作。而服務(wù)端這邊,完全可以擺脫傳統(tǒng)的客戶端和服務(wù)端耦合的開發(fā),增強(qiáng)了整個服務(wù)端的專業(yè)性和穩(wěn)定性,這樣更易于服務(wù)端的擴(kuò)展性和可維護(hù)性。如果服務(wù)端之間也需要相互調(diào)用也可以通過遠(yuǎn)程調(diào)用服務(wù)實現(xiàn),由于遠(yuǎn)程調(diào)用服務(wù)的統(tǒng)一性,這樣就避免了服務(wù)調(diào)用之間報文和調(diào)用方式的不統(tǒng)一,規(guī)范了整個開發(fā)的流程。如果遠(yuǎn)程調(diào)用服務(wù)還有負(fù)載均衡功能,整個服務(wù)集群就變成了一個私有的云,所以說遠(yuǎn)程調(diào)用服務(wù)是云計算的重要組成部分,這個說法一點都不為過。
? ? 遠(yuǎn)程調(diào)用服務(wù)的理論依據(jù)是什么,這個問題的表述可能有點問題,其實我要講的是遠(yuǎn)程調(diào)用服務(wù)的技術(shù)原型就是SOA(Service-Oriented?Architecture),在云計算出現(xiàn)前,SOA曾一度是IT的技術(shù)熱點,雖然之后很多人說中國的SOA做的一點不好,就和早年的DHTML一樣,詬病遠(yuǎn)多于贊賞,寫本文時候我在京東里搜索了下SOA,從書籍的出版日期和書籍評價數(shù)就可以看出SOA已經(jīng)有點無人問津的凄涼了。下面我要簡單介紹下SOA,SOA的定義:
? ? ?SOA是一個軟件架構(gòu),它包含四個關(guān)鍵概念:應(yīng)用程序前端、服務(wù)、服務(wù)庫和服務(wù)總線。一個服務(wù)包含一個合約、一個或多個接口以及一個實現(xiàn)。
? ?應(yīng)用程序前端可以理解為我上面所講述的調(diào)用者和前端系統(tǒng),服務(wù)庫可以理解為服務(wù)集群,這里還有個服務(wù)是什么呢?服務(wù)就是調(diào)用者和服務(wù)提供者完成某一個特定業(yè)務(wù)的合約,換句話說就是封裝的業(yè)務(wù)規(guī)則,打個比方,我們在淘寶去購物,下訂單,付款,查物流,確定付款這些操作在服務(wù)端都有獨(dú)立的服務(wù)提供,但是從購物這個概念去理解,這些獨(dú)立的服務(wù)才能構(gòu)成這個完整的購物行為,如果其中有地方出了問題,會有相應(yīng)不同的操作,那么這個就絕對不是調(diào)用者簡單調(diào)用服務(wù)接口的問題,需要更高層次的業(yè)務(wù)封裝,將上面這些操作封裝為一個統(tǒng)一的服務(wù),這個就是所謂的服務(wù)。最后一個要素服務(wù)總線,這就是我們本文所談的重要主題:遠(yuǎn)程調(diào)用服務(wù)了。
? ?這里談?wù)?span style="font-family:'Times New Roman';">SOA的目的是想起到拋磚引玉的作用,讓那些想深入研究遠(yuǎn)程調(diào)用服務(wù)的人可以從SOA的角度理解遠(yuǎn)程調(diào)用服務(wù),而那些還是不明白遠(yuǎn)程調(diào)用是何物的童鞋可以通過SOA的概念來理解遠(yuǎn)程調(diào)用服務(wù)。
?
三、遠(yuǎn)程調(diào)用服務(wù)技術(shù)詳解
? ? ?遠(yuǎn)程調(diào)用服務(wù)技術(shù)詳解,詳解,嗚嗚~~,這兩個字很有壓力,我怕有童鞋看了這個標(biāo)題會以為我會將整套技術(shù)實現(xiàn)方案寫到里面,這個難度太高了,寫幾萬字估計都說不清楚,再說真的寫的那么細(xì)致,估計很多人都看不懂了(嘿嘿,我自己也沒有技術(shù)實現(xiàn)過哦,這些都是構(gòu)思,構(gòu)思哦),所以詳解就是詳解原理。
? ? ?下面我將上篇文章的架構(gòu)圖放進(jìn)來,大家再仔細(xì)看看這張圖:
?
? ? ?傳統(tǒng)的服務(wù)調(diào)用都是服務(wù)提供者和服務(wù)調(diào)用者的直接調(diào)用,從架構(gòu)圖里我們看到這里多了一個遠(yuǎn)程調(diào)用管理組件,遠(yuǎn)程調(diào)用管理組件是一個獨(dú)立的服務(wù)系統(tǒng),為了保證該系統(tǒng)的穩(wěn)定性,它也一定是一個分布式的系統(tǒng),但是這個分布式系統(tǒng)和Web的分布式系統(tǒng)是完全不同的分布式系統(tǒng),傳統(tǒng)Web應(yīng)用集群是基于HTTP協(xié)議的無狀態(tài)的特點設(shè)計的,因為每個HTTP請求都是一個獨(dú)立的事務(wù),不同請求之間是沒有任何關(guān)系的,所以我們可以將Web應(yīng)用部署到不同服務(wù)器上,請求不管到了那臺服務(wù)器,都能正常的給用戶提供相應(yīng)的服務(wù),但是Web應(yīng)用的session機(jī)制是有狀態(tài)的,所以傳統(tǒng)Web集群都是要有session同步的操作,大型網(wǎng)站往往會把session功能抽象為獨(dú)立的緩存系統(tǒng),但是這里的遠(yuǎn)程調(diào)用管理組件的集群原理或者說分布式原理是有別于Web應(yīng)用集群分布式原理的,遠(yuǎn)程調(diào)用管理組件可以當(dāng)做一個注冊中心,它會記錄下服務(wù)提供者和服務(wù)調(diào)用者的相關(guān)信息,并將這些信息推送給服務(wù)提供者或者服務(wù)調(diào)用者,為了保證系統(tǒng)的執(zhí)行效率,這些注冊信息都是記錄在內(nèi)存里,我們試想下,如果這些注冊信息丟失,整個系統(tǒng)將會不可用,因此遠(yuǎn)程調(diào)用管理組件的集群是一種保證數(shù)據(jù)可靠性和服務(wù)提供健壯性的集群,而不是建立在HTTP無狀態(tài)特性基礎(chǔ)上的集群。我們這里假想下遠(yuǎn)程調(diào)用服務(wù)的集群運(yùn)行場景,我們假如有5臺服務(wù)器作為遠(yuǎn)程調(diào)用服務(wù)運(yùn)行的服務(wù)器,那么每臺服務(wù)器都必須有注冊信息的冗余備份,當(dāng)服務(wù)運(yùn)行時候其中一臺服務(wù)器發(fā)生了故障,這臺故障的服務(wù)器上的數(shù)據(jù)不會丟失,此外集群應(yīng)該還要有一個檢查故障的機(jī)制,當(dāng)發(fā)現(xiàn)有臺服務(wù)器不可用的時候,能及時剔除該服務(wù)器,而zookeeper就是解決這種問題的技術(shù)框架。此外除了保證系統(tǒng)的穩(wěn)定性和可用性外,集群的數(shù)據(jù)存儲方式也是很重要的,前面我講到集群的數(shù)據(jù)存儲要有一個冗余機(jī)制,除了冗余機(jī)制還要有一個很適合快速訪問和讀寫的數(shù)據(jù)模型,而zookeeper正好包含這種數(shù)據(jù)模型,所以我設(shè)計的遠(yuǎn)程調(diào)用服務(wù)是一個很適合zookeeper應(yīng)用的場景,至于zookeeper的詳細(xì)知識我會在下篇里詳細(xì)講到。
? ? ?遠(yuǎn)程調(diào)用管理組件還有一個心跳機(jī)制,心跳機(jī)制的作用是檢測服務(wù)提供者的健康性及服務(wù)提供者是否可用,服務(wù)提供者啟動時候會將自己的注冊信息發(fā)送給遠(yuǎn)程調(diào)用管理組件,這個注冊信息里包含服務(wù)端的ip地址和端口號,遠(yuǎn)程調(diào)用管理組件會啟動一個線程,根據(jù)定時對這個ip地址和端口號去ping這個ip和端口號對應(yīng)的應(yīng)用是否可用,如果不可用遠(yuǎn)程調(diào)用管理組件會反復(fù)嘗試幾次,這個次數(shù)和多久檢測心跳都是可以配置的,如果反復(fù)幾次還是不通,那么就認(rèn)定該服務(wù)不可用了。有網(wǎng)友在QQ上問我,為什么不檢測服務(wù)調(diào)用者的心跳,這個完全沒必要哦,調(diào)用者是主動方,提供者是被動方,這就好比你訪問網(wǎng)站,如果你生病了不去訪問了,系統(tǒng)沒有必要檢查你是否已經(jīng)生病了。
? ? ?遠(yuǎn)程調(diào)用框架需要使用序列化和反序列化技術(shù),這點也讓很多童鞋不太理解,不理解的原因還是對序列化和反序列化技術(shù)的不理解,序列化技術(shù)主要是應(yīng)用與數(shù)據(jù)持久化(數(shù)據(jù)存到硬盤)或者網(wǎng)絡(luò)通訊,不管是數(shù)據(jù)存儲到硬盤還是進(jìn)行網(wǎng)絡(luò)通訊,這些數(shù)據(jù)都會轉(zhuǎn)化為二進(jìn)制,序列化就是將正在運(yùn)行的對象轉(zhuǎn)化為可以存儲和傳輸?shù)亩M(jìn)制數(shù)據(jù),而反序列化是可以將這些二進(jìn)制數(shù)據(jù)反向還原成原來的對象信息,還原的對象還是可以被程序操作的,而我們設(shè)計的遠(yuǎn)程調(diào)用框架傳遞就是不同系統(tǒng)之間可以相互使用的程序代碼,所以我們需要使用序列化和反序列化技術(shù)。這里就有一個問題,例如我們傳輸一個對象,這個對象對應(yīng)的類是N多個類的繼承子類,而且這個對象里可能還會引用其他的對象例如String,ArrayList等等,那么為了讓反序列化的對象可用,序列化的時候就會將這些信息也包含在二進(jìn)制數(shù)據(jù)里,并且這些信息一起進(jìn)行網(wǎng)絡(luò)傳輸,這就導(dǎo)致數(shù)據(jù)傳輸量特別大,而jdk自帶的序列化機(jī)制會導(dǎo)致這些附帶信息更大,所以有必要使用比jdk更好的序列化機(jī)制,讓數(shù)據(jù)量變小,并且序列化和反序列化的效率更高,上篇文章里我推薦了一種序列化框架hession,當(dāng)然用戶想使用什么序列化機(jī)制這個我也讓用戶可以自己配置,這也是外部配置文件的一個選項。
? ? 前面文章里我還講到了壓縮技術(shù)并且推薦了google公司使用snappy,這個壓縮技術(shù)也是為了讓網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)量變小,提升網(wǎng)絡(luò)的傳輸效率。
? ? 對于服務(wù)提供者和服務(wù)調(diào)用者我會提供一個jar包,這些工程都要引入這個jar包,同時還需要一個配置文件來定義一些需要用戶定義的參數(shù),例如我們使用一個名字叫ycdy_config.properties配置文件,里面的key值介紹如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | Config_center_url=ip:port;這個就是配置遠(yuǎn)程管理中心的ip地址和端口號; Server_type=provider/consumer;配置是服務(wù)調(diào)用者還是提供者,不配置默認(rèn)是提供者; Provider_post=9999,這是服務(wù)提供者的端口號,調(diào)用者可以不配置,其實調(diào)用配置了也沒啥用,如果提供者不配置,會有默認(rèn)值的; Provider_session_timeout=9000;服務(wù)提供者的超時時間,如果實際調(diào)用超過了這個時間,那么說明服務(wù)調(diào)用超時,適用于服務(wù)調(diào)用者,提供者無效 Tick_time=3000;心跳時間,這是遠(yuǎn)程調(diào)用中心檢測服務(wù)端心跳的間隔時間,適用于服務(wù)提供者; Again_time=3;當(dāng)服務(wù)提供者不通的時候,心跳反復(fù)檢測的次數(shù),超過了次數(shù)就標(biāo)記該服務(wù)不可用;Provider_session_timeout、Tick_time和Again_time三者之間是有一定關(guān)系,這個關(guān)系要實現(xiàn)這具體把控了; Ip_include_pattern=172\\.17\\.138.*|192\\.168\\.0\\..*,這個適用于服務(wù)提供者,因為一臺服務(wù)器可能存在多個ip地址,當(dāng)遠(yuǎn)程調(diào)用服務(wù)組件接收到提供者的ip,用這個配置項來辨認(rèn)那個ip可用,這里采用正則表達(dá)式的方式; Ip_exclude_pattern=用于服務(wù)提供者,需要忽略的ip; Consumer_policy=random/rotate;適用于調(diào)用者,調(diào)用者向提供者請求的負(fù)載均衡策略,我熟悉的只有兩種一種是使用隨機(jī)數(shù),一種使輪詢,所以這里目前就這兩種選項; Monitor_log=true/false;是否開啟監(jiān)控日志,適用于服務(wù)提供者,任何系統(tǒng)日志時最重要的,否則沒法查生產(chǎn)問題,其實這個配置項應(yīng)該可以充實點,但是我現(xiàn)在還沒想好,所以先給個提示,具體到了生產(chǎn)看如何實現(xiàn)吧。 |
? ? ?大家看到了不管是作為服務(wù)提供者還是服務(wù)調(diào)用者使用的配置文件是一致的,而且一個應(yīng)用既可以配置成服務(wù)的調(diào)用者也可以配置成服務(wù)的提供者,非常的靈活。
? ? ?遠(yuǎn)程調(diào)用服務(wù)還需要一個重要的技術(shù)就是通訊技術(shù),這里的通訊技術(shù)我推薦netty,netty是個非常好的選擇,講到通訊是個復(fù)雜的課題,如果以后有空我再做詳細(xì)介紹,通訊層的東西是封裝到服務(wù)提供者和服務(wù)調(diào)用者引入的jar包里,但是通訊的ip地址和端口號則是需要遠(yuǎn)程調(diào)用管理組件推送過來的。
? ? ?那么在應(yīng)用里遠(yuǎn)程調(diào)用服務(wù)到底如何使用了?哈哈,這時候spring就要上場了,我們看看服務(wù)調(diào)用者和服務(wù)提供者的spring配置,如下所示:
?
<!-- 服務(wù)提供者配置 --> <bean id="serverProvider" class="cn.com.sharpxiajun.RmifSpringProviderBean"><property name="interfaceName" value="cn.com.ITest"></property><!-- 遠(yuǎn)程調(diào)用的接口 --><property name="target" ref="clsTest"></property><!-- clsTest實現(xiàn)ITest的實現(xiàn)類,clsTest這里是一個bean的id值 --> </bean><!-- 服務(wù)調(diào)用者配置 --> <bean id="clientConsumer" class="cn.com.sharpxiajun.RmifSpringConsumerBean"><property name="interfaceName" value="cn.com.ITest"></property><!-- value就是Provider定義的target的接口實現(xiàn)類 --><property name="serialType" value="hessian"></property><!--序列化方式 --><property name="compressEnabled" value="true"></property><!-- 壓縮標(biāo)記 --> </bean>?
? ? ?我們發(fā)現(xiàn)這個新配置和以前不同了,這個配置將更加適合生成的開發(fā)。
? ? ?我們首先看看serverProvider的設(shè)計,這個bean對應(yīng)的class是cn.com.sharpxiajun.RmifSpringProviderBean,里面有個參數(shù)是一個interfaceName即提供者對外的接口,這里我會使用反射機(jī)制將接口注入到RmifSpringProviderBean,而target則是具體的實現(xiàn)對象了,這就是業(yè)務(wù)對象,注意interfaceName一定要是接口,因為調(diào)用者會根據(jù)接口進(jìn)行轉(zhuǎn)化,如果是類的話,那么通用性就很差了。
? ? ?clientConsumer的設(shè)計,這個bean所對應(yīng)的class是cn.com.sharpxiajun.RmifSpringConsumerBean,其中interfaceName的value值對應(yīng)的就是遠(yuǎn)程定義的接口,和提供者的interfaceName保持一致,當(dāng)提供者的數(shù)據(jù)傳導(dǎo)調(diào)用者后,就會根據(jù)這個雙方約定好的接口反序列化成可以操作的對象,serialType是選擇序列化機(jī)制,不寫的話就是調(diào)用jdk的序列化機(jī)制,這里附帶提下啊,外部的序列化程序也是放到jar包里的哦,還有一個選項是compressEnabled作用是是否啟用傳輸報文壓縮。
? ? 當(dāng)調(diào)用者調(diào)用提供者服務(wù)時候,jar包里netty程序會根據(jù)推送的信息(主要是ip,端口)和spring配置的bean結(jié)合起來就可以完成一次服務(wù)的調(diào)用。
? ?好了,上篇寫好了,本篇主要是講解遠(yuǎn)程調(diào)用服務(wù)的架構(gòu)設(shè)計,我自我感覺這篇文章比上篇更接地氣,希望看了本文的童鞋,能對遠(yuǎn)程調(diào)用框架設(shè)計的原理更加清晰。
? ?其實netty的使用學(xué)問也很大,也是遠(yuǎn)程調(diào)用服務(wù)的核心之一,本文這塊講的比較少,以后有時間我盡量補(bǔ)充上這塊知識。
? ?下篇文章我將詳細(xì)介紹遠(yuǎn)程調(diào)用框架里使用到的zookeeper技術(shù)。
? ?這是2013年的最后一篇博文了,祝大家新年快樂哦。
?
轉(zhuǎn)自http://www.cnblogs.com/sharpxiajun/p/3496639.html
總結(jié)
以上是生活随笔為你收集整理的架构设计:远程调用服务架构设计及zookeeper技术详解(上篇)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用ColorUI组件
- 下一篇: 「工具」IndexDB 版备忘录