從 Spring Cloud 開始丐枉,聊聊微服務架構的實踐之路

背景

隨著公司業(yè)務量的飛速發(fā)展,平臺面臨的挑戰(zhàn)已經(jīng)遠遠大于業(yè)務掘托,需求量不斷增加瘦锹,技術人員數(shù)量增加,面臨的復雜度也大大增加。在這個背景下弯院,平臺的技術架構也完成了從傳統(tǒng)的單體應用到微服務化的演進辱士。

enter image description here

系統(tǒng)架構的演進過程

單一應用架構(第一代架構)

這是平臺最開始的情況,當時流量小听绳,為了節(jié)約成本,并將所有應用都打包放到一個應用里面颂碘,采用的架構為.net+sqlserver:

enter image description here

表示層
位于最外層(最上層),最接近用戶椅挣。用于顯示數(shù)據(jù)和接收用戶輸入的數(shù) 據(jù)头岔,為用戶提供一種交互式操作的界面,平臺所使用的是基于.net的web形式鼠证。

業(yè)務邏輯層
業(yè)務邏輯層(Business Logic Layer)無疑是系統(tǒng)架構中體現(xiàn)核心價值的部分峡竣。它的關注點主要集中在業(yè)務規(guī)則的制定、業(yè)務流程的實現(xiàn)等與業(yè)務需求有關的系統(tǒng)設計量九,也即是說它是與系統(tǒng)所應對的領域(Domain)邏輯有關适掰,很多時候,也將業(yè)務邏輯層稱為領域層荠列。
業(yè)務邏輯層在體系架構中的位置很關鍵类浪,它處于數(shù)據(jù)訪問層與表示層中間,起到了數(shù)據(jù)交換中承上啟下的作用肌似。由于層是一種弱耦合結構费就,層與層之間的依賴是向下的,底層對于上層而言是“無知”的锈嫩,改變上層的設計對于其調用的底層而言沒有任何影響受楼。如果在分層設計時,遵循了面向接口設計的思想,那么這種向下的依賴也應該是一種弱依賴關系舅桩。對于數(shù)據(jù)訪問層而言憋槐,它是調用者;對于表示層而言弓候,它卻是被調用者。

數(shù)據(jù)層
數(shù)據(jù)訪問層:有時候也稱為是持久層,其功能主要是負責數(shù)據(jù)庫的訪問瑟捣,可以訪問數(shù)據(jù)庫系統(tǒng)、二進制文件栅干、文本文檔或是XML文檔迈套,平臺在這個階段使用的是hibernate.net+sqlserver。

第一代架構看似很簡單碱鳞,卻支撐了平臺的早期業(yè)務發(fā)展桑李,滿足了網(wǎng)站用戶訪問量在幾萬規(guī)模的處理需求。但是當用戶訪問量呈現(xiàn)大規(guī)模增長,問題就暴露出來了:

  • 維護成本不斷增高:當出現(xiàn)故障時贵白,有可能引起故障的原因組合就會比較多率拒,這也會導致分析故障、定位故障禁荒、修復故障的成本相應增高猬膨,故障的平均修復周期會花費很多時間,并且任何一個模塊出現(xiàn)故障將會影響其它應用模塊呛伴;在開發(fā)人員對全局功能缺乏深度理解的情況下勃痴,修復一個故障,經(jīng)常引入其他的故障磷蜀,導致該過程陷入“修復越多召耘,故障越多”的惡性循環(huán)。

  • 可伸縮性差:應用程序的所有功能代碼都運行在同一個服務器上褐隆,將會導致應用程序的水平擴展非常困難污它,只能使用垂直擴展。

  • 交付周期變長:應用程序做任何細微的修改以及代碼提交庶弃,都會觸發(fā)對整個應用程序進行代碼編譯衫贬、運行單元測試、代碼檢查歇攻、構建并生成部署包固惯、驗證功能等,這也就版本的反饋周期變長缴守,單位時間內構建的效率變得很低葬毫。

  • 新人培養(yǎng)周期變長:隨著應用程序的功能越來越多,代碼變得越來越復雜的同時屡穗,對于新加入團隊的成員而言贴捡,了解業(yè)務背景、熟悉應用程序村砂、配置本地開發(fā)環(huán)境烂斋,這些看似簡單的任務,卻會花費了更長的時間础废。

垂直應用架構(第二代架構)

為了解決第一代架構面臨的問題汛骂,團隊制定了如下的策略,并形成了第二代應用架構(垂直應用架構)

enter image description here
  • 應用拆成獨立的應用模塊评腺。

  • 各個應用模塊獨立部署帘瞭,并在負載均衡通過session保持解決應用模塊的水平擴展問題。

Sticky就是基于cookie的一種負載均衡解決方案蒿讥,通過cookie實現(xiàn)客戶端與后端服務器的會話保持, 在一定條件下可以保證同一個客戶端訪問的都是同一個后端服務器蝶念。請求來了锋拖,服務器發(fā)個cookie,并說:下次來帶上祸轮,直接來找我!兽埃。在項目中,我們使用了taobao開源的tengine中的session_sticky模塊适袜。

  • 數(shù)據(jù)庫拆分成不同數(shù)據(jù)庫柄错,由對應應用訪問。

  • 域名拆分苦酱。

  • 動靜分離售貌。

可以看到第二代架構解決應用級別的水平擴展擴展,經(jīng)過優(yōu)化后疫萤,該架構支撐了幾十萬用戶的訪問需求颂跨,在這一階段有部分應用已經(jīng)使用java 完成了mvc架構的重寫。當然也存在一些問題扯饶。

  • 應用之間耦合度高恒削,相互依賴嚴重。

  • 應用模塊之間交互復雜尾序,有時直接訪問對方模塊數(shù)據(jù)庫钓丰。

  • 數(shù)據(jù)庫涉及過多的關聯(lián)查詢與慢查詢,數(shù)據(jù)庫優(yōu)化困難每币。

  • 數(shù)據(jù)庫單點訪問嚴重携丁,出現(xiàn)故障無法恢復。

  • 數(shù)據(jù)復制問題嚴重兰怠,造成大量數(shù)據(jù)不一致梦鉴。

我們曾經(jīng)嘗試使用sql server AlwaysOn 解決擴展問題,但是實驗發(fā)現(xiàn)在復制過程中出現(xiàn)至少10s的延遲揭保,因此放棄了這個方案肥橙。

  • 系統(tǒng)擴展困難。

  • 各個開發(fā)團隊各自為戰(zhàn)掖举,開發(fā)效率低下快骗。

  • 測試工作量巨大娜庇,發(fā)布困難塔次。

微服務化架構(平臺現(xiàn)狀:第三代架構)

為了解決第一代與第二代架構存在的問題,我們對平臺進行了梳理優(yōu)化名秀。根據(jù)平臺業(yè)務需要以及對第一二代架構的總結励负,我們確定了第三代架構的核心需求:

  • 核心業(yè)務抽取出來,作為獨立的服務對外服務匕得。

  • 服務模塊持續(xù)獨立部署继榆,減少版本交付周期巾表。

  • 數(shù)據(jù)庫按服務分庫分表。

  • 大量使用緩存略吨,提高訪問集币。

  • 系統(tǒng)間交互使用輕量級的rest協(xié)議,摒棄rpc協(xié)議翠忠。

  • 去.net化鞠苟,開發(fā)語言使用java來實現(xiàn)。

并以此為基礎進行了平臺的第三代架構的重構工作秽之。

enter image description here

看第三代架構里面的組成当娱,主要分為八個部分:

  • CDN:CDN系統(tǒng)負責實時地根據(jù)網(wǎng)絡流量和各節(jié)點的連接、負載狀況以及到用戶的距離和響應時間等綜合信息將用戶的請求重新導向離用戶最近的服務節(jié)點上考榨。其目的是使用戶可就近取得所需內容跨细,解決 Internet網(wǎng)絡擁擠的狀況,提高用戶訪問網(wǎng)站的響應速度河质。

平臺在選擇CDN廠商時冀惭,需要考慮經(jīng)營時間長短,是否有可擴充的帶寬資源掀鹅、靈活的流量和帶寬選擇云头、穩(wěn)定的節(jié)點、性價比淫半;綜合前面幾個因素平臺采用了七牛的CDN服務溃槐。

  • LB層:平臺包括很多個業(yè)務域,不同的業(yè)務域有不同的集群科吭,LB層(Load Balancer)是對多臺業(yè)務服務器進行流量分發(fā)的負載均衡服務昏滴,通過流量分發(fā)擴展應用系統(tǒng)對外的服務能力,并消除單點故障提升了應用系統(tǒng)的可用性对人。

選擇哪種負載谣殊,需要綜合考慮各種因素(是否滿足高并發(fā)高性能,Session保持如何解決牺弄,負載均衡的算法如何姻几,支持壓縮,緩存的內存消耗)势告,主要分為以下兩種:

LVS:工作在4層蛇捌,Linux實現(xiàn)的高性能高并發(fā)、可伸縮性咱台、可靠的的負載均衡器络拌,支持多種轉發(fā)方式(NAT、DR回溺、IP Tunneling)春贸,其中DR模式支持通過廣域網(wǎng)進行負載均衡混萝。支持雙機熱備(Keepalived或者Heartbeat)。對網(wǎng)絡環(huán)境的依賴性比較高萍恕。

Nginx:工作在7層逸嘀,事件驅動的、異步非阻塞的架構允粤、支持多進程的高并發(fā)的負載均衡器/反向代理軟件厘熟。可以針對域名维哈、目錄結構绳姨、正則規(guī)則針對http做一些分流。通過端口檢測到服務器內部的故障阔挠,比如根據(jù)服務器處理網(wǎng)頁返回的狀態(tài)碼飘庄、超時等等,并且會把返回錯誤的請求重新提交到另一個節(jié)點购撼,不過其中缺點就是不支持url來檢測跪削。對于session sticky,我們通過基于cookie的擴展nginx-sticky-module來實現(xiàn)迂求。這種也是平臺目前所采用的方案碾盐。

  • 業(yè)務層:代表平臺某一領域的業(yè)務提供的服務,對于平臺而言揩局,有商品毫玖、會員、直播凌盯、訂單付枫、財務、論壇等系統(tǒng)驰怎,不同的系統(tǒng)提供不同的領域服務阐滩。

  • 網(wǎng)關與注冊中心:提供了統(tǒng)一的底層微服務api 入口與注冊管理。封裝了內部的系統(tǒng)架構并向每個客戶端提供Rest API县忌,同時實現(xiàn)了監(jiān)控掂榔、負載均衡、緩存症杏、服務降級装获、限流等職責。目前平臺采用nginx+consul來實現(xiàn)鸳慈。

  • 服務層:該層為一些協(xié)同工作的小而自治的服務饱溢,平臺根據(jù)業(yè)務的邊界來確定了服務的邊界喧伞,每個服務只專注自己邊界之內走芋。該層基于spring cloud來構建绩郎。

  • 基礎設施層:該層為上層服務提供基礎設施服務,主要為以下幾類:

    redis 集群:以高響應速度翁逞、內存操作為上層提供緩存服務肋杖。

    mongodb集群:由于mongodb具有靈活文檔模型 、高可用復制集 挖函、可擴展分片集群等特性状植,平臺基于此為上層提供如文章、帖子怨喘、鏈路日志等存儲服務津畸。mongodb集群采用了復制+分片的架構解決可用性與擴展性問題。

    MySQL集群:存儲會員必怜、商品肉拓、訂單等具有事務性要求的數(shù)據(jù)。

    Kafka:支撐了平臺的所有的消息服務梳庆。

    ES(elasticsearch):提供了平臺的商品暖途、會員、訂單膏执、日志等搜索服務驻售。

  • 集成層:這個特點是整個平臺中的最大亮點,包括實踐持續(xù)集成CI更米、持續(xù)交付CD欺栗、DevOps文化,讓每個人都參與交付征峦,在規(guī)范的流程和標準的交付下纸巷,完成一個服務的自動部署發(fā)布,進而提高了版本交付鏈路的整體效率眶痰。

  • 監(jiān)控層:將系統(tǒng)拆分為更小的瘤旨、細粒度的微服務給平臺帶來了很多好處,但是竖伯,它也增加了平臺系統(tǒng)的運維復雜性存哲。給最終用戶提供的任務服務都是有大量的微服務配合完成,一個初始調用最終會觸發(fā)多個下游的服務調用七婴,如何才能重建請求流祟偷,以重現(xiàn)與解決這個問題?為此部署開源的open-falcon平臺提供應用級以上監(jiān)控打厘、使用ELK提供應用日志的分析修肠、使用自建服務提供鏈路日志跟蹤以及基于spring config server實踐統(tǒng)一配置服務。

微服務團隊的工作方式

康威定律:任何組織在設計一套系統(tǒng)時户盯,所交付的設計方案在結構上都與該組織的溝通結構保持一致嵌施。

工作方式

在實踐第三代架構時饲化,我們對團隊組織做了幾個調整:

  • 按照業(yè)務邊界進行了劃分,在一個團隊內全棧吗伤,讓團隊自治吃靠,按照這樣的方式組建,將溝通的成本維持在系統(tǒng)內部足淆,每個子系統(tǒng)就會更加內聚巢块,彼此的依賴耦合能變弱,跨系統(tǒng)的溝通成本也就能降低
enter image description here
  • 專門建立了一個架構師部門來負責第三代架構的推行工作巧号。通常對于一個的架構師團隊有系統(tǒng)架構族奢、應用架構、運維丹鸿、DBA歹鱼、敏捷專家五個角色組成是一個比較合理的結構。那么又如何控制好架構組的產(chǎn)出卜高,保證架構工作的順利推行呢弥姻?

  • 首先:打造持續(xù)改進的自組織文化是實施微服務的關鍵基石。只有持續(xù)改進掺涛,持續(xù)學習和反饋庭敦,持續(xù)打造這樣一個文化氛圍和團隊,微服務架構才能持續(xù)發(fā)展下去薪缆,保持新鮮的生命力秧廉,從而實現(xiàn)我們的初衷。

  • 其次:架構組的產(chǎn)品要經(jīng)過嚴格的流程拣帽,因為架構組推行的是通用的解決方案疼电,為了保證方案的質量,我們從方案調研到評審再到實施都有一個嚴格的閉環(huán)减拭。

enter image description here

再談談整個團隊的交付流程與開發(fā)模式蔽豺,如果沒有預先定義好,則很難讓微服務架構發(fā)揮出真正的價值拧粪,下面我們先來看看微服務架構的交付流程修陡。

enter image description here

使用微服務架構開發(fā)應用程序,我們實際上是針對一個個微服務進行設計可霎、開發(fā)魄鸦、測試、部署癣朗,因為每個服務之間是沒有彼此依賴的拾因,大概的交付流程就像上圖這樣。

設計階段:

架構組將產(chǎn)品功能拆分為若干微服務,為每個微服務設計 API 接口(例如 REST API)绢记,需要給出 API 文檔扁达,包括 API 的名稱、版本庭惜、請求參數(shù)罩驻、響應結果穗酥、錯誤代碼等信息护赊。

在開發(fā)階段,開發(fā)工程師去實現(xiàn) API 接口砾跃,也包括完成 API 的單元測試工作骏啰,在此期間,前端工程師會并行開發(fā) Web UI 部分抽高,可根據(jù) API 文檔造出一些假數(shù)據(jù)(我們稱為“mock 數(shù)據(jù)”)判耕,這樣一來,前端工程師就不必等待后端 API 全部開發(fā)完畢翘骂,才能開始自己的工作了壁熄,實現(xiàn)了前后端并行開發(fā)。

測試階段:

這一階段過程全自動化過程碳竟,開發(fā)人員提交代碼到代碼服務器,代碼服務器觸發(fā)持續(xù)集成構建、測試聪铺,如果測試通過則會自動通過Ansible腳本推送到模擬環(huán)境尼荆;在實踐中對于線上環(huán)境則是先要走審核流程,通過之后才能推送到生產(chǎn)環(huán)境诈泼。提高工作效率懂拾,并且控制了部分可能因為測試不充分而導致的線上不穩(wěn)定。

開發(fā)模式

在以上交付流程中铐达,開發(fā)岖赋、測試、部署這三個階段可能都會涉及到對代碼行為的控制瓮孙,我們還需要制定相關開發(fā)模式贾节,以確保多人能夠良好地協(xié)作。

  • 實踐"絞殺者模式":
enter image description here

由于第三代架構跨度較大衷畦,并且面臨了無法修改的.net遺留系統(tǒng)栗涂,我們采用絞殺者模式,在遺留系統(tǒng)外面增加新的Proxy代理微服務祈争,并且在LB控制upstream的方式斤程,而不是直接修改原有系統(tǒng),逐步的實現(xiàn)對老系統(tǒng)的替換。

  • 開發(fā)規(guī)范
enter image description here

經(jīng)驗表明忿墅,我們需要善用代碼版本控制系統(tǒng)扁藕,我曾經(jīng)遇到一個開發(fā)團隊,由于分支沒有規(guī)范疚脐,最后一個小版本上線合代碼居然化了幾個小時亿柑,最后開發(fā)人員自己都不知道合到哪個分支。拿 Gitlab 來說棍弄,它很好地支持了多分支代碼版本望薄,我們需要利用這個特性來提高開發(fā)效率,上圖就是我們目前的分支管理規(guī)范呼畸。

最穩(wěn)定的代碼放在 master 分支上痕支,我們不要直接在 master 分支上提交代碼,只能在該分支上進行代碼合并操作蛮原,例如將其它分支的代碼合并到 master 分支上卧须。

我們日常開發(fā)中的代碼需要從 master 分支拉一條 develop 分支出來,該分支所有人都能訪問儒陨,但一般情況下花嘶,我們也不會直接在該分支上提交代碼,代碼同樣是從其它分支合并到 develop 分支上去蹦漠。

當我們需要開發(fā)某個特性時椭员,需要從 develop 分支拉出一條 feature 分支,例如 feature-1 與 feature-2津辩,在這些分支上并行地開發(fā)具體特性拆撼。

當特性開發(fā)完畢后,我們決定需要發(fā)布某個版本了喘沿,此時需要從 develop 分支上拉出一條 release 分支闸度,例如 release-1.0.0,并將需要發(fā)布的特性從相關 feature 分支一同合并到 release 分支上蚜印,隨后將針對 release 分支推送到測試環(huán)境莺禁,測試工程師在該分支上做功能測試,開發(fā)工程師在該分支上修改 bug窄赋。待測試工程師無法找到任何 bug 時哟冬,我們可將該 release 分支部署到預發(fā)環(huán)境,再次驗證以后忆绰,均無任何 bug浩峡,此時可將 release 分支部署到生產(chǎn)環(huán)境。待上線完成后错敢,將 release 分支上的代碼同時合并到 develop 分支與 master 分支翰灾,并在 master 分支上打一個 tag,例如 v1.0.0。

當生產(chǎn)環(huán)境發(fā)現(xiàn) bug 時纸淮,我們需要從對應的 tag 上(例如 v1.0.0)拉出一條 hotfix 分支(例如 hotfix-1.0.1)平斩,并在該分支上做 bug 修復。待 bug 完全修復后咽块,需將 hotfix 分支上的代碼同時合并到 develop 分支與 master 分支绘面。

對于版本號我們也有要求,格式為:x.y.z侈沪,其中揭璃,x 用于有重大重構時才會升級,y 用于有新的特性發(fā)布時才會升級峭竣,z 用于修改了某個 bug 后才會升級塘辅。針對每個微服務晃虫,我們都需要嚴格按照以上開發(fā)模式來執(zhí)行皆撩。

微服務開發(fā)體系

我們已經(jīng)對微服務團隊的架構、交付流程哲银、開發(fā)模式進行了描述扛吞,下面我們聊聊歸納一下微服務開發(fā)體系。

什么是微服務架構

Martin Flower的定義:

In short, the microservice architectural style [1] is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies

簡單的說荆责,微服務是軟件系統(tǒng)架構上的一個設計風格滥比,它倡導將一個原本獨立的系統(tǒng)分成多個小型服務,這些小型服務都在各自獨立的進程中運行做院,服務之間通過基于HTTP的RESTful 輕量級API進行通信協(xié)作盲泛。被拆分的每個微服務圍繞系統(tǒng)中的某項或一些耦合度較高的業(yè)務進行構建,并且每個服務都維護著自身的數(shù)據(jù)存儲键耕、業(yè)務開發(fā)寺滚、自動化測試案例以及獨立部署機制。由于有了輕量級通信機制屈雄,這些微服務間可以使用不通的語言來編寫村视。

微服務的拆分粒度

微服務到底拆分到一個多大的粒度,更多時候是需要在粒度與團隊之間找到一個平衡點酒奶,微服務越小蚁孔,微服務獨立性帶來的好處就越多。但是管理大量微服務也會越復雜惋嚎「芮猓基本上拆分需要遵循以下幾個原則:

  • 單一職責原則:即"把因相同原因而變化的東西聚合到一起,把因不同原因而變化的東西分離開來"另伍。通過這個原則確定微服務邊界鼻百。

  • 團隊自主原則:團隊越大,溝通與協(xié)助成本就會越高,我們在實踐中一個團隊不會超過8人愕宋,團隊內全棧玻靡,是一個全功能團隊。

  • 先分數(shù)據(jù)庫中贝、后分服務:數(shù)據(jù)模型能否徹底分開囤捻,決定了微服務的邊界功能是否徹底劃清,實踐中我們先討論數(shù)據(jù)模型邊界邻寿,數(shù)據(jù)模型的邊界映射了業(yè)務的邊界蝎土,進而從底向上完成服務拆分。

如何搭建微服務架構

為了搭建好微服務架構绣否,技術選型是一個非常重要的階段誊涯,只有選擇合適的"演員",才能把這臺戲演好蒜撮。

enter image description here

我們使用 Spring Cloud 作為微服務開發(fā)框架暴构,Spring Boot 擁有嵌入式 Tomcat,可直接運行一個 jar 包來發(fā)布微服務段磨,此外它還提供了一系列“開箱即用”的插件,例如:配置中心取逾,服務注冊與發(fā)現(xiàn),熔斷器苹支,路由砾隅,代理,控制總線债蜜,一次性令牌晴埂,全局鎖,leader選舉寻定,分布式 會話儒洛,集群狀態(tài)等,可大量提高我們的開發(fā)效率特姐。

