發(fā)布時(shí)間:2023-03-20 18:12:00
通過(guò)閱讀本文,您將了解到一個(gè)售后系統(tǒng)應(yīng)該具備的一些能力、在整個(gè)上下游系統(tǒng)中的定位、基本的系統(tǒng)架構(gòu),以及針對(duì)售后業(yè)務(wù)場(chǎng)景中常見(jiàn)問(wèn)題的解決方案。
一、核心價(jià)值
京東到家售后系統(tǒng)作為逆向流,強(qiáng)依賴京東到家業(yè)務(wù)域,目前涵蓋了:退款、退貨、換貨、維修等四大類場(chǎng)景,并且為用戶與商家提供申訴、仲裁場(chǎng)景支持,為計(jì)費(fèi)與結(jié)算系統(tǒng)提供逆向金額數(shù)據(jù)支持。
售后系統(tǒng)業(yè)務(wù)結(jié)構(gòu):
售后系統(tǒng)上下游依賴:
二、系統(tǒng)架構(gòu)
售后系統(tǒng)使用的就是基礎(chǔ)的三層架構(gòu)。應(yīng)用層有不同身份的三個(gè)端入口,服務(wù)層提供了一些業(yè)務(wù)支持和數(shù)據(jù)支持,數(shù)據(jù)層目前使用到了MySQL和Redis以及ElasticSearch。當(dāng)然還有一些中間件使用,比如rpc框架,zk配置中心,worker分布式定時(shí)任務(wù),jmq消息。還有完善的基礎(chǔ)設(shè)施,統(tǒng)一監(jiān)控和日志采集。
三、業(yè)務(wù)形態(tài)
當(dāng)正向訂單履約完成后,如訂單中商品有缺件、錯(cuò)件、質(zhì)量等問(wèn)題可以發(fā)起售后申請(qǐng)。目前申請(qǐng)售后支持用戶端、商家端、到家客服發(fā)起。用戶端申請(qǐng)需要根據(jù)不同責(zé)任方分配到商家或者客服審核。商家端只能選擇商家責(zé)任原因申請(qǐng)售后,然后自動(dòng)審核通過(guò)??头脩羯暾?qǐng)售后和用戶端一致,流轉(zhuǎn)到商家或客服審核。
用戶端申請(qǐng)售后流程:
1. 申請(qǐng)售后
1)多端操作并發(fā)場(chǎng)景下問(wèn)題
2)售后商品拆分信息如何獲取
在正向訂單履約完成后一定的時(shí)效內(nèi),可以通過(guò)用戶端,商家端,運(yùn)營(yíng)端基于訂單中商品選擇性申請(qǐng)售后。當(dāng)接收到一個(gè)售后單提交申請(qǐng),售后這邊會(huì)依賴訂單數(shù)據(jù),拆分?jǐn)?shù)據(jù)來(lái)構(gòu)建售后單詳情數(shù)據(jù)。那么對(duì)于多端申請(qǐng)售后入口,我們?cè)趺茨鼙WC訂單中商品不會(huì)被重復(fù)申請(qǐng)呢?申請(qǐng)時(shí)我們使用了redis分布式鎖。
售后申請(qǐng)場(chǎng)景下分布式鎖需要注意點(diǎn):
?、俨煌娜肟谑褂孟嗤膋ey,這里我們通過(guò)前綴加訂單號(hào)來(lái)區(qū)分,來(lái)保證對(duì)同一訂單加鎖。
?、诩尤脒^(guò)期時(shí)間,比如第一個(gè)申請(qǐng)獲取到鎖,如果釋放鎖異常,這里只需要等到超時(shí)時(shí)間自動(dòng)過(guò)期,防止死鎖。
?、鄣却i時(shí)間,同一個(gè)訂單多個(gè)入口同時(shí)申請(qǐng)售后,如果獲取不到鎖就進(jìn)入等待,直到獲取到鎖或者等待超時(shí)后退出。
④使用uuid來(lái)保證token唯一性,每次都釋放自己當(dāng)前請(qǐng)求鎖。
我們保證了同一時(shí)間只能有一個(gè)訂單下的售后能夠申請(qǐng),接下來(lái)就是組裝售后單詳情數(shù)據(jù)。一個(gè)完整的售后單數(shù)據(jù)來(lái)源于訂單詳情和拆分詳情。
通過(guò)從訂單詳情中取用戶基礎(chǔ)信息,訂單信息,商家門店信息來(lái)保存到售后單主表中。根據(jù)申請(qǐng)選擇的商品skuid從訂單商品詳情中獲取對(duì)應(yīng)商品基礎(chǔ)信息保存到售后商品表中。接下來(lái)就是比較重要的售后商品拆分信息,這個(gè)數(shù)據(jù)來(lái)源于拆分系統(tǒng)。先了解下拆分?jǐn)?shù)據(jù)結(jié)構(gòu):
可以看到,拆分系統(tǒng)會(huì)根據(jù)訂單中所有商品把金額拆分到每一件商品上,并且通過(guò)num_下標(biāo)來(lái)區(qū)分。當(dāng)選擇訂單中某個(gè)商品發(fā)起售后我們是怎么去找到這個(gè)商品對(duì)應(yīng)的拆分信息呢?
我們通過(guò)sku_promotionType(商品+促銷類型)來(lái)區(qū)分不同的商品拆分信息,然后通過(guò)記錄num商品下標(biāo)來(lái)確定找到哪一個(gè)商品。
比如下面的場(chǎng)景:
假設(shè)訂單中購(gòu)買了3個(gè)正價(jià)A商品,1個(gè)促銷A商品。
?、俚谝淮紊暾?qǐng)一個(gè)正價(jià)A售后。這時(shí)售后系統(tǒng)會(huì)記錄一個(gè)售后單,對(duì)應(yīng)售后詳情為商品A。從拆分獲取sku_A_正價(jià)_num0信息并記錄到售后商品拆分詳情表。
?、谠偕暾?qǐng)一個(gè)正價(jià)A和一個(gè)促銷A售后。這里售后會(huì)發(fā)現(xiàn)此訂單已申請(qǐng)過(guò)一個(gè)正價(jià)A,記錄的是sku_A_正價(jià)_num0。這時(shí)就會(huì)去取拆分的 sku_A_正價(jià)_num1這條數(shù)據(jù)。
?、鄣诙紊暾?qǐng)售后對(duì)應(yīng)一個(gè)新售后單,商品詳情記錄為sku_A_正價(jià),sku_A_促銷。商品拆分記錄數(shù)據(jù)為:sku_A_正價(jià)_num1,sku_A_促銷_num0。
初步了解了售后商品獲取對(duì)應(yīng)拆分?jǐn)?shù)據(jù)的邏輯,這時(shí)如果同一個(gè)訂單中購(gòu)買了相同促銷的A商品,但是價(jià)格不一樣怎么辦呢?按照上面獲取邏輯,獲取的售后商品金額就會(huì)出現(xiàn)多退或者少退情況。
比如下面的捆綁促銷:
A+B捆綁銷售,A金額3元。A+C捆綁銷售,此時(shí)A金額2元。這時(shí)拆分的數(shù)據(jù)結(jié)構(gòu)為:sku_A_捆綁_num0價(jià)格3元,sku_A_捆綁_num0價(jià)格2元。此時(shí)如果兩個(gè)A都申請(qǐng)了售后,我們?cè)侔凑誷ku_promotionType去獲取拆分那么永遠(yuǎn)獲取的都是第一個(gè)的金額。因此針對(duì)這種特殊的促銷場(chǎng)景,我們?cè)谠蝎@取拆分維度基礎(chǔ)上又增加了一個(gè)價(jià)格。
區(qū)分維度:sku_promotionType_price(商品+促銷類型+價(jià)格)
上面的方案可以滿足各種不同促銷場(chǎng)景的售后,但是針對(duì)稱重退差訂單申請(qǐng)售后還會(huì)適用么?
稱重退差訂單含義:當(dāng)正向訂單揀貨時(shí),商家發(fā)現(xiàn)實(shí)際揀貨的稱重品和售賣規(guī)格有誤差,此時(shí)可以發(fā)起退差單把差額的錢退給用戶。之后訂單正常履約,訂單完成后用戶也可以申請(qǐng)售后。此時(shí)再申請(qǐng)售后退給用戶的錢就應(yīng)該是減去退差后的部分。
比如下面的場(chǎng)景:
假設(shè)一個(gè)訂單中買了2個(gè)原價(jià)A+1個(gè)促銷價(jià)A,原價(jià)3元,促銷價(jià)2元,整單共8元。揀貨時(shí)發(fā)現(xiàn)A商品實(shí)際重量比標(biāo)重少,退差1元,此時(shí)退差單中會(huì)記錄商品A退差金額,退差重量。這時(shí)選擇正價(jià)A發(fā)起售后申請(qǐng),售后系統(tǒng)就需要根據(jù)實(shí)際重量獲取退差商品金額,然后計(jì)算實(shí)際退款金額。這時(shí)我們又在原來(lái)的基礎(chǔ)上增加了一個(gè)重量維度。
sku_promotionType_price_weight(商品+促銷類型+價(jià)格+重量)
系統(tǒng)都是為了業(yè)務(wù)來(lái)服務(wù)的,隨著業(yè)務(wù)變更場(chǎng)景的增多,我們的架構(gòu)也在演變。目前所有的計(jì)算拆分邏輯都封裝成統(tǒng)一方法,統(tǒng)一入口,未來(lái)再增加不同促銷,或者其他業(yè)務(wù)都可以很友好的支持。
2. 審核售后
1)多條件復(fù)雜查詢性能問(wèn)題
當(dāng)售后單申請(qǐng)成功后,會(huì)根據(jù)審核方分配給商家或者客服審核。這里涉及到兩個(gè)列表查詢,一個(gè)是運(yùn)營(yíng)端客服使用,一個(gè)是商家端根據(jù)商家賬號(hào)權(quán)限來(lái)展示可操作的售后單列表。最初我們的售后單表數(shù)據(jù)并不是很大,隨著業(yè)務(wù)品類擴(kuò)增以及用戶量的增加遇到了一些問(wèn)題。
?、贁?shù)據(jù)庫(kù)頻繁報(bào)警,慢SQL,影響其他業(yè)務(wù)
?、谏碳疫\(yùn)營(yíng)反饋售后單列表查詢過(guò)慢,影響審核效率。
通過(guò)分析慢SQL日志,我們根據(jù)查詢字段增加索引來(lái)提高查詢速率。由于支持各種查詢場(chǎng)景過(guò)多,目前主表中已經(jīng)建立了20多個(gè)索引。而且基于業(yè)務(wù)的發(fā)展需要支持查詢的時(shí)間區(qū)間也會(huì)更長(zhǎng)。主表的數(shù)據(jù)量一直在增長(zhǎng),還是會(huì)遇到查詢性能問(wèn)題,過(guò)多的索引對(duì)于售后單流程中變化更新也有一定的影響。
因?yàn)镋S是基于倒排索引實(shí)現(xiàn)的搜索,配合分詞器在文本模糊搜索上表現(xiàn)比較好,使用的業(yè)務(wù)場(chǎng)景廣泛,因此我們考慮把售后單數(shù)據(jù)同步到ES中,列表查詢走ES。
基于我們目的是為了解決查詢問(wèn)題,每次操作業(yè)務(wù)都會(huì)根據(jù)主鍵再查詢一次mysql庫(kù)詳情,數(shù)據(jù)遷移同步方案如下:
?、俅媪繑?shù)據(jù)如何同步?
首先增加一個(gè)開(kāi)關(guān)來(lái)控制操作是走mysql還是es。先關(guān)閉開(kāi)關(guān)然后通過(guò)批量同步接口,根據(jù)主鍵id范圍區(qū)間查詢把存量數(shù)據(jù)分批同步到ES中。打開(kāi)開(kāi)關(guān),這時(shí)如果有新的售后單數(shù)據(jù),通過(guò)MQ異步同步到ES中,同時(shí)把開(kāi)關(guān)打開(kāi)前產(chǎn)生的一部分?jǐn)?shù)據(jù)同步到ES中。最后再通過(guò)count總數(shù)校驗(yàn)下數(shù)據(jù)是否全部同步。
?、谌绾伪WC數(shù)據(jù)同步一致性?
涉及到同步數(shù)據(jù),難免就會(huì)有數(shù)據(jù)不一致問(wèn)題。從售后單申請(qǐng)到售后單狀態(tài)變更,提交事務(wù)后每個(gè)節(jié)點(diǎn)都會(huì)發(fā)送一個(gè)需要同步的MQ消息。接收到消息后通過(guò)主鍵id查詢mysql獲取售后單詳情。然后全量字段同步到ES中。這樣不管先消費(fèi)哪個(gè)節(jié)點(diǎn)的MQ,同步的數(shù)據(jù)都是實(shí)時(shí)查詢的數(shù)據(jù)庫(kù),以此來(lái)保證每次同步的數(shù)據(jù)都是當(dāng)時(shí)最新數(shù)據(jù)。
?、蹟?shù)據(jù)延遲怎么處理?
MQ消費(fèi)有延時(shí),就有可能造成ES和mysql中數(shù)據(jù)狀態(tài)不一致問(wèn)題。我們只是為了解決查詢性能問(wèn)題,因此所有復(fù)雜查詢都是查的ES數(shù)據(jù),但當(dāng)商家或者客服操作售后單時(shí)會(huì)根據(jù)主鍵查詢mysql售后單詳情,然后執(zhí)行審核操作。針對(duì)所有的業(yè)務(wù)操作后端也增加了前置狀態(tài)校驗(yàn),來(lái)屏蔽這種數(shù)據(jù)延時(shí)帶來(lái)的問(wèn)題。
沒(méi)有最好的方案,只有最適用自己業(yè)務(wù)的方案。當(dāng)然現(xiàn)在也有一些工具類插件可以支持不同的同步方案,比如cancel基于binlog的同步以及CloudCanal。我們的目的是為了解決查詢效率問(wèn)題,因此選擇了上面的同步方案。
3. 售后退貨
1)合單召喚物流配送方案
退貨退款售后單,商家或平臺(tái)審核通過(guò)后,需要退回訂單中貨物。這里就需要與達(dá)達(dá)交互,召喚配送員走逆向取件流程。在創(chuàng)建運(yùn)單召喚達(dá)達(dá)配送前售后這邊會(huì)有一個(gè)合單邏輯。
?、俸蠁嗡枷?/p>
訂單完成后申請(qǐng)售后可以分多次申請(qǐng),每次可以選擇不同數(shù)量的商品。如果用戶同一個(gè)訂單中商品分多次售后都申請(qǐng)為退貨,那么在售后單審核通過(guò)后這些售后的商品都需要配送員送回商家。這里為了提升用戶多次退貨體驗(yàn),也同時(shí)為了節(jié)約配送成本。因此就需要有一個(gè)合單邏輯,同一訂單下的售后單退貨只需召喚一次物流配送即可。
?、诤蠁芜壿?/p>
合單worker定時(shí)掃描待召喚物流的售后單,當(dāng)?shù)竭_(dá)用戶預(yù)計(jì)取件開(kāi)始時(shí)間前10分鐘就會(huì)觸發(fā)需要合單的任務(wù)。合單任務(wù)會(huì)根據(jù)訂單號(hào)獲取此訂單下所有需合單的售后單,然后獲取預(yù)計(jì)取件開(kāi)始時(shí)間最近的售后單。依據(jù)最近上門取件開(kāi)始時(shí)間來(lái)創(chuàng)建物流運(yùn)單。
?、蹌?chuàng)建運(yùn)單
創(chuàng)建運(yùn)單前需要前置狀態(tài)校驗(yàn),只處理待退貨售后單。然后組裝訂單下用戶基本信息,需要合單的所有售后單商品信息以及累計(jì)重量,創(chuàng)建運(yùn)單。運(yùn)單接口根據(jù)訂單號(hào)做冪等處理,重復(fù)調(diào)用會(huì)返回相同的運(yùn)單號(hào)。
?、芙邮战Y(jié)果
通過(guò)監(jiān)聽(tīng)運(yùn)單狀態(tài)消息,來(lái)同步更新配送員信息。
?、莓惓V卦?/p>
針對(duì)合單任務(wù)失敗數(shù)據(jù),記錄失敗標(biāo)識(shí),等待下次合單worker執(zhí)行。記錄失敗次數(shù),如果超過(guò)失敗最大次數(shù),跳過(guò)合單并預(yù)警處理。避免一直合單失敗的數(shù)據(jù)影響正常合單業(yè)務(wù)數(shù)據(jù)。
4. 售后退款
1)退款準(zhǔn)確性問(wèn)題
通過(guò)上面的流程圖了解了售后單審核退款到退款結(jié)束的一個(gè)過(guò)程。那么我們都做了哪些來(lái)保證審核退款的售后單金額是正確的呢?
?、僭黾臃植际芥i
商家角色審核退款可以通過(guò)商家中心、商家端APP、系統(tǒng)對(duì)接接口。同時(shí)客服端也可以通過(guò)運(yùn)營(yíng)平臺(tái)審核退款。
因?yàn)檫@里也涉及多端操作,所以這里的鎖主要為了防止重復(fù)審核退款。
審核退款時(shí)已經(jīng)確定是售后單維度,每個(gè)售后單只能審核退款一次,所以這里的key維度是售后單維度。并且獲取不到鎖直接拋出失敗,提示業(yè)務(wù)異常。
?、趩涡猩唐泛戏ㄐ孕r?yàn)
為什么要做單行商品合法性校驗(yàn)?zāi)??可以看下下面這個(gè)場(chǎng)景:
假設(shè)當(dāng)前訂單購(gòu)買了1個(gè)A商品和2個(gè)B商品,A商品單價(jià)10元,B商品單價(jià)15元,整單金額40元。申請(qǐng)售后接口參數(shù)為:
skuList:[{"skuCount":1,"skuName":"skuA","procotionType":"1"},{"skuCount":1,"skuName":"skuA","promotionType":"1"}]
系統(tǒng)對(duì)接的商家通過(guò)到家開(kāi)放平臺(tái)發(fā)布的售后接口創(chuàng)建售后單,由于開(kāi)放平臺(tái)入口面對(duì)的是所有商家,每個(gè)商家系統(tǒng)對(duì)接能力不一樣,可以看出訂單中只買了1個(gè)A商品,但是傳了兩遍。正常我們的做法是解析入?yún)ist,然后校驗(yàn)每一行商品的合法性。查詢當(dāng)前訂單已申請(qǐng)商品個(gè)數(shù),以及訂單中總商品個(gè)數(shù),然后與當(dāng)前審核售后單商品個(gè)數(shù)做比較。但是循環(huán)比較等于比較了兩次,每次個(gè)數(shù)都是1。而且由于2個(gè)商品A總額小于訂單總額,所以即使有后面的臺(tái)賬總額校驗(yàn),還是會(huì)造成多退情況。因此這里需要根據(jù)當(dāng)前申請(qǐng)商品總數(shù)加已申請(qǐng)此商品總數(shù)與訂單中商品總數(shù)做校驗(yàn)。
?、塾唵闻_(tái)賬金額校驗(yàn)
訂單臺(tái)賬金額校驗(yàn),是最后一道校驗(yàn),校驗(yàn)的維度不同,是獲取每一項(xiàng)支付明細(xì)剩余可退金額。校驗(yàn)當(dāng)前要退售后單金額與臺(tái)賬余額比較,必須小于等于臺(tái)賬余額。
④異步退款結(jié)果
審核退款后,通過(guò)異步接收退款mq來(lái)更新退款狀態(tài)。退款成功通知下游依賴系統(tǒng)。
總結(jié)
逆向售后的業(yè)務(wù)是依賴于正向訂單的,隨著正向單不同場(chǎng)景玩法的增加,售后需要支持的場(chǎng)景也在增多,我們也在不斷的迭代進(jìn)步。在這當(dāng)中也遇到了一些需要解決和完善的問(wèn)題,比如售后系統(tǒng)沒(méi)有自己的網(wǎng)關(guān),這樣會(huì)造成業(yè)務(wù)邏輯維護(hù)多處,業(yè)務(wù)不閉環(huán)。整個(gè)售后業(yè)務(wù)中各種不同場(chǎng)景下邏輯配置都不同,我們也在規(guī)劃通過(guò)模板引擎配置做到智能化。最后也非常歡迎大家留言交流,共同進(jìn)步。
今天的分享就到這里了,想了解更多關(guān)于十大京東代運(yùn)營(yíng)公司、京東代運(yùn)營(yíng)等內(nèi)容,敬請(qǐng)關(guān)注火蝠電商官網(wǎng)。
本站部分文章及圖片來(lái)自互聯(lián)網(wǎng)及其他公眾平臺(tái),版權(quán)歸原作者,如有侵權(quán)請(qǐng)聯(lián)系qq:1248031689,我們會(huì)在第一時(shí)間刪除!
國(guó)家工信部備案/許可證號(hào):鄂ICP備15020535號(hào)-4 版權(quán)所有:武漢火蝠電子商務(wù)有限公司 網(wǎng)站地圖