微服務從程式碼到k8s部署應有盡有系列(七、支付服務)

語言: CN / TW / HK

我們用一個系列來講解從需求到上線、從程式碼到k8s部署、從日誌到監控等各個方面的微服務完整實踐。

整個專案使用了go-zero開發的微服務,基本包含了go-zero以及相關go-zero作者開發的一些中介軟體,所用到的技術棧基本是go-zero專案組的自研元件,基本是go-zero全家桶了。

實戰專案地址:https://github.com/Mikaelemmmm/go-zero-looklook

1、支付服務業務架構圖

2、依賴關係

payment-api(支付api)

  • order-rpc(訂單rpc)
  • payment-rpc(支付rpc)
  • usercenter(使用者rpc)

payment-rpc(支付rpc)

  • mqueue-rpc(訊息佇列)

order-rpc(訂單rpc)

  • mqueue-rpc(訊息佇列)
  • travel-rpc

usercenter(使用者rpc)

  • identity-rpc(授權認證rpc)

3、微信支付舉例

3.1 建立支付預處理訂單

1、使用者在我們這邊建立完訂單之後,要去微信那邊建立預支付訂單

app/payment/cmd/api/desc/payment.api

// 支付服務v1版本的介面
@server(
	prefix: payment/v1
	group: thirdPayment
)
service payment {
	@doc "第三方支付:微信支付"
	@handler thirdPaymentwxPay
	post /thirdPayment/thirdPaymentWxPay (ThirdPaymentWxPayReq) returns (ThirdPaymentWxPayResp)
	
	...
}

app/payment/cmd/api/internal/logic/thirdPayment/thirdPaymentwxPayLogic.go

  • ThirdPaymentwxPay

見下圖,我們建立微信預支付訂單時候做了一次封裝,因為我們平臺後續支付業務肯定不止民宿支付訂單,肯定還會有其他的,比如我們後續可以推出商城,推出課程等,所以在這裡使用switch做了個業務分類,目前我們只有民宿訂單,但是除了查詢業務不一樣,其他都一樣,我們把一樣的邏輯封裝起來,所以我們繼續看封裝後的方法 createWxPrePayOrder

app/payment/cmd/api/internal/logic/thirdPayment/thirdPaymentwxPayLogic.go

  • createWxPrePayOrder

這裡就是拿到使用者的登陸userId去換openid(這塊我們之前註冊登陸那裡有小程式註冊登陸,那時候就獲取了openid),然後呼叫paymentRpc中的CreatePayment建立我們本地的支付流水單號,再通過呼叫微信sdk-> svc.NewWxPayClientV3(這裡是我基於go-zero封裝了一次,沒啥難度都能看懂) ,

然後在微信端建立了一個關聯我們本地流水單號的預支付訂單,返回給前端,前端通過js發起請求即可

3.2 微信支付回撥

當前端拿著我們給的微信預處理訂單發起支付,使用者輸入密碼支付成功後,微信伺服器會回撥我們伺服器,回撥地址在我們配置中填寫的

這個回撥地址,一定要填寫我們支付api服務中的回撥處理方法,也就是如下圖的介面,這樣我們才能接收到微信回撥進來,我們才可以做後續處理。

微信回調回來之後,我們要處理回撥邏輯,我們要呼叫verifyAndUpdateState 將我們流水單號改為已支付

我們來看看verifyAndUpdateState方法,我們要查詢單號是否存在,比對回調回來的金額與建立時候金額是否一致更新流水單號即可。這裡不用在校驗簽名了,前一步的sdk已經做了處理了

這裡還要給前端寫一個輪訓介面,前端使用者支付成功後前端不能以前端的微信返回結果為準,要通過後端提供的介面輪訓,判斷這個流水單是否真的是後端返回支付成功狀態,如果這個介面返回成功才算成功,微信前端返回的不能作為依據,因為微信前端返回的不安全,一般開發都明白不知道的自己百度。

