微服務基礎與案例
今天的分享主要是結合精靈云在Docker和微服務領域的實踐進行分享。精靈云(Ghostcloud——云端的Ghost),是國內第一批從事容器虛擬化研發的創業型公司,主要提供容器云管理平臺、容器私有云建設及咨詢服務。秉承Eat Your Own Dogfood的思想,他們的整體架構就是全部運行在容器中的微服務架構,他們擁有國內領先的PaaS/CaaS研發能力,Ghostcloud平臺也是國內唯一全自主研發的PaaS/CaaS平臺。

產生微服務的背景

首先我們從微服務出現的背景說起,我覺得首先是移動互聯網這個時代促使微服務的出現。過去10年是移動互聯網飛速發展的10年,我們的生活受到了翻天覆地的變化,我們每時每刻都在享受著移動互聯網帶來的福利。整個系統對組件復用,水平擴展性,高可用性都提出了新的要求。這就要求我們用敏捷的思想來進行開發,持續的集成,持續交互,精益方法論都逐步深入人心。然后是虛擬化技術的發展,從傳統的硬件級虛擬化逐步過渡到操作系統級虛擬化,也就是我們所說的容器虛擬化。而Docker無疑是這里面的杰出代表。同時,隨著AWS的興起,公有云, IaaS, PaaS, 等都紛紛出現。總的來說,都是要突出一個“快”字,凡是能加快我們交互的途徑都值得去改進。微服務架構下,將功能相對獨立的模塊進行了封裝,模塊間的交互取而代之的是接口,極大的實現了“高內聚”,“低耦合”,同時模塊與模塊間沒有了硬性的語言要求,而更關注于功能。
架構的轉變

與Microservice相對立的就是Monolithic模式,翻譯過來就是單體模式。單體模式把很多功能或者組件柔和在一起,在開發和部署方面是有很大的優勢。但是其缺點也很明顯,首先測試成本很高,之前我曾經供職的一家公司,要測試一個系統需要完整編譯一次系統,至少需要1個小時,這種情況下就根本沒辦法持續交付。維護成本由于整個系統的耦合性,也會增加。同時,系統要進行擴展時,大多只能垂直擴展,即使是水平擴展也需要高配置的硬件。而在微服務模式下,模塊獨立,低耦合,每一個模塊都可以單獨測試,并發測試,并發部署。同時,具有很強的擴展性及更高的資源利用率。但是,微服務也存在諸多缺點,比如:設計的要求增加,系統的復雜度增加,模塊的增多以后管理和運維的要求也會增加。
如何應對轉變

這其實是我深有體會的。要實行微服務架構,肯定需要一個人來進行推動,而這個推動勢必會影響活著損害部分人的利益,這不僅是技術層面的,還會上升到管理層面。因此,推動的人必須首先對微服務有深刻的認識和理解,同時需要得到公司管理層的支持,而這個角色可以是老板或者CTO。你需要說服管理層,同時也需要說服中層。這些中層包括架構師、高級工程師,這些人往往是公司的骨干也是經驗最豐富的,這類人如果不與時俱進,在具體實施過程中要么遇到很大的阻力,要么成為形式上的微服務。中國的IT企業普遍落后于國外,同時對IT基礎架構也不夠重視,很多老板根本不管你什么架構,搞出來就好,這就導致后期維護成本非常高。因此,我覺得思想的轉變比什么都重要,真正從上到下意識到我們需要進行轉變。從物理機到虛擬機是轉變,從虛擬機到容器是轉變,從私有云向公有云到混合云同樣是轉變,只有團隊具有這種持續改進的傳統和顛覆的魄力,微服務才可能落到實處。
架構師的欠缺

現在的技術發展光JavaScript就有幾十種框架,各個領域都有層出不窮的技術。一個合格的架構師,需要時刻有空杯的學習心態,不停的快速學習。我一個很好的朋友是唯品會的資深架構師,他到現在每年都會看20多本的技術書籍。盡管如此,他在很多時候都會感覺不能跟上時代的步伐。這一頁是我羅列的一些需要的技能,從中你可以看出溝通能力和影響力也被我加了進來,很多高級技術人員都不注重非技術方面的提升,這一步是邁向架構師的一個坎。我自己是一個純粹的技術人員,在創業之后我深刻認識到,技術對我們都不是多大的問題,性格、溝通、情商、大局的把控才是真正需要修煉的地方,所謂人生無處不修行。
微服務生存周期

對于微服務架構,我大致整理了上面幾個步驟。首先從用戶需求開始,然后是模塊拆分和技術選型,接下來就是通過敏捷的思想進行持續集成,然后是部署,之后是運維,然后進行下一次迭代。有的時候我們可能會將持續集成、測試和部署合并在一起,有的時候可能又會根據實際情況分拆開來。
語言的選擇

