如果现在要开发一个功能:

要为一款交友App实现查找附近的人,并按距离进行排序。

让你来开发这个功能,你会如何实现?

MySQL 不合适

你可能想到,把用户用户的经纬度坐标使用MySQL等关系数据库(用户id,经度x,纬度y)存储,但是该如何计算距离和排序呢?

不可能通过遍历来计算所有的用户和目标用户的距离,然后再进行排序,因为这个计算量太大了,性能指标肯定无法满足。

GeoHash的编码方法

为了能高效地对经纬度进行比较,Redis 采用了业界广泛使用的 GeoHash 编码方法,这个方法的基本原理是“二分区间,区间编码”。

关于 GeoHash 参考 https://www.cnblogs.com/LBSer/p/3310455.html

简单来说,GeoHash 能够将二维的经纬度转换为字符串,然后位置就能够直接进行比较和范围查询了。

Redis 中 Geo 的使用

命令 说明  可用版本 时间复杂度
GEOADD 添加位置的经纬度 >= 3.2.0 O(logN)
GEOPOS 返回位置的经纬度 >= 3.2.0 O(logN)
GEODIST 返回两个位置的距离 >= 3.2.0 O(logN)
GEORADIUS 返回与指定位置距离距离不大于指定值的位置的经纬度 >= 3.2.0 O(N+logM)
GEORADIUSBYMEMBER 这个命令和 GEORADIUS 命令一样 >= 3.2.0 O(logN+M)
GEOHASH 返回位置的 GeoHash 值 >= 3.2.0 O(logN)

示例

假设用户ID是33,经纬度位置是(116.054579, 39.030452),我们可以用一个 GEO 集合保存所有用户的经纬度,集合 key 是 users:locations。执行下面的这个命令,就可以把ID号为33的用户的当前经纬度位置存入GEO集合中:

GEOADD users:locations 116.034579 39.030452 33

当用户想要寻找自己附近的人时,就可以使用 GEORADIUS 命令。

例如,执行下面的命令,Redis 会根据输入的用户的经纬度信息(116.054579, 39.030452),查找以这个经纬度为中心的5公里内的用户信息。

GEORADIUS users:locations 116.054579 39.030452 5 km ASC COUNT 10

总结

在一个地图应用中,车的数据、餐馆的数据、人的数据可能会有百万千万条,如果使用 Redis 的 Geo 数据结构,它们将全部放在一个 Sorted Set 集合中。在 Redis 的集群环境中,集合可能会从一个节点迁移到另一个节点,如果单个 key 的数据过大,会对集群的迁移工作造成较大的影响,在集群环境中单个 key 对应的数据量不宜超过 1M,否则会导致集群迁移出现卡顿现象,影响线上服务的正常运行。

所以,这里建议 Geo 的数据使用单独的 Redis 实例部署,不使用集群环境。

如果数据量过亿甚至更大,就需要对 Geo 数据进行拆分,按国家拆分、按省拆分,按市拆分,在人口特大城市甚至可以按区拆分。这样就可以显著降低单个 Sorted Set 集合的大小。

参考资料

