1. 程式人生 > >你的解耦戰術,決定了架構高度!

你的解耦戰術,決定了架構高度!

轉自:http://developer.51cto.com/art/201711/557827.htm

架構設計中,大家都不喜歡耦合,但有哪些典型的耦合是我們系統架構設計中經常出現的,又該如何優化?

這裡列舉了 6 個點:IP、jar 包、資料庫、服務、訊息、擴容。

這些點,如果設計不慎,都會導致系統出現一些耦合問題,基本都是大家實際遇到的痛點。本文將與大家分享如何用常見的方案去解除這些耦合。

如何找到系統中的耦合

什麼是耦合?就是每每我們作為技術人,在心中罵上下游、罵兄弟部門,說這個東西跟我有什麼關係?為什麼我要配合來做這個事情?這裡面就非常有可能是系統中存在耦合的地方。

明明我們不應該聯動,但兄弟部門要做一個事情,上下游要做一個事情,我卻要被動地配合來做這個事情。還有可能這個配合的範圍特別特別的大,那就說明耦合非常非常的重。

下面來看具體的六個案例。

典型耦合與對應解耦實踐

IP 耦合

第一個案例,特別常見。原來線上有服務或者有條資料庫,因為各種原因,例如磁碟硬體有故障,要換一臺機器,然後運維給了我們一臺機器,我們把資料庫或者把服務給部署好了。

部署好了 IP 要換,原來有個舊 IP,現在有個新 IP。那就有很多上游依賴我,我 IP 換了怎麼辦?就找到上游說我的 IP 換了,麻煩上游部門改配置重啟一下,連到我新的 IP 上去。

不知道大家工作中會不會遇到這樣的場景,這時如果你作為上游的呼叫方,不管你調資料庫還是調服務,你心裡可能就在罵他了,明明是你 IP 變了,為什麼配合重啟、配合改配置的人是我?

特別是如果一個基礎服務或者一個基礎資料庫,依賴它的人很多,那麼你可能要找到這些依賴它的人,可能有 A 部門、B 部門、C 部門,所有業務都依賴你,你要全部找一遍,全部重啟。

所以這個因為 IP 配置使得上下游耦合在一起的案例,它的耦合範圍其實是非常廣的,我們都覺得很討厭。

我們的希望是:你改一個 IP,能不能我不動,你自己升級了,我流量就默默遷移過去,這是一個非常直觀的理解上下游的耦合。

內網 IP 修改為內網域名,這是我們的實踐,強烈的建議大家回去馬上幹這個事情。為什麼我們 IP 要修改、要重啟?

很有可能是我們將 IP 寫在了自己的配置檔案中。如果我們把這個內網 IP 變為內網域名,那麼我們是不是就可以不讓上游配合去改配置重啟呢?

假設我們現在不用 IP 了,用域名了。現在換了一臺機器域名沒變,IP 指向變了。我們可以讓運維統一將內網 DNS 切到新的機器上面去,並將舊機器的連線切斷,重連後就會自動連到新機器上去了。

這樣的話只要運維配合就可以完成遷移,對於所有上游的呼叫方、服務的呼叫方、資料的呼叫方都不需要動,這是第一個案例。

我們的最佳實踐是強烈建議使用內網域名來替換內網的 IP,連服務、連資料庫統統取走。

公共庫耦合

第二個案例是公共庫,這個公共庫可能是一個跟業務相關的通用業務庫,比如使用者的業務、支付的業務,這些業務寫在了一個 jar 包裡,各個業務線通過這個 jar 包來實現相關的一些業務邏輯。

所有的業務方因為這個公共庫耦合了,不管你是 so、dll,還是 jar 包程式碼,不同語言的公共庫方式不一樣,本質是上游通過這個公共庫耦合在一起。

我們曾經碰到什麼樣的情況呢?58 有招聘、房產、二手很多業務線,使用者的一些操作,登入、查詢資訊、修改資訊可能都是相通的,所以我們有一個 user.jar,對所有使用者的操作可能通過這個 jar 包去做。

然後有個業務線,比如說招聘,他可能修改了使用者的操作的一些程式碼,修改了這個 jar 包。

