無論你喜不喜歡微服務,如今微服務無疑已是程序員們繞不過去的話題了。不管你是想把目前的架構改爲微服務,仍是你要出去面試高級一點的崗位,須要深刻理解微服務。程序員
提起微服務,不少程序員對它是又愛又恨,想學微服務不知道如何開始,學了一點以後,又找不到地方去實踐。總之就是感受微服務高不可攀,又很難駕馭。面試
首先要明白的是微服務是有套路的,而這些套路基本上解決了微服務結構面臨的幾乎全部重要問題。數據庫
這些套路就是微服務本身的架構模式編程
若是咱們能深刻了解這些模式的其前因後果,就能夠理解了微服務絕大部份內容。學習快速,實用價值也極大。服務器
1. 微服務最基本的模式
這篇文章先來說第一個最基本的模式,這個模式我估計須要三篇文章才能講透,這是上篇。打算中篇寫實踐,下篇寫問題。架構
但願你們能學的輕鬆。併發
微服務最基本的模式就是:app
一個服務一個數據庫運維
上圖就是一個最簡單的微服務模式了。分佈式
一個服務一個數據庫這種模式,是微服務體系結構中的最基礎也是最核心的模式。看着簡單,可是,這個模式蘊含着微服務的最基本的思想。
要弄清楚一個服務一個數據庫這種模式,首先咱們就須要問一下,爲何咱們要搞微服務。
2. 傳統系統的問題
在談及微服務的時候,和微服務對應的概念叫作單體系統( Monolithic application )。簡單說,微服務是爲了解決單體系統的問題才衍生出來的。單體系統結構以下圖:
那麼這種單體結構出現了什麼問題,致使如今你們必須開口閉口微服務了呢?
3. 單體系統太大了
最首要的一個緣由就是應用系統太大。而因爲應用系統的過於龐大,若是僅是單體系統的話,就引起了各類各樣的問題,體如今如下三個方面:
3.1. 系統自己業務複雜,模塊衆多
系統隨着時間的發展,業務需求愈來愈多。而爲了知足這些需求,就致使整個系統的模塊愈來愈多。而系統模塊愈來愈多,就致使能理解整套系統的人變得愈來愈少,直到最後沒有人能夠理解整套系統。
3.2. 系統的代碼庫很是龐大
代碼量也會隨着系統的增大而增大,代碼量的龐大影響了整個開發流程,會致使整個開發成本變得很高。
- 首先,代碼量大,依賴關係複雜,因此對新接手的開發人員來講,配置開發環境很是耗費精力。
- 其次,代碼量大,加載這些代碼和對應的依賴須要的內存就多,因此就會致使開發人員的 IDE 運行很是緩慢,致使編輯代碼都很麻煩。
- 再次,代碼量大,若是要把整個代碼編譯打包,須要的內存也不少,因此也會致使功能開發完成後,對系統的構建會很是緩慢,致使整個構建的時間很是漫長。
- 再有,代碼量大,幾乎沒人能對總體代碼有比較深刻的瞭解,哪怕可能其中一個要改動的功能,都會由於過於複雜致使開發人員理解不深刻。而這些不深刻的理解又會讓開發人員不能使用最佳的方式去作功能開發,從而致使隱藏的 bug。
3.3. 技術團隊變得很是龐大
因爲功能模塊愈來愈多,這就須要愈來愈多的開發人員去開發和維護這套系統。可是,這些開發人員都是面對的同一套代碼庫,雖然能夠搞分支,你們各搞各的。但是一旦須要合代碼,發佈上線,就是場噩夢。
各類代碼衝突,代碼丟失,均可能在上線的時候發生。
不只如此,因爲顧慮代碼丟失和衝突,就須要在上線前,進行足量的測試,而這些測試又須要投入巨大的時間成本。
可是,如今都講敏捷開發,極可能在還沒上線的時候,後續的業務需求又接踵而至,簡直要命。
4. 業務需求的個性化
搞微服務,還有一個很重要的緣由是業務需求的個性化和顆粒化。
隨着業務的發展,無論是因爲市場競爭仍是自己發展的須要,勢必須要對自己業務模型的深度挖掘以及提升用戶使用系統的各類體驗。而基於此類種種,就勢必要把系統的各個功能模塊作深作透。
這又會引起幾個新的問題:
4.1. 系統功能模塊可能變得更多更雜
系統功能模塊可能被不斷拆分紅了更細碎的模塊,以至可能碎成了顆粒。而因爲功能變得更碎更顆粒了,就會讓產品經理們更容易的提出一些很是細緻的業務需求。
這些很是細緻的需求,極可能會形成頻繁的功能修改和上線要求。而這些無窮盡的快速需求相對總體龐大的系統上線和開發人員的疲於奔命造成了最激烈的衝突。
4.2. 功能模塊對系統的技術要求出現了衝突
好比,不一樣的功能模塊,訂單模塊和支付模塊。訂單模塊就但願系統能儘量的能同時處理大量的訂單,甚至能夠有必定的容錯性,出問題了砍單就能夠了。
可是支付模塊則不同,支付模塊但願系統能儘可能的穩定,而且必須對準確度要求極高,幾乎沒有容錯的空間。
一樣的,在一樣的支付模塊中(根據系統模塊劃分而定),可能同時存在本地帳戶轉帳和三方渠道支付,本地帳戶轉帳可能須要即時,要求極高的響應時間。可是對於第三方支付,則能夠有必定的響應時間容忍度。
若是系統自己是個單體系統,就勢必要求開發人員對整套系統作必定的妥協,對衝突的技術需求作出必定的權衡。而這種權衡極可能影響的就是系統總體的體驗度。
4.3. 系統模塊對服務器的要求出現了衝突
因爲功能的深耕細做,則勢必會出現性能上的不一樣需求。
好比,系統的訂單模塊,我的下單可能會被頻頻訪問,此時,就須要系統的集羣多一些,去處理這些大規模的訪問。可是,一樣的功能模塊裏,可能還存在一些企業團購需求,他們沒有那麼大的訪問量,就不須要那麼多的服務器集羣。
又好比,用戶評論截圖,可能須要大量的數據存儲。可是,一樣的,針對用戶的個性化推薦就可能須要大規模的密集運算。
除了上面說的,系統龐大引起的問題帶來的一些附屬問題:
4.4. 故障的連鎖反應問題
單體系統從技術上,各個模塊是耦合在一塊兒的。在實際運行裏,極可能就會出現一處故障致使整個系統崩盤的現象。
好比,不經常使用的一個 XX 功能出現了內存泄露,致使整個系統所有不可用了。
4.5. 系統的技術鎖死問題
坦白來講,你得認可在編程裏,沒有一種語言是完美的,也沒有一個數據庫是萬能的。
好比,Java 作科學計算就沒有 Python 那麼方便高效。好比,咱們須要存儲很複雜的對象關係的時候,MySQL、Oracle 就不如任何一種圖形數據庫。
因此,系統越複雜,須要不一樣技術的機率就越高。可是又因爲系統的複雜,引入新技術的風險也就越大。因此,新技術的使用很是困難。
同時,系統龐大後,若是一些組件,甚至語言 SDK 自己的問題若是須要升級,也是一件既繁瑣,又充滿風險的事情,因此,技術版本升級也很是困難。
綜上,對於傳統的單體應用來說,系統龐大引起的技術問題,業務發展引起的需求衝突問題……都是沒法單憑單體系統的架構思想就能夠解決的。
那爲何 SOA 也不能解決這些問題呢?
5. SOA 的問題
我們先來看看SOA的結構
能夠看到 SOA 架構中有個 ESB(企業服務總線)。這個 ESB 就是專門用於 SOA 的服務和服務之間的互動,是 SOA 必備的基礎技術設施。
正由於 SOA 有了服務總線的思想,就註定 SOA 切分的服務不可能太細,由於服務出現的越多,這個服務總線就最終會變成一個總體系統的瓶頸。
SOA 的服務切分規模自己就受到了限制,這個限制就會帶來如下的問題:
-
切分不夠細——咱們說過,咱們的主要問題根源是系統過於龐大,而且還堆在了一塊兒。若是咱們切分不夠細,那麼可能的結果就會變爲,從一個很大的系統被切分爲了寥寥幾個也很大的系統,最終沒有解決問題不說,還可能由於系統變成了不一樣的分佈式服務,又引入了新的分佈式系統自己所帶來的問題。
-
ESB 自己就可能成爲一個龐大無比的系統怪獸——ESB 做爲 SOA 的基礎設施,它自己就已經足夠複雜,極可能因爲業務的發展,它本身也變成了一個恐怖的系統怪物。從而讓開發人員不只須要維護原來的系統,極可能還須要爲如何維護和修改ESB自己而傷透腦筋。
因此,能夠看出來,SOA這種思惟方式和架構實現自己不足以解決龐大單體系統帶來的問題。
6. 爲何須要服務
回到咱們的微服務的話題。咱們知道了問題的根源,咱們就須要着手解決這些問題。
首先,既然問題是因爲系統的龐大複雜引發的,那麼咱們就能夠參考軟件裏很廣泛的解決思想:分而克之。
不管一個系統有多大,若是咱們將其拆的足夠小,就能夠把一個複雜的大系統拆分紅許多個小系統,再讓這分解出來的小系統經過對外提供服務的手段,將他們再聚合成一套大的完總體系,從結果上,就等價爲了原來的複雜的大系統了。而這,就是微服務的最樸實的思想。
因此,微服務思想核心有兩個:
- 把系統拆分紅不一樣的部分
- 這些部分要足夠小
微服務這樣作帶來了幾個好處:
-
不管多大多複雜的系統,我只要能拆,會拆,就能把問題簡化,從而不用害怕系統變得複雜。
-
拆分出來的服務只要足夠小,那麼不管開發、部署、運維上,都能獲得無數原來由於系統龐大而沒法得到的好處:修改代碼可能變得簡單了,測試和運行也變得容易了……
-
拆分出來的服務能各自獨立發展,不會互相制約。原來系統是單體系統的時候,模塊之間因爲技術上的耦合,致使沒法自由自在的選用最適合當前功能模塊的技術,也不能爲所欲爲的根據當前功能模塊的負載狀況去彈性的安排服務器。
-
故障自然被隔離開了。咱們把系統切分紅了服務,每一個服務都有本身的進程或者服務器,這樣故障從物理層面就被隔離開了,從而避免了一處不重要的功能故障致使整個系統崩盤。咱們只須要把核心的功能弄的足夠健壯,即便非核心功能有了問題,也不會形成太大的損失。
因此,一套巨大的系統,因爲自己的臃腫和複雜,就可能會要對其自身進行拆分。而這些拆分,根據一些指導原則,將其拆解的夠小,夠簡單,那麼,拆解後帶來的效益是很可觀的。
7. 爲何須要拆庫
服務已經拆了,已經得到那麼大的好處了。
「可是爲何數據庫也必需要拆?」——這實際上是不少使用微服務的同窗最疑惑的問題了。
數據庫拆分不拆分本質上其實就是數據共享的問題。而一個服務一個庫自己的觀念,其實就是盡最大程度的避免數據的共享。
數據共享會帶來以下幾個問題:
7.1. 技術實現依然可能耦合
由於沒有拆分數據庫,因此,極可能一個原本應該獨立出來的服務模塊,必須依賴於另外的服務模塊,而這和咱們拆分服務的初衷出現了衝突。
好比,訂單服務和個性化推薦服務,極可能都須要訪問訂單相關數據。此時,若是不拆數據庫,則極可能因爲訂單業務需求致使的訂單表結構的修改,倒逼個性化推薦服務也要跟着修改。
7.2. 底層數據的過分暴露
仍是上面訂單服務和個性化推薦服務的例子,個性化推薦極可能只是須要一些用戶 id、訂單類別之類的東西,可是因爲數據庫是共享的,極可能開放的就是訂單表的所有數據,而這些數據有不少算是敏感數據,應該被隱藏的,如今則被暴露出去了。
7.3. 無必要的數據訪問競爭
由於是同一個數據庫,這勢必會形成對共享數據的競爭性訪問,而這些競爭性訪問則會大大影響業務模塊的彈性部署。好比,訂單模塊極可能因爲個性化推薦的一些定時批量查詢,被影響了其能承載的併發數據量。
因此,看出來了吧,分庫是必需要考慮進微服務整個體系結構的。
8. 最後留個尾巴
每個服務對應一個數據庫這種模式,是微服務中的最核心最基本的模式,它體現了微服務最核心的思想:
拆分與解耦
通常來講,微服務大部分時候,都會盡可能採用一個服務一個數據庫的模式。
這裏只說了爲何要使用一個服務一個數據庫,而如何去分服務,如何去分數據庫,它們是否還存在一些實踐上的妥協,這會在下一篇文章裏仔細解析。
你好,我是四猿外,一家上市公司的技術總監,管理的技術團隊一百餘人。
我從一名非計算機專業的畢業生,轉行到程序員,一路打拼,一路成長。
我會把本身的成長故事寫成文章,把枯燥的技術文章寫成故事。
歡迎關注個人公衆號:四猿外