轉自:http://www.58maisui.com/2016/06/28/a⑶27/?ref=myread
本次分享的大綱以下:
- 傳統(tǒng)利用開發(fā)面臨的挑戰(zhàn)
- 服務化實踐
- 服務化不是銀彈
- 服務化架構的演進方向
1 、傳統(tǒng)利用開發(fā)面臨的挑戰(zhàn)
挑戰(zhàn)1– 研發(fā)本錢高
主要體現在以下幾個方面:
- 代碼重復率高
在實際項目分工時,開發(fā)都是各自負責幾個功能,即使開發(fā)之間存在功能堆疊,常常也會選擇自己實現,而不是類庫同享,主要緣由以下:
- 從技術架構角度看,傳統(tǒng)垂直架構的特點是本地API接口調用,不存在業(yè)務的拆分和相互調用,使用到甚么功能就本地開發(fā),非常方便,不需要過度依賴于其它功能模塊;
- 從考核角度來看,同享很難推行。開發(fā)只需要對自己開發(fā)的模塊交付質量負責,沒有義務為他人提供并保護公共類庫,這個非常耗費本錢;
- 時間依賴很難把控:對公共類庫的使用者而言,依賴他人提供此功能,但是功能提供者可能有更重要的事情在做,提供時間沒法滿足使用者。與其坐等他人提供,還不如自己開發(fā)效力高;
跨地域、跨開發(fā)小組調和很困難,業(yè)務團隊可能跨地域研發(fā),內部通常也會分成多個開發(fā)小組,各開發(fā)小組之間的調和和溝通本錢非常高。
- 需求變更困難
代碼重復率變高以后,已有功能變更或新需求加入都會非常困難,以充值繳費功能為例,不同的充值渠道開發(fā)了相同的限額保護功能,當限額保護功能產生變更以后,所有重復開發(fā)的限額保護功能都需要重新修改和測試,很容易出現修改不1致或被遺漏,致使部份渠道充值功能正常,部份存在Bug的問題,示例以下:
- 沒法滿足新業(yè)務快速創(chuàng)新和敏捷交付
挑戰(zhàn)2– 運維效力低
在傳統(tǒng)的MVC架構中,業(yè)務流程是由1長串本地接口或方法調用串連起來的,臃腫而冗雜,而且常常由1個人負責開發(fā)和保護。隨著業(yè)務的發(fā)展和需求變化,本地代碼在不斷的迭代和變更,最后構成了1個個垂直的功能孤島,只有原來的開發(fā)者才理解接口調用關系和功能需求,1旦原本的開發(fā)者離職或調到其他項目組,這些功能模塊的運維就會變得非常困難:
當垂直利用愈來愈多時,連架構師都沒法描寫利用間的架構關系,隨著業(yè)務的發(fā)展和功能膨脹,這類架構很容易產生腐化。
- 測試、部署本錢高:業(yè)務運行在1個進程中,因此系統(tǒng)中任何程序的改變,都需要對全部系統(tǒng)重新測試并部署
- 可伸縮性差:水平擴大只能基于全部系統(tǒng)進行擴大,沒法針對某1個功能模塊按需擴大
- 可靠性差:某個利用BUG,例如死循環(huán)、OOM等,會致使全部進程宕機,影響其它合設的利用
如何解決傳統(tǒng)單體架構面臨的挑戰(zhàn)?
解決對策:1、拆分 2、解耦 3、透明 4、獨立 5、分層。
- 拆分:對利用進行水平和垂直拆分,例如商品中心、計費中心、定單中心等。
- 解耦:通過服務化和定閱、發(fā)布機制對利用調用關系解耦,支持服務的自動注冊和發(fā)現
- 透明:通過服務注冊中心管理服務的發(fā)布和消費、調用關系
- 獨立:服務可以獨立打包、發(fā)布、部署、啟停、擴容和升級,核心服務獨立集群部署
- 分層:梳理和抽取核心利用、公共利用,作為獨立的服務下沉到核心和公共能力層,逐步構成穩(wěn)定的服務中心,使前端利用能更快速的響應多變的市場需求
2、服務化實踐
服務的定閱發(fā)布機制
它的核心理念是實現服務消費者和服務提供者的解耦,讓服務消費者能夠像使用本地接口1樣消費遠真?zhèn)€服務提供者,而不需要關心服務提供者的位置信息,實現透明化調用。
關鍵技術點:服務的定閱、發(fā)布機制、服務的健康狀態(tài)檢測和高HA。
經常使用的服務注冊中心有Zookeeper、ETCD,和基于數據庫的配置中心。
大家在技術選型的時候,需要根據自己的業(yè)務實際情況進行選擇。例如超大范圍集群,服務實例數超過10W,Zookeeper就會存在性能問題。
現在開源的散布式配置服務很多,如無特殊需求,建議選擇開源方案。
服務化實踐-零侵入
實際上,完全的零侵入很難做到,即便是聲明式配置,配置本身也是代碼的1部份,只不過相比于代碼類庫依賴,它不是編譯器依賴。
1種好的做法是,服務的發(fā)布和消費通過聲明式或注解的方式,而不是直接調用服務框架的接口,例如Thrift。客戶端需要調用Thrift提供的類庫訪問服務端,這就是代碼API級的依賴,對業(yè)務代碼侵入比較大。
1種比較成熟的實踐是 利用Spring的擴大機制,通過XML的方式實現服務的發(fā)布和消費。
服務化實踐-容錯和路由
單體利用服務化以后,通常采取散布式集群的部署模式。
這會帶來兩個問題:
- 服務如何路由;
- 遠端服務訪問失敗以后,如果進行容錯。
大部份的容錯和路由策略可以抽象到散布式服務框架中,通過策略配置的方式提供給用戶使用,下降用戶的開發(fā)本錢。
從業(yè)務擴大性角度看,服務框架通常會提供擴大點,供業(yè)務做路由和容錯定制。例如,業(yè)務希望根據手機號碼和地市進行路由:
服務化實踐-本地短路策略
在電信行業(yè)中,小機還是很普遍,利用通常會合設,例如服務提供者和消費者部署到同1臺主機上。
為了提升性能,下降時延,常常會提供本地短路策略,具體策略以下:
服務化實踐-多樣化調用方式
服務的調用方式,主要有3種:同步服務調用、異步服務調用、并行服務調用。最經常使用、簡單的就是同步服務調用。
異步服務調用的工作原理以下:
詳細步驟以下:
- 消費者調用服務端發(fā)布的接口,接口調用由散布式服務框架包裝成動態(tài)代理,發(fā)起遠程服務調用;
- 通訊框架異步發(fā)送要求消息,如果沒有產生I/O異常,返回;
- 要求消息發(fā)送成功后,I/O線程構造Future對象,設置到RPC上下文中;
- 用戶線程通過RPC上下文獲得Future對象;
- 構造Listener對象,將其添加到Future中,用于服務端應對異步回調通知;
- 用戶線程返回,不阻塞等待應對;
- 服務端返回應對消息,通訊框架負責反序列化等;
- I/O線程將應對設置到Future對象的操作結果中;
- Future對象掃描注冊的監(jiān)聽器列表,循環(huán)調用監(jiān)聽器的operationComplete方法,將結果通知給監(jiān)聽器,監(jiān)聽器獲得到結果以后,繼續(xù)后續(xù)業(yè)務邏輯的履行,異步服務調用結束。
并行服務調用,目的是為了提升服務調用的并行度,下降E2E時延。
服務化實踐-高性能、低時延
服務框架的性能,主要強調3個要素:1、I/O通訊;2、序列化框架;3、線程調用模型。
如果使用Java語言,I/O框架推薦 Netty。
序列化框架推薦:Thrift、Avro序列化框架、PB等。線程調度模型建議參考Reactor。
1種線程模型的參考實現方式:Netty的線程模型
無鎖化串行設計理念
服務化實踐-故障隔離
故障隔離非常重要,由于常常會采取同步服務調用模式,核心服務和非核心服務共用同1個線程池和消息隊列,非核心服務處理慢常常會阻塞核心服務,致使雪崩現象。
故障隔離的核心技術點以下:
1. 支持服務部署到不同線程/線程池中
2. 核心服務和非核心服務隔離部署
服務化實踐-服務治理
隨著業(yè)務范圍的不斷擴大,小服務資源浪費等問題逐步顯現,需要能夠基于服務調用的性能KPI數據進行容量管理,公道分配各個服務的資源占用,提高機器的利用率。
線上業(yè)務產生故障時,需要對故障業(yè)務做服務降級、流量控制、流量遷移等,快速恢復業(yè)務。
隨著開發(fā)團隊的不斷擴大,服務的上線愈來愈隨便,乃至產生功能相同、服務名不同的服務同時上線。上線容易下線難,為了規(guī)范服務的上線和下線,在服務發(fā)布前,需要走服務預發(fā)布流程,由架構師或項目經理對需要上線的服務做發(fā)布審核,審核通過的才能夠上線。
為了滿足服務線下管控、保障線上高效運行,需要有1個統(tǒng)1的服務治理框架對服務進行統(tǒng)1、有效管控,保障服務的高效、健康運行。
服務治理是散布式服務框架的1個可選特性,雖然從服務開發(fā)和運行角度看它不是必須的,但是如果沒有服務治理功能,散布式服務框架的服務SLA很難得到保障,服務化也很難真正實行成功。
從架構上看,散布式服務框架的服務治理分為3層:
第1層為服務治理展現層,它主要由服務治理Portal組成,提供可視化的界面,方燕服務運維人員進行治理操作。
第2層為服務治理SDK層,它主要由以下幾部份組成:
- 服務治理元數據:服務治理元數據主要包括服務治理實體對象,包括服務模型、利用模型、治理組織模型、用戶權限模型、數據展現模型等。元數據模型通過Data Mapper和模型擴大,向上層界面屏蔽底層服務框架的數據模型,實現展現層和服務框架的解耦,元數據也能夠用于展現界面的定制擴大;
- 服務治理接口:服務治理Portal調用服務治理接口,實現服務治理。例如服務降級接口、服務流控接口、服務路由權重調劑接口、服務遷移接口等。服務接口與具體的協(xié)議無關,它通常基于散布式服務框架本身實現,可以是Restful接口,也能夠是內部的私有協(xié)議;
- 服務治理客戶端類庫:由于服務治理服務本身通常也是基于散布式服務框架開發(fā),因此服務治理Portal需要集成份布式服務框架的客戶端類庫,實現服務的自動發(fā)現和調用;
- 調用示例:客戶端SDK需要提供服務治理接口的參數說明、注意事項和給出經常使用的調用示例,方便前端開發(fā)人員使用;
- 集成開發(fā)指南:服務治理SDK需要提供集成開發(fā)指南,指點使用者如何在開發(fā)環(huán)境中搭建、集成和使用服務治理SDK。
第3層為后臺服務治理服務層:它通常由1組服務治理服務組成,可以單獨部署,也能夠與利用合設。斟酌到硬朗性,通常選擇獨立集群部署。治理服務的可靠性由散布式服務框架本身來保證,治理服務宕機或異常,不影響業(yè)務的正常使用。服務治理服務通常其實不隨服務框架發(fā)布,治理服務是可選的插件,單獨隨服務治理框架交付。
服務化實踐-高可靠性
關鍵技術點設計以下:
- 服務無狀態(tài)設計
- 服務注冊中心集群,宕機不影響業(yè)務運行
- 服務提供者集群,集群容錯屏蔽服務提供者故障
- 服務健康狀態(tài)檢測,基于時延等性能KPI指標
- 服務治理中心集群,宕機不影響業(yè)務運行
- 服務級故障隔離
- 核心服務獨立部署和集群
- 跨機房路由和異地容災
3、服務化不是銀彈
服務化會帶來很多收益,但是它卻不是銀彈。
服務化不是銀彈-時延問題
在服務化之前,業(yè)務通常都是本地API調用,本地方法調用性能消耗較小。服務化以后,服務提供者和消費者之間采取遠程網絡通訊,增加了額外的性能消耗。
服務化不是銀彈-問題定位
在散布式環(huán)境下,如何高效的進行問題定界定位和日志檢索
服務化不是銀彈-事務1致性
服務化、散布式部署以后,有邏輯關聯(lián)關系的多個數據庫操作被打散到集群中各個獨立的服務實例中,引入散布式環(huán)境下的事務1致性問題。
服務化不是銀彈-前后臺直接通訊問題
前后臺直接通訊問題以下:
存在的問題以下:
- 客戶端需求和每一個微服務暴露的細粒度API不匹配
- 微服務使用的RPC私有協(xié)議,不是閱讀器友好或防火墻友好的
- 微服務難以重構。隨著時間推移,我們可能想要更改系統(tǒng)劃分成服務的方式。如果客戶端與微服務直接通訊,那末履行這類重構就非常困難了
服務化不是銀彈-團隊協(xié)作問題
- 同享服務注冊中心問題:為了方便開發(fā)測試,常常會在線下共用1個所有服務同享的服務注冊中心,這時候,1個正在開發(fā)中的服務發(fā)布到服務注冊中心,可能會致使1些消費者不可用。
- 多團隊進度協(xié)同問題:服務提供者和消費者相互依賴問題,開發(fā)依賴、測試依賴等。
- 接口前向兼容性問題:由于線上的Bug修復、內部重構和需求變更,服務提供者會常常修改內部實現,包括但不限于:接口參數變化、參數字段變化、業(yè)務邏輯變化和數據表結構變化。在實際項目中常常會產生服務提供者修改了接口或數據結構,但是并沒有及時知會到所有消費者,致使服務調用失敗
4、未來演進方向-微服務架構
微服務的劃分原則是難點,根據華為的經驗:微服務劃分不是1步到位,而是不斷的迭代和演進,終究找到合適自己團隊和業(yè)務的微服務劃分原則。
未來演進方向-基于Docker部署微服務
使用Docker部署微服務的優(yōu)點總結:
- 1致的環(huán)境:線上線下環(huán)境1致
- 避免對特定云基礎設施提供商的依賴
- 下降運維團隊負擔
- 高性能:接近裸機的性能
- 多租戶
未來演進方向-云端微服務
利用云平臺的彈性資源調度,動態(tài)性等,可以實現微服務的Dev&Ops
最后我們1起回顧下服務化的演進歷程:
Q&A
Q1:上面提到服務化缺點的第3條接口變更問題,請問微服務是如何解決這個問題的呢?或說微服務相比之下甚么優(yōu)勢會避免這個問題?
A1:根據我們團隊的經驗,主要從以下幾個方面下降影響:1、微服務的接口就是契約,制定 接口兼容性規(guī)范;觸及到技術和管理兩個層面;2、微服務鼓勵只做1件事情,因此它更加穩(wěn)定;3、基于消費者契約測試,快速發(fā)現兼容性問題。
Q2:微服務架構里,散布式事務如何做的,對數據1致性要求較高的系統(tǒng)是不是合適拆分成微服務,或說微服務的粒度如何掌控?
A2:散布式事務是難點,策略以下:1)如果業(yè)務上能夠承受非強1致性,建議通過事務補償的方式做終究1致性,可以基于MQ等中間件來實現;2)如果是轉賬、實時計費、充值等對實時性要求高的,常常選擇強1致性事務,就需要引入TCC等散布式事務框架。不管如何,只要做散布式,事務1致性就會成為問題,跟是不是是微服務沒必定關系。
Q3:生產環(huán)境中的服務注冊中心必定是同享的,那如何去做灰度發(fā)布或A/B Test呢?
A3:1種比較好的服務灰度策略是:1)服務框架提供灰度規(guī)則框架,包括后臺引擎和前臺Portal,由業(yè)務配置灰度規(guī)則;2)散布式服務框架支持灰度規(guī)則推送和業(yè)務自定義路由;3)前端SLB ,例如Ngix做灰度插件,接收灰度規(guī)則。消息從前端門戶接入到后端服務路由,都支持基于規(guī)則的路由分發(fā)策略,實現灰度發(fā)布。
Q4:Netty的無鎖化串行會比有鎖的并行性能更高嗎?有案例嗎?華為現在都是用Docker部署利用嗎?
A4:Netty的無鎖化串行性能問題:1)在實際項目中,線程池爭用模式和串行模式我們都使用過,Netty的無鎖化串行模式性能更高。Docker部署利用:華為的公有云和私有云都支持基于Docker部署利用,由客戶根據需要自主選擇。
Q5:IO通訊是怎樣保證每次連接成功的呢?
A5:NIO通訊本身其實不保證每次連接都成功,它的連接是異步的,你可以根據以下兩種策略取得異步鏈接的結果:1)發(fā)起連接以后主動調用同步方法等待結果返回,阻塞式;2)獲得異步連接Future,添加Listener監(jiān)聽器監(jiān)聽連接結果,這類模式是異步回調,不會阻塞當前線程。
Q6:使用zk作為服務注冊中心,對與某個服務當客戶端連接數很多時候節(jié)點變化會引發(fā)羊群效應,怎樣處理這類問題呢?或說如何避免這類問題呢?
A6:這個問題真是好!通常而言,大家會使用服務注冊中心做服務可用性檢測,如果發(fā)現某個服務節(jié)點不可用,就會將其從注冊中心中刪除。但是,有1種場景是ZK檢測的結果跟客戶端和服務端實際的連接狀態(tài)不1致。從ZK看,服務提供者可使用。但是由于服務消費者跟提供者之間的鏈路已中斷,跟ZK的鏈路卻是正常,這類情況下就會出現狀態(tài)不1致問題。所以,只依托ZK做狀態(tài)檢測還不夠,需要服務提供者和消費者的鏈路層做雙向心跳檢測。
Q7:我現在做的系統(tǒng)是zk做注冊中心服務把地址注冊上去(臨時節(jié)點),客戶端拿地址要求,http的,現在發(fā)現如果是公網調用的話,對公網資源要求還挺多的,zk公網, 利用公網;為了減少對公網需求,中間加1層nginx,把nx地址注冊上去,不過又得加個http探測監(jiān)控程序,異常還得刪掉注冊數據,不知道這類做法是不是妥當?
A7:Ng監(jiān)聽ZK注冊的服務提供者URL便可,問題不大。
Q8:用Netty做同通訊框架,監(jiān)控上報應當怎樣設計更完善?
A8:建議的方式以下:Netty本身不用告警,監(jiān)聽Netty的異常事件,然后通過MQ吐出去,監(jiān)控系統(tǒng)定閱通訊框架的事件主題,實現通訊框架和監(jiān)控系統(tǒng)解耦。
Q9:SOA和微服務架構的區(qū)分和聯(lián)系是?看起來好像啊!
A9:1) 服務拆分粒度:SOA首先要解決的是異構利用的服務化;微服務強調的是服務拆分盡量小,最好是獨立的原子服務;
2) 服務依賴:傳統(tǒng)的SOA服務,由于需要重用已有的資產,存在大量的服務間依賴;微服務的設計理念是服務自治、功能單1獨立,避免依賴其它服務產生耦合,耦合會帶來更高的復雜度;
3) 服務范圍:傳統(tǒng)SOA服務粒度比較大,多數會采取將多個服務合并打成war包的方案,因此服務實例數比較有限;微服務強調盡量拆分,同時很多服務會獨立部署,這將致使服務范圍急劇膨脹,對服務治理和運維帶來新的挑戰(zhàn);
4) 架構差異:微服務化以后,服務數量的激增會引發(fā)架構質量屬性的變化,例如企業(yè)集成總線ESB(實總線)逐步被P2P的虛擬總線替換;為了保證高性能、低時延,需要高性能的散布式服務框架保證微服務架構的實行;
5) 服務治理:傳統(tǒng)基于SOA Governance的靜態(tài)治理轉型為服務運行態(tài)微治理、實時生效;
6) 敏捷交付:服務由小研發(fā)團隊負責微服務設計、開發(fā)、測試、部署、線上治理、灰度發(fā)布和下線,運維全部生命周期支持,實現真實的DevOps。
總結:量變引發(fā)質變,這就是微服務架構和SOA 服務化架構的最大差異。
Q10:如果要將現有單機服務重構到微服務,應當斟酌哪些問題?數據遷移的安全問題怎樣解決?有甚么實踐方案嗎?
A10:需要斟酌的問題以下:1)當前單機利用是不是能夠滿足業(yè)務發(fā)展需要,有無必要做服務化改造和散布式部署;2)評估遷移的工作量,和人員技能培訓等。3)自研服務框架還是使用開源的方案。
數據遷移安全問題:如果內網,通常不會觸及到復雜的安全控制問題;如果跨公網,建議加入API Gateway統(tǒng)1做安全管控。
實踐方案:公然的資料,可以參考淘寶的服務化實踐、京東的服務化實踐等。其實華為也有,不過遺憾的是目前政策不允許公然出來。
Q11:麻煩李老師介紹下你們華為內部基于netty做socke通訊的協(xié)議設計的最好實踐。
A11:這個問題很大,簡單介紹下思路。在11年和13年的時候我分別主持設計了華為基于Mina和Netty的統(tǒng)1NIO通訊框架。設計要點以下:1)要熟習Netty的線程調度模型、經常使用的類庫等,能夠熟練使用Netty;2)NIO通訊框架的分層原則,哪些該做、哪些不該做,需要辨認出來;3)擴大點,預留足夠的擴大點給上層利用協(xié)議棧做擴大;4)可之內置配置化的安全策略、握手認證、心跳檢測等機制;5)可服務性設計,包括日志、性能KPI指標等。
作者介紹 李林鋒
- 從事華為軟件PaaS平臺的架構設計和開發(fā)工作,8年多NIO、平臺中間件領域設計、開發(fā)和運維經驗,精通NIO通訊框架、散布式服務框架、PaaS平臺等;
- 參與設計和開發(fā)某網關平臺;
- 曾取得公司總裁技術創(chuàng)新獎;
- 《散布式服務框架原理與實踐》作者。