修改之後,上線之前會進行測試,但招聘只會測試自己的業務,不會測試兄弟業務線的業務,導致上線的結果是,上線後兄弟業務線全掛了。

於是就出現了一個很有意思的場景, A 和 B 的業務老大在群裡面說怎麼業務都掛了,然後有研發兄跳出來解釋說 C 部門上線了,所以我們都掛了,這個解釋是很難說通的。

為什麼兄弟部門好好的,他上線了他沒問題,而我們掛了,就是因為 jar 包耦合在一起,可能我們也在心裡會默默地罵他們,修改程式碼的是你,沒問題的也是你,有問題的是我,我其實什麼都沒動,我很委屈。

多個上游因為 jar 包耦合在了一起,那有什麼樣的優化方法?

如果程式碼庫個性很強

如果這個 jar 包、這個公共庫的個性比較強,如果是偏招聘的、房產的、二手的,我們的建議是把這些個性的程式碼拆分到各個業務線自己的 jar 包裡面去。

這樣的話,你修改的那一塊隻影響你自己,至少不會擴大影響範圍,這個需要對業務進行剖析,把個性的地方拿出來。

如果長時間解決不了,我剛剛說的那種耦合頻發,出現的次數特別多,最差的情況下我們可以 copy 程式碼,比如說拷三份,但這個不推薦。

我們的建議:還是抽取其中的個性部分,把原來的一個 business 的 jar 包變成三個加包,每一塊只跟一塊業務相關。

如果公共庫通用性很強

那如果這個庫的共性比較強,我們建議通用的部分下沉獨立一個 service,這個 service 對上游提供介面,我每次測試你也要測試介面的相容性。

如果是新的業務,我們建議新增介面,這樣至少不會對舊有的程式碼產生影響,通過 service 或 RPC 呼叫的方式來解除耦合。

資料庫耦合

第三個案例應該也是大家會遇到比較多的情況,資料庫的耦合。

我先說一下業務場景:業務 A、業務 B、業務 C,這裡還是拿使用者的業務舉例,有些使用者的資料是通用的,存在 table-user 裡,而個性的資料我們存在個性的資料庫裡。

比如業務 A 我們可能有個 table-A、業務 B 有 table-B、業務 C 有 table-C。

假設我的業務線既要取個性的資料,又要取共性的資料,我們的程式碼往往這麼寫,個性表 join 個性表,UID 相同,UID 等於我的使用者 1、2、3,個性的資料和共性的資料一起抽取出來,沒有任何問題。

業務線 B、業務線 C 也是這麼做的。所以你會發現 join 語句其實導致了 user 的 table 和業務線 A、B、C 的 table 耦合到一個數據庫例項裡。

這樣會導致什麼問題呢?比如 A 業務線要上線一個功能,這個功能沒有索引,對全表都要掃描,資料庫 CPU 100%,資料庫例項 IO 效能下降,影響業務。

對B 和 C 都有影響,即某個業務線的資料庫效能急劇下降導致所有業務都受影響。

這時 DBA 兄弟、運維兄弟殺過來說效能不行了,我再給你兩臺機器,給我兩個例項,你會發現沒用,所有表都耦合在一個例項裡,給機器也拆不開,擴不了容。

2015 年我調去 58 到家時,當時整個 58 到家有一個庫叫做 58 到家庫,裡面有幾百個表,效能越來越低,但因為各種 join 又必須耦合在一個例項裡,很悲慘。

我們怎麼做呢?垂直切分與服務化。你會發現跟 jar 包解耦非常相似,垂直拆分。

比如說使用者的基礎資料,我抽向一個使用者的服務,user 最基礎的資料庫只能夠被這個服務鎖訪問,資料庫私有是服務化的一個特點。

此時業務線原來的業務怎麼樣滿足?原來是業務方直接一個 join 既取了共有的資料又取了私有的資料,此時原來的一次資料庫訪問變成了兩次資料庫訪問,第一次取個性資料,第二次取共性資料,然後業務層拼裝。

之前的方式和之後的方式相比,之前的方式業務程式碼可能會更簡單一些,因為它是將這個業務邏輯放在了 SQL 語句中,但是導致資料庫耦合在了一起。

