
微服務架構(gòu)可以視為面向組件架構(gòu)和面向服務架構(gòu)結(jié)合的產(chǎn)物。大多數(shù)和微服務相關(guān)的討論都是分析業(yè)務應用如何微服務化,如何遠程調(diào)用,如何服務治理,談論基礎(chǔ)設施服務的卻很少,本文主要討論基礎(chǔ)設施服務的微服務化方案。
本文由 SFDC 演講內(nèi)容整理而成,共 3015 字,閱讀大概需要 13 分鐘。
多微的服務才叫微服務?
微服務這一兩年非常火,云、容器等技術(shù)的發(fā)展都是在給微服務鋪路,因為用戶本質(zhì)上需要的是服務,不是資源。
但大多數(shù)和微服務相關(guān)的討論都是分析業(yè)務應用如何微服務化,如何遠程調(diào)用,如何服務治理,談論基礎(chǔ)設施服務的卻很少,我們今天來聊聊這個。

討論微服務,遇到的第一個問題就是多微的服務才能叫微服務呢?是否有個標準,比如多少行代碼?多少個方法?多少個接口?
我們來看看微服務這個概念的最早定義:

大家不用全部仔細看完,只需看看我標出來的幾個關(guān)鍵詞:
- Small Service 這個好理解,就是微服務就是小服務。
- Independently Deployable 可獨立部署。微服務就是將原來的共享庫的依賴方式,改為遠程調(diào)用的依賴方式,每個微服務都是獨立部署的服務。
- Fully AutoMated Deployment 完全的自動化部署。
最后一點往往被大家忽略,為什么微服務就要完全的自動化部署呢?因為以前的幾個服務,被拆分為成百上千的服務,如果沒有完全的自動化部署,基本上是不可維護的。
當然,你可以說『我就是不差錢,我就招上千個人來管這些服務』就不叫微服務了?但這違背了我們搞微服務的目標。

再回歸到微服務這個概念。我個人認為微服務化本身包含兩層意思:
一層是拆。這個大家提到的多,將大的服務拆成小的服務粒度,通過遠程調(diào)用解決依賴。
一層是合。就是整個系統(tǒng)的微服務的所有組件之間應該是一個整體的分布式系統(tǒng),按集群化的方式來設計,服務之間能互相感知,進行自動化協(xié)作。
我們來看一個微服務的例子。


這里面有 A、B、C、D 四個服務,每個服務都依賴數(shù)據(jù)庫以及緩存,對外的服務有負載均衡器,服務之間互相依賴,異步交互通過隊列進行。如上圖所示,通過這樣一個簡單的微服務例子,我們可以看出基礎(chǔ)設施都有哪些。
基礎(chǔ)設施是否需要微服務化?
要解答這個問題,我們先看看當前的基礎(chǔ)設施服務的主要解決方案:

第一種是大的互聯(lián)網(wǎng)公司普遍使用的一種方案。
基礎(chǔ)設施服務托管給基礎(chǔ)設施部門,基礎(chǔ)設施部門包含運維、DBA 等。比如開發(fā)人員需要一套 MySQL 服務的時候,提出申請,基礎(chǔ)設施部門負責搭建和運維,開發(fā)人員只需要連接 MySQL 的 IP 進行使用即可。
第二種方式是托管給云廠商,是使用當前云的基礎(chǔ)設施服務。
比如 QingCloud、AWS 都提供基礎(chǔ)設施服務,當你需要一套 MySQL ,在控制臺即可創(chuàng)建,然后獲取到連接 IP ,這樣可以省去運維基礎(chǔ)設施服務的成本。
但是這兩種方式都有一些問題:

