【系統設計】鄰近服務

848774de3e80f6ec361754434a03e17a.gif

在本文中,我們將設計一個鄰近服務,用來發現用戶附近的地方,比如餐館,酒店,商場等。

8d6def4c69276d35d524efa79041593d.png

? 設計要求??

從一個小明去面試的故事開始。

1b79e3249426fe01dc92bec8b8a640c3.png

面試官:你好,我想考察一下你的設計能力,如果讓你設計一個鄰近服務,用來搜索用戶附近的商家,你會怎么做?

小明:好的,用戶可以指定搜索半徑嗎?如果搜索范圍內沒有足夠的商家,系統是否支持擴大搜索范圍?

面試官:對,用戶可以根據需要修改,大概有以下幾個選項,0.5km,1km,2km,5km,10km,20km。

小明:嗯,還有其他的系統要求嗎?

面試官:另外還需要考慮的是,系統的低延遲,高可用,和可擴展性,以及數據隱私。

小明:好的,了解了。

總結一下,需要做一個鄰近服務,可以根據用戶的位置(經度和緯度)以及搜索半徑返回附近的商家,半徑可以修改。因為用戶的位置信息是敏感數據,我們可能需要遵守數據隱私保護法。

? 高層次設計??

高層次設計圖如下所示,系統包括兩部分:基于位置的服務 (location-based service)LBS 和業務(bussiness)相關的服務。

讓我們來看看系統的每個組件。

95445be3032ec0a0c2618def2b9e7518.png

負載均衡器

負載均衡器可以根據路由把流量分配給多個后端服務。

基于位置的服務 (LBS)

LBS 服務是系統的核心部分,通過位置和半徑尋找附近的商家。LBS 具有以下特點:

  • ??沒有寫請求,但是有大量的查詢

  • ? QPS 很高,尤其是在密集地區的高峰時段。

  • ??服務是無狀態的,支持水平擴展。

Business 服務

商戶創建,更新,刪除商家信息,以及用戶查看商家信息。

數據庫集群

數據庫集群可以使用主從配置,提升可用性和性能。數據首先保存到主數據庫,然后復制到從庫,主數據庫處理所有的寫入操作,多個從數據庫用于讀取操作。

接下來,我們具體討論位置服務 LBS 的實現。

? 1. 二維搜索??

這種方法簡單,有效,根據用戶的位置和搜索半徑畫一個圓,然后找到圓圈內的所有商家,如下所示。

e586ed50c06a9d7f8ab5174ac77405de.png

商家的緯度用 latitude 表示,經度用 longitude 表示。同樣的用戶的緯度和經度可以用 user_latitude 和 user_longitude 表示,半徑用 radius 表示。

上面的搜索過程可以翻譯成下面的偽 SQL 。

SELECT?business_id,?latitude,?longitude,
FROM?business
WHERE?
latitude?>=?(@user_latitude?-?radius)?AND?latitude?<?(@user_latitude?+?radius)
AND
longitude?>=?(@user_longitude?-?radius)?AND?longitude?<?(@user_longitude?+?radius)

這種方式可以實現我們的需求,但是實際上效率不高,因為我們需要掃描整個表。雖然我們可以對經緯度創建索引,效率有提升,但是并不夠,我們還需要對索引的結果計算取并集。

4ed36689ebc4605256e4f762749afc1d.png

? 2. Geohash??

我們上面說了,二維的經度和緯度做索引的效果并不明顯。而 Geohash 可以把二維的經度和緯度轉換為一維的字符串,通過算法,每增加一位就遞歸地把世界劃分為越來越小的網格,讓我們來看看它是如何實現的。

首先,把地球通過本初子午線和赤道分成四個象限,如下

092bca48c8b7bb443a3f633d49acbe69.png
  • ??緯度范圍 [-90, 0] 用 0 表示

  • ??緯度范圍 [0, 90] 用 1 表示

  • ??經度范圍 [-180, 0] 用 0 表示

  • ??經度范圍 [0, 180] 用 1 表示

然后,再把每個網格分成四個小網格。

6a9f223f0608bd2f1cc6329e897096b2.png

重復這個過程,直到網格的大小符合我們的需求,Geohash 通常使用 base32 表示。讓我們看兩個例子。

  • ???Google 總部的 Geohash(長度 為 6):

    • 1001?10110?01001?10000?11011?11010?(base32?convert)?→?9q9hvu?(base32)

  • ? Facebook 總部的 Geohash(長度 為 6):1001?10110?01001?10001?10000?10111?(base32?convert)?→?9q9jhr?(base32)

Geohash 有 12 個精度(也稱為級別), 它可以控制每個網格的大小,字符串越長,拆分的網格就越小,如下

287ec41da27c07fb910e9346e624eadf.png