後面這種方式就是業務的程式碼會更復雜,會變成多次訪問,將原來在 SQL 中進行的邏輯計算變成我們自己的程式碼的邏輯計算。

此時業務有自己的庫,公共有公共的庫,你會發現很有可能這些庫早期也在一個例項,但是效能下降時可以很容易地新增例項,把其中一個公共的庫從一個例項裡放到另外一個例項,甚至新增一臺機器做到硬體的擴容。

所以垂直切分是指業務側自己的資料庫放到自己的上去,公共的放到公共的上去,不要耦合在一個例項當中,這是一個比較典型的業務場景。

服務化耦合

第四個案例是服務化耦合的例子。服務化之後,如果業務程式碼拆分得不乾淨,即使你做了服務化也不能夠解除耦合。這裡舉一個服務化解耦不徹底的案例。

上面是 ABC 三個業務方,底下是一個通用的服務。假如你解耦不徹底,你這個通用的服務裡有業務側的程式碼,最典型的業務側的程式碼是什麼樣的?

即服務層 switch case,根據呼叫方的型別走不通的業務邏輯程式碼。我們做服務化其實是想把共性的部分抽象下沉,是共性的部分會做的服務。但如果解耦不徹底,就會有傳入不同 biz-type 執行不同邏輯這樣的程式碼。

這會出現什麼問題呢?如果新增業務需求,你會發現很有可能要改程式碼的是底層的服務,比如說業務 1 來了一個需求,他過來找到你,說我這個需求有個擴充套件,麻煩你這邊升級一下。

業務 2 和業務 3 相同,明明有需求的是業務方,為什麼修改程式碼的是我底層呢,業務需求方很多,所有業務需求側都是你來實現,你是忙不過來的。這時你可能在心中罵他。

這個的耦合範圍相對較小,因為只有一個基礎服務維護的痛點。解決方案也很容易想到,當然是把業務個性化的 case 分支搬到上游去,底層只做通用的功能。

業務程式碼上浮,這樣的話上游的業務迭代速度、迭代效率會提升,每塊業務有功能就會自己實現了,不需要兄弟部門去實現,沒有一個溝通的過程。這是服務化不徹底的一個常見的耦合的案例。

訊息通知耦合

第五個案例是訊息通知的耦合。我猜應該也有很多公司遇到過,有一些事件,這個事件可能要讓很多下游知曉,這裡舉一個我們曾經出現過的案例。

58 同城釋出帖子,釋出帖子的這個事件可能要周知很多方,例如有一個使用者分級的服務,他發了帖之後,這個使用者發帖的一些統計資料,一些資訊資料可能要進行更新。

還要通知離線訊息反作弊的部門在釋出這個帖子之後,可能做一些離線的分析和處理,看有沒有反作弊的嫌疑。

甚至我們這個訊息可能要通知業務線,比如說招聘業務線,最近做了一些營銷活動,只要發招聘的帖子就給你獎積分。

帖子釋出服務,這本來應該是一個非常基礎的服務,它是否要承擔將帖子訊息同步給通知關注方的職責呢?

最早我們是怎麼實現的?58 同城都是服務化的架構,通過 RPC 告訴你釋出一個帖子。

所以我們的上游是帖子釋出的基礎服務,他會通知反作弊的部門說發了一個帖子,會通知資料統計的部門發個帖子,會通知業務線說發個帖子,這樣的架構其實是因為這個通知上下游耦合在了一起。

然後我們在什麼時候會偷偷地去罵這個下游呢?假設現在又新增了一個業務線,房產業務線也做營銷活動,也要關注帖子釋出,麻煩釋出的兄弟能不能呼叫一下我。

釋出的兄弟會發現改的是釋出服務的程式碼,他原來要調 123,他現在還要調 4,有人有新增的需求還要調 5。釋出服務的工程師很痛苦,明明有需求的是業務方,但修改程式碼的卻是我。

原因就是訊息的上下游耦合在一起。非常常見的解耦方案是通過 MQ,這個案例裡的 MQ 以及下一個案例裡的配置中心是網際網路架構中兩個非常常見的解耦工具。

