
現在微服務大行其道,好像搞應用開發還不懂微服務,就落後别人一個時代了。那麼什麼是微服務?為什麼是微服務?微服務應用的場景是什麼?應該如何上手微服務?
軟體開發的幾種模式
在了解微服務之前,有必要先了解一下軟體開發的組織曆史,這樣才能讓我們更好的了解微服務。
瀑布式開發
軟體工程的名詞借鑒與建築工程,軟體開發的思想和套路,很長時間也來自建築行業。在建築行業,我們要蓋一座大廈,先要搞清楚想要什麼樣子的大廈,然後找設計院設計好建築圖紙,然後剩下的就是交給工程隊依據設計圖紙進行施工,樓改好以後要讓負責驗收的驗收隊進行質檢驗收。那麼對應的軟體開發也就變成需求分析,先搞清我們要開發一個什麼樣的軟體,然後軟體設計,接下來交給碼農做軟體開發,最後交給測試人員進行品質測試。這樣的分工貌似還不錯,而且在很長一段時間确實取得了不菲成就。這樣分工以後,突破了一個人開發軟體的時代,讓不同層次的人負責不同的業務,大家互相協調分工合作。而且有人專門負責設計,有人負責編碼,有人負責測試。軟體無論規模,穩定性和品質較個人時代都有了大規模的提升。
然而随着軟體工程規模的越來越大,特别是網際網路出現以後,不但軟體規模大,而且變化還快,上午人們還在尋找一匹快馬,晚上就已經變成了汽車。人們漸漸發現軟體不像建築一樣很容易具象化,然後可以清楚的表達設計,而且還不容易變化,很少有一年前需要一個大褲衩的建築,一年後希望給它改成鳥巢。但是在軟體行業這樣的需求變化簡直是家常便飯。人們發現軟體越來越難設計,變化太經常了。這個時候,一般的軟體開發和需求方都要反複确認,每次确認要簽字畫押,保證不能修改需求。但是這麼幹明顯不能适應市場。為了解決這些問題,人們也想和很多辦法,比如面向對象程式設計,軟體工程的原則,總結設計模式,都是為了來更好的應對變化。但是都不能很好的面對變化,軟體人總結:沒有銀彈。
靈活開發
這個時候有人提出來了:既然變化是不可避免的,不如我們先不要抱怨了,接受這種變化吧。既然軟體不那麼好設計架構。那麼要不然,讓我們先把架構的問題放一放。先把現在需要的最小的核心功能做出來。然後市場需要啥,咱們就在上面加什麼,我們要擁抱變化嘛!但是這樣一來,又出現很多問題,一直這樣修修補補的代碼,用不了多久就變成一團意大利面了,連他媽都不認識他是誰了,别說開發的人了。而且修修改改很容易觸一發而動全身。上周遞交的bug确實修改好了,但是上上周明明測試沒有問題的代碼,又出現大問題了。而且這個時候,如果每次修改都要對整個系統進行檢查和測試,又太浪費人力物力,變化依然是噩夢。
為了解決這些問題。軟體人又想到了很多辦法。比如: 1. 面向測試開發。我們既然要擁抱變化,那麼我們不如把需要實作的結果直接寫成測試用例。然後再去寫能滿足測試用例的代碼,這樣讓機器去自己跑一邊,如果測試用例沒問題,證明我們的代碼至少沒大的問題。而且如果不幸發生了觸一發而動全身的問題。那麼測試用例能幫我們及時的發現問題。 2. 依賴抽想而非依賴實作的面向接口程式設計。人們發現無論如何變化,總體的契約很少變化,那麼我們定義好接口。所有的實作都依賴于接口,然後用各種設計模式來保證接口不變依然可以擁抱變化,這樣的變化最少是萬變不離其宗了,就有章法可尋。 3. 既然是面向接口程式設計,不依賴實作,那麼我們就很少去new一個對象,而是通過反射或者容器技術去實作IOC。 4. 既然是擁抱變化開發,那麼就意味着更新疊代特别快,我們僅僅保證開發和開發品質還不行,還想實作快速自動化的部署,這就是持續內建的概念。
即便是這些問題都解決,還是感覺少點什麼!
每次開發都要下載下傳所有的應用代碼,然後開發完成後要測試所有的用例,然後再進行所有代碼的編譯。然後把程式停掉進行更新。能不能把不變得代碼不進行修改,然後隻修改更新變化的代碼。能不能每次隻編譯變化的代碼?而不動不變得代碼?能不能進行熱更新,不需要停服就可以完成更新。甚至能不能先讓一部分客戶測試下新的功能?
微服務時代
如果我們把每部分都做成一個獨立的應用。然後哪塊需要變化我們就把那一塊進行開發,編譯然後更新,隻要保證每塊和每塊直接的契約(接口)不變化。那麼幾乎都可以做到我們上面的要求。這樣把一個應用拆解廠多個應用的辦法,我們就稱之為微服務。這樣我們就可以實作熱更新,而且還不用動其他的代碼,需要更新那個,我們就單獨架設一個應用,然後讓其他應用調用即可。同時還可以儲存新舊兩個版本,然後一部分客戶走舊的接口,另外一部分走新的接口。而且還可以突破以前單台伺服器的問題,我們可以把不同的應用部署在不同的伺服器,甚至一個應用部署多個伺服器,既可以減負,還可以保證高可用,想想就激動,太有才了!
先别急着激動。因為馬上就會遇到一大堆的問題。 1. 單體應用相對來說調用簡單,直接函數調用,出錯的可能性小很多。現在分成一堆應用,每個應用直接互相調用。網路通信出問題的可能性更大。 2. 一個應用如果更新,那麼是把以前的應用直接停掉進行更新呢?還是不停以前的,先開一個新的應用,那麼調用他的應用怎麼能知道呢? 3. 這一大堆的應用,萬一那個出問題了?要如何确認并且及時的修正呢? 4. 以前單體應用,每次更新,更新1個應用,即便有多台伺服器,數量相對較少。現在一下子幾十個應用。以前更新都要熬夜通宵,到0點使用者少了,進行更新。然後還要反複測試,現在更新這麼多豈不是要搞死人。 5. 如果一個應用啟動多個執行個體,那麼調用者到底要調用哪一個,萬一其中一個有問題了,調用者如何屏蔽掉這個去調用其他餓。 6. 相比之下微服務互相調用,效率肯定遠遠低于單體應用。說好的高并發變成了高負載。
那麼既然有這麼多問題,就得找到解決方法嘛。
docker 容器技術
這個時候出來一個神器,叫做docker.他可以把一個伺服器虛拟化好多伺服器,而且環境相同。更主要的是這個玩意效率高,比以前的虛拟機運作的成本低,消耗伺服器資源少,這樣才能在一個伺服器中虛拟化成百上千的虛拟機而不會當機。此外這個家夥的環境配置,安裝程式,啟動服務,都是用指令行就可以執行。你可以把這些指令行提前寫好,結合CI工具,一個按鈕,就可以自動完成從倉庫拉去代碼,然後配置好環境,并且按照需求或者要求,在伺服器中啟動若幹個配置好的應用。docker的容器技術,為微服務奠定了基本的基礎。
服務治理中心
這麼多微服務A調用B,B又調用C,容器把他們一股腦地安裝到了好多台伺服器上,每個伺服器的位址都不一樣,而且端口也不一樣,固定下來寫調用關系吧,端口一發生改變,就崩塌了。這個時候很容易寫到一個東西。就是大家把每個服務的位址和端口都登記到一個地方,然後再去這個地方查找具體的服務對應的位址和端口,然後再去調用,有點類似網際網路的DNS伺服器。這個東西就叫做伺服器治理中心,Java中常用的Spring cloud 裡面的Eureka,或者阿裡的Nacos, Zookeeper。負責登記儲存資訊的叫做治理伺服器,而每個應用都需要一個治理的用戶端來把自己登記到伺服器上。
用戶端負載均衡器
我們提到了每個子產品都會搭建很多應用,或者說每個應用都會有很多執行個體。怎麼決定調用這個子產品的時候,具體走哪個應用。而且我們去手寫調用代碼,總是感覺非常麻煩。這個時候就有了負載均衡器這個概念。一方面簡化自己寫網絡請求處理的代碼,另外可以根據不同的政策,把請求按期望的分布到不同的應用上去。這個就是負載均衡器的概念。如spring cloud中 Ribbon。
斷路器
我們提到的問題中,會有某個特殊情況,其中的一個應用當機了,那麼傳遞給他請求都會出錯。如果不能及時把這個應用給剔除掉,就會有若幹請求總是出錯。這個時候就用到了斷路器。當滿足一定的條件,我們就把一個應用給剔除掉,直接剔除掉,或者給出一個簡單的提示。這個時候就叫做降級服務,比如你雙十一去某寶購物,它伺服器壓力太大,在奔潰的邊緣了,就會給你一個提示:目前使用者通路太多,請稍後。另外如果可以限制某個接口流量,而不是到他崩潰了再剔除,豈不是更好,這個就是限速器。都集合在斷路器中,如spring cloud中的Hystrix和resilience4j等等。
網關
我們的斷路器和負載均衡都是給内部調用使用的。但是我們面向客戶的應用,不可能要求每個客戶都在自己浏覽器上安裝斷路器或者負載均衡。我們需要一個東西擋在我們面向客戶的接口和客戶之間。以前我們做單體應用的時候,我們用硬體負載均衡或者nginx來實作。當然現在我們依然可以用ngix來實作,但是如果我們希望能夠更加精确的程式設計比如某個接口進行限流,熔斷以後如何降級服務。然後什麼接口優先保證,什麼接口次要。這個時候如果能程式設計就更好,nginx給人的感覺總是配置。是以我們經常用到spring cloud中的zuul或者gateway
配置服務
這麼多應用,萬一我們想修改個什麼東西。比如修改下資料庫密碼,這下可算是捅了馬蜂窩了。挨着一個一個修改,然後重新開機。如果能有幾種在一個地方,我們隻需要修改一處該多好了。這個時候就用到了spring cloud config.我們可以在本地檔案,或者git倉庫,或者資料庫中修改,就可以幾種管理所有的配置服務。是不是更加友善了呢?
全鍊路追蹤
基本上經過我們上面的學習和了解,跑起來一組微服務一點問題都沒有了。但是如果中間某個應用出問題了,咱們隻能等待斷路器給他斷掉,然後等流量過去了,再自行恢複。能不能恢複,我們隻能聽天由命,因為我們也不一定知道哪個出問題,不知道問題在哪裡,怎麼解決。這個時候就需要一個追蹤的東西,能知道一個通路調用了多少環節,每個環節占用多少時間,友善及時的發現問題,并且處理問題。同時還有助于我們盡早優化代碼。這個玩意兒,我們叫做全鍊路追蹤如spring cloud sleuth.
監控
有了鍊路追蹤,我們的更容易發現問題。我們還需要需要一個監控器,讓各種資料彙總成圖示。spring cloud提供了一個spring cloud admin很友善容易的讓我們對所有的微服務進行監控。
日志管理
我們做單體應用的時候,就少不了日志來發現問題。微服務那麼多應用,更少不了日志。如果想以前一樣的儲存到一個檔案,查找問題就是大海撈針,不用擔心,前人已經給我們開發了十分完善的輪子。比如Elasticsearch和Kibana,友善我們可視化的對日志進行管理。
消息隊列 資料流軟體
在這麼多服務互相調用,然後有的服務可能會一次調用多個其他服務。比如一個訂單服務,收到訂單以後,肯定得從買家賬戶扣錢,還得添加購物車,同時還得通知賣家庫存減少等等操作。那麼可能每個部分都是一個服務,這樣互相調用耦合度就非常大。特别是,如果業務鍊條需要延長了,那麼就需要去修改具體的服務。這個時候就引入了消息隊列,和資料流的感念。負責訂單的子產品,隻需要把相關的消息放到消息隊列,然後其他需要接受到訂單消息進行的操作,隻需要訂閱該隊列,就可以依次執行。大大降低耦合,擁抱變化。
如果了解了微服務的由來的必要性,就很容易了解每一個部分為什麼出現,是應對什麼樣的應用場景。學習起來就會事半功倍。