實際中,按照具體的場景選擇合適的 Geohash 精度。

通過這種方式,最終把地圖分成了下面一個個小的網格,一個 Geohash 字符串就表示了一個網格,這樣查詢每個網格內的商家信息,搜索是非常高效的。

7ee5f61cec70fe3c301e9edda6651ac1.png

可能你已經發現了一些規律,上圖的每個網格中,它們都相同的前綴?wtw3。是的,Geohash 的特點是,兩個網格的相同前綴部分越長,就表示它們的位置是鄰近的。

反過來說,兩個相鄰的網格,它們的 Geohash 字符串一定是相似的嗎?

不一定,因為存在?邊界問題。當兩個網格都在邊緣時,雖然它們是相鄰的,但是 Geohash 的值從第一位就不一樣,如下圖,兩個紫色的點相鄰。

d62bb71633884d968f62a290404db1dd.png

下面是一個精度比較高的網格,有些相鄰網格的 Geohash 的值是完全不一樣的。

9524410766f499008790a24fa850864a.png

還有一個邊界問題是,對于用戶(橙色)來說,隔壁網格的商家(紫色)可能比自己網格的商家(紫色)的距離還要近,如下圖

bf0037c7208b9b6c8866f4ebb8d0ac45.png

所以,在查詢附近的商家時,不能只局限于用戶所在的網格,要擴大到用戶相鄰的4個或者9個網格,然后再計算距離,進行篩選,最終找到距離合適的商家。

另外,當在用戶在偏遠的郊區時,我們可以按照下面的方式,擴大搜索范圍,返回足夠數量的商家。

0791027bdddf1fb690746fb4608822a4.png

Geohash 的使用非常廣泛的,另外 Redis 和 MongoDB 都提供了相應的功能,可以直接使用。

? 3 . 四叉樹??

還有一種比較流行的解決方案是四叉樹,這種方法可以遞歸地把二維空間劃分為四個象限,直到每個網格的商家數量都符合要求。

如下圖,比如確保每個網格的數量不超過10,如果超過,就拆分為四個小的網格。

4f4526f4bc605ec6c0489814923464cc.png

請注意,四叉樹是一種內存數據結構,它不是數據庫解決方案。它運行在每個LBS 服務上,數據結構是在服務啟動時構建的。

637eaea0d153b1cafaf815694c2c646a.png

接下來,看一下節點都存儲了哪些信息?

內部節點

網格的左上角和右下角的坐標,以及指向 4個 子節點的指針。

葉子節點

網格的左上角和右下角的坐標,以及網格內的商家的 ID 數組。

現實世界的四叉樹示例

Yext 提供了一張圖片 ,顯示了其中一個城市構建的四叉樹。我們需要更小、更細粒度的網格用在密集區域,而更大的網格用在偏遠的郊區。

ad8035b2d0bfa4ad9aa5f987927a67cc.png

? Google S2 和 希爾伯特曲線??

Google S2 庫是這個領域的另一個重要參與者,和四叉樹類似,它是一種內存解決方案。它基于希爾伯特曲線把球體映射到一維索引。

而?希爾伯特曲線?是一種能填充滿一個平面正方形的分形曲線(空間填充曲線),由大衛·希爾伯特在1891年提出,如下

ef6a52c8e0cfcdcdd675189a577d57e9.gif

希爾伯特曲線是怎么生成的?

最簡單的一階希爾伯特曲線,先把正方形平均分成四個網格,然后從其中一個網格的正中心開始,按照方向,連接每一個網格。

3e3235d4159d2d8db5c7a295d0f45203.gif

二階的希爾伯特曲線, 每個網格都先生成一階希爾伯特曲線 , 然后把它們首尾相連。

28647084257601ded541a0becdcf38c3.gif

三階的希爾伯特曲線

da5aabf15c20ad4ba557fe583a4d00af.gif

n階的希爾伯特曲線, 實現一條線連接整個平面。

9e3a69fcf229d0ffb1760450cf2b3976.gif

同樣,希爾伯特曲線也可以填充整個三維空間。

outside_default.png

希爾伯特曲線的一個重要特點是?降維,可以把多維空間轉換成一維數組,可以通過動畫看看它是如何實現的。

7840abd296a262960b37c685dee826c9.gif

在一維空間上的搜索比在二維空間上的搜索效率高得多了。

? 多數據中心和高可用??

我們可以把 LBS 服務部署到多個區域,不同地區的用戶連接到最近的數據中心,這樣做可以提升訪問速度以及系統的高可用,并根據實際的場景,進行擴展。

babfe9f50d3ca43026c81060b0d05501.png

最終設計圖

