构建毫秒级地理位置查询服务:基于阿里云 Tair TairGIS 的工程实践
地理位置查询服务已经成为现代互联网应用的重要基础能力。从外卖平台常见的“附近商家”,到网约车系统中的“实时派单”,背后都依赖空间索引技术(如 R-Tree、GeoHash)对经纬度坐标进行组织与加速检索。本文将基于阿里云 Tair(企业级内存数据库,兼容 Redis,性能可达开源 Redis 的 3 倍)的增强模块 TairGIS,搭建一套支持点、线、面三类空间数据存储与检索的 GIS 查询服务,实现附近搜索、范围查询以及相交/包含判断,并将查询延迟控制在 5ms 级别。

最终效果
完成本次实践后,你将能够:
- 使用 TairGIS 高效存储并查询点(POI)、线(路径)、面(配送区域)等多种几何对象。
- 实现毫秒级地理位置检索能力,包括“附近搜索”“多边形范围查询”和“空间关系判断(包含/相交)”。
- 在百万级 POI 数据规模下,将附近商家查询延迟从 50ms(原生 Redis GEO + 应用层计算)优化至 5ms。
- 将电子围栏、配送范围判断等复杂空间计算从应用层下沉到数据库层,减少约 60% 的业务代码量。
技术方案
本方案采用阿里云 Tair 的 TairGIS 扩展模块,核心能力来自 R-Tree 空间索引。该索引针对二维地理空间数据进行了专门优化,支持以下能力:
- 几何类型:支持点(POINT)、线(LINESTRING)、面(POLYGON)等 WKT 几何对象的存储与管理。
- 空间关系运算:支持
GIS.CONTAINS(包含)、GIS.INTERSECTS(相交)、GIS.WITHIN(在内部)等常见 GIS 空间判断操作。 - 命令生态:提供
GIS.ADD写入、GIS.SEARCH范围搜索、GIS.GET/GIS.GETALL读取等常用命令。
如果直接使用原生 Redis GEO(基于 Sorted Set + GeoHash),通常只能处理点位距离计算和半径搜索,无法原生存储线和面数据,也不支持多边形范围检索、空间包含关系判断或相交分析。这意味着复杂的地理围栏逻辑需要放在应用层实现,不仅代码维护成本高,而且查询延迟也更高。TairGIS 借助 R-Tree 索引和原生空间运算能力,可以更高效地解决这些地理位置查询场景中的核心问题。
环境与依赖
- 阿里云 Tair 实例:兼容 Redis 协议,推荐选择企业版实例以获得更好的性能与稳定性。
- 客户端:任意支持 Redis 协议的客户端均可使用,如
redis-cli、Jedis、Lettuce。 - 示例数据:外卖业务场景中的商家 POI 坐标数据,以及骑手配送范围多边形数据。
核心实现
下面以外卖平台为例,逐步实现“附近商家查询”和“配送范围判断”这两个典型的地理位置服务能力。
1. 存储商家位置(点)
使用 GIS.ADD 命令将商家 POI 坐标写入 TairGIS。每个商家位置都以一个点表示,并采用 WKT(Well-Known Text)格式进行描述。
GIS.ADD merchant_location "POINT (116.397128 39.916527)" "merchant_001"
GIS.ADD merchant_location "POINT (116.405285 40.004867)" "merchant_002"
GIS.ADD merchant_location "POINT (116.419020 39.921094)" "merchant_003"
执行后,这些商家坐标会被写入名为 merchant_location 的 Key,并自动建立 R-Tree 空间索引,便于后续进行高性能附近搜索。
2. 附近商家搜索(半径查询)
使用 GIS.SEARCH 命令,以用户当前位置为中心,指定搜索半径,即可快速完成附近商家查询。
GIS.SEARCH merchant_location "POINT (116.397128 39.916527)" 1000
- 命令:
GIS.SEARCH key centrePoint radius - 作用:在
merchant_location中搜索以坐标116.397128, 39.916527为中心、半径 1000 米范围内的所有商家。 - 预期结果:返回命中范围内的商家 ID 列表,例如
merchant_001、merchant_003。
3. 存储骑手配送范围(面)
在外卖配送场景中,配送区域通常使用多边形(POLYGON)表示。可以通过 GIS.ADD 将配送范围直接写入 TairGIS。
GIS.ADD delivery_area "POLYGON ((116.392 39.910, 116.400 39.910, 116.400 39.920, 116.392 39.920, 116.392 39.910))" "rider_001_area"
这条命令会将一个矩形配送区域作为多边形对象存储到 delivery_area Key 中,适合后续做配送范围校验与电子围栏判断。
4. 判断订单地址是否在配送范围内(空间关系判断)
使用 GIS.CONTAINS 命令,可以判断一个点(订单收货地址)是否落在某个面(配送范围)内部,这是外卖配送、门店服务范围校验等场景中的常见需求。
GIS.CONTAINS delivery_area "POINT (116.395 39.915)"
- 命令:
GIS.CONTAINS key geometry - 作用:判断坐标
116.395, 39.915是否位于delivery_area中任意一个多边形范围内。 - 预期结果:返回
1(包含)或0(不包含)。如果命中了具体多边形,还可能返回对应的对象标识,如rider_001_area。
5. 电子围栏触及判断(相交判断)
使用 GIS.INTERSECTS 可以判断两个几何对象之间是否存在相交关系,常用于电子围栏检测、区域冲突校验、商圈重叠分析等场景。
GIS.INTERSECTS delivery_area "POLYGON ((116.39 39.91, 116.41 39.91, 116.41 39.93, 116.39 39.93, 116.39 39.91))"
该命令用于判断新输入的多边形区域,是否与 delivery_area 中已有的配送区域发生重叠或相交。
配置说明
无需进行额外配置。TairGIS 作为阿里云 Tair 的内置模块,在实例创建完成后即可直接使用。所有命令均兼容 Redis 协议,因此可以通过标准 Redis 客户端快速接入和调用。
运行方法
在阿里云控制台创建好 Tair 实例后,使用 redis-cli 连接实例,并按顺序执行上述命令,即可完成地理位置查询能力验证。
redis-cli -h -p 6379 -a
结果验证
迁移到 TairGIS 方案后,性能对比结果如下:
| 指标 | 迁移前(Redis GEO + 应用层) | 迁移后(Tair TairGIS) |
| 附近商家查询延迟 | 50ms | 5ms |
| 支撑 POI 规模 | 约 30 万 | 百万级 |
| 配送范围判断 | 应用层计算 | 数据库原生 GIS.CONTAINS |
| 业务代码量 | 复杂 | 下降约 60% |
从验证结果可以看出,TairGIS 在查询延迟、吞吐能力以及业务开发复杂度等方面,均明显优于原生 Redis GEO 方案,更适合构建高性能地理位置查询系统。
常见问题
Q1: 如何迁移现有 Redis GEO 数据到 TairGIS?
通常需要编写脚本,将原有 GEO 数据逐条转换为 GIS.ADD 命令写入 TairGIS。需要注意的是,TairGIS 的 Key 结构独立于 Redis Sorted Set,因此迁移完成后,应用层调用逻辑也需要同步调整,例如将 GEOSEARCH 替换为 GIS.SEARCH。
Q2: 多边形查询性能表现如何?
在百万级 POI 数据规模、且多边形复杂度合理(例如 10-20 个顶点)的情况下,GIS.CONTAINS 和 GIS.SEARCH 的延迟通常都可以稳定在 5ms 级别。整体性能主要取决于 R-Tree 空间索引的过滤效率。
Q3: 是否支持动态更新配送范围?
支持。可以使用 GIS.ADD 对同一个 Key 进行覆盖写入,从而实现多边形配送范围的动态更新。在高频更新场景下,建议重点关注 Tair 实例的 CPU 利用率和内存使用情况,以保证服务稳定性。
后续优化
- 冷热数据分离:对于历史订单地址等访问频率较低的数据,可以迁移到磁盘型数据库,让 Tair 更专注承载高频热点地理数据。
- 索引优化:对于极其复杂的多边形(如上百个顶点),可先在应用层进行图形简化处理,例如使用 Douglas-Peucker 算法,再写入 TairGIS,以更好地平衡精度与查询性能。
- 监控与告警:建议为 Tair 实例配置 CPU、内存和请求延迟相关的监控告警,确保在业务高峰期地理位置服务依然稳定可用。
验证清单:
- 已成功使用
GIS.ADD存储点、面等空间数据。 - 已通过
GIS.SEARCH完成附近搜索,且返回结果符合预期。 - 已通过
GIS.CONTAINS完成配送范围判断,并返回正确的布尔结果。 - 已通过
GIS.INTERSECTS完成电子围栏相交判断。 - 查询延迟达到 5ms 级,且可支撑百万级 POI 数据规模。
