流水號(hào)在銀行業(yè)最為常見(jiàn)。相信很多人接觸到流水號(hào)都是從銀行相關(guān)的憑條或銀行系統(tǒng)查詢(xún)獲知。
自從進(jìn)入金融相關(guān)的公司或業(yè)務(wù)開(kāi)發(fā)之后,對(duì)流水號(hào)的應(yīng)用開(kāi)發(fā)就有了更深刻的認(rèn)知。
那么,今天我們通過(guò)流水號(hào)來(lái)應(yīng)用到實(shí)際開(kāi)發(fā)中。解決我們開(kāi)發(fā)中的問(wèn)題。
一、流水號(hào)的特點(diǎn):唯一性
流水號(hào),對(duì)于整個(gè)系統(tǒng)而言是全局唯一。這算是流水號(hào)最基礎(chǔ)最重要的特點(diǎn)。這個(gè)特點(diǎn),能解決最根本實(shí)際開(kāi)發(fā)中最實(shí)際的問(wèn)題。
二、實(shí)際案例:卡券發(fā)放
A 系統(tǒng)屬于核心系統(tǒng)。提供了各種各樣的核心功能,以及暴露一些 API 接口。這些接口可以給圍繞 A 系統(tǒng)做運(yùn)營(yíng)功能的系統(tǒng)使用。
假如,現(xiàn)在有一個(gè) B 系統(tǒng)有一個(gè)需求:
制作一個(gè)導(dǎo)流的活動(dòng)頁(yè)面,在該頁(yè)面輸入手機(jī)號(hào)并接收驗(yàn)證碼之后實(shí)現(xiàn)快捷注冊(cè),然后給這個(gè)手機(jī)號(hào)對(duì)應(yīng)的賬戶(hù)贈(zèng)送一張減免 10 元的卡券。
為什么不直接在導(dǎo)流的注冊(cè)流程里面直接贈(zèng)送呢?
因?yàn)?,有以下幾個(gè)原因:
- (1)導(dǎo)流頁(yè)面是調(diào)用 A 系統(tǒng)的注冊(cè)接口。A 系統(tǒng)屬于核心業(yè)務(wù)系統(tǒng),不會(huì)經(jīng)常為了這些活動(dòng)而定制改動(dòng)系統(tǒng)代碼,影響系統(tǒng)穩(wěn)定性。
- (2)B 系統(tǒng)只有 A 系統(tǒng)的可讀權(quán)限或可讀權(quán)限都沒(méi)有。所以,無(wú)法直接干涉核心業(yè)務(wù)數(shù)據(jù)庫(kù)的功能。
- (3)B 系統(tǒng)引流注冊(cè),如果用戶(hù)此時(shí)只是注冊(cè),并不會(huì)去下載 App 登錄的話。那么,這時(shí)贈(zèng)送卡券將變得毫無(wú)意義。只會(huì)產(chǎn)生更多的垃圾數(shù)據(jù)。
那么,該如何做?
- (1)A 系統(tǒng)提供快捷注冊(cè)接口、短信發(fā)送接口、卡券發(fā)送接口。
- (2)B 系統(tǒng)制作一個(gè)注冊(cè)導(dǎo)流 H5 頁(yè)面。用戶(hù)填寫(xiě)手機(jī)號(hào),獲取驗(yàn)證碼,輸入驗(yàn)證碼點(diǎn)擊,點(diǎn)擊提交調(diào)用 A 系統(tǒng)快捷注冊(cè)接口實(shí)現(xiàn)注冊(cè)用戶(hù)。
- (3)B 系統(tǒng)調(diào)用 A 系統(tǒng)的注冊(cè)接口成功之后,在自己的系統(tǒng)存儲(chǔ)手機(jī)號(hào)、用戶(hù)ID、注冊(cè)時(shí)間、導(dǎo)流 H5 的頁(yè)面唯一標(biāo)識(shí)(自己定一個(gè))。
- (4)A 系統(tǒng)在系統(tǒng)當(dāng)中實(shí)現(xiàn)一系列事件(登錄、注冊(cè)、下單、充值、提現(xiàn))。并且寫(xiě)入隊(duì)列。然后,把這些事件實(shí)時(shí)推送給 B 系統(tǒng)。
- (5)B 系統(tǒng)收到這些事件之后,根據(jù)自己是否有建立在這些事件上的后續(xù)功能。比如,我們這個(gè)導(dǎo)流功能,就需要導(dǎo)流注冊(cè)成功之后,用戶(hù)首次登錄的時(shí)候贈(zèng)送 10 元卡券。
上面的 (1)、(2)、(3)、(4)都很好實(shí)現(xiàn)。其中,第(4)步主要是為了實(shí)現(xiàn)系統(tǒng)解耦。并且這也是目前比較常用的方案。我們今天要講的是怎樣通過(guò)流水號(hào)來(lái)解決第(5)步的問(wèn)題。
那么第(5)步會(huì)有什么問(wèn)題?
比如,現(xiàn)在 B 系統(tǒng)收到了導(dǎo)流的用戶(hù)成功首次登錄的事件推送了。結(jié)果,去調(diào)用 A 系統(tǒng)提供的發(fā)送卡券功能贈(zèng)送 10 元卡券。結(jié)果,調(diào)用卡券發(fā)送失敗了。于是,準(zhǔn)備在程序里面實(shí)現(xiàn)一個(gè)功能:失敗之后重發(fā)。最后成功了。但是,真的成功了嗎?
我們來(lái)分析一下??ㄈl(fā)送失敗的可能原因:
- 請(qǐng)求被 A 系統(tǒng)正確接收。但是,由于網(wǎng)絡(luò)原因 B 系統(tǒng)中斷了。
- 請(qǐng)求沒(méi)有被 A 系統(tǒng)接收。
- 請(qǐng)求被 A 系統(tǒng)正確接收,也正確發(fā)送了卡券。但是, A 系統(tǒng)故障了。
- 請(qǐng)求被 A 系統(tǒng)正確接收,也正確發(fā)送了卡券。B 系統(tǒng)自己故障了。
當(dāng)然,情況不止上面這幾種,還有其他原因。不管何種原因,當(dāng)我們要重發(fā)的時(shí)候,問(wèn)題就來(lái)了:會(huì)導(dǎo)致卡券發(fā)送多次。
這時(shí)候我們可以利用流水號(hào)的特性。每次導(dǎo)流注冊(cè)成功之后,給每條入庫(kù)的記錄一個(gè)唯一的流水號(hào)。流水號(hào)一定要保證它的唯一性。該流水號(hào)在 A 系統(tǒng)當(dāng)中的發(fā)送卡券接口也要實(shí)現(xiàn)防重發(fā)的功能。
怎樣在 A 系統(tǒng)當(dāng)中的發(fā)送卡券接口防重復(fù)呢?
很簡(jiǎn)單。我們正確接收到 B 系統(tǒng)的請(qǐng)求之后,以此流水號(hào)寫(xiě)入緩存。然后,接著處理卡券發(fā)送的業(yè)務(wù)。當(dāng)?shù)诙瓮瑯拥恼?qǐng)求發(fā)送過(guò)來(lái)的時(shí)候,檢查這個(gè)流水號(hào)是否在我們的緩存當(dāng)中,如果存在立即查詢(xún)發(fā)送的狀態(tài)。并返回發(fā)送的結(jié)果。
這樣 A 系統(tǒng)不管因?yàn)楹畏N原因?qū)е掳l(fā)送失敗,重發(fā)的時(shí)候都不會(huì)導(dǎo)致福利卡券發(fā)送失敗。
當(dāng)然,A 系統(tǒng)也有可能會(huì)發(fā)送失敗。這時(shí)我們可以找到發(fā)送失敗的原因修復(fù)代碼。然后, B 系統(tǒng)重新處理就好了。
以上只是一個(gè)理論分析。沒(méi)有給出具體的 PHP代碼示例。在我司的金融產(chǎn)品當(dāng)中,我們就用該思想理論,實(shí)現(xiàn)了諸如此類(lèi)的重發(fā)問(wèn)題。