c07eda6403619a98931c4665e649bf64.png
  1. 1. 用戶需要尋找附近 500 米的餐館。客戶端把用戶位置(經度和緯度),半徑(500m)發送給后端。

  2. 2. 負載均衡器把請求轉發給 LBS。

  3. 3. 基于用戶位置和半徑信息,LBS 找到與搜索匹配的 geohash 長度。

  4. 4. LBS 計算相鄰的 Geohash 并將它們添加到列表中。

  5. 5. 調用 Redis 服務獲取對應的商家 ID。

  6. 6. LBS 根據返回的商家列表,計算用戶和商家之間的距離,并進行排名,然后返回給客戶端。

? 總結??

在本文中,我們設計了一個鄰近服務,介紹了4種常見了實現方式,分別是二維搜索,Geohash, 四叉樹和 Google S2。它們有各自的優缺點,您可以根據實際的業務場景,選擇合適的實現。

? Reference??

https://halfrost.com/go_spatial_search/#toc-25

https://www.amazon.com/System-Design-Interview-Insiders-Guide/dp/1736049119

END

做了一個 .NET 的學習網站,內容涵蓋了分布式系統,數據結構與算法,設計模式,操作系統,計算機網絡等,以及工作推薦和面試經驗分享,歡迎來撩。

ebc7d4ecfd265afa361e842c9999466f.gif

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/285490.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/285490.shtml
英文地址,請注明出處:http://en.pswp.cn/news/285490.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[轉]Redis持久化存儲(AOF與RDB兩種模式)

Redis中數據存儲模式有2種&#xff1a;cache-only,persistence; cache-only即只做為“緩存”服務&#xff0c;不持久數據&#xff0c;數據在服務終止后將消失&#xff0c;此模式下也將不存在“數據恢復”的手段&#xff0c;是一種安全性低/效率高/容易擴展的方式&#xff1b;pe…

C語言試題112之一個數如果恰好等于它的因子之和,這個數就稱為“完數”。例如 6=1+2+3.編程 找出 1000 以內的所有完數。

?作者簡介:大家好我是碼莎拉蒂,CSDN博客專家?????? ??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 1、題目 題目:一個數如果恰好等于它的因子之和,這個數就稱為“完數”。例如 6=1+2+3.編程 找出 …

關于jstl.jar引用問題及解決方法

在前文SSM說到因為從MyEclipse換成了Eclipse。有些架包自動缺失。 造成&#xff1a;"org.apache.jasper.JasperException: This absolute uri (http://java.sun.com/jsp/jstl/core ) cannot be resolved in either web.xml or the jar files deployed with this applicati…

網絡技術基礎與計算思維實驗教程_2.3_單交換機VLAN配置實驗

2.3.1 實驗內容 2.3.2實驗目的 實驗的目的一是驗證交換機 VLAN 配置過程; 二是驗證屬于同一 VLAN的終端之間的通信過程; 三是驗證每一個 VLAN 為獨立的廣播域; 四是驗證屬于不同 VLAN的兩個終端之間不能通信; 五是驗證轉發項和 VLAN的對應關系。 2.3.3實驗原理 默認情況下,交換…

【數據庫原理及應用】經典題庫附答案(14章全)——第一章:數據庫基礎知識

【數據庫原理及應用】經典題庫附答案&#xff08;14章全&#xff09;——第一章&#xff1a;數據庫基礎知識 【數據庫原理及應用】經典題庫附答案&#xff08;14章全&#xff09;——第二章&#xff1a;關系數據庫知識 【數據庫原理及應用】經典題庫附答案&#xff08;14章全&a…

mockito mock測試框架

1.簡介 mock&#xff0c;[m?k]&#xff0c;adj. 虛擬的&#xff0c;模擬的。 如果你的代碼對另一個類或者接口有依賴&#xff0c;mock測試能夠幫你模擬這些依賴&#xff0c;從而完成測試。 使用場景&#xff1a; 類A有一個方法fun(B b)&#xff0c;它依賴于B類的一個對象。所以…

dotnet-exec 0.5.0 released

dotnet-exec 0.5.0 releasedIntrodotnet-exec 是一個 C# 程序的小工具&#xff0c;可以用來運行一些簡單的 C# 程序而無需創建項目文件&#xff0c;而且可以自定義項目的入口方法&#xff0c;支持但不限于 Main 方法Install/Updatedotnet-exec 是一個 dotnet tool&#xff0c;可…

C語言試題113之一球從 100 米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在 第 10 次落地時,共經過多少米?第 10 次反彈多高?

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:一球從 100 米高度自由落下,…

超酷的 Vim 搜索技巧