開發(fā)測試流程中的基礎(chǔ)設施服務如何部署,如何自動化?
這個沒法委托給基礎(chǔ)設施部門,需要開發(fā)人員自己動手搞。但開發(fā)人員一方面也沒有精力搞一套完整的自動化工具,但即便是搞了,也解決不了開發(fā)環(huán)境和線上環(huán)境異構(gòu)的問題。前面有位講師的分享也說到了這個問題,異構(gòu)問題總會導致故障,沒出現(xiàn)故障也是時候沒到。
基礎(chǔ)設施服務遷移、伸縮、故障恢復時應用如何感知?
比如有個 MySQL 集群,當前數(shù)據(jù)庫請求量太大,擴容了從庫,應用如何自動感知到這個變化,從而使用新的從庫?
我們再回顧下微服務的要求:集群化與自動化。當前的基礎(chǔ)設施服務的解決方案,不能滿足微服務的集群化,自動化這兩點要求。我們可以得出結(jié)論:基礎(chǔ)設施服務屬于微服務系統(tǒng)中的一部分,需要和業(yè)務服務互相感知,需要被微服務化。
基礎(chǔ)設施服務如何微服務化?

基礎(chǔ)設施服務種類多樣。比如前面那個簡單的微服務系統(tǒng),就用到了很多基礎(chǔ)設施服務,各種服務的有各種不同的配置方式。同時,這些服務的集群機制也是多種多樣的。
我們舉幾個例子來說明下。
[

Zookeeper 的主要配置文件是 zoo.cfg,這個配置文件中需要列出整個集群中的所有節(jié)點,以及對應的 Server ID。
另外,每個節(jié)點還有一個獨立的 MyID 配置文件,這個文件中寫了當前節(jié)點的 Server ID 。比如要把這個集群擴展到 5 個節(jié)點,首先要算出新的節(jié)點的 Server ID 號,生成新的節(jié)點的 MyID 配置文件,同時需要變更每個節(jié)點的 zoo.cfg 配置文件,把新節(jié)點的 Server ID 和 IP 都寫進去,然后重啟服務。

HAproxy 的配置文件中的每個 Backend 后會配置一個 Server 列表。如果后端服務伸縮,就需要變更這個 Server 列表。

Redis Cluster 的這個例子我只是想說明下, Redis 并不是通過配置文件來維護集群信息的,而是通過動態(tài)命令。創(chuàng)建集群,增刪節(jié)點,都需要調(diào)用命令進行。

Kafka 是通過 Zookeeper 來做服務發(fā)現(xiàn)的,所以如果 Zookeeper 集群變更,就需要變更它的配置文件中的 zookeeper.connect 配置項。

粗略的看了以上的幾個例子,大家對基礎(chǔ)設施服務的配置和集群的多樣性有了初步的體驗。
既然要微服務化,就需要設計服務的注冊發(fā)現(xiàn)以及配置變更方案。微服務理想中的方案是應用內(nèi)部自發(fā)現(xiàn),監(jiān)聽配置中心,自動進配置變更。但現(xiàn)實的狀況前面的例子也看到了,我們不可能等待這么多的服務逐漸都改造升級了再用,所以唯一可行的辦法就是通過非侵入的方式,進行第三方的服務注冊,以及配置變更。
QingCloud 應用調(diào)度系統(tǒng)實踐
青云QingCloud 在 IaaS 調(diào)度系統(tǒng)之上構(gòu)建了應用集群的調(diào)度系統(tǒng),它知道集群里的 VM 節(jié)點的變化,然后將集群的基礎(chǔ)信息注冊到我們的元信息服務 Metad 中。

每個 VM 節(jié)點里面都運行一個 Confd 進程,監(jiān)聽 Metad 的元信息,一旦發(fā)生變化,則變更本地的配置和服務。如上圖所示,應用集群依賴一個 Zookeeper 集群,二者都關(guān)聯(lián)在 Metad 中。如果 Zookeeper 集群的節(jié)點發(fā)生變化,應用集群是可以通過 Metad 感知到變化,并且通過 Confd 進行配置變更。
下面我分別介紹一下該過程使用到的一些組件。

Etcd 是一個開源的分布式的一致性 KV 存儲,提供元信息的持久化,同時它支持 Watch 機制,可以實現(xiàn)變更推送。

Metad 是我們自己研發(fā)的一個開源的元信息服務。它的后端對接 Etcd ,和 Etcd 實時同步數(shù)據(jù)。
前面也說了,當前青云QingCloud 的方案是通過調(diào)度系統(tǒng)進行服務注冊。這種注冊方式有一個問題就是,節(jié)點啟動的時候,它不清楚自己所處的角色,也就是不知道『我是誰』。人生哲學的頭一個難題就是回答『我是誰』,服務器也有這個困境。所以我們在 Metad 中保存了 IP 到元信息之間的映射關(guān)系,客戶端請求一個固定的接口 /self 就可以拿到自己本節(jié)點的信息,當前節(jié)點所處的集群的信息,以及當前集群依賴的其他集群的信息。它也支持 Watch 機制,實現(xiàn)變更推送。

Confd 是一個開源的配置變更工具,我們在其基礎(chǔ)上進行了二次開發(fā),后端對接 Metad。
它通過監(jiān)聽 Metad 的變更通知,同步元信息到本地緩存,然后根據(jù)模板渲染配置文件,如果發(fā)現(xiàn)配置不一樣,則進行應用的配置變更,同時觸發(fā)腳本讓應用程序重新加載配置(Reload 或者 Restart)。
下面我們通過一個例子來說明下。

還是一個 Zookeeper 的例子,我們首先有個集群的編排配置文件,定義了其中每個節(jié)點的鏡像、CPU、內(nèi)存、磁盤、節(jié)點數(shù)量,以及啟動、停止等 Service 腳本。

我們給 zoo.cfg 定義了一個配置文件模板,這個模板是給 Confd 用來渲染配置文件的。模板的語法是 Go Template 語法,如果不熟悉這個模板語法也沒關(guān)系,大家可以看出這段腳本是在循環(huán)配置中心的 Hosts 列表,然后生成 Server ID 和 IP 之間的映射配置。

這是那個 MyID 配置文件的模板,這個很簡單,我們給集群的每個節(jié)點都會分配一個 SID,直接將 SID 寫到 MyID 配置文件就好。
對與 Docker 的支持

青云QingCloud 的集群編排支持 KVM 和 Docker 兩種鏡像,這樣就可以實現(xiàn) KVM 和 Docker 的混排。如果應用有特殊需求 Docker 鏡像不能滿足,比如 Kernel 版本,則可以使用 KVM 鏡像。
當然我們這里的 Docker 鏡像不是標準的 Docker 鏡像方式,鏡像默認啟動的進程,也就是 Init 進程必須是 Confd,然后應用通過 Confd 來啟動。這個方式和大家用 Docker 的習慣不一樣,比如 Zookeeper 的鏡像,習慣啟動的第一個進程就是 Zookeeper 服務。
那我們?yōu)槭裁床挥?Docker 默認的方式呢?

