韓立峰, 亓雪冬
(中國石油大學(華東) 信息化建設處, 山東 青島 266580)
目前,高校普遍建設了校園一卡通系統,它集成了身份認證和電子支付的功能,師生在餐廳等消費場所通過刷卡,就可使用個人賬戶資金進行支付。隨著互聯網應用的普及,為了支撐校園一卡通的互聯網應用,我校建設了校園一卡通開放平臺[1]。平臺提供了一系列有關一卡通查詢、轉賬、支付功能的Rest API,第三方應用系統通過調用這些接口,就可將一卡通認證和支付功能嵌入到自己的系統或業務流程里。
當前,網上預訂和網上支付逐漸成為師生的行為喜好。建設網上訂餐系統,師生可提前獲知當日餐品供應并根據個人口味預訂;餐廳銷售方可根據預訂情況合理安排餐品供應。同時在后疫情時代,線上自主預訂、線下分散取餐,可有效減少人員現場聚集,避免交叉傳染。
因此我們設計了基于微服務架構的網上訂餐系統,系統將用戶認證、預訂、支付等功能抽取為相互獨立的微服務,供前端PC、手機、自助點餐機等客戶端調用,同時系統以校園一卡通開放平臺為基礎,通過調用平臺接口,實現基于一卡通的身份認證和網上支付功能。
隨著互聯網應用規模的不斷擴大,傳統的垂直應用架構已經無法應對。微服務架構[2-3]是一種新興的互聯網應用架構,它將單一應用程序劃分成一組小的服務,每個服務運行在其獨立的進程中,服務之間通訊采用輕量級的通訊協議。微服務架構可以根據應用的需求,動態擴充服務資源,具有很強的伸縮性。
微服務架構帶來了服務治理的問題,面對數量龐大的服務,如何實現服務的動態注冊和發現,明確服務間的依賴關系,合理調整服務的容量,Dubbo解決了以上問題。Dubbo是一款高性能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向接口的遠程方法調用、智能容錯和負載均衡、以及服務自動注冊和發現[4]。Dubbo框架對系統各種服務的運行過程進行管理,管理架構如圖1所示。

圖1 Dubbo服務管理架構
圖中共有5個角色,各角色之間調用關系為:服務提供者在注冊中心注冊其提供的服務;服務消費者從注冊中心訂閱自己的服務;服務容器負責啟動運行服務進程;監控中心負責統計服務調用的次數和時間。
網上訂餐系統的整體設計分為三層架構,其設計思想為:最底層是數據訪問層,數據訪問層作為服務支撐的基礎保障,由一卡通開放平臺提供功能支持;中間層是業務層,里面對業務模塊進行細化和拆分,將系統用戶所需的功能抽取成多個微服務,微服務向下調用基礎服務層一卡通開放平臺的API,向上對用戶訪問層提供微服務接口;用戶訪問層包括PC、手機、自助機等各種類型終端調用微服務接口,實現相應用戶功能,系統架構如圖2所示。

圖2 網上訂餐系統架構
本文重點說明業務微服務層設計,訂餐系統業務非常明確,將其拆分成5個子服務,分別是餐品發布服務、餐品查詢服務、餐品預訂服務、用戶支付服務和商戶結算服務。每個子服務都是獨立的功能設計單元,其代碼實現不同但技術架構相似。以支付微服務為例,支付微服務首先構建好實現代碼,然后將其部署到服務器上運行,這里可根據實際訪問量來進行服務器數量的選擇。初期可以先搭建一臺服務器,然后通過ZooKeeper對服務模塊的提供方進行注冊,此時一個靈活的、可監控、可管理的子業務就初步完成了。后期隨著業務量上升,可以復制原有的代碼,完成新服務器的部署搭建,只需將新的服務提供者注冊到ZooKeeper中,就形成了一個最輕量的負載集群。由于系統采用Dubbo的服務治理框架,隨著數據量和訪問量的上升,Dubbo可以使用權重算法分析負載,動態調配系統資源。另外非常重要一點是對服務進行管理和監控,它可以保證系統長時間的在各種復雜的情況下正常運行。
用戶通過網頁、微信、App等方式,首先對菜品進行瀏覽,在選擇好需要的菜品后,進行支付,最后系統自動根據對每日支付的訂單為商戶進行結算,如圖3所示。