盡管目前我們已經涉及[1] Vim 的多種特性&#xff0c;但此編輯器的特性集如此龐大&#xff0c;不管我們學習多少&#xff0c;似乎仍然遠遠不足。承接我們的 Vim 教程系列&#xff0c;本文我們將討論 Vim 提供的多種搜索技術。 不過在此之前&#xff0c;請注意文中涉及到的所有…

對面的00后萌新看過來:淺析計算機編程在高等職業GIS專業中的重要性

文章目錄什么是傳說中的GIS&#xff1f;GIS必修哪些課程&#xff1f;學GIS到底何去何從&#xff1f;什么是計算機編程&#xff1f;編程在GIS中的地位如何&#xff1f;高等職業GIS如何教學&#xff1f;專科生怎樣學好GIS&#xff1f;什么是傳說中的GIS&#xff1f; GIS是“3S”之…

SQLServer Agent執行[分發清除: distribution] 無法刪除快照文件

由于之前創建的發布訂閱造成嚴重的性能壓力&#xff0c;癥狀表現為發布訂閱表查詢產生CMEMTHREAD suspend等待&#xff0c;由于開發配置每隔十分鐘會產生大量的SQLCOMMAND&#xff08;create table&#xff0c;create index大量的命令&#xff09;發布訂閱 復制監視器 有Memor…

二維碼

二維碼 QR_Code http://www.psoft.sk/product.php?id27 http://www.barcodesoft.com/zh-cn/delphi-barcode.aspx 生成二維碼 Bar_Code:TpsBarcode; Bar_Code.BarCode : www.aaa.com; procedure TForm1.Button4Click(Sender: TObject);var R: TRect;begin R.Create(700, 1,1000…

C語言試題114之猴子吃桃問題

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:猴子吃桃問題:猴子第一天摘…

.NET 7 的 JWT 配置太方便了!

微軟宣布 .NET 7 preview5 有一些較大的改進&#xff0c; 包括 JWT 身份驗證的簡化和自動配置。我安裝了 preview 5 嘗試了新的 JWT 身份配置。如果您想把現有的項目更新到 .Net 7 preview 5, 下面是一個快速更新的命令。Update all Microsoft.AspNetCore.* package references…

【數據庫原理及應用】經典題庫附答案(14章全)——第二章:關系數據庫知識

【數據庫原理及應用】經典題庫附答案&#xff08;14章全&#xff09;——第一章&#xff1a;數據庫基礎知識 【數據庫原理及應用】經典題庫附答案&#xff08;14章全&#xff09;——第二章&#xff1a;關系數據庫知識 【數據庫原理及應用】經典題庫附答案&#xff08;14章全&a…

[轉]面試官,不要再問我三次握手和四次揮手

文章目錄 1. 三次握手 1.1 為什么需要三次握手&#xff0c;兩次不行嗎&#xff1f;1.2 什么是半連接隊列&#xff1f;1.3 ISN(Initial Sequence Number)是固定的嗎&#xff1f;1.4 三次握手過程中可以攜帶數據嗎&#xff1f;1.5 SYN攻擊是什么&#xff1f;2. 四次揮手 2.1 揮手…

杭電2090

1 //這題是有多水。。。。。。。2 #include<stdio.h>3 char s[100];4 int main()5 {6 double n,price,sum0;7 while(~scanf("%s%lf%lf",s,&n,&price))8 sumn*price;9 printf("%.1lf\n",sum); 10 } 轉載于:https://www.c…

touch 修改文件時間戳,或者新建一個不存在的文件 - 副本

linux的touch命令不常用&#xff0c;一般在使用make的時候可能會用到&#xff0c;用來修改文件時間戳&#xff0c;或者新建一個不存在的文件。1&#xff0e;命令格式&#xff1a;touch [選項]... 文件...2&#xff0e;命令參數&#xff1a;-a 或--timeatime或--timeaccess或-…

C語言試題115之兩個乒乓球隊進行比賽,各出三人。甲隊為 a,b,c 三人,乙隊為 x,y,z 三人。已抽簽決定 比賽名單。有人向隊員打聽比賽的名單。a 說他不和 x 比,c 說他不和 x,z 比,請

?作者簡介:大家好我是碼莎拉蒂,CSDN博客專家?????? ??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 1、題目 題目:兩個乒乓球隊進行比賽,各出三人。甲隊為 a,b,c 三人,乙隊為 x,y,z 三人。已抽簽決定…

【數據庫原理及應用】經典題庫附答案(14章全)——第三章:結構化查詢語言SQL

【數據庫原理及應用】經典題庫附答案(14章全)——第一章:數據庫基礎知識 【數據庫原理及應用】經典題庫附答案(14章全)——第二章:關系數據庫知識 【數據庫原理及應用】經典題庫附答案(14章全)——第三章:結構化查詢語言SQL 【數據庫原理及應用】經典題庫附答案(14章…