這是一個理想和現(xiàn)實相互妥協(xié)的方案。理想中 Docker 的應用配置,應該是靜態(tài)配置通過環(huán)境變量,動態(tài)的通過配置中心。
比如 JVM 的啟動內(nèi)存設置就是靜態(tài)配置,通過環(huán)境變量傳遞,如果應用需要變更內(nèi)存設置,直接銷毀舊的容器實例,重新啟動新的并傳遞新的環(huán)境變量即可。但現(xiàn)實的狀況,大多數(shù)應用的配置還都是通過配置文件,無論動態(tài)還是靜態(tài)。
我們?yōu)榱俗兏鼞玫呐渲梦募托枰ㄟ^ Confd,所以我們的 Docker 鏡像默認先啟動 Confd。
下面我們和業(yè)界的其他一些方案做一些比較。

Ansible/Puppet/Salt/Chef 這一系列配置變更以及自動化工具,本質(zhì)上都是純靜態(tài)的配置變更工具。
它們是把變量通過模板渲染成配置文件,這里的靜態(tài)指的是這些變量在編寫配置規(guī)則時就是確定的,所以它們的服用機制并不通用。
比如有人寫了一個自動部署 Zookeeper 集群的 Ansible 模塊,但當你想用這個模塊部署自己服務的時候,會發(fā)現(xiàn)需要修改許多變量,比如網(wǎng)絡、存儲等等。
它們的靜態(tài)模式導致的另外一個問題就是服務的依賴變更不好解決,比如 HAProxy 那個例子,當后端服務伸縮的時候,要變更 HAProxy 配置,還是得手動修改變量,然后重新執(zhí)行配置變更腳本。所以它們只能是半人工半自動化工具,對動態(tài)的故障遷移以及伸縮,容災也沒有好的辦法。