Redis实战篇(四)基于GEO实现查找附近的人功能的更多相关文章

  1. Redis实战篇

    Redis实战篇 1 Redis 客户端 1.1 客户端通信 原理 客户端和服务器通过 TCP 连接来进行数据交互, 服务器默认的端口号为 6379 . 客户端和服务器发送的命令或数据一律以 \r\n ...

  2. Redis 实战篇:巧用数据类型实现亿级数据统计

    在移动应用的业务场景中,我们需要保存这样的信息:一个 key 关联了一个数据集合,同时还要对集合中的数据进行统计排序. 常见的场景如下: 给一个 userId ,判断用户登陆状态: 两亿用户最近 7 ...

  3. Redis 实战篇:巧用Bitmap 实现亿级海量数据统计

    在移动应用的业务场景中,我们需要保存这样的信息:一个 key 关联了一个数据集合. 常见的场景如下: 给一个 userId ,判断用户登陆状态: 显示用户某个月的签到次数和首次签到时间: 两亿用户最近 ...

  4. Redis实战篇(一)搭建Redis实例

    今天是Redis实战系列的第一讲,先从如何搭建一个Redis实例开始. 下面介绍如何在Docker.Windows.Linux下安装. Docker下安装 1.查看可用的 Redis 版本 访问 Re ...

  5. Redis 实战篇:GEO助我邂逅附近女神

    码老湿,阅读了你的巧用数据类型实现亿级数据统计之后,我学会了如何游刃有余的使用不同的数据类型(String.Hash.List.Set.Sorted Set.HyperLogLog.Bitmap)去解 ...

  6. Redis实战篇(二)基于Bitmap实现用户签到功能

    很多应用上都有用户签到的功能,尤其是配合积分系统一起使用.现在有以下需求: 签到1天得1积分,连续签到2天得2积分,3天得3积分,3天以上均得3积分等. 如果连续签到中断,则重置计数,每月重置计数. ...

  7. Redis实战篇(三)基于HyperLogLog实现UV统计功能

    如果现在要开发一个功能: 统计APP或网页的一个页面,每天有多少用户点击进入的次数.同一个用户的反复点击进入记为 1 次,也就是统计 UV 数据. 让你来开发这个统计模块,你会如何实现? 如果统计 P ...

  8. Redis 实战篇之搭建集群

    Redis 集群简介# Redis Cluster 即 Redis 集群,是 Redis 官方在 3.0 版本推出的一套分布式存储方案.完全去中心化,由多个节点组成,所有节点彼此互联.Redis 客户 ...

  9. 微信小程序实战篇:基于wxcharts.js绘制移动报表

    前言 微信小程序图表插件(wx-charts)是基于canvas绘制,体积小巧,支持图表类型饼图.线图.柱状图 .区域图等图表图形绘制,目前wx-charts是微信小程序图表插件中比较强大好使的一个. ...

随机推荐

  1. flex item default All In One

    flex item default All In One flex item default 初始值 === flex: 0 1 auto; https://drafts.csswg.org/css- ...

  2. js array flat all in one

    js array flat all in one array flat flatMap flatMap > flat + map https://developer.mozilla.org/en ...

  3. PEP 8 & Style Guide

    PEP 8 & Style Guide Style Guide for Python Code https://www.python.org/dev/peps/pep-0008/ PEP Py ...

  4. rem & 16px & 62.5%

    rem & 16px & 62.5% 浏览器的默认字体大小都是16px 兼容性:IE9+,Firefox.Chrome.Safari.Opera 的主流版本都支持了rem 对不支持的浏 ...

  5. js in depth: arrow function & prototype & this & constructor

    js in depth: arrow function & prototype & this & constructor https://developer.mozilla.o ...

  6. VAST算力增值效应,助力NGK全生态产业链!

    虽然比特币和区块链在2009年就诞生了,但它们对于一些人来说好像还是很遥远,归根结底还是由于数字货币始终未能在全球真正实现流通和支付功能.区块链1.0,以比特币为代表,实现了数字支付:区块链2.0,E ...

  7. BGV再度爆发,流通市值破500万美金!

    BGV似乎以超乎寻常的姿态,开启了爆发的模式.这两天,BGV一路上涨,日内最高涨至548.78美金,24小时成交额达到了98.07万美金,24小时成交量达到1844.93枚BGV,流通市值更是突破了5 ...

  8. PBN离场定高转弯保护区插件发布测试

    昨天2月29日,是四年才有一次的日子,本想着应该写点什么,但一测试发现还有问题,只能先放下. 今天是三月份的第一天,一年已经过去了六分之一.疫情的关系,原本并不紧急的工作,现在也开始积压的有些多了,时 ...

  9. 内核栈与thread_info结构详解

    本文转载自内核栈与thread_info结构详解 什么是进程的内核栈? 在内核态(比如应用进程执行系统调用)时,进程运行需要自己的堆栈信息(不是原用户空间中的栈),而是使用内核空间中的栈,这个栈就是进 ...

  10. iOS拍照定制之AVCaptureVideoDataOutput

    问题 领导看了前面做的拍照,问了句"哪来的声音", "系统的,自带的,你看系统的拍照也有声音" "有办法能去掉吗?挺糟心的" "我 ...