一、緣起
很多公司,技術(shù)經(jīng)常遇到這樣的場景:
1)硬件升級,要換一臺高配機器
2)網(wǎng)絡(luò)重新規(guī)劃,若干服務(wù)器要調(diào)整機架
3)服務(wù)器宕機,要重新部署恢復(fù)服務(wù)
…

更具體的,如上圖:數(shù)據(jù)庫換了一個ip,此時往往連接此數(shù)據(jù)庫的上游需要修改配置重啟,如果數(shù)據(jù)庫有很多上游調(diào)用方,改配置重啟的調(diào)用方會很多,每次換ip的成本往往很高,成為大家共性的痛點。
由A的調(diào)整(數(shù)據(jù)庫換ip),配合修改和調(diào)整的卻是BCDE(改配置重啟),BCDE內(nèi)心非常的郁悶:明明換ip的是你,憑什么配合重啟的卻是我?
根本上,這是一個“架構(gòu)耦合”的問題,是一個
架構(gòu)設(shè)計上“反向依賴”的問題,本文將討論的是架構(gòu)設(shè)計中常見的“反向依賴”的設(shè)計,以及對應(yīng)的優(yōu)化方案,希望對大伙有所啟示。
二、如何尋找不合理“反向依賴”
方法論:變動方是A,配合方卻是BCDE(或者說
需求方是A,改動方確是BCDE)
想想“換IP的是你,配合重啟的卻是我”更好理解。
如果系統(tǒng)中經(jīng)常出現(xiàn)了這類情況,就是“反向依賴”的特征,往往架構(gòu)上有優(yōu)化的空間。
三、常見的“反向依賴”與優(yōu)化方案
【case1:公共庫導(dǎo)致耦合】

三個服務(wù)s1/s2/s3,通過一個公共的庫biz.jar來實現(xiàn)一段業(yè)務(wù)邏輯,s1/s2/s3其實間接通過biz.jar耦合在了一起,
一個業(yè)務(wù)s1修改一塊公共的代碼,導(dǎo)致影響其他業(yè)務(wù)s2/s3,架構(gòu)上是不合理的。
優(yōu)化方案1:業(yè)務(wù)垂直拆分
如果biz.jar中實現(xiàn)的邏輯“業(yè)務(wù)特性”很強,可以拆分為biz1.jar/biz2.jar/biz3.jar,來對s1/s2/s3進行解耦。這樣的話,
任何業(yè)務(wù)的改動,影響范圍只是自己,不會影響其他人。
優(yōu)化方案2:服務(wù)化
如果biz.jar中實現(xiàn)的邏輯“業(yè)務(wù)共性”很強,可以將biz.jar優(yōu)化為biz.service服務(wù),來對s1/s2/s3進行解耦。服務(wù)化之后,兼容性能更好的通過接口自動化回歸測試來保證。
基礎(chǔ)服務(wù)的抽象,本身是一種共性聚焦,是系統(tǒng)解耦常見的方案。
【case2:服務(wù)化不徹底導(dǎo)致耦合】

服務(wù)化是解決“業(yè)務(wù)共性”組件庫導(dǎo)致系統(tǒng)耦合的常見方案之一,但如果服務(wù)化不徹底,service本身也容易成為業(yè)務(wù)耦合點。
典型的服務(wù)化不徹底導(dǎo)致的業(yè)務(wù)耦合的特征是,共性服務(wù)中,包含大量“根據(jù)不同業(yè)務(wù),執(zhí)行不同個性分支”的代碼。
switch (biz-type)
case biz-1 : exec1
case biz-2 : exec2
case biz-3 : exec3
…
在這種架構(gòu)下,
biz-1/biz-2/biz-3有個性的業(yè)務(wù)需求,可能導(dǎo)致修改代碼的是共性的biz-service,使其成為研發(fā)瓶頸,架構(gòu)上也是不合理的。
優(yōu)化方案:業(yè)務(wù)特性代碼上浮,業(yè)務(wù)共性代碼下沉,徹底解耦
把swithc case中業(yè)務(wù)
特性代碼放到業(yè)務(wù)層實現(xiàn),這樣biz-1/biz-2/biz-3有個性的業(yè)務(wù)需求,升級的是自己的業(yè)務(wù)系統(tǒng)。
【case3:notify的不合理實現(xiàn)導(dǎo)致的耦合】

