為什么用Dubbo而不是Spring Cloud?基于支付場景的微服務高可用架構(gòu)實戰(zhàn)
今天給大家?guī)淼姆窒硎腔谥Ц秷鼍暗囊粋€微服務實戰(zhàn),會更偏向于應用層的內(nèi)容。
主要圍繞以下四點進行分享:
- SOA 與微服務
- 老支付架構(gòu)遇到的挑戰(zhàn)
- 基于微服務怎么做的改造
- 未來計劃要做的事
SOA 與微服務
在我看來,微服務雖是國外傳進來的技術(shù),卻和咱們中國的一些理論是掛鉤的。所以在正式進入主題之前,先給大家簡單介紹一下麥田理論。
關(guān)于麥田理論
古代周朝時期,老百姓種地實際是沒有任何規(guī)劃的,也沒有任何區(qū)域的限制。
一般來說在地里一會種水稻,一會種小麥,一會種蔬菜地交叉來種,可收成之后發(fā)現(xiàn)莊稼受陽光程度非常低,營養(yǎng)非常不均衡,后期維護成本非常高。
直到戰(zhàn)國時期,有一位農(nóng)業(yè)專家把地劃分為多個區(qū)域,每一個區(qū)域種一種莊稼,地跟地隔開,形成最初的微服務理念。
過去我們看到的很多文章都只是講到 SOA 和微服務之間的比較,我今天在這個基礎上加了一個 DDD。下面就 DDD、SOA 以及微服務的演進過程先做個引子。
DDD、SOA 與微服務
SOA 架構(gòu)
SOA 是上一個時代的產(chǎn)物,大概是在 2010 年之前出現(xiàn)的,最早提出時是提供給傳統(tǒng)行業(yè)計算領(lǐng)域的解決方案,當時 Oracle、IBM 也提了很多方案,包括出現(xiàn)的很多流程引擎。
它的思想是將緊耦合的系統(tǒng),劃分為面向業(yè)務的粗粒度、松耦合、無狀態(tài)的服務。
在這之后,微服務的提出者基于 SOA 做了一個改進,就把它變成單一職責、獨立部署、細小的微服務,是一個相反的概念。
微服務與 DDD
今天我們一說到微服務就會想到 DDD,有不少朋友認為 DDD 就是為微服務而生的。其實不是這樣的,我在接觸 DDD 時,它最早是用來做 UML 設計、領(lǐng)域建模的。
DDD 講究充血模型,而 J2EE 模型以傳統(tǒng)的分層架構(gòu)和 Spring 架構(gòu)捆綁在一起形成了以貧血模型為主的架構(gòu)模式。
貧血模型的優(yōu)點是容易入門、分層清晰,而充血模型要求設計者前期對業(yè)務理解較深,不然后期項目會產(chǎn)生混亂。
另外就是 DDD 思想比較寬泛,導致形成百家爭鳴的姿態(tài),沒有形成一套固定的方法論。
開發(fā)者不容易理解,所以后面關(guān)注 DDD 的人變少了,而微服務的提出巧妙地借鑒了 DDD 里面的限界上下文、子域、領(lǐng)域事件等關(guān)鍵詞,在微服務得到越來越多業(yè)界認可的情況下,也給 DDD 帶來了重新的煥發(fā)機會。
老支付架構(gòu)遇到的挑戰(zhàn)
判斷項目好壞的兩個角度
我們判斷一個優(yōu)秀項目的好壞,可以從優(yōu)秀的代碼和高可用架構(gòu)兩個方向來講。
我們在設計高可用架構(gòu)的同時,也不能忽視代碼的重要性,優(yōu)秀的代碼指的是冗錯能力、冥等操作、并發(fā)情況、死鎖情況等,并不一定是指代碼寫得多漂亮。
這就好比蓋樓一樣,樓房的基礎架子搭得很好,但蓋房的工人不夠?qū)I(yè),有很多需要注意的地方忽略了,那么在往里面填磚加瓦的時候出了問題。
后果就是房子經(jīng)常漏雨,墻上有裂縫等各種問題出現(xiàn),雖然不至于樓房塌陷,但樓房也已經(jīng)變成了危樓。
從代碼和設計的角度來看有:
- 由不合理的代碼所引起的項目無擴展性
- 數(shù)據(jù)庫經(jīng)常發(fā)生死鎖
- 數(shù)據(jù)庫事務亂用,導致事務占用時間過長
- 代碼容錯能力很差,經(jīng)常因為考慮不足引起事故
- 程序中打印的大量的無用日志,并且引起性能問題
- 常用配置信息依然從數(shù)據(jù)庫中讀取
- 濫用線程池,造成棧和堆溢出
- 從庫中查詢數(shù)據(jù),每次全部查出
- 業(yè)務代碼研發(fā)不考慮冪等操作
- 使用緩存不合理,存在驚群效應、緩存穿透等情況
- 代碼上下流流程定義混亂
- 異常處理機制混亂
再從整體架構(gòu)角度來看:
- 整體依然使用單體集群架構(gòu)
- 采用單機房服務器布署方式
- 采用 Nginx+hessian 的方式實現(xiàn)服務化
- 業(yè)務架構(gòu)劃分不徹底,邊界模糊
- 項目拆分不徹底,一個 Tomcat 共用多個應用
- 無故障降級策略
- 監(jiān)控系統(tǒng)不合理(網(wǎng)絡、系統(tǒng))
- 支付運營報表,大數(shù)據(jù)量查詢
- 運維手動打包,手動上線
- 系統(tǒng)擴容手動布署
基于以上兩點,我們可以清晰地看到以前老項目的存在問題,并開始思考新的微服務架構(gòu)應該怎么去做。
基于微服務怎么做的改造
如上圖,想做高可用的微服務架構(gòu),必須先確立以下五個點:
- 產(chǎn)品迭代速度,當架構(gòu)設計完以后一定是對產(chǎn)品有利的,不能設計完了之后反而比以前開發(fā)得更慢了。這也是微服務的核心,通過把業(yè)務拆遷,將不同的產(chǎn)品一個個進行產(chǎn)品化,而不是項目化。
- 系統(tǒng)穩(wěn)定性,單體架構(gòu)時一個系統(tǒng)報錯就全部報錯,現(xiàn)在更是粒度細一些,同時架構(gòu)各種監(jiān)控。
- 研發(fā)效率。
- 問題快速定位,也就是每年給我們幾十分鐘的故障時間。
- 系統(tǒng)耦合度,不要把系統(tǒng)都放在一起,要多拆開。
利用 DDD 來劃分限界上下文
這是根據(jù)一些業(yè)務場景做的業(yè)務架構(gòu)圖,中間綠色部分是產(chǎn)品服務層。用 DDD 的思想來分析,產(chǎn)品服務層也就是產(chǎn)品服務域,這個域里包含三個子域,一個是收銀臺子域,一個是商戶子域,一個是個人子域。
每一個域里都包含有限界上下文,收銀臺包含兩個,商戶包含四個,個人包含兩個。
有些同學可能不太了解限界上下文概念,可以把它理解為一個系統(tǒng)、一個邊界或者一個實體。
比如說我們每天上班要倒三次地鐵,這里面的關(guān)鍵事件是什么?就是上班,那限界上下文就是坐地鐵,中間切換三次。
限界上下文就可以把它理解為一個微服務,也可以把它理解為一個系統(tǒng)、一個模塊。
限界上下文的劃分可以根據(jù)我們的團隊規(guī)模來定,如果團隊規(guī)模沒有達到一定的程度,可以將邊界定的粗一些,如果項目規(guī)模和團隊規(guī)模不斷擴大,還可以再把大的領(lǐng)域和限界上下文繼續(xù)拆分成多個小的。
微服務治理架構(gòu)圖
這是我們大致的一個微服務整體流程圖,采用的是 Spring Boot+Dubbo 的架構(gòu)。
為什么主張用 Dubbo 而不是 Spring Cloud?有兩點原因:
- 要看目前這個架構(gòu)是什么,如果是 Dubbo,很多組件的一些設施都要圍繞它來做,如果這時把它完全推倒換成別的架構(gòu),成本部分我們需要慎重考慮。
- Spring Cloud 技術(shù)雖新但不見得一定比 Dubbo 好用。目前公司就維護了一個叫 Dubbo Cloud,自己研發(fā)一套基于 Dubbo 的微服務體系。
上圖中間這塊的探針也是我們自主研發(fā)的,能夠?qū)崿F(xiàn)把整個服務鏈路的各種信息采集到。
比如掉網(wǎng)時間、報錯、返回值以及參數(shù)全部采集到,采集完之后就把這些信息用一個開源組件進行改造,把信息全部推給它,透過那個界面展示出我們要的東西。
后面這一套比如 Hystrix 熔斷、Dubbo Admin 和 Mock Server,我們是參考 Dubbo 的思路做的智能化攔截和服務降級。
后面的服務注冊、服務發(fā)現(xiàn)、服務路由、失敗重試和服務監(jiān)控等是 Dubbo 本身提供的,也就是圖片綠色的部分是我們自研的新功能,未來我們會把這個 Dubbo Cloud 體系進行開源。
通道報警切換系統(tǒng)的演進
這是我們通道報警系統(tǒng)的框架演進。為什么叫“通道”呢?因為我們的支付要接銀行,但銀行本身是相對偏傳統(tǒng)的,它們的通道不是很穩(wěn)定。
經(jīng)常有各種各樣的問題,而每個銀行都有 N 個通道,我們無法得知哪個通道近期是穩(wěn)定的或不穩(wěn)定,都是會來回變的。
這里我們自研了一個 Agent,通過采集它通道里的一些使用數(shù)據(jù),比如說這次我們連成功了,獲取到了數(shù)據(jù),然后放到 Kafka 里。
之后還有一個統(tǒng)計分析的東西,如果這個通道連接成功一次會對它的統(tǒng)計加一次,***把每隔一段時間的結(jié)果存到 Redis 集群里。
圖中的路由系統(tǒng)就是做通道選擇的。這是一個業(yè)務系統(tǒng),路由系統(tǒng)每次在做通道選擇時要先從 Redis 集群里把這個銀行的通道拿出來,選出評分***的一個。
拿出后再經(jīng)過自己的一套路由選舉的配套做一個清洗或者選擇,***得到一個***的通道,直接連到銀行通道上,這樣我們就能知道哪些通道是高可用的。
底下的過程還是通過 Kafka,并進行各種各樣的統(tǒng)計分析,也非常好用。然后這里會有一個圖表,如果當前有問題,在界面上都能可以看到,同時可以給你發(fā)短信、發(fā)郵件。
為什么我們這里做了兩套?***期的時候我們要做一個數(shù)據(jù)的比對,因為如果采集的數(shù)據(jù)不準確,這個通道就會存在問題。
所以我們一方面是通過上面這種方式來做評分策略,另一方面是把數(shù)據(jù)采集過來以后放到一個庫里,通過這個庫再做一次,***每次做一個比較,以統(tǒng)計正確率。
當這個通道也發(fā)生了問題,比如某一個銀行通道發(fā)生了問題,我們的監(jiān)控系統(tǒng)就會直接把銀行通道設置為不可用,然后通知研發(fā)部門讓他們?nèi)ソ鉀Q,完了以后再把這個通道變?yōu)榭捎谩?/p>
如果這個過程數(shù)據(jù)不準確,會造成頻繁的通道切換,會產(chǎn)生很多不必要的問題,所以在***期時我們先做成半自動化的。
雙活體系架構(gòu)的演進
雙活機房的演進,也是需要兩個階段:
***個階段是偽雙活
- 兩個機房同時提供服務,但需要設置主備機房;備機房的應用只能通過專線訪問主機房的數(shù)據(jù)庫;備機房的 Redis 也需要通過專線訪問主機房的 Redis。
- 當主機房掛了后,需要先將備機房應用的數(shù)據(jù)庫配置改成備庫,同時備庫停機,修改備庫為主庫。
第二個階段是泳道雙活
雙活體系架構(gòu)的演進,在ZK做數(shù)據(jù)同步的時候,采用兩種方式 Curator 的 TreeCacheListener 監(jiān)控相應節(jié)點的變化從而同步數(shù)據(jù),另一個是修改 ZK 源碼偽裝成 Observer 接收事務日志數(shù)據(jù)從而實現(xiàn)數(shù)據(jù)同步。
ZK 的同步***還是不進行同步、泳道隔離,比如像使用 Dubbo 這種的時候,完全可以同步二套環(huán)境,如果使用當當?shù)?Elastic-Job,在做雙活的時候就會相對麻煩。
微服務架構(gòu)全景圖
這個就是我們整個微服務的整體架構(gòu)。圖中左半部分體現(xiàn)了怎么把服務進行劃分,劃分了哪些領(lǐng)域,然后有哪些服務,數(shù)據(jù)庫內(nèi)容怎么劃分,網(wǎng)關(guān)層怎么做的,是從業(yè)務角度來做的一個劃分。
右邊這塊是體現(xiàn)我們?nèi)绾伪U衔⒎盏目煽啃浴?**層主要是給項目運營人員使用,第二層是我們?yōu)榱吮U衔⒎斩甲隽耸裁礀|西,有統(tǒng)一調(diào)度中心、雙活管控架構(gòu),還有大數(shù)據(jù)平臺、分布式緩存,做了各種各樣的組件來保障微服務順利的開展。
再下面是一些監(jiān)控,這里我們用了 APM 分布式調(diào)鏈的監(jiān)控,包括我們自己也做了一些監(jiān)控平臺。
持續(xù)集成測試
接下來講講我們的持續(xù)測試經(jīng)驗。怎么來保證代碼的質(zhì)量?這里就涉及到了集成測試的概念。
我們分了四個象限:一是單元測試,這是由開發(fā)自己來做的,一般覆蓋率在60-80%就不錯了;二是驗收測試和探索測試。
這兩個實際上是我們的測試人員在做,一個是驗證業(yè)務的可行性,一個是采取一些非法條件或者是一些破壞性測試,***是壓力測試,通過壓測看系統(tǒng)能承受的負載情況。
這是我們的整個測試流程:
- 首先,我們參照了阿里和其他公司的一些編碼規(guī)范,制定一套自己的編碼規(guī)范,并跟所有開發(fā)人員達成共識。
- 然后我們有自己的靜態(tài)代碼檢查,這里也可以用阿里的組件,這是前兩步。
- 第三步就是單元測試,基本上前三部分都是由開發(fā)來保障代碼的健壯性和正確性。
- 第四是持續(xù)集成,我們根據(jù)自己的規(guī)則和模板對它再進行一次代碼的掃描,掃描完之后就組織一些架構(gòu)師或是技術(shù)專家,對一些關(guān)鍵核心代碼再做一個代碼重構(gòu),大致是分了五步。
未來計劃要做的事
上圖幾點就是未來我們計劃要做的一些事情,因為現(xiàn)在業(yè)務量越來越大了,而不久后央行會再出一個文件,要考慮異地多活這個情況,這塊我覺得是一種趨勢,目前也有很多公司在做這件事情。
然后我們也會有一個 Dubbo Cloud,未來也是會開源的。后面就是大數(shù)據(jù)平臺的持續(xù)建設,目前我們的大數(shù)據(jù)平臺還不是特別完善。
像數(shù)據(jù)的挖掘這塊還沒有做,而現(xiàn)在一般的金融公司還有支付公司的風控都要做得特別好,而我們才剛起步。
程超,智慧支付***支付專家,12 年 Java 開發(fā)經(jīng)驗,對互聯(lián)網(wǎng)支付、電商業(yè)務方向較為了解,擅長分布式、性能調(diào)優(yōu)等技術(shù)領(lǐng)域,對高并發(fā)、大數(shù)據(jù)有濃厚興趣。《深入分布式緩存》一書聯(lián)合作者。