功能 Spring Cloud
路由與負載均衡 Ribbon
注冊中心 Eureka
網(wǎng)關 Zuul
斷路器 Hystrix
分布式配置 Config
服務調用跟蹤 sleuth
日志輸出 elk
認證集成 oauth2
消息總線 Bus
批量任務 Task

工程結構規(guī)范

enter image description here

上圖是我們實踐中每個服務應該具有的項目組成結構晶丘。

其中:

  1. 微服務名+service:

為對內其它微服務提供服務調用。服務名+api模塊為服務間定義的接口規(guī)范唐含,使用swagger+rest接口定義浅浮。服務名+server模塊包含了能直接啟動該服務的應用與配置。

  1. 微服務名+web:

供上層web應用請求的入口捷枯,該服務中一般會調用底層微服務完成請求滚秩。

API 網(wǎng)關實踐

enter image description here

API網(wǎng)關作為后端所有微服務和API的訪問入口, 對微服務和API進行審計淮捆,流控郁油, 監(jiān)控本股,計費等。常用的API網(wǎng)關解決方案有:

  • 應用層方案

最有名的當然是Netflix的zuul桐腌, 但這不意味著這種方案就最適合你拄显, 比如Netfilx是因為使用AWS,對基礎設施把控有限案站, 所以才不得不在應用層做了zuul這樣的方案躬审,如果通盤考慮, 這種方案不是最合適或者說最有的方案蟆盐。

但如果自己的團隊對整體技術設施把控有限承边,且團隊結構不完善,應用層方案也可能是最適合你的最佳方案石挂。

  • nginx + lua方案

也是我們采用并認為最合適的方案博助,OpenResty和Kong是比較成熟的可選方案, 不過Kong使用Postgres或者Cassandra痹愚, 國內公司估計選擇這倆貨的不多富岳,但Kong的HTTP API設計還是很不錯的。

  • 我們的方案

使用nginx+lua+consul組合方案里伯,雖然我們團隊大多是java城瞎,選擇zookeeper會是更加自然的選擇渤闷,但作為新銳派疾瓮,對壓測結果進行了分析, 我們最終選擇使用consul飒箭。

良好的HTTP API支持狼电, 可以動態(tài)管理upstreams, 這也意味著我們可以通過發(fā)布平臺或者膠水系統(tǒng)無縫的實現(xiàn)服務注冊和發(fā)現(xiàn)弦蹂, 對服務的訪問方透明肩碟。

enter image description here

在以上的方案里:

consul作為狀態(tài)存儲或者說配置中心(主要使用consul的KV存儲功能);nginx作為API網(wǎng)關凸椿, 根據(jù)consul中upstreams的相關配置削祈,動態(tài)分發(fā)流量到配置的upstreams結點;

nginx根據(jù)配置項脑漫, 連接到consul集群髓抑;

啟動的API或者微服務實例, 通過手工/命令行/發(fā)布部署平臺优幸, 將實例信息注冊/寫入consul;

nginx獲取到相應的upstreams信息更新吨拍, 則動態(tài)變更nginx內部的upstreams分發(fā)配置,從而將流量路由和分發(fā)到對應的API和微服務實例結點网杆;

將以上注冊和發(fā)現(xiàn)邏輯通過腳本或者統(tǒng)一的發(fā)布部署平臺固化后羹饰,就可以實現(xiàn)透明的服務訪問和擴展伊滋。

鏈路監(jiān)控實踐

我們發(fā)現(xiàn),以前在單應用下的日志監(jiān)控很簡單队秩,在微服務架構下卻成為了一個大問題笑旺,如果無法跟蹤業(yè)務流,無法定位問題馍资,我們將耗費大量的時間來查找和定位問題燥撞,在復雜的微服務交互關系中,我們就會非常被動迷帜,此時分布式鏈路監(jiān)控應運而生物舒,其核心就是調用鏈。通過一個全局的ID將分布在各個服務節(jié)點上的同一次請求串聯(lián)起來戏锹,還原原有的調用關系冠胯、追蹤系統(tǒng)問題、分析調用數(shù)據(jù)锦针、統(tǒng)計系統(tǒng)指標荠察。

分布式鏈路跟蹤最早見于2010年Google發(fā)表的一篇論文《dapper》。