《
究竟什么時候該使用MQ》一文中有一類業(yè)務(wù)場景,
消息發(fā)送方不關(guān)注消息接收方的執(zhí)行結(jié)果,如果采用調(diào)用的方式來實現(xiàn)通知,
會導(dǎo)消息發(fā)送方和消息接收方耦合。
如何新增消息接收方biz-4,會發(fā)現(xiàn)修改代碼的是消息發(fā)送方,新增一個對biz-4的調(diào)用,極不合理。
優(yōu)化方案:通過MQ實現(xiàn)解耦
消息發(fā)送方upper將消息發(fā)布給MQ,消息接收方從MQ去訂閱,
任何新增對消息的消費,upper都不需要修改代碼。
【case4:配置中的ip導(dǎo)致上下游耦合】

即“緣起”中舉的例子,
下游服務(wù)換ip,可能導(dǎo)致多個服務(wù)調(diào)用方修改配置重啟。上下游間接的通過ip這個配置耦合在了一起,架構(gòu)不合理。
優(yōu)化方案:通過內(nèi)網(wǎng)域名而不是ip來進行下游連接
如果在配置中
使用內(nèi)網(wǎng)域名來進行下游連接,當下游服務(wù)或者數(shù)據(jù)庫更換ip時,只需要
運維層面將內(nèi)網(wǎng)域名指向新的ip,然后統(tǒng)一切斷原有舊的連接,連接就能夠
自動切換到新的ip上來。這個過程不需要所有上游配合,非常帥氣,強烈推薦!
【case5:下游擴容導(dǎo)致上下游耦合】

這次不是換換ip這么簡單了,下游服務(wù)提供方原來是集群(ip1/ip2/ip3,當然,上游配置的是內(nèi)網(wǎng)域名),現(xiàn)在
集群要擴容為(ip1/ip2/ip3/ip4/ip5),如果沒有特殊的架構(gòu)設(shè)計,上游往往需要修改配置,新增擴容后的節(jié)點,再重啟,導(dǎo)致上下游耦合。
這類case,大伙有什么好的方案解耦么?
技術(shù)細節(jié),且聽下回分解。
四、總結(jié)
如何發(fā)現(xiàn)系統(tǒng)架構(gòu)中不合理的“反向依賴”設(shè)計?回答:
(1)變動方是A,配合方卻是BCDE
(2)需求方是A,改動方確是BCDE
想想“換IP的是你,配合重啟的卻是我”,此時往往架構(gòu)上可以進行解耦優(yōu)化。
常見反向依賴及優(yōu)化方案?(1)
公共庫導(dǎo)致耦合優(yōu)化一:如果公共庫是
業(yè)務(wù)特性代碼,進行公共庫
垂直拆分
優(yōu)化二:如果公共庫是
業(yè)務(wù)共性代碼,進行
服務(wù)化下沉抽象
(2)
服務(wù)化不徹底導(dǎo)致耦合特征:服務(wù)中
包含大量“根據(jù)不同業(yè)務(wù),執(zhí)行不同個性分支”的代碼優(yōu)化方案:個性代碼放到業(yè)務(wù)層實現(xiàn),
將服務(wù)化更徹底更純粹(3)
notify的不合理實現(xiàn)導(dǎo)致的耦合特征:調(diào)用方不關(guān)注執(zhí)行結(jié)果,
以調(diào)用的方式去實現(xiàn)通知,新增訂閱者,修改代碼的是發(fā)布者
優(yōu)化方案:通過MQ解耦(4)
配置中的ip導(dǎo)致上下游耦合特征:
多個上游需要修改配置重啟優(yōu)化方案:
使用內(nèi)網(wǎng)域名替代內(nèi)網(wǎng)ip,通過“修改DNS指向,統(tǒng)一切斷舊連接”的方式來上游無感切換
(5)
下游擴容導(dǎo)致上下游耦合特性:多個上游需要修改配置重啟
更多建議: