【系统设计】邻近服务

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.mzph.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实验原理 默认情况下,交换…

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…

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…

[转]面试官,不要再问我三次握手和四次挥手

文章目录 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 挥手…

C语言试题115之两个乒乓球队进行比赛,各出三人。甲队为 a,b,c 三人,乙队为 x,y,z 三人。已抽签决定 比赛名单。有人向队员打听比赛的名单。a 说他不和 x 比,c 说他不和 x,z 比,请

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 题目:两个乒乓球队进行比赛,各出三人。甲队为 a,b,c 三人,乙队为 x,y,z 三人。已抽签决定…

(04).NET MAUI实战 MVVM

1.概要本章将讲解如何在MAUI中使用简单的MVVM模式开发“ListView”内容的增删功能&#xff0c;MVVM在MAUI中也同样适用。Microsoft.Toolkit.Mvvm在学习之前我们先了解一个nuget包&#xff0c;它可以帮助我们省去一些代码的开发时间。包Microsoft.Toolkit.Mvvm (aka MVVM Toolki…

WTM重大更新,多租户和单点登录

WTM重大更新多租户单点登录随着WTM被越来越多地应用于企业&#xff0c;用户对于多租户和单点登录的需求越来越强烈。经过了几个月的努力&#xff0c;我们把WTM底层代码又进行了一次优化和重构&#xff0c;加入了多租户和单点登录的功能。VUE&#xff0c;Blazor&#xff0c;LayU…

struts2注解

2019独角兽企业重金招聘Python工程师标准>>> 以下均为本人工作中的笔记内容&#xff0c;不够全面具体。碰到什么我就记录什么&#xff0c;只是作为笔记使用&#xff0c;希望大家多提宝贵意见&#xff0c;共同进步。Action("login"):定义action //或者写…

[转]H5直播之从推流服务搭建到视频直播

转自http://www.php.cn/html5-tutorial-403035.html 最近视频直播比较火&#xff0c;发现目前 WEB 上主流的视频直播方案有 HLS 和 RTMP&#xff0c;移动 WEB 端目前以 HLS 为主&#xff0c;PC端则以 RTMP 为主实时性较好&#xff0c;接下来将围绕这两种视频流协议来展开H5直播…

webform数据导出

把数据放到一个泛型集合里&#xff0c;再把泛型集合里面的数据放到一个table中&#xff0c;设置好文件路径&#xff0c;然后进行文件读取&#xff0c;最后供用户下载。 数据导出放在一个按钮中就可以了 using System; using System.Collections.Generic; using System.Linq; us…

C语言试题117之有一分数序列:2/1,3/2,5/3,8/5,13/8,21/13...求出这个数列的前 20 项之和

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 题目:有一分数序列:2/1,3/2,5/3,8/5,13/8,21/13…求出这个数列的前 20 项之和。 分析…

Ionic Mac 环境配置

2019独角兽企业重金招聘Python工程师标准>>> Ionic Mac 环境配置 安装cordova之前要安装nodejs 会包含npm安装&#xff08;npm是个包管理器&#xff09;&#xff0c;到官网下载https://nodejs.org/en/download/ 是个pkg包下载之后双击下载包运行然后 step …