圖3 訂餐業務流程
如本文前面所述,訂餐業務劃分成很多子服務,任何一個子服務都是可供其他程序獨立調用的,在前置條件充足的情況下子服務之間完全解耦,這是本系統設計的核心思想,也旨在建立起一個健壯而又可擴展的現代化網絡應用系統。本文以支付微服務為例,闡述采用Dubbo框架對子服務進行管理,同時采用微服務的設計思想,由服務提供者創建微服務、由ZooKeeper注冊微服務,并通過服務消費者調用微服務的設計理念。
網上訂餐系統作為服務提供者創建支付微服務,首先需要定義服務接口,繼而實現服務接口。這里筆者創建了支付微服務PayService,提供線上支付扣款功能。
(1) 服務端定義支付微服務接口
public interface PayService {
int Pay(String account, double tranamt, string meraccc, string order_no);
}
Pay方法中,參數account表示學工號;tranamt表示扣款金額;meraccc表示商戶號;order_no表示訂單號;返回值為0表示支付成功,非0表示支付失敗。
(2) 服務端實現支付微服務接口
public class PayServiceImpl implements PayService {
int Pay(String account, double tranamt, string meraccc, string order_no) {
String jsonStr = JSONObject.toJSONString(inJsonObject);
HttpClient httpClient = HttpClient.newBuilder().build();
HttpRequest request = HttpRequest.newBuilder()
.POST(HttpRequest.BodyPublishers.ofString(jsonStr))
.uri(URI.create("https://一卡通開放平臺IP/…/card_pay"))
.build();
int retcode=Integer.parseInt(outJsonObject.getString("retcode"));
return retcode;
}
}
接口PayService的Pay方法在實現時需調用基礎服務層一卡通開放平臺的支付接口card_pay,實現基于一卡通賬戶的支付,接口地址https://一卡通開放平臺IP/…/card_pay,數據交換格式為JSON,請求方法HTTPS POST,一卡通開放平臺執行完扣費操作后,返回JSON格式的處理結果,retcode和errmsg分別表示返回碼和錯誤信息,返回值0表示扣費成功,否則表示扣費失敗,調用過程如圖4所示。

圖4 一卡通開放平臺支付接口調用
(3) 聲明暴露支付微服務
配置provider.xml文件,在網絡中暴露支付微服務:
interface="com.hanlifeng.Dubbo.provider.service.PayService" ref="payService"/> (4) 服務消費者調用支付微服務 用戶使用PC、手機等客戶端與訂餐系統發生交互,調用支付微服務,客戶端程序首先根據消費者配置文件consumer.xml建立應用上下文context,然后通過context.getBean()語句獲取遠程支付微服務的代理對象payService。接下來代理對象的GetOrderInfo方法獲取掃描訂單二維碼得到的訂餐信息,包括學工號、訂餐金額、商戶號、訂單編號等。最后調用支付微服務payService的Pay方法完成支付。 根據訂餐系統架構,實際部署方案為:1.前端部署2臺Nginx用于應用反向代理,服務器配置成主從模式,單臺Nginx并發數可達3萬,足以滿足學校高峰時使用。2.部署1臺ZooKeeper服務器用于服務的注冊,保存服務列表地址。3.部署1臺RabbitMQ[5]服務器,消息隊列主要負責處理高峰時段訂單的下發,將其排隊并按序推送給支付微服務網關,從而實現高峰時段對集中請求分發的處理要求。4.部署1臺 Redis服務器和1臺MySQL服務器,高峰訂餐時段菜品的查詢會非常頻繁,如果采用通過關系型數據庫直接查詢,可能會導致數據查詢緩慢。系統采用在餐品發布完成后,記錄到MySQL數據庫的同時,在Redis內存中也生成一個餐品的數據高速緩存,高峰期所有的查詢都是直接通過內存中的高速緩存來進行查詢,這樣可以保證查詢速度在毫秒級別,滿足師生在訂餐時段的用戶體驗。5.部署2臺微服務業務的服務器,將微服務Java源文件進行編譯,并打包成mealOrdering.jar分別拷貝到兩臺服務器的tomcat / webapps目錄下,啟動tomcat即可,程序會把微服務的節點(各個子服務提供者)注冊到ZooKeeper服務器的樹狀節點中,此時服務消費端可以通過ZooKeeper服務器的樹狀列表找到自己需要的服務,從而實現分布式微服務的功能。 網上訂餐系統采用微服務架構設置,在業務層將餐品預訂、支付、商戶結算等功能抽取拆分形成一個個微小的子服務,借助校園一卡通開放平臺和數據平臺提供的基礎用戶認證和支付能力,同時利用Dubbo框架對系統子服務進行治理,有效解決了微服務的注冊、調用、監控、追溯以及高低峰負載均衡等設計問題,使系統具有很高的并發處理能力和伸縮擴展性,可以有效應對校園師生在訂餐中大規模使用的場景。5 系統部署方案
6 總結