Kubernetes 的目標是通用的容器編排系統(tǒng),做了很多通用的抽象,試圖通過 DNS,虛擬 IP 這樣的通用機制來解決服務間的依賴問題。
比如 MySQL 的例子,MySQL 從庫伸縮后應用如何感知?
它的解決方案是 MySQL Slave 可以作為一個獨立的服務,會分配一個 DNS Name,以及一個 虛擬 IP。應用連接的時候通過 DNS 以及虛擬 IP 進行,并不需要知道后面的每個從庫節(jié)點 IP。
但這種方式的問題就是有些場景滿足不了,比如 Zookeeper 集群中的每個節(jié)點都需要能和其他節(jié)點直接通信,類似的還有 Elasticsearch。Kubernetes 的 Elasticsearch 解決方案是給 Elasticsearch 寫一個插件,通過 Kubernetes 提供的注冊中心接口來發(fā)現(xiàn)集群中的其他節(jié)點。
但如果應用不支持插件就比較麻煩,比如 Redis Cluster,Redis Cluster 運行在 Kubernetes 上,需要把每個節(jié)點都作為一個 Service,如果要擴展節(jié)點的話,必須新增 Kubernetes 的 Service 配置文件,然后節(jié)點運行之后再通過手動調(diào)用命令進行初始化。它支持全局的配置文件映射,但只是純靜態(tài)配置,不支持變更。

Mesos 的目標是通用的資源調(diào)度和分配系統(tǒng)。
如果把應用要放到 Mesos 之上,應用需要通過擴展 Framework 來實現(xiàn),開發(fā)成本比較高。如果用通用的容器方式,也有和 Kubernetes 類似的問題。
所以當前看來,我們的方案是相對可行度比較高,容易實踐,對各種不同的集群應用的包容性也比較高的方案。
最后再介紹一下我們的新應用中心。

主要基于前面的應用調(diào)度系統(tǒng),給企業(yè)提供應用標準化開發(fā)平臺,可以快速將應用云化,實現(xiàn)應用的秒級部署和彈性伸縮。同時提供計費服務以及客服平臺,讓企業(yè)應用快速實現(xiàn)商業(yè)化。當前還在邀請內(nèi)測階段。
那這個對開發(fā)者有什么意義呢?
我覺得可能會帶來基礎(chǔ)研發(fā)運維部門在企業(yè)中的角色轉(zhuǎn)換。
因為當前基礎(chǔ)研發(fā)運維部門在企業(yè)中屬于業(yè)務支撐的部門,基本上是成本部門,并不是直接生產(chǎn)利潤的部門。但如果有了這樣的平臺,基礎(chǔ)研發(fā)運維部門可以通過企業(yè)應用市場將自己的基礎(chǔ)組件共享出來,進行售賣。
比如每個大一點的互聯(lián)網(wǎng)公司都會搞一套 MySQL 分布式的集群方案,進行自動的分庫分表,如果能在應用市場中找到這樣的工具,中小企業(yè)肯定也是愿意買單的,所以也可以說服務器端研發(fā)人員的春天到了。
