閱讀216 返回首頁    go 阿裏雲 go 技術社區[雲棲]


如何高效存儲GPS數據

最近幾年,移動設備已經非常普及,對GPS的使用也越來越常見,比如快車專車產品中的實時位置和曆史軌跡圖,運動App中的跑步,騎行軌跡等,很多研發人都遇到了如何設計係統架構來高效存儲和查詢GPS數據的問題。
21f63d1be4d082dd615abed82eaea110

對於一個互聯網產品,要麵對大流量,突發大壓力,要保證低延時,高穩定性,還要考慮以後的實時擴展性,作為負責人的話,還需要考慮成本。這樣,設計一個滿足這些需求的係統就不怎麼簡單了。

在這篇文章中,我們將通過設計一個運動類App的GPS功能來說明多種架構及其區別。

產品功能

我們先明確這款騎行產品需要具備的基礎功能:

  1. 用戶騎行過程中,App記錄GPS軌跡
  2. 用戶在騎行過程中可以在手機App中看到自己當前的位置,曆史騎行軌跡以及最大時速,平均時速,騎行時間等統計值
  3. 用戶在騎行完成後,可以查看自己曆史的騎行記錄
  4. 給好友、家人或戀人實時共享當前軌跡
  5. 運營需要分析用戶軌跡某個維度的特征

存儲係統

首先,我們來看一下此類產品的特點:

  1. 用戶數大,比較有名的產品可能會有百萬,甚至更多的用戶。
  2. 有明確的高峰低穀,比如早晨,傍晚是高峰期,淩晨是低峰期。
  3. 存儲的數據量比較大,數據量和場景,用戶量極度相關。
  4. 產品可能會有爆發發展期,係統需要有非常快速的擴展能力。
  5. 跟時間相關,需要按時間查詢範圍,或者需要在不知道起始時間和結束時間情況下查詢軌跡點。
  6. 成本低。
  7. 穩定性高,尤其是寫。

總結下就是:

  1. 支持高並發寫入,尤其是寫:百萬,甚至千萬TPS。
  2. 按量付費。
  3. 單表大容量存儲,最好不限表大小:PB級別。
  4. 實時水平擴展能力。
  5. 支持範圍查詢。
  6. 低成本。
  7. 高穩定性:SLA保障。

表格存儲(Tablestore)是由阿裏雲自主研發的基於共享存儲的NoSQL數據庫,是一款專為大數據而設計的存儲係統,10G以下免費。表格存儲可以完全滿足上述所有要求,另外,還提供多版本,TTL遞增ID,增量通道等功能。
確定了存儲係統後,我們再來看方案。

方案

gps_4

表結構設計

表格存儲最多支持四個主鍵,每個主鍵都支持三種類型,字符串,二進製和長整型,屬性列是schema free的,可以自由修改。

在當前方案中,表格存儲的表格可以這麼設計:

主鍵順序 名稱 類型 備注
1 partition_key string md5(user_id)前四位 為了負載均衡
2 user_id string/int 用戶id 可以是字符串也可以是長整型數字
3 task_id string/int 此次軌跡圖的id 可以使字符串也可以是長整型數字
4 timestamp int 時間戳 使用長整型,64位,足夠保存毫秒級別的時間戳

GPS軌跡存儲

  • 關鍵點:
    • 使用表格的形式保存用戶騎行過程中的meta數據
  • 手機端:
    • 用戶啟動後,手機每隔5秒鍾,發送一條數據給應用服務器,這條消息包括當前GPS數據和meta值(經度,緯度,速度,距離等)
  • 服務器端
    • 應用服務器收到客戶端發送的消息後,先對其中的GPS數據做糾正,然後將消息保存到表格存儲中的GPS軌跡表中,主鍵保存用戶id,任務id,時間戳,屬性列保存經度,緯度,耗費時間,距離等。某一個時刻的數據保存在一行中。
    • 【補充】用戶數據發送給用戶的應用服務器後,應用服務器可以先做數據訂正,訂正好後再寫到表格存儲,但是有時候需要考慮到寫流程是關鍵路徑,清洗訂正是非關鍵路徑,需要寫入和訂正流程是異步流程,這時候可以直接使用表格存儲Stream功能。數據直接寫表格存儲,然後用戶應用服務器通過表格存儲stream功能實時讀取到新增數據,訂正、清洗等完成後將結果寫回表格存儲,因為表格存儲會在stream中保存12小時,所以,就算訂正清洗功能短時間不可用,也不影響用戶的使用。

GPS軌跡查詢

  • 通過表格存儲GetRange接口可以查詢到完整曆史軌跡圖。
  • 手機端:
    • 當要查詢自己這次騎行的曆史軌跡和當前位置時,隻需要通過一個範圍查詢(GetRange)就可以查到此次騎行的位置軌跡圖。也就是查詢這次任務從最早時間到當前時間內的GPS數據,對應於範圍查詢,首次查詢時起始鍵可以是(md5(user_id).sub(0,4), user_id, task_id, MIN),結束鍵是(md5(user_id).sub(0,4), user_id, task_id, NOW),首次查詢完後可以將NOW值保存下來,下次查詢的時候起始鍵就可以是上一次查詢的結束鍵,一直到此次騎行結束。
  • 服務器端
    • 接收到手機端的查詢請求後,將其轉換成表格存儲的範圍查詢(GetRange),就可以查詢到此次騎行的曆史軌跡圖。
    • 對於之前的曆史軌跡圖,也可以使用範圍查詢獲取到曆史軌跡。

其他人的GPS軌跡查詢

  • 關鍵點:
    • 讀擴散:自己的GPS軌跡數據隻保存在自己的user id下,其他用戶過來讀取。
    • 新表:shard_gps_table,記錄分享的user id,task id等信息。
    • 加密:對於分享過程中設計的ID等值加密,防止惡意用戶冒充。
  • 手機端:
    • A用戶啟動後,可以分享當前騎行給自己的朋友B,也就是隻需要把A的user_id和此次的task_id分享給朋友B。
    • 朋友B的客戶端獲取到用戶A的user_id和task_id後,就可以使用範圍查詢獲取用戶A在此次騎行中的實時位置和軌跡圖了。
  • 服務器端:
    • 如果是分享者A通過二維碼,鏈接等分享給用戶B,這時候用戶B的手機端可以獲取到用戶A的user id和此次task id(可以使用加密,防止被人篡改id),用戶B可以去服務器端獲取這次的用戶A的騎行實時軌跡圖。通過這種方式的分享記錄可以持久化到表shard_gps_table中,也可以不持久化。
    • 在App內部用戶A分享給用戶B,用戶A將分享記錄發送給服務器後,服務器記錄在shard_gps_table表中,然後給用戶B發送一個通知,包含一個特殊的ID值(可以是用戶A的user id和task id加密後的一個值,這個值不能允許反向解析出user id和task id)。
    • 用戶B收到通知後,通過這個特殊的ID值到服務器端來查看表shard_gps_table中是否有對應的分享記錄,如果有,則將對應的用戶A的user id和task id發送給用戶B,用戶B再通過這些來讀取用戶A的軌跡圖。

組團GPS軌跡查詢

有時候,用戶會組團去騎行,這時候,團員都希望可以在一張地圖裏麵看到大家所有人的實時位置和曆史軌跡圖,團長也希望能通過這些值作為參考,安排大家休息地點和時間。對於這種場景,可以按下麵方式實現:

  • 關鍵點:
    • 所有團員都使用同一個任務ID
    • 讀擴散(寫的時候寫到自己的user id下麵,讀的時候讀其他成員的同任務id的數據)
    • 使用新表:group_user_table,記錄每個組的當前用戶和曆史用戶(使用表格存儲多版本功能可以保存用戶的多次加入和離開時間)
  • 手機端:
    • 團長發起隊伍,創建一個task id,其他成員加入,獲取task id
    • 每個成員騎行過程中,將自己的gps軌跡數據記錄在自己的數據中(前兩個主鍵為:user_id, task_id)
    • 如果有成員先退出,後加入,仍然使用同task id,前後兩段gps軌跡仍然有關聯。
  • 服務器端:
    • 使用新表(group_user_table)記錄每個task id下對應的成員id。這裏可以使用多版本記錄成員的多次退出加入事件。
    • 查看整個隊伍gps軌跡時,先通過task id查看所有成員ID,然後使用表格存儲的BatchGetRow或者GetRange獲取所有成員的軌跡數據。

團員異常路線報警

組團騎行或者組織的大型比賽中,有可能某些成員掉隊或者騎錯路線,這時候就需要讓組織者知道,使用表格存儲的stream功能就可以很容易對於異常騎行者做出報警。

  • 關鍵點:
    • 使用表格存儲的stream功能【即將在五月份上線】
    • 讀擴散:App中有可能會搞全國運動,這樣同時參加用戶可能數十萬或者百萬,這時候讀擴散的優勢就比較明顯了。
  • 服務器端:
    • 每個組員的GPS軌跡數據發給表格存儲後,表格存儲會持久化數據後,然後新數據和更新數據會實時進入stream通道,用戶可以實時或者周期性的使用SDK提供的接口讀取到這些新進來的GPS數據,然後在自己的應用服務器中計算這些GPS數據和安全區域做比較,如果出了安全區域或者掉隊太遠,發送一條報警短信給組織者或者組織機構。這裏可以使用阿裏雲存儲團隊的消息服務(MNS)。
  • 手機端:
    • 組織者收到團員掉隊或者走出安全區域的報警後,可以立即查看這名成員的曆史軌跡和當前位置,然後安排人員聯係異常團員,防止危險事件發生。

粉絲圍觀大V騎行

有社區後就有可能會有大V,大V可以在App中搞騎行直播,旁邊可以展示GPS軌跡,幾十萬,甚至幾百萬粉絲圍觀,打賞等

  • 關鍵點:
    • 讀擴散:這時候就隻能使用讀擴散了。由於前麵的功能都使用了讀擴散,那這裏處理就非常簡單。
  • 手機端:
  • 服務器端:
    • 和前麵處理邏輯差不多,這裏就省略了。

運營分析

  • 全量分析:
    • SQL:使用Max Computer 2.0 (原ODPS)的SQL功能,可以直接讀取表格存儲中的數據,無需導出,節省了導出時間,更快地計算出結果。
    • 自有job:使用dataX可以全量高並發的導出到Max Computer中去做分析處理,處理完後繼續可以用dataX寫會表格存儲。
    • 適用於批處理方式。
  • 增量分析:
    • 使用表格存儲的stream功能可以獲取最近十二小時的用戶新增,更新,刪除事件涉及的數據,即可以獲取到數據的實時變化情況後做分析處理。
    • 適用於實時處理方式。

直寫方案

上述方案已經可以完全滿足高並發,低延遲的需求了,那麼這個技術架構是否是還可以繼續優化呢?當然是可以。上述方案中,手機App其實可以直接將數據存儲到表格存儲,不需要經過應用服務器中轉,減少對應用服務器的壓力。

使用STS架構

上述5個步驟分別是:

  1. 用戶啟動後,手機向應用服務器請求寫表格存儲的寫權限。
  2. 應用服務器審批後,如果認為可以給予這個用戶寫權限,那麼可以繼續向阿裏雲的STS服務申請表格存儲的臨時寫權限和授權時間。
  3. STS服務接收到請求後,生成一個臨時的令牌,包括臨時AccessKeyId,臨時AccessKeySecret和臨時token,將其返回給應用服務器。
  4. 應用服務器接收到STS的結果後,將其返回給手機端的APP。
  5. 手機端的App接收到臨時令牌後,可以向表格存儲開始寫數據。等過了一段時間後,臨時令牌會失效,如果到時候還需要寫入,可以繼續申請新的令牌。

總結

前麵講了下如何用表格存儲(Tablestore)存儲各種場景GPS數據,以及stream功能在各個重要場景中的使用。雖然講了很多點,但是由於篇幅問題,每個部分都還比較簡單,如果大家有興趣,針對上述的每個點後續都可以繼續展開再詳細講講。

最後更新:2017-04-25 21:31:24

  上一篇:go 4月24日雲棲精選夜讀:噓,別聲張!阿裏研究員的書單被我“偷”來了
  下一篇:go 笛卡爾積