都在說(shuō)微服務(wù),那么微服務(wù)的反模式和陷井是什么(一)
http://www.lxweimin.com/p/3986239138fe
六、無(wú)因的開(kāi)發(fā)者陷阱
名字來(lái)自詹姆斯·迪恩演的電影《無(wú)因的反叛》(Rebel Without a Cause),一個(gè)問(wèn)題青年因?yàn)殄e(cuò)誤的原因做了錯(cuò)誤的決定。
很多架構(gòu)師和開(kāi)發(fā)者在微服務(wù)的開(kāi)發(fā)中權(quán)衡利弊, 比如服務(wù)粒度和運(yùn)維工具,但是基于錯(cuò)誤的原因,做了錯(cuò)誤的決定。
6.1 做出錯(cuò)誤的決定
圖6-1說(shuō)明了一種情況是通過(guò)測(cè)試發(fā)現(xiàn)服務(wù)劃分的太細(xì)了,因此非常影響性能,主要是由于服務(wù)劃分的太細(xì)導(dǎo)致增加了通信工作量也在一定程度上對(duì)穩(wěn)定性造成一定影響。在這種情況下,開(kāi)發(fā)人員或架構(gòu)師決定將這些服務(wù)整合到一個(gè)更粗粒度的服務(wù)中,以解決性能和可靠性問(wèn)題。
這個(gè)方案看起來(lái)似乎合情合理,但是之后的布署、更改控制和測(cè)試都會(huì)受到影響。
再看圖6-2,這種場(chǎng)景是左邊的服務(wù)太粗了,影響了服務(wù)的測(cè)試和布署,于是進(jìn)行了拆分,減少了每個(gè)服務(wù)的范圍。
通過(guò)以上二個(gè)場(chǎng)景我們可以看出,如果服務(wù)太細(xì)我們就需要考慮將服務(wù)合并,如果服務(wù)太粗,我們又會(huì)考慮將服務(wù)進(jìn)行拆分。太細(xì)的話會(huì)增加通信成本和容易造成可靠性不穩(wěn)定,太粗的話又容易導(dǎo)致不容易測(cè)試和上線布署,所以這就要看我們?nèi)绾蝸?lái)權(quán)衡利弊。
6.2 了解業(yè)務(wù)驅(qū)動(dòng)
了解業(yè)務(wù)驅(qū)動(dòng)對(duì)于合理設(shè)計(jì)微服務(wù)至關(guān)重要,每一個(gè)架構(gòu)師或者開(kāi)發(fā)者都應(yīng)該先回答以下三個(gè)問(wèn)題:
- 我們?yōu)槭裁匆O(shè)計(jì)微服務(wù)架構(gòu)?
- 主要的業(yè)務(wù)驅(qū)動(dòng)是什么?
- 最重要的架構(gòu)特點(diǎn)是什么?
使用可布署、性能、健壯性和可擴(kuò)展作為主要的架構(gòu)特性,我們其實(shí)最先需要考慮的是如何利用業(yè)務(wù)來(lái)進(jìn)行服務(wù)的整合和拆分。
場(chǎng)景一:遷移到微服務(wù)主要是想達(dá)到快速上線和布署
在這種場(chǎng)景下服務(wù)的可布署能力相對(duì)要大于性能、穩(wěn)定性因素,所以要拆分服務(wù)的時(shí)候可以考慮稍微細(xì)粒度一些。
場(chǎng)景二:遷移到微服務(wù)主要是想提高系統(tǒng)的性能和健壯性
這種場(chǎng)景是從單一應(yīng)用程序遷移到微服務(wù)架構(gòu)的一個(gè)常見(jiàn)因素,很多公司都是業(yè)務(wù)驅(qū)動(dòng),那么就需要考慮服務(wù)的可靠性和健壯性,因此傾向于更粗粒度的服務(wù),而不是細(xì)粒度的服務(wù)。
我經(jīng)常使用的一種方式借助白板和團(tuán)隊(duì)成員一起討論,如圖6-3所示,每當(dāng)有服務(wù)粒度的劃分問(wèn)題的時(shí)候,我們經(jīng)常在白板上做草稿討論清楚。
七、趕潮流陷阱
你必須擁抱微服務(wù),因?yàn)檫@是目前的趨勢(shì),而且其他人和公司目前都已經(jīng)這么做了。
我們盲目的使用微服務(wù),卻還沒(méi)有仔細(xì)分析業(yè)務(wù)需求、組織架構(gòu)和技術(shù)環(huán)境,這就是隨大流陷阱。
避免這個(gè)陷阱的方式充分理解微服務(wù)的好處和短處,俗話說(shuō),知己知彼,百戰(zhàn)不殆。
7.1 微服務(wù)的優(yōu)點(diǎn)和缺點(diǎn)
優(yōu)點(diǎn):
- 發(fā)布:易于發(fā)布
- 測(cè)試:易于測(cè)試
- 改變控制:更容易的改變一個(gè)服務(wù)的功能
- 模塊
- 規(guī)模可擴(kuò)展
缺點(diǎn):
- Team組織改變
- 性能
- 可靠性降低
- 運(yùn)維難度加大
7.2 其他架構(gòu)模型
微服務(wù)的架構(gòu)很好,但是不是唯一的架構(gòu)模式,比如下面還有一些其它的架構(gòu)模式:
- Service-Based Architecture
- Service-Oriented Architecture
- Layered Architecture
- Microkernel Architecture
- Space-Based Architecture
- Event-Driven Architecture
- Pipeline Architecture
當(dāng)然你并不一定只使用唯一的一種架構(gòu)模式,你可能在系統(tǒng)中混用這些架構(gòu)模式。
下面有一些架構(gòu)的參考資料:
Software Architecture Fundamentals: Understanding the Basics
Software Architecture Fundamentals: Beyond the Basics
Software Architecture Fundamentals: Service-Based Architecture
Software Architecture Patterns
Microservices vs. Service-Oriented Architecture
八、靜態(tài)契約陷阱
在微服務(wù)的消費(fèi)者和提供者之間提供了一種契約,契約主要包括輸入和輸出數(shù)據(jù)、以及操作的名稱,契約通常是以XML、JSON或者JAVA對(duì)象等來(lái)表示。但是這些契約永遠(yuǎn)不會(huì)改變嗎?
這里舉個(gè)例子來(lái)說(shuō)明因?yàn)榉?wù)契約版本控制而發(fā)生的問(wèn)題:
假如你有一個(gè)服務(wù)是由三個(gè)不同的客戶端訪問(wèn)(client1、client2和client3),這時(shí)client1想更改服務(wù)契約,你要檢查client2和client3能否適應(yīng)這個(gè)改變,并且client2和client3告訴我適應(yīng)不了這個(gè)改變,需要數(shù)周時(shí)間才能調(diào)整完成。這時(shí)候我需要告訴client1,client2和client3需要數(shù)周時(shí)間才能適應(yīng)調(diào)整完成,但是client1卻不能等待這么長(zhǎng)時(shí)間。
可以在你的服務(wù)契約中提供版本控制,實(shí)現(xiàn)向后兼容。現(xiàn)在我們可以根據(jù)client1的請(qǐng)求做一些靈活的控制,我們可以創(chuàng)建一個(gè)新版本的契約,比如v1.1,client2和client3依然使用v1版本,這樣client1就可以立刻作為契約更改,而不必糾結(jié)于client2和client3需要適應(yīng)調(diào)整的時(shí)間。
有兩種實(shí)現(xiàn)方式:在header中加入版本號(hào),或者在契約自身scheme中加入版本號(hào)。
8.1 header版本控制
契約版本的第一種辦法是把版本號(hào)放在遠(yuǎn)程訪問(wèn)協(xié)議頭,如圖8-1所示,遠(yuǎn)程訪問(wèn)協(xié)議包括REST, SOAP, AMQP, JMS, MSMQ等等。
例如在使用REST的時(shí)候,可以使用MIME類型來(lái)指定協(xié)議版本,如下代碼:
POST /trade/buy
Accept: application/vnd.svc.trade.v2+json
通過(guò)在header的MIME類型中指定契約版本號(hào),服務(wù)端就可以通過(guò)header的MINE類型解析得到相應(yīng)的版本號(hào)。
8.2 Schema版本控制
第二種版本控制方式是在契約自身中進(jìn)行,不需要在header中指定版本號(hào),如圖8-2所示。
請(qǐng)先看如下json格式數(shù)據(jù):
{
"$schema": "http://json-schema.org/draft-04/schema#",
"properties": {
"version": {"type": "integer"},
"acct": {"type": "number"},
"cusip": {"type": "string"},
"sedol": {"type": "string"},
"shares": {"type": "number", "minimum": 100}
},
"required": ["version", "acct", "shares"]
}
該模式直接將版本號(hào)定義在契約的輸入數(shù)據(jù)中,這種模式最大的優(yōu)點(diǎn)是與協(xié)議無(wú)關(guān),只與數(shù)據(jù)格式有關(guān)。
POST /trade/buy
Accept: application/json
{ "version": "2",
"acct": "12345",
"sedol": "2046251",
"shares": "1000" }
String msg = createJSON(
"version","2",
"acct","12345",
"sedol","2046251",
"shares","1000")};
jmsContext.createProducer().send(queue, msg);
這種方式也有一些不足就是每一次都需要對(duì)消息數(shù)據(jù)進(jìn)行解析,提取出版本號(hào)進(jìn)行校驗(yàn),而且數(shù)據(jù)格式也有可能會(huì)改變也不太容易做到自動(dòng)映射到JAVA對(duì)象中。