新聞中心
本文假定你已經(jīng)閱讀過之前的文章:

成都創(chuàng)新互聯(lián)技術(shù)團隊十年來致力于為客戶提供成都做網(wǎng)站、成都網(wǎng)站設(shè)計、高端網(wǎng)站設(shè)計、營銷型網(wǎng)站、搜索引擎SEO優(yōu)化等服務(wù)。經(jīng)過多年發(fā)展,公司擁有經(jīng)驗豐富的技術(shù)團隊,先后服務(wù)、推廣了1000+網(wǎng)站,包括各類中小企業(yè)、企事單位、高校等機構(gòu)單位。
- 為什么要重構(gòu)到微服務(wù)
- 重構(gòu)中的外部準備工作
- 重構(gòu)中的內(nèi)部準備工作
- 使用微服務(wù)架構(gòu)重構(gòu)支付網(wǎng)關(guān)
上一篇文章使用微服務(wù)架構(gòu)重構(gòu)支付網(wǎng)關(guān)是從橫向的角度來分析如何分解服務(wù)以及建立微服務(wù)之間的關(guān)系。這篇文章從縱向詳細介紹如何對SSH框架的支付系統(tǒng)實施具體的技改。這里不涉及具體代碼寫法,重點在于說明方法論。雖然以SSH(Apache Struts + Springframework + Hibernate) 框架為例,也適合各種常用的web架構(gòu) (Apache Struts/Spring MVC / Apache Velocity + Springframework + Mybatis/Hibernate) 。
選取入手模塊
如果遺留系統(tǒng)規(guī)模龐大,那應(yīng)該如何挑選入手點?以支付系統(tǒng)為例,如前文所述,支付系統(tǒng)一般包括賬戶,交易,訂單,優(yōu)惠券,錢包,支付渠道,清結(jié)算,支付網(wǎng)關(guān),運營系統(tǒng)等模塊。模塊很多,如何選擇突破點? 我們采取的方法是尋找對外依賴最小的模塊,由此開始調(diào)整。 首先模塊依賴關(guān)系整理出來。
從上圖可以看出來,賬戶系統(tǒng)在依賴樹中是處于樹根的位置,對它的調(diào)整相對容易。只要保持對外接口不變即可。
重構(gòu)策略
重構(gòu)如同飛行中更換引擎,必須非常小心,我們采取的策略是:小步快跑,積小勝為大勝。
- 每一個改進點,需在1~3天內(nèi)完成,不能超過一個周。
- 每次改進,均可直接上線運行,不需要長時間的AB測試。
在功能也就是對外接口不變的前提下,開始進行拆分工作。 在結(jié)構(gòu)上,原SSH系統(tǒng)是一個大項目,所有代碼分層分模塊堆在一起。微服務(wù)系統(tǒng)需要將它們拆分。直觀的拆分方法是按層,按模塊同構(gòu)的拆分成各個獨立運行和維護的系統(tǒng)。由此帶來了一系列的調(diào)整。在SSH架構(gòu)下,重構(gòu)可以采用自上而下的方法進行,這樣可以確保每一層的重構(gòu)都有明確的輸入輸出,并且是可測試的。
整體上,重構(gòu)分為三個步驟:
- 參考原有系統(tǒng)的DAO層和業(yè)務(wù)邏輯層,實現(xiàn)基礎(chǔ)服務(wù),一般是使用RPC來實現(xiàn).
- 將對外的接口層進行重構(gòu),調(diào)整為調(diào)用RPC服務(wù)。
- 將原有服務(wù)切一部分流量到新服務(wù)上進行試運行。
- 試運行成功,全部流量都切過來。 舊服務(wù)廢棄。
API網(wǎng)關(guān)
在SSH架構(gòu)下,對API網(wǎng)關(guān)一般是通過NGINX的rewtite模塊來實現(xiàn),邏輯簡單,人工維護即可。而一旦接口層按照業(yè)務(wù)來拆分后,網(wǎng)關(guān)路由邏輯復雜多了,通過人工維護配置文件難度激增,需要調(diào)整成自動注冊更新路由的方式。也就是每個服務(wù)需要將自己提供的服務(wù)和API注冊到API網(wǎng)關(guān)上, API網(wǎng)關(guān)需要自動識別并加載新的路由。
針對這個需求,我們開發(fā)了一個connector, 其工作原理如下:
- 服務(wù)在啟動完成后,注冊到zookeeper上。
- connector監(jiān)聽 zookeeper,一旦有變更,則獲取服務(wù)列表,更新nginx.conf文件
- connector在更新完成nginx.conf文件后,執(zhí)行nginx的reload命令,讓配置生效。
- load balancer 將服務(wù)打到nginx上,nginx可以按照新配置來執(zhí)行服務(wù)路由。
在服務(wù)關(guān)閉時,執(zhí)行類似的操作。第一步是在服務(wù)關(guān)閉前,將服務(wù)從zookeeper上刪除。注意必須在服務(wù)關(guān)閉前刪除,否則會發(fā)生服務(wù)不可用的錯誤。 服務(wù)注冊項從zookeeper上刪除,并且本地服務(wù)沒有流量后,才能關(guān)閉服務(wù)。connector可以和nginx部署在同一臺機器上。
服務(wù)接口調(diào)整
使用Spring MVC實現(xiàn)的Controller或者使用Apache Struts實現(xiàn)的Action,需要按照業(yè)務(wù)進行組合,拆分到具體項目中,原則上,一個項目不應(yīng)該有超過5個接口,避免接口過于復雜。本次調(diào)整需要做的工作包括:
- 增加服務(wù)注冊機制,在服務(wù)啟動時將服務(wù)注冊到zookeeper上;
- 增加服務(wù)退出機制,在服務(wù)關(guān)閉時將服務(wù)解除注冊;
- 將服務(wù)按照業(yè)務(wù)組合,建立對應(yīng)的項目;
- 將服務(wù)依賴的業(yè)務(wù)邏輯層打包到同一個jar中,作為后續(xù)改進的基礎(chǔ)。
- 服務(wù)上線,替換掉現(xiàn)有的服務(wù)。
業(yè)務(wù)邏輯層調(diào)整
在springframework框架下,業(yè)務(wù)邏輯層被實現(xiàn)為服務(wù)層和DAO層之間的橋梁。 對于絕大多數(shù)應(yīng)用來說,業(yè)務(wù)邏輯層都是非常薄的一層封裝,調(diào)整為微服務(wù)架構(gòu)下,業(yè)務(wù)邏輯層有三種處理方式:
- 抽象為獨立的RPC服務(wù),對于功能比較復雜業(yè)務(wù)邏輯,可以使用這種方式。
- 下沉到DAO層,如果邏輯上涉及數(shù)據(jù)訪問操作多,或者需要事務(wù)處理的,可以合并到DAO中,一同實現(xiàn)為RPC。
- 上浮到接口層。如果業(yè)務(wù)邏輯比較簡單,也可以上浮。
DAO層的重構(gòu)
DAO層的重構(gòu)的工作量比較大。 需要將原來訪問數(shù)據(jù)庫的邏輯,調(diào)整為遠程RPC調(diào)用:
針對DAO的接口,開發(fā)RPC服務(wù),將數(shù)據(jù)訪問邏輯通過RPC來隔離;
提供DAO的RPC接口客戶端,替換原DAO服務(wù)接口的實現(xiàn)。
這樣在業(yè)務(wù)邏輯層和服務(wù)層中調(diào)用的DAO,調(diào)整為RPC調(diào)用,將數(shù)據(jù)訪問邏輯和業(yè)務(wù)邏輯分離。這樣在DAO層就可以根據(jù)業(yè)務(wù)需要選用合適的存儲數(shù)據(jù)庫。
性能優(yōu)化
1.完成上述調(diào)整,這才是萬里長征走完的第一步。接下來就是碼農(nóng)們最心愛的性能優(yōu)化了。 對于大部分線上應(yīng)用來說,性能優(yōu)化主要的工作是選擇合適的存儲介質(zhì)來滿足性能的需求。
2.數(shù)據(jù)可以直接寫入MySQL或者其他的持久化存儲。這個庫也會被稱之為主庫。但是如果寫入性能要求高,可以調(diào)整為先寫入內(nèi)存數(shù)據(jù)庫,再同步到持久化存儲中。
3.線上數(shù)據(jù)訪問,指根據(jù)ID或者其他的某個屬性值來讀取1-2條數(shù)據(jù)。一般不要直接從MySQL等持久化存儲中出,需要采用couchbase,redis等內(nèi)存數(shù)據(jù)庫。
4.線上數(shù)據(jù)檢索,檢索和訪問需要分開。按照關(guān)鍵字、時間等條件的檢索,一般用Elastic來滿足。
線上數(shù)據(jù)列表,如最新、最熱、推薦等,都需要將數(shù)據(jù)預先計算好,放在couchbase或者redis等內(nèi)存數(shù)據(jù)庫中,讀取的時候直接從庫中出數(shù)據(jù),不能執(zhí)行實時計算。
通過這幾個步驟,就可以優(yōu)化線上服務(wù)的性能,最終呢,瓶頸應(yīng)該不是在數(shù)據(jù)庫或者CPU上,而是在帶寬上。 那這就是砸錢的商務(wù)行為了。 這樣處理,帶來的最大的問題是空間浪費,是典型的以空間換時間的做法。 技術(shù)上的挑戰(zhàn),那就是數(shù)據(jù)一致性問題。 對于一致性要求不強的需求,這個做法是沒問題的。 那如何在不同存儲之間同步數(shù)據(jù)呢?主要的做法有:
5.使用數(shù)據(jù)庫本身自帶的同步機制。好處是一般不需要開發(fā),問題是數(shù)據(jù)庫的同步機制,如MysQL、HBase的replication機制,僅支持少數(shù)類型的備庫,對數(shù)據(jù)庫本身也有壓力。
6.使用公共同步工具,如阿里的canal。
7.使用消息中間件來實現(xiàn)數(shù)據(jù)同步。
采用消息中間件目前主流的做法,適合于對數(shù)據(jù)實時性要求不高的場景。 如下圖所示,在數(shù)據(jù)寫入的服務(wù)中,完成寫入后,拋出消息。其他數(shù)據(jù)庫通過接受消息來更新數(shù)據(jù)。 優(yōu)點是系統(tǒng)靈活,無論是同DC還是跨DC的情況都可以正常工作。 對數(shù)據(jù)同步的情況,可以通過MQ提供的監(jiān)控系統(tǒng)也能夠了解。 缺點是開發(fā)工作量大,數(shù)據(jù)同步實時性不高。
如果時間不夠
上述重構(gòu)是非常理想的場景了,那如果時間不足,只能部分重構(gòu),應(yīng)該如何處理?一種方式是針對DAO層來改進。 一般來說,重構(gòu)往往意味著數(shù)據(jù)結(jié)構(gòu)的變更。另一方面,由于數(shù)據(jù)寫入的服務(wù)相對數(shù)據(jù)讀取服務(wù)要少得多,所以可以采用的策略是:
- 調(diào)整DAO服務(wù)中數(shù)據(jù)寫入操作,將數(shù)據(jù)寫入到新的庫表中;
- 采用MQ來實現(xiàn)新庫表和老庫表的數(shù)據(jù)同步。 參見上圖。
- 老的DAO服務(wù)中數(shù)據(jù)讀取的操作保持不變。
畢竟大部分的服務(wù)并不需要太高的性能需求。 只需要將性能要求高的服務(wù)進行重構(gòu),實現(xiàn)讀寫分離即可。重構(gòu)方式如上描述。
總之,技改的難度在于如何梳理出頭緒來。 本文算是拋磚引玉,歡迎大家熱烈討論。
【本文為專欄作者“鳳凰牌老熊”的原創(chuàng)稿件,轉(zhuǎn)載請通過微信公眾號“鳳凰牌老熊”聯(lián)系作者本人】
當前題目:對SSH框架系統(tǒng)進行微服務(wù)改進
新聞來源:http://m.5511xx.com/article/cdodcdc.html


咨詢
建站咨詢
