最近留言問「微服務」的朋友頗多,找歷史文章又找不到,故從新優化發佈,但願你們有收穫,不要被「微服務大潮」誤導。nginx
「微服務架構」的話題很是之火,不少朋友都在小窗我,說怎麼作服務化?解答「怎麼作」以前,先得了解「爲何作」。
畫外音:作技術千萬不能是這種思路,「別人都在作,因此咱們也要搞」。程序員
並非全部的業務都適合「服務化」,互聯網高可用架構,到底爲何要服務化?web
在服務化以前,互聯網的典型高可用架構以下:
(1)客戶端,APP,H5,小程序,PC瀏覽器;
(2)後端入口,高可用的反向代理nginx集羣;
(3)站點應用,高可用的web-server集羣;
(4)後端存儲,高可用db集羣;數據庫
更典型的,web-server集羣經過DAO/ORM等技術來訪問數據庫。小程序
能夠看到,最初是沒有服務層的,此時架構會碰到什麼典型痛點呢?後端
舉一個最多見的業務例子,用戶數據訪問,絕大部分公司都有一個數據庫存儲用戶數據,各個業務都有訪問用戶數據的需求。
在有用戶服務以前,各個業務線都是本身經過DAO寫SQL訪問user庫來存取用戶數據,這無形中就致使了代碼的拷貝。瀏覽器
隨着併發量的愈來愈高,用戶數據的訪問數據庫成了瓶頸,須要加入緩存來下降數據庫的讀壓力,因而架構中引入了緩存,若是沒有統一的服務層,各個業務線都須要關注緩存的引入致使的複雜性。緩存
對於寫請求,全部業務線都要升級代碼:
(1)先淘汰cache;
(2)再寫db;網絡
對於讀請求,全部業務線也都要升級代碼:
(1)先讀cache,命中則返回;
(2)沒命中則讀db;
(3)再把數據放入cache;架構
這個複雜性是典型的「業務無關」的複雜性,業務方須要被迫升級。
隨着數據量的愈來愈大,數據庫須要進行水平拆分,因而架構中又引入了分庫分表,若是沒有統一的服務層,各個業務線都須要關注分庫分表的引入致使的複雜性。
這個複雜性也是典型的「業務無關」的複雜性,業務方須要被迫升級。
典型的耦合,還包括bug的修改,發現一個bug,多個地方都須要修改。
服務化並非惟一的解決上述兩痛點的方法,抽象出統一的「庫」是最早容易想到的解決(1)代碼拷貝;(2)複雜性擴散;的方法。
抽象出一個user.so,負責整個用戶數據的存取,從而避免代碼的拷貝。至於複雜性,也只有user.so這一個地方須要關注了。
解決了舊的問題,會引入新的問題,庫的版本維護會致使業務線之間的耦合。
業務線A將user.so由版本1升級至版本2,若是不兼容業務線B的代碼,會致使B業務出現問題。
業務線A若是通知了業務線B升級,則是的業務線B會無端作一些「自身業務無關」的升級,很是鬱悶。固然,若是各個業務線都是拷貝了一份代碼則不存在這個問題。
畫外音:有時候拷貝代碼也是有好處的。
業務線經過DAO訪問數據庫,本質上SQL語句仍是各個業務線拼裝的,資深的工程師寫出高質量的SQL,經驗沒有這麼豐富的工程師可能會寫出一些低效的SQL。
假如業務線A寫了一個全表掃描的SQL,致使數據庫的CPU100%,影響的不僅是一個業務線,而是全部的業務線都會受影響。
畫外音:臨時工程序員要背鍋了。
業務線不僅訪問user數據,還會結合本身的業務訪問本身的數據。
畫外音:user_biz表,也是用uid作主鍵。
典型的,經過join數據表來實現各自業務線的一些業務邏輯。
業務線A的table-user與table-A耦合在了一塊兒,業務線B的table-user與table-B耦合在了一塊兒,業務線C的table-user與table-C耦合在了一塊兒,結果就是:table-user,table-A,table-B,table-C都耦合在了一塊兒。
隨着數據量的愈來愈大,業務線ABC的數據庫是沒法垂直拆分開的,必須使用一個大庫(瘋了,一個大庫300多個業務表 =_=)。
互聯網高可用分層架構演進的過程當中,引入了「服務層」。
以上文中的用戶業務爲例,引入了高可用user-service,對業務線響應所用用戶數據的存取。
有服務層以前,業務方訪問用戶數據,須要經過DAO拼裝SQL訪問。
有服務層以後,業務方經過RPC訪問用戶數據,就像調用一個本地函數同樣,很是之爽:
User = UserService::GetUserById(uid);
傳入一個uid,獲得一個User實體,就像調用本地函數同樣,不須要關心序列化,網絡傳輸,後端執行,網絡傳輸,範序列化等複雜性。
全部user數據的存取,都經過user-service來進行,代碼只此一份,不存在拷貝。
升級一處升級,bug修改一處修改。
在沒有服務層以前,全部業務線都須要關注緩存、分庫分表這些細節。
在有了服務層以後,只有服務層須要專一關注底層的複雜性了,向上遊屏蔽了細節。
原來是業務向上遊直接拼接SQL訪問數據庫。
有了服務層以後,全部的SQL都是服務層提供的,業務線不能再隨心所欲了。底層服務對於穩定性的要求更好的話,能夠由更資深的工程師維護,而不是像原來SQL難以收口,難以控制。
原來各個業務的數據庫都混在一個大庫裏,相互join,難以拆分。
服務化以後,底層的數據庫被隔離開了,能夠很方便的拆分出來,進行擴容。
在服務化以前,各業務線上遊想怎麼操縱數據庫都行,遇到了性能瓶頸,各業務線容易扯皮,相互推諉。
服務化以後,服務只提供有限的通用接口,理論上服務集羣可以提供無限性能,性能出現瓶頸,服務層一處集中優化。
服務化不能解決全部問題,若是沒有碰到這些問題,架構未必須要服務化。
但願你們有收穫。
架構師之路-分享可落地的技術文章
推薦閱讀:《近期好文彙總》