那么我們先來看一下什么是調用鏈奈搜,調用鏈其實就是將一次分布式請求還原成調用鏈路悉盆。顯式的在后端查看一次分布式請求的調用情況,比如各個節(jié)點上的耗時馋吗、請求具體打到了哪臺機器上焕盟、每個服務節(jié)點的請求狀態(tài),等等宏粤。它能反映出一次請求中經(jīng)歷了多少個服務以及服務層級等信息(比如你的系統(tǒng)A調用B脚翘,B調用C,那么這次請求的層級就是3)绍哎,如果你發(fā)現(xiàn)有些請求層級大于10来农,那這個服務很有可能需要優(yōu)化了
常見的解決方案有:

  • Pinpoint

github地址:GitHub - naver/pinpoint: Pinpoint is an open source APM (Application Performance Management) tool for large-scale distributed systems written in Java.

對APM有興趣的朋友都應該看看這個開源項目,這個是一個韓國團隊開源出來的崇堰,通過JavaAgent的機制來做字節(jié)碼代碼植入(探針)沃于,實現(xiàn)加入traceid和抓取性能數(shù)據(jù)的目的。
NewRelic海诲、Oneapm之類的工具在java平臺上的性能分析也是類似的機制繁莹。

  • Zipkin

官網(wǎng):OpenZipkin · A distributed tracing system

github地址:GitHub - openzipkin/zipkin: Zipkin is a distributed tracing system

這個是twitter開源出來的,也是參考Dapper的體系來做的饿肺。

Zipkin的java應用端是通過一個叫Brave的組件來實現(xiàn)對應用內部的性能分析數(shù)據(jù)采集蒋困。

Brave的github地址:https://github.com/openzipkin/brave

這個組件通過實現(xiàn)一系列的java攔截器,來做到對http/servlet請求敬辣、數(shù)據(jù)庫訪問的調用過程跟蹤雪标。然后通過在spring之類的配置文件里加入這些攔截器零院,完成對java應用的性能數(shù)據(jù)采集。

  • CAT

github地址:GitHub - dianping/cat: Central Application Tracking

這個是大眾點評開源出來的村刨,實現(xiàn)的功能也還是蠻豐富的告抄,國內也有一些公司在用了。不過CAT實現(xiàn)跟蹤的手段嵌牺,是要在代碼里硬編碼寫一些“埋點”打洼,也就是侵入式的。

這樣做有利有弊逆粹,好處是可以在自己需要的地方加埋點募疮,比較有針對性;壞處是必須改動現(xiàn)有系統(tǒng)僻弹,很多開發(fā)團隊不愿意阿浓。

前面三個工具里面,如果不想重復造輪子蹋绽,我推薦的順序依次是Pinpoint—>Zipkin—>CAT芭毙。原因很簡單,就是這三個工具對于程序源代碼和配置文件的侵入性卸耘,是依次遞增的退敦。

  • 我們的解決方案

針對于微服務,我們在spring cloud基礎上蚣抗,對微服務架構進行了擴展侈百,基于Google Dapper的概念,設計了一套基于微服務架構的分布式跟蹤系統(tǒng)(WeAPM)忠聚。

enter image description here

如上圖所示设哗,我們可以通過服務名、時間两蟀、日志類型、方法名震缭、異常級別赂毯、接口耗時等參數(shù)查詢響應的日志。在得到的TrackID可以查詢到該請求的整個鏈路日志拣宰,為重現(xiàn)問題党涕、分析日志提供了極大方便。

enter image description here

斷路器實踐

在微服務架構中巡社,我們將系統(tǒng)拆分成了一個個的微服務膛堤,這樣就有可能因為網(wǎng)絡原因或是依賴服務自身問題出現(xiàn)調用故障或延遲,而這些問題會直接導致調用方的對外服務也出現(xiàn)延遲晌该,若此時調用方的請求不斷增加肥荔,最后就會出現(xiàn)因等待出現(xiàn)故障的依賴方響應而形成任務積壓绿渣,最終導致自身服務的癱瘓。為了解決這樣的問題燕耿,因此產(chǎn)生了斷路器模式

enter image description here

我們在實踐中使用了Hystrix 來實現(xiàn)斷路器的功能中符。Hystrix是Netflix開源的微服務框架套件之一,該框架目標在于通過控制那些訪問遠程系統(tǒng)誉帅、服務和第三方庫的節(jié)點淀散,從而對延遲和故障提供更強大的容錯能力。Hystrix具備擁有回退機制和斷路器功能的線程和信號隔離蚜锨,請求緩存和請求打包档插,以及監(jiān)控和配置等功能。