MQ 能夠做到上下游物理上和邏輯上都解耦,增加 MQ 之後,首先上游互不知道彼此的存在,它當然不會建立物理連線了,大家都與 MQ 建立物理連線,就是物理連線上解耦了。

邏輯上也解耦了,訊息釋出方甚至不用知道哪些下游訂閱了這個訊息。新增訊息的訂閱方只需要找 MQ 就行了,上游不需要關注。

所以 MQ 是一個非常常見的物理上解耦、邏輯上也解耦的利器。

下游擴容耦合

第六個案例,我相信也幾乎是所有的公司都會遇到的一個案例,它和第一個案例很像,但又不一樣。

我們的第一個案例是說 IP 變化,上游調下游 IP 發生了變化,我們的建議是使用內網域名,而不是 IP 來做配置,來做上下游的連線解耦。

擴容換 IP 是一個場景,擴容又是第二個場景。

現在有 service1、service2、Web1,底層的 service 是個叢集,隨著業務、資料量、併發的增長,service 要擴容了,我要新增兩個節點。

假設我要新增 IP4、IP5,你會發現案例一的場景又出現了,你得通知所有的上游麻煩幫忙增加兩 個IP,增加兩個內網域名,因為我擴容了。擴容的明明是下游,但需要修改配置、需要重啟的是上游。

我們早期的解決方案是怎麼樣的?我們對配置採用的是配置私藏的方式。

一般對於每個上游來說,都有個自己的配置檔案,依賴於下游,這個配置檔案會放在上游的配置檔案裡。

service2 一般有一個配置 conf,這個裡面寫了依賴於內網配置,內網域名是 123,然後這個服務在啟動時可能通過配置把這個連線建立上。

Web 也是一樣,它有一個 Web1.conf,大家想想自己所服務的公司是不是這樣的。

它是一個數據的擴散,本來資料在這一份,但是你會發現這個資料擴散到不同的上游,每個人都儲存一份這樣的資料,我這個資料要變動時每個上游都需要變動。

如果資料只存在一個地方,這一個地方變了就都變了,不用擔心資料的一致性。

如果你能夠知道上游是誰,通知你的上游去為使用者改善配置重啟還好,我們碰到的痛點是什麼?

58 同城幾千號人,業務幾百個,那麼多,我不知道誰依賴了我,如果我能知道 123 依賴了我,那我就告訴你就行了。

現在我不知道誰依賴了我,因為你連線我,你不需要經過我的允許,你在手冊上看呼叫方式是什麼就看懂了。我們會增加 IP,我怎麼通知你?

剛剛說根本的原因其實是一份配置資料擴散到了多個上游,那我們能不能將這個配置資料放在一個地方不擴散,我改了這一個地方就都改了?

解決方案是配置中心,配置中心的細節我在這不展開講,網上可能也有一些公司的實踐,配置後臺、DB 儲存等。

配置中心是一個典型的邏輯上解耦、但物理上不解耦的一個架構工具。我們的所有上游依賴於下游,還要建立物理的連線。

你引入配置中心之後,它不是通過私有的配置,也不是通過全域性的配置檔案去讀取下游的 IP,而是配置中心說我要訪問 user service。

配置中心告訴他 user service 的內網域名是 123,service 的 1、2、3 還是按照內網的 1、2、3,物理上還是連線 user service,所有的上游都按照這種方式讀取下游的配置。

在配置中心側,他就能夠知道有哪些人連線了 user service,他在配置中心的後臺就可以配哪些人我設定多少的限流,然後將這個限流可以同步到呼叫方的客戶端,當然也可以同步到服務端進行雙向的保護。

如果 user service 進行擴容,比如我要增加幾個節點,我增加了 4 和 5,那麼我在配置後臺說增加了 4 和 5,後臺能夠知道哪些上游依賴了它,反向給後臺通知,就完全不需要上游去做了。

總結

解耦之後系統能夠更美好一點,程式設計師心中能夠少一點怨氣,希望今天分享的主題及案例能夠幫助大家解決一些工作中的實際問題,謝謝大家。