3.3 支付成功傳送小程式模版訊息

我們支付回撥成功之後,會給使用者傳送一個入駐碼,去了商家那裡要展示這個碼,商家通過後臺核對碼,其實就是美團的樣子,我們去美團下單,美團會給你個碼,使用者拿著這個碼去入住或者消費等。

ok,回撥成功,我們會呼叫pyamentRpc去修改當前流水單狀態成功

我們來看看paymentRpc中做了什麼,

前面是校驗,核心做了兩件事情,第一是更新狀態,第二向訊息佇列傳送了一條訊息,我們看看訊息佇列中對應的程式碼

可以看到我們使用了go-queue傳送了一條kq訊息到kafka,而不是asynq延遲訊息,因為我們想讓所有訂閱了該支付狀態的業務都能收到此訊息後做相應的處理,雖然目前我們只有一個地方監聽做處理(傳送小程式模版訊息通知使用者支付成功),所以這裡就是發了一條該支付流水相關資訊到kafka中,這裡跟之前訂單那裡是一樣的只是新增訊息到佇列,沒有處理,那我們看看order-mq中怎麼處理的。

前面order一節已經介紹了整個order-mq的運作機制,這裡不再多說了,我們只說kq這裡

當order-mq啟動後,go-queue會監聽kafka中的訊息

我們再來看下具體實現 , 當前面支付回撥成功新增到kafka中時候,order-mq中kafka會接受訊息,也就是PaymentUpdateStatusMq.Consume會接收到kafka的訊息,然後反序列化資料,傳遞給execService 執行具體業務,那execService中執行了什麼呢?

可以看到下方紅框內,一個是修改訂單狀態(非支付狀態,訂單也有自己狀態),一個是發訊息(簡訊、微信小程式模版訊息)給使用者

app/order/cmd/mq/internal/mqs/kq/paymentUpdateStatus.go

修改訂單狀態的我們就不看了,我們可以來看看傳送小程式模版訊息,下方LiveStateDate\LiveEndDate之前除錯寫死的,這個直接改成方法傳遞過來的時間就好了,轉換一下

【注】使用者想收到小程式模版訊息,必須在前端讓使用者授權才行,這是小程式必須的不是我們能控制的

這裡傳送訊息我們也不是真正的呼叫微信sdk去傳送訊息,也是往訊息佇列MqueueRpc中插入模版訊息(其實這裡也可以直接發),然後由message訊息服務從kafka中取出來真正傳送,是想所有的簡訊、email、微信等訊息統一從這個服務傳送出去,這個自己根據自己公司業務或者架構去靈活設計吧,不一定非得這樣。

那我們說到這裡了就直接去看看message訊息服務程式碼吧

message業務中只有一個mq,因為他不需要rpc、api,只需要定時從佇列去訊息傳送訊息,所以它執行邏輯跟order-mq一樣的,同樣適用serviceGroup管理

我們不細說了,執行邏輯可以去看訂單服務那一節的order-mq有細說,我們只看具體實現邏輯,go-queue從kafka佇列中取出每一條要傳送的微信小程式模版訊息資料,然後反序列化交給execService去處理,我們來看看execService

execService 主要就是整合資料,通過小程式sdk的client 傳送給小程式即可,這裡有個注意點,小程式是可以區分環境的,是傳送到線上小程式還是體驗版小程式,在下方紅色框內有做區分,實際這樣是不安全的 通過這種方式,最好搞到配置檔案裡,萬一開發環境有人搗亂改成formal,隨便發給別人openid就出事了,這個自己可以改改哈

4、小結

到這裡基本上整體專案服務邏輯都差不多說明完了,後續會介紹收集日誌、監控、部署等

專案地址

https://github.com/zeromicro/go-zero

https://gitee.com/kevwan/go-zero

歡迎使用 go-zerostar 支援我們!

微信交流群

關注『微服務實踐』公眾號並點選 交流群 獲取社群群二維碼。