斷路器的使用流程如下:

啟用斷路器

    @SpringBootApplication
    @EnableCircuitBreaker
    public class Application {
    public static void main(String[] args) {
        SpringApplication.run(DVoiceWebApplication.class, args);
        }
    }

代用使用方式

    @Component
    public class StoreIntegration {
    @HystrixCommand(fallbackMethod = "defaultStores")
    public Object getStores(Map<String, Object> parameters) {
        //do stuff that might fail
    }
    public Object defaultStores(Map<String, Object> parameters) {
        return /* something useful */;
        }
    }

配置文件

enter image description here

資源控制實踐

聊到資源控制亚再,估計很多小伙伴會聯(lián)系到docker阀捅,docker確實是一個實現(xiàn)資源控制很不錯的解決方案,我們前期做調研時也對是否使用docker進行了評審针余,但是最終選擇放棄饲鄙,而使用linux 的libcgroup腳本控制,原因如下:

  • docker 更適合大內存做資源控制圆雁、容器化忍级,但是我們線上服務器一般都是32G左右,使用docker會有資源浪費伪朽。

  • 使用docker會使運維復雜轴咱、來自業(yè)務的壓力會很大。

為什么要有cgroup?

Linux系統(tǒng)中經(jīng)常有個需求就是希望能限制某個或者某些進程的分配資源烈涮。也就是能完成一組容器的概念朴肺,在這個容器中,有分配好的特定比例的cpu時間坚洽,IO時間戈稿,可用內存大小等。于是就出現(xiàn)了cgroup的概念讶舰,cgroup就是controller group鞍盗,最初由google的工程師提出,后來被整合進Linux內核中跳昼,docker也是基于此來實現(xiàn)般甲。

libcgroup使用流程:

安裝

    yum install libcgroup

啟動服務

    service cgconfig start

配置文件模板(以memory為例):

    cat /etc/cgconfig.conf
enter image description here

看到memory子系統(tǒng)是掛載在目錄/sys/fs/cgroup/memory下,進入這個目錄創(chuàng)建一個文件夾鹅颊,就創(chuàng)建了一個control group了敷存。

    mkdir test
    echo "服務進程號">>  tasks(tasks是test目錄下的一個文件)

這樣就將當前這個終端進程加入到了內存限制的cgroup中了。

總結

總結一下堪伍,本文從我們微服務實踐的背景聊起锚烦,介紹了微服務實踐的工作方式觅闽,技術選型,以及相關的一些微服務技術挽牢。包括:API網(wǎng)關谱煤、注冊中心、斷路器等禽拔。相信這些技術會給大家在實踐中帶來一些新的思路刘离。當然整個微服務實踐之路內容繁多,一篇文章不可能全部包括睹栖,大家有興趣可以提出來硫惕!

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嬉愧,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件豁辉,死亡現(xiàn)場離奇詭異,居然都是意外死亡舀患,警方通過查閱死者的電腦和手機徽级,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來聊浅,“玉大人餐抢,你說我怎么就攤上這事〉统祝” “怎么了旷痕?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長顽冶。 經(jīng)常有香客問我欺抗,道長,這世上最難降的妖魔是什么渗稍? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任佩迟,我火速辦了婚禮,結果婚禮上竿屹,老公的妹妹穿的比我還像新娘。我一直安慰自己灸姊,他們只是感情好拱燃,可當我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著力惯,像睡著了一般碗誉。 火紅的嫁衣襯著肌膚如雪召嘶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天哮缺,我揣著相機與錄音弄跌,去河邊找鬼。 笑死尝苇,一個胖子當著我的面吹牛铛只,可吹牛的內容都是我干的。 我是一名探鬼主播糠溜,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼淳玩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了非竿?” 一聲冷哼從身側響起蜕着,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎红柱,沒想到半個月后承匣,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡锤悄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年韧骗,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铁蹈。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡宽闲,死狀恐怖,靈堂內的尸體忽然破棺而出握牧,到底是詐尸還是另有隱情容诬,我是刑警寧澤,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布沿腰,位于F島的核電站览徒,受9級特大地震影響,放射性物質發(fā)生泄漏颂龙。R本人自食惡果不足惜习蓬,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望措嵌。 院中可真熱鬧躲叼,春花似錦、人聲如沸企巢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至或听,卻和暖如春探孝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背誉裆。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工顿颅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人足丢。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓粱腻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親霎桅。 傳聞我的和親對象是個殘疾皇子栖疑,可洞房花燭夜當晚...
    茶點故事閱讀 45,781評論 2 361

推薦閱讀更多精彩內容