需求分析方面我覺得沒什么多講的,我直接進入模塊拆分階段。模塊拆分就涉及到到底拆分的多細,我覺得這個沒什么定論,總體準則就是功能盡量單一,框架盡量單一,開發測試方便,然后最重要的是團隊覺得好。只有團隊覺得好才是真的好。過細過粗都不是很好的方式。我首先從語言選擇方面來講一下我們的實踐。我們團隊之前是做內核開發的對c/c++非常熟悉,但是確實不大適合當今的開發,c語言的包管理和語言內部的易錯性絕對是最高的。后來我們集體轉到了Java,對于我們來說Java基本沒任何語言層面的難度,兩三個星期就上手了。但是,我們沒有選擇重量級的框架,而是選擇了Spring Boot, Spring Data, Spring Data REST等一系列最新的框架技術,選擇這些框架主要還是方便容器化的封裝。整體來看開發速度確實很快,也沒什么過多的問題,性能也都還可以,當然不能和c比。但是一個比較麻煩的事情就是Java的外部包太多,同時JRE也很大,對于我們這種擁有幾十個微服務的設計,明顯是不合適的。后來,我們切換到了Go, 基本上Go和c大同小異,我們很快就上手了。我們招人都是招c語言和數據結構好的人,然后讓他轉,基本都是2周就能做事了。Go與Java比除了空間小,一個比較大的優勢就是原生跨平臺。這一點跟Python和Ruby都不一樣,Python和Ruby, nodejs,其實都有一個類似虛擬機的機制,并不是運行的原生二進制程序。而Go是把程序編譯成了原生二進制,這一點就在性能上有非常大的提升,你運行的c語言編譯的程序沒有什么區別。但是Go也不是完美的,Go目前的反射相對偏弱;Go的開發工具目前也還不是很完善,調試和MVC框架都還不是很完善,我們在開發過程中還自己寫了一些調試器和一個REST框架。但是相比于性能和空間,我們覺得都是值得的。我們現在最小的rest服務只有幾十k大小。
持續集成-鏡像型

說到微服務肯定就離不開容器,我們使用的是Docker。我們團隊基本所有的服務都是運行在容器中的,我們帶代碼管理和bug跟蹤系統都是gitlab來管理的,通過注入代碼提交的hook,通知我們的編譯型控制容器,之后會push到我們的私有鏡像倉庫中,緊接著我們會啟動測試型容器拉取鏡像,并運行測試用例,最后是發布。這種模式我們稱為鏡像型持續集成,如果你的業務偏簡單,沒有多少服務是很不錯的,但是如果你的鏡像多,服務多,在公網上的拉取就會非常慢。我們那個時候更新一次版本要差不多10分鐘,后來我們就過渡到了代碼型持續集成。
持續集成-代碼型

這種改進型的持續集成是將容器預先做好放在那兒,當有變化時去取代碼,然后編譯,測試和運行,同時異步push到倉庫,在完成好內部測試以后,啟動公網的容器進行編譯、測試和發布。整個過程都是以代碼為線索,不會出現大鏡像的拉取動作。
持續集成-容器-代碼庫

如上圖,我們采用的是一個容器對應一個代碼庫的方式來的,這樣可以并行的測試、構建和部署。同時容器和容器之間是通過無狀態協議交互的,可以自動構建相互間的聯系,這樣做主要是為了方便的更新和擴展。
容器的網絡訪問方式

這里是幾種可能會用到的容器網絡模式,
第一種是默認的橋接方式,容器可以通過主機ip+端口來進行訪問,這種方式是可以跨集群訪問的;
第二種是直接使用容器的內部ip,因此只能在內部訪問
第三種是link的方式將容器連接到一起,這種方式只能在主機層面訪問;
第四種是使用主機的網絡,容器使用主機的網絡通訊,因此也可以跨主機訪問;
第五種是給容器賦予可路由的ip,這種方式需要借助MacVlan等技術來實現,也是可跨主機訪問的;
第六種是Overlay+link方式,Overlay是在docker1.9以后加入的虛擬網絡訪問方式,它可以在多主機間建立虛擬網絡,因此也是可以跨主機訪問的;
我們在實際使用過程中,會根據業務場景來選擇。
服務發現

作為微服務架構,一個比較核心的問題就是服務發現。目前服務發現一般可以通過zookeeper, consul, 或etcd來做。這些都是高可用中間件,每一種都有特有的棧。拿consul來說,它的注冊可以通過Registrator,服務倉庫用Consul,然后配置更新用consul-template,然后負載均衡用Nginx/HAProxy。
案例分析

這是我們其中一個用戶的案例,這個用戶主要是做基于微信的開發和運營。他們的業務有一個特點,閑的時候會沒有多大的用戶訪問量,一旦做活動(比如:搶紅包,做游戲)并發量就會暴增。由于他們的主要精力是集中在不同場景的活動,所以非常適合微服務架構。但是,他們目前基本都是手動來調配資源,并且對容器和主機也沒有系統的監控。基于此,他們和我們平臺一起研發了動態的負載均衡及彈性伸縮功能,可以根據各種資源使用情況自動伸縮服務。而Ghostcloud的平臺,則為他們提供了一系列的相關服務。