1. 程式人生 > >基於中臺思想的物流系統設計(三):構建物流地址能力

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

一、引言

在電商物流領域我們會涉及到地址,其中包括了基礎的四級地址和使用者填寫的地址。四級地址在整個從下單到收貨的業務流程中都會用到,因此設計的時候要考慮如何最大限度地提高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 表示單位為英尺。

五、總結

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

聯絡郵箱:[email protected]

(未經同意,請勿轉載)