沈劍,架構師之路公眾號作者。曾任百度高階工程師、58 同城高階架構師、58 同城技術委員會主席、58 同城 C2C 技術部負責人。現任 58 到家技術委員會主席,高階技術總監,負責 58 速運研發與管理工作。本質,技術人一枚。

相關推薦

戰術決定架構高度

轉自:http://developer.51cto.com/art/201711/557827.htm 架構設計中,大家都不喜歡耦合,但有哪些典型的耦合是我們系統架構設計中經常出現的,又該如何優化? 這裡列舉了 6 個點:IP、jar 包、資料庫、服務、訊息、擴容

從普通程式設計師到身價過百億:追求長期價值的耐心決定能走多遠

一提到程式設計師,很多人腦海裡馬上會出現這些標籤:格子襯衫、牛仔褲、程式碼、bug、木訥、不善言辭等等。但有一個詞似乎更能概括:改變世界。 程式改變世界,已經有幾十年了,但真正進入大眾的生活,應該是從2007年智慧手機的應用開始,越來越多的人開始關注技術和程式設計師。 在中國網際網路圈,我們

數據讓生活更幸福三分鐘帶智慧城市交通大數據應用

行業 都是 小型 駕駛員 大數據量 來源 電信 數據類型 不一定 隨著城市交通人腦的出現,大數據在交通管理和交通運輸領域得到了廣泛的應用。大數據已逐漸成為城市交通管理的基礎資源,在交通管理中日益顯示出其關鍵作用和地位。許多公司對交通數據的理解存在偏見。他們認為大數據就是大數

學習Python這些好習慣和壞習慣決定是大神還是碼農

IT 行業的變化快是眾人皆知的,需要持續去學習新的知識內容。但是,往往我們工作之後,經常發現學習的東西很少了,學習效率非常低,感覺自己到了一個瓶頸期,久而久之,就演變成『一年工作經驗,重複去用十年』的怪圈。 不管你是已經工作了,還是正在學習中的初學者,如果你想在Python

多久更新一次簡歷決定的收入多久能提升

    提到更新簡歷,或許大家第一時間就想到換工作,因為只有在換工作時才會更新。一般程式設計師大概1年半到2年跳槽一次,也就是說最多2年會更新一次。                更新簡歷是在其中更新自己的技

如果想搞懂“分散式鎖”必須要看這篇文章 很意外

對於鎖大家肯定不會陌生,在 Java 中 synchronized 關鍵字和 ReentrantLock 可重入鎖在我們的程式碼中是經常見的,一般我們用其在多執行緒環境中控制對資源的併發訪問。 但是隨著分散式的快速發展,本地的加鎖往往不能滿足我們的需要,在我們的分散式環境中上面加鎖的方法

bb視訊 mg電子游藝最新爆分技巧如何止損做好才能穩勝

BB視訊MG電子游藝首選直營網,老牌信譽好 845996.com 老牌信譽 值得信賴MG擺脫遊戲 、規則、玩法、技巧:本人也是電子之類老玩家了,總結以下經驗!僅供參考…1,電子是一種機率遊戲,那麼就有很多操縱空間!,每個時間段的彩池累計不一樣,有些時間段會爆分,有些時間段吃分就 尤其嚴重!2,好的平 臺 輸和

bb視訊 mg電子遊藝最新爆分技巧如何止損做好才能穩勝

... 會有 電子 參考 快的 技巧 經驗 目的 有意 BB視訊MG電子遊藝首選直營網,老牌信譽好 845996.com 老牌信譽 值得信賴MG擺脫遊戲 、規則、玩法、技巧:本人也是電子之類老玩家了,總結以下經驗!僅供參考…1,電子是一種機率遊戲,那麽就有很多操縱空間!,

小心Python爬取的微信隱私用Python分析數千個微信暱稱後發現這些祕密

01 Let's get it 1. 基本資訊獲取 訪問 英文取名 的使用者基本信介面,獲取 英文取名 使用者微信名(NickName)、訪問次數(Count)、總資料集(ResponseData),並將微信名存入檔案。 # 獲取所有使用

從普通Java程序員到阿裏高級架構他用6年

mage 任務 開發工程師 模塊 硬盤 https 代碼質量 scala 最終 6年間,一位架構師待過四大門戶中的兩戶,已完成了工程師到架構師的蛻變。經手幾款從零到一產品的開發和增漲,也親身經歷國內最大社交網絡平臺億級數據流量和用戶的架構設計及優化工作。在工作中思路清晰、盡

來遲用Python助疊貓貓搶618大紅包

目錄: 0 引言 1 環境 2 需求分析 3 前置準備 4 逛店鋪流程回顧 5 程式碼全景展示 6 總結 0 引言 最近疊貓貓的活

Guitar Pro中文版下載想要的都在這啦

全能 cnblogs strong 開始 demo 愛好 blank 支持 詳細 我的音樂我做主!Guitar Pro7中文版的發布為更多音樂愛好者帶來更多更優質的體驗!為幫助所有吉他愛好者學習、繪譜、創作而設計的音樂空間!為前所未有的音樂盛聽而震撼,音樂才子,等的就是你!

【轉】萬字幹貨 | 數據分析的基本方法論收藏慢慢看

好奇心 進度 直接 用戶數 話題 分析師 這也 工具 場景 原文鏈接:http://www.sohu.com/a/211316886_165070 2017.12.3受「水滴互助」的朋友相邀,分享了個人在數據分析領域的一些基本方法論。數據產品以沈澱數據分析思路為

Unity3D新手教學十二小時從入門到掌握(三 )

這一講,我會教大家如何寫碰撞檢測的程式碼,然後還會教大家如何使用我介紹給大家的第一個Unity的外掛。 那麼,廢話不多說,我先介紹外掛如何下載和安裝。 進入這個頁面,按編譯器版本進行下載,我用的是2010,所以要下載這個。 安裝就不用我教了,下面開

蟲師帶入門Chrome Headless從此爬蟲0門檻

爬蟲終結者 Chrome Headless 簡介 自從Google官方釋出了Chrome瀏覽器的無形態模式之後,PhantomJS 維護者 Vitaly Slobodin 隨即在郵件

Mysql高手系列 - 第9篇:詳分組查詢mysql分組有大坑

這是Mysql系列第9篇。 環境:mysql5.7.25,cmd命令中進行演示。 本篇內容 分組查詢語法 聚合函式 單欄位分組 多欄位分組 分組前篩選資料 分組後篩選資料 where和having的區別 分組後排序 where & group by & having & order

17.EVE-NG增添監控服務器鏡像再上新高度

eve-ng 網絡 eve 模擬器 gns3 虛擬仿真平臺 文章列表(關註微信公眾號EmulatedLab,及時獲取文章以及下載鏈接)1、EVE-NG介紹(EVE-NG最好用的模擬器,仿真環境時代來臨!)2、EVE-NG安裝過程介紹3、EVE-NG導入Dynamips和IOL4、EVE

前端技術學習路線及技術匯總(從到學習的思維格局決定的未來)

了解 戰略 com image 分享圖片 交互 敵人 img 學習效率 前端技術學習路線及技術匯總 一、了解前端 個人覺得,要學習前端,首先應該了解一些B/S開發模式的基本常識,對網頁,網站及服務器有一定的了解,你要了解什麽是前端,前端中包含的編程

知彼知己務必的導師

世界 閃電 16px HA 決策 組成 我想 內部 實驗   你或許已經問他要做什麽才能畢業。 現在你需要分析他。 發現他喜歡研究的內容。   你可能會認為你的教授正在利用你來推動他的職業生涯。 你可能聽說博士只不過是便宜的科學勞動力。 但是你猜猜我想說什麽? 我想說,你也

想投朋友圈廣告之前應該先進來這些內容防止被忽悠

想做朋友圈廣告的朋友們,今天KUK酷可科技,就給大家介紹下朋友圈的廣告推廣流程,預防各位被廣告公司給忽悠了,看完記得幫我轉發點贊哦! 1、朋友圈廣告投放流程: 1.明確推廣目標 品牌活動、應用下載、還是公眾號推廣; 選擇廣告形式:圖文廣告或視訊廣告; 選擇本條廣告的購買方