口述/孫培然‧彙整/CIO編輯室
傳統 HIS 微服務化最後要談的是微服務實踐的經驗。有人會問,我現在的程式是單體,要怎麼開始作微服務?有哪些狀況就必須要盡快重構微服務?
重構微服務策略的優先順序
第一個重構微服務的時機點,就是舊系統不易維護,系統一旦有問題或者要改需求時,得花一大半的時間才能看懂程式,不如就重寫,重新訪談使用者的需求去把它改成微服務架構。
系統常常出問題不穩定時,尤其是攸關核心業務的相關系統,如醫院的核心系統就是醫囑系統,或是這個服務有很多人在使用,如醫院最多人使用的就是護理系統,就應該優先規劃微服務。
此外,如果把原本前、後端程式寫在一起的專案,切開成前、後端個別專案,讓很多後端的程式,可以提供給不同的前端程式呼叫服務,此時也可以透過重構微服務,循序漸進的去汰舊換新單體的程式。
重構微服務的三大策略
如果你已經決定要重構微服務,記住要「先用加法,別用減法」。這個部分有三個策略:停止挖掘(Stop Digging)、前後端分離(Split Frontend and Backend),以及提取服務(Extract Services)。
第一個策略停止挖掘,是指如果現在有新的功能需求,記住不要再加注在單體的程式上了,你應該重新以微服務架構,去寫出一個小的微服務,再透過RESTful API來呼叫,也就是向外擴充,用這種方式慢慢逐步的汰舊換新原本的單體程式。
第二個策略是將前、後端分離,就是把本來寫在一起的前端跟後端一分為二,後端就可以即時重複給其他前端程式使用。
第三個策略提取服務的目的是重構服務。如果某一個服務內有三個模組(如圖一),首先 A 模組去呼叫 B 模組,而 B 模組會再去呼叫 C 模組,而且三個模組皆互相獨立功能,因此將這三個模組提取出來重新拆解,重新發展成三個微服務,而它們之間的溝通,再透 RESTful API 呼叫達到真的完全解耦,互不干擾,如圖二所示。
假設很多程式都已經變成可以水平擴充的微服務,當有高併發(High Concurrency)時,便可以隨時水平擴展微服務實例(Instance)來服務更多的請求(Request)。比如說一個服務實例原本可以服務 100 請求,今天有 1,000 請求需要服務,我只要開 10 個實例來服務這 1,000 請求,系統一樣可以保持平穩運行,也不會因為負載太大而死掉,就不用再怕高併發量的情形發生。
但是上述的做法只是將前端與後端去做成微服務,傳統的集中式關聯資料庫卻還沒有重構微服務,也就很可能會成為未來的瓶頸。但資料庫也要微服務化嗎?
集中式關聯資料庫的問題根源,就是太過度依賴「關聯」及「交易」處理,也常常必須使用到 Join/View/Transaction 的指令。要處理集中式關聯資料庫的問題,首先是用垂直切割,比如說我有一個醫囑的資料表(Table),也就是醫師每次開給病人的處方資料表可能太大了,怕影響效能,所以我們會把它切成門診跟住院,分別放在獨立不同的資料庫,解決集中式的問題。
還有一種是水平切割,就算我把門診醫囑已經拆成一個資料表,但以中國附醫而言,門診醫囑裡面的資料多達一、二十年,不能只是要找一個病人的資料,都要去那個一、二十年的資料庫裡面去找,此時就需要用水平切割來降低資料表的筆數,將不同的年份的資料放到獨立的資料庫,如最近一、兩年的資料,就放在短期資料庫,超過兩年了,就把它放到另外一個長期資料庫。
但就算這兩個問題都解決了,不同資料庫之間的交易要怎麼去做到 ACID?這是個需要深思的問題,就像我在前面的文章提到的 NoSQL 資料庫的概念,也就是要用分散式資料庫的概念去思考你的微服務架構。
合理有效拆分應用 實現敏捷開發和部署
至於要怎麼去拆微服務,可以利用 SOLID 物件導向五大原則。
S 是單一職責(Single Responsibility Principle),指一個類別只負責一件事情,專心做好;
O 是開放封閉(Open Closed Principle),就是當新增功能時,確保不改變現有程式碼的前提,只是增加新的程式碼來實作新的功能。
L 是里氏替換原則(Liskov Substitution Principle),也就是說子類別要完全繼承父類別所有的功能。
I 是介面分離(Interface Segregation Principle),要把不同功能透過介面分離出來,互不干擾,比如說我們現在很多的電腦是 All-in-one,一旦螢幕壞掉了,等於 CPU 及記憶體也不能用,但如果把螢幕、鍵盤、CPU 分離,一旦螢幕壞了,我只要換螢幕就好了;
D 是依賴倒轉(Dependency Inversion Principle),講白一點就是「不要把話說得太死,盡量講得較為抽象化一點」,例如早期備份是用磁帶備份,若你的程式寫死磁帶備份,日後若改為光碟或隨身碟、或者雲端等不同的備份設備,那每一次改變設備時都得要改寫程式,也就違反了開放封閉原則,所以要把它依賴倒轉,抽象化為「備份」就好了,日後只要注入什麼設備就是是什麼備份,如注入雲端就是雲端備份。
[ 加入 CIO Taiwan 官方 LINE 與 Facebook ,與全球CIO同步獲取精華見解 ]
再來是利用 DCI(Data,Context,Interactive),也就是物件導向的軟體架構模式。與傳統的物件導向相比,DCI 可以更精確的描述資料跟流程或行為之間的關係進行建模,從而更容易被人理解,也就是之前講過很多不同的情境,要有不同的角色扮演的概念。
可以做到合理有效拆分應用之後,就可以實現敏捷的開發方式,也就是在 SCRUM 的每一個衝刺(2 到 4 周左右),就可以讓使用者看到產品開發的初步結果,讓使用者針對產品做到我們所謂的敏捷反應,不斷迭代更新部署。也就是把整個部署工作透過 CI/CD 工具自動化,用持續整合、持續部署的方式,在開發階段就自動協助開發人員偵測程式碼問題,並部署到伺服器,讓開發環境更加接近生產環境,也就更貼近使用者。
基礎建設要完備 以免欲速則不達
值得注意的是微服務架構要實際落地,並沒有想像的那麼簡單。如果沒有完善的基礎建設,就開始去嘗試微服務架構,反而會產生很大的困擾。所以在導入微服務架構之前,包括平台框架方面的容器化、CI/CD、微服務治理、監控等平台,以及研發團隊方面的技術、回應及維護能力都必須要達到比較高的要求,若沒有完善的 DevOps、CI/CD 與容器化協作技術的支持,可能導致部署到生產環境時,會長達好幾個小時。所以在開始落地微服務架構以及之後的落地過程中,需要不斷補全、完善微服務架構所需的基礎建設能力,否則只會「欲速則不達」。
[ 瀏覽孫培然所有文章 ]
微服務需要的基礎建設,第一個就是容器化能力,需要如 Kubernetes、雲平台之類的平台技術,幫助應用提升標準化部署、測試快速回饋、可移植性保障、版本化發佈等方面的效率。
第二個是微服務治理,也就是說如果系統的服務成千上萬,需要微服務治理平台做支撐,做到服務路由、限流、降級及熔斷等服務治理,充分掌控服務健康狀態。
第三個是監控報警方面,針對實體機、虛擬化及容器化的資源使用監控、服務調用數量異常、服務回應異常、整體調用鏈路狀況等,都要可以隨時的去監控,同時要提高監控報警平台的視覺化能力,也能夠有效增加系統維運的整體效率。
不要忽略人和業務的複雜性
除此之外,千萬別忘了人的行為跟業務的複雜性。當整個微服務架構已經從中心化的組織架構轉變成去中心化的組織架構,很難保證組織內相應的變更能夠及時跟進。
比如說在微服務改造之前,開發人員跟維護人員之間的交集並不多。但實施微服務化以後,有很多的設定跟資源要由誰來定義?此時開發人員跟維護人員可能會互相推辭。
所以整個微服務化改造以後,企業組織架構也必須要去重新改造,也必須要考慮「人的因素」,重新定義每一個角色的責任跟服務邊界,才能讓服務可以快速的展開維運,架構調整所帶來的工作內容變動與團隊各研發角色,也要再重新規劃分配。
微服務架構並非完美無缺
我最後要強調的是,微服務架構並不是銀彈,如果想把它當作擺脫現有困境的救命仙丹,反而會適得其反。微服務雖然是個好東西,但無論是從單體直接切換到微服務,或者是從 SOA 過渡到微服務,都必須要根據自己本身的技術能力跟業務規劃,還有組織情況、預期規模去多方面的考量。
所以不要讓整個團隊隨風起舞,要找到讓整個資訊團隊在一個階段內都相對舒適的平衡點,不要因為跟風「微服務」及「雲原生」而過於激進,也不要在架構變更上一味求穩而過於保守。
要針對不同的情境、不同的模式,用循序漸進的方式去做轉變。沒有一種架構可以通吃所有的場景,如果企圖使用單一種架構模式,這種想法是很危險的。
(本文授權非營利轉載,請註明出處:CIO Taiwan)