基於中臺思想的物流系統設計(三):構建物流地址能力

銀河1號發表於2018-11-11

一、引言

在電商物流領域我們會涉及到地址,其中包括了基礎的四級地址和使用者填寫的地址。四級地址在整個從下單到收貨的業務流程中都會用到,因此設計的時候要考慮如何最大限度地提高QPS。使用者地址在下單的時候讓使用者填寫或者選擇,然後存在交易訂單和物流訂單上,後續的流程一般不會變,如果使用者需要修改地址,直接變更交易訂單和物流訂單的地址資訊即可,因此設計的時候主要考慮滿足各種使用者地址場景。

二、物流地址資料模型設計

基於中臺思想的物流系統設計(三):構建物流地址能力

1、dvc_division表

描述:四級地址表
表結構:
欄位名稱
欄位型別
是否可以為空
描述
id
bigint
主鍵
name
varchar(128)
名稱
code
varchar(32)
編碼
level
int
層級:1、2、3、4
parent_code
varchar(32)
上級地址code
country
varchar(16)
預設CN
language
varchar(16)
預設ZH_CN
status
int
1正常,2廢棄
post_code
varchar(16)
郵編
longititude
varchar(32)
經度
latitude
varchar(32)
維度
version
int
版本號
feature
varchar(1024)
擴充套件欄位
gmt_created
datetime
建立時間
gmt_modified
datetime
修改時間
上面的表結構以一種一維的角度描述了四級地址,可能不太直觀,下面用一個例子來說明四級地址是怎麼組織的:

基於中臺思想的物流系統設計(三):構建物流地址能力

四級地址第一級:
省份編碼兩位,從1開始到34代表34個省級行政區(23省+4直轄市+5自治區+2特別行政區),以浙江為例為8
四級地址第二級:
城市編碼兩位,從01開始遞增,省份+城市構成二級地址,以杭州為例就是801
四級地址第三級:
區域編碼兩位,從01開始遞增,省份+城市+區域構成三級地址,以杭州西湖區為例就是80103
四級地址第四級:
街道編碼兩位,從01開始遞增,省份+城市+區域+街道構成四級地址,以浙江省杭州市西湖區古蕩街道為例就是8010301
上面的每一級地址都通過parent_code關聯上一級地址,因此只要知道任意一級地址,都可以把整個四級地址都查出來。

2、user_address表

描述:使用者地址表
表結構
欄位名稱
欄位型別
是否可以為空
描述
id
bigint
主鍵
user_id
bigint
使用者ID
user_name
varcahr(64)
使用者名稱稱
shop_id
bigint
店鋪ID
user_type
int
使用者型別:1買家,2賣家
telephone
varchar(16)
手機號
phone
varchar(16)
座機號
country
varchar(16)
國家,預設CN
province
varchar(16)
省份名稱
province_code
varchar(32)
省份code
city
varchar(32)
城市名稱
city_code
varchar(32)
城市code
area
varchar(32)
地區名稱
area_code
varchar(32)
地區code
street
varchar(32)
街道名稱
street_code
varchar(32)
街道code
detail_address
varchar(1024)
詳細地址
address_code
varchar(32)
最小code
is_default
int
是否預設,1預設,2非預設
language
varchar(16)
語言,預設ZH_CN
post_code
varchar(16)
郵編
version
int
版本號
feature
varchar(1024)
擴充套件欄位
gmt_created
datetime
建立時間
gmt_modified
datetime
修改時間
索引:
user_id普通索引


三、四級地址庫高併發設計

四級地址庫的使用場景是查詢非常多,修改和建立幾乎沒有,因此我們首先想到的是使用快取。對於快取,有基於redis的集中式快取,也有基於JVM的本地快取,考慮到四級地址庫的使用場景,基於redis的集中式快取在後期不一定能支撐巨大的查詢量,因此我們從一開始就選擇基於JVM的本地快取,下面是對本地快取的技術選型:

1、基於Guava Cache+定時任務

基於中臺思想的物流系統設計(三):構建物流地址能力

該策略使用guava cache做本地快取,由於guava cache本質上是KV資料,因此針對不同的查詢場景,需要構建不同的快取,然後通過elastic-job定時(比如每天凌晨)將資料庫資料重新整理到快取。這種策略編碼實現比較簡單,但是無法適應複雜場景的查詢,而且隨著查詢場景的增多,記憶體資料會越來越大。

2、基於H2記憶體資料庫

基於中臺思想的物流系統設計(三):構建物流地址能力

該策略基於H2記憶體資料庫+Mybatis實現了複雜查詢場景,同時又保證了效能。但是,由於H2資料庫的資料是在啟動的時候從檔案載入的,執行期無法變更,因此,每次地址庫更新,都需要更新啟動時的資料檔案。

3、最終決策

考慮到四級地址資料一年也更新不了幾次,我們最終選擇了方案二:基於H2記憶體資料庫的快取。我們把H2資料檔案、H2資料庫SQL、Mybatis介面都封裝在了一個client中打包出去,外部系統直接依賴這個client包就可以獲得四級地址庫的能力。當地址庫資料更新,我們會重新打包client,其他應用只要升級這個client包就可以獲得最新的四級地址資料。

四、基於經緯度的使用者地址查詢

使用者在下單的時候,需要填寫收貨地址,普通的填寫方式通過四級地址一級一級往下填,使用者體驗比較繁瑣。為了提升使用者體驗,我們可以根據使用者的經緯度直接匹配出四級地址。
我們使用Redis GEO API進行地址與經緯度的對映,整體架構如下:

基於中臺思想的物流系統設計(三):構建物流地址能力

我們首先將使用者地址經緯度對映到四級地址code中,存入redis,前端應用根經緯度從redis獲取四級地址code,然後根據code查詢四級地址詳細資訊。由於資料儲存在redis,為了防止快取被逐出或者redis被重啟,每天凌晨使用定時任務重新整理redis的資料。
我們使用redis geo API主要使用兩個命令:
1.GEOADD
命令:GEOADD key longitude latitude member [longitude latitude member ...]
命令描述:將指定的地理空間位置(緯度、經度、名稱)新增到指定的key中。
返回值:新增到sorted set元素的數目,但不包括已更新score的元素。

2.GEORADIUS
命令:GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
命令描述:
以給定的經緯度為中心, 返回鍵包含的位置元素當中, 與中心的距離不超過給定最大距離的所有位置元素。
範圍可以使用以下其中一個單位:
  • m 表示單位為米。
  • km 表示單位為千米。
  • mi 表示單位為英里。
  • ft 表示單位為英尺。

五、總結

通過上面的介紹,我們基本介紹完了一個物流地址系統的關鍵技術要點,接下來的一篇文章會把物流詳情和物流服務的能力一併介紹,然後進入我們的重頭戲:如何構建一個具有良好擴充套件性的物流產品服務層。

更多文章歡迎訪問 http://www.apexyun.com/


聯絡郵箱:public@space-explore.com

(未經同意,請勿轉載)


相關文章