上次有朋友說,想讓老王講講如何部署線上服務(wù)的,那這周跟大家分享一下分布式系統(tǒng)里面的一個(gè)中樞系統(tǒng):命名服務(wù)。看懂了這個(gè),基本上就知道線上服務(wù)是如何部署的了。
在很久很久以前,有一個(gè)叫老王的人為了解決在學(xué)校搭服務(wù)器性能頂不住的問題,加入了百度去學(xué)習(xí)技術(shù)。剛剛進(jìn)去的時(shí)候,就發(fā)現(xiàn)百度真的好先進(jìn),用 C 語言寫web 服務(wù)。邏輯服務(wù)層的程序叫做 UI (這個(gè)也是用 c 寫的,包括頁面渲染……),他的配置文件里面有一個(gè)長(zhǎng)長(zhǎng)的列表,這個(gè)列表里面都是他連接的存儲(chǔ)系統(tǒng)服務(wù)器 IP 和Port ,大概長(zhǎng)這個(gè)樣子:

用戶請(qǐng)求到達(dá) UI 程序服務(wù)器的時(shí)候,他先從 login--list 中按照某種負(fù)載均衡算法(比如:隨機(jī),忘了的朋友可以看看老王之前寫的關(guān)于負(fù)載均衡的文章),取出一個(gè) ip 和 port ,然后去連接對(duì)應(yīng)的服務(wù)器的進(jìn)程做登錄,登錄成功后,又取出一個(gè) message--list 中的元素,去獲取用戶消息。如果獲取失敗,則按照某種重試的原則,再獲取另外一個(gè) ip 和 port 重新連接。
初出茅廬的老王(那會(huì)兒應(yīng)該還叫小王,正是意氣風(fēng)發(fā)的年代)覺得好牛 * 啊,可以用 c 語言程序來實(shí)現(xiàn)分布式的程序,通過配置管理服務(wù)器列表,這樣就可以將請(qǐng)求分擔(dān)到不同的機(jī)器,最終達(dá)到應(yīng)對(duì)大流量的要求。
可是隨著在百度呆的日子越來越長(zhǎng),就日益發(fā)現(xiàn)這里面問題越來越多。特別是當(dāng)服務(wù)越來越多、流量越來越大的時(shí)候,之前的工作方式似乎 work 的不好了。比如,剛剛那個(gè) UI 程序,在線上部署了 10 臺(tái)機(jī)器(比方: 10.0.3.1 - 10.0.3.10 ),這個(gè)時(shí)候, login 的服務(wù)要增加一臺(tái)機(jī)器,怎么辦呢?將這個(gè) IP 添加到上述 10 臺(tái)機(jī)器的服務(wù)器配置里(這還不復(fù)雜,對(duì)吧)。后來,流量大了, UI 服務(wù)器從 10 臺(tái)變成了 100 臺(tái),這時(shí)候,有一臺(tái) login 服務(wù)器出問題了,要從配置列表中刪除,所以…… 運(yùn)維人員就快瘋了。但是,他們想起來,還有一種絕密武器: shell 腳本,可以批量處理。
又到后來,為了將提交和瀏覽分隔開來,雖然用了同樣的程序,但是他們的配置是不一樣的,有些服務(wù)器連瀏覽相關(guān)的服務(wù),有些服務(wù)器連提交相關(guān)的服務(wù)。而且產(chǎn)品經(jīng)理瘋狂的加需求,使得后端服務(wù)越來越多,這個(gè)時(shí)候研發(fā)說,我要上線改一個(gè) ip 配置,運(yùn)維人員真的瘋了……
老王離開百度以后,據(jù)說逐步解決了這個(gè)問題。與此同時(shí),老王加入了百詞斬,做了一件現(xiàn)在都覺得千值萬值的事情:寫了一個(gè)系統(tǒng),他叫 Naming-Service 。
1 、整體的拓?fù)浼軜?gòu)
從名字上就可以看出這個(gè)系統(tǒng)是跟名字相關(guān)的,不錯(cuò),他就是管理其他服務(wù)的服務(wù)。所有的線上服務(wù)都要到他這里來注冊(cè)才能提供給其他人服務(wù)。是不是覺得好拗口?哈哈,老王畫了兩張圖,大家一看就明白了。

這是我們之前的部署拓?fù)鋱D,看下那些密密麻麻的線,如果再多幾臺(tái)服務(wù)器,做運(yùn)維的同學(xué)心里陰影面積會(huì)有多大?

這是我們?cè)黾?Naming-Service 以后的服務(wù)拓?fù)鋱D,從以前的混聯(lián)狀態(tài)變成了星形狀。所有的服務(wù)都將自己的名字、 IP 、 Port 注冊(cè)到命名服務(wù)器,如果其他人要調(diào)用這個(gè)服務(wù),就去命名服務(wù)器根據(jù)名字獲取對(duì)應(yīng)的 IP:PORT 列表???,這種結(jié)構(gòu)是不是就清爽很多了。
就算服務(wù)再多 N 倍,我們的架構(gòu)也是很清晰的(當(dāng)然,在不同服務(wù)量級(jí)的體量下,這種架構(gòu)也可能不是最好的一種結(jié)構(gòu))。就算服務(wù)器再增加 M 臺(tái),我們也不需要去改配置。怎么樣,是不是感到運(yùn)維的同學(xué)馬上就要請(qǐng)你吃飯了呢?
2 、需要解決的問題
是不是有這個(gè)拓?fù)浣Y(jié)構(gòu)就完了呢?回答:肯定不是,不然老王怎么湊字?jǐn)?shù)呢,哈哈哈 ~
其實(shí)這種結(jié)構(gòu)我們有幾個(gè)問題需要去解決:
A 、服務(wù)如何注冊(cè)?
老王在做這個(gè)系統(tǒng)的時(shí)候,采用了兩種方式:主動(dòng)注冊(cè)和手動(dòng)添加。
絕大部分服務(wù)(主要是我們自己寫的服務(wù))都自己每隔一段時(shí)間向 Naming-Service做一次注冊(cè),大體像這樣的 RPC 調(diào)用: regist("simplemain.login","10.0.1.2", 1031) 。Naming-Service 則判斷,這個(gè)服務(wù)器是否已經(jīng)注冊(cè)過,如果已經(jīng)注冊(cè)過則直接返回,否則向系統(tǒng)里添加一條記錄: simplemain.login -> [10.0.1.1:1031, 10.0.1.2:1031 ]。那為什么要隔一段時(shí)間就要注冊(cè)一次呢?老王當(dāng)時(shí)是這樣考慮的:如果我們的 Naming-Service 數(shù)據(jù)遭到了破壞(比如磁盤壞了),我能在很短的時(shí)間內(nèi),重新注冊(cè)上這些服務(wù)。而且重復(fù)注冊(cè)本身沒有太大的代價(jià)。