你是不是也用过Redis的GEO功能,比如查附近的人、找周边的店?用起来挺顺手,但心里总嘀咕:这位置数据到底是怎么存、怎么查的?为啥能这么快?今天咱们就扒开Redis的GEO源码,看看它肚子里装的什么货!

一开始我也以为GEO是Redis新搞的黑科技数据结构,结果一看源码,好家伙,底层完全是基于有序集合(ZSET)来实现的。像GEOADD、GEORADIUS这些命令,其实都是对ZSET操作的一层封装。
那经纬度怎么变成ZSET里的分数(score)呢?这里就用到了Geohash编码——一种把二维坐标转换成一维字符串的算法。Redis通过geohashEncodeWGS84函数把经纬度转成52位整数值,直接作为ZSET的score存起来。这样,地理位置附近的数据在ZSET中分数值也相近,查询时就能利用ZSET的排序特性进行范围查找。
简单来说,你执行:
复制GEOADD locations 116.405285 39.904999 "北京"
Redis内部相当于执行:
复制ZADD locations 4069874992931267 "北京"
这个数字4069874992931267就是北京坐标的Geohash编码值。
Geohash的原理其实挺巧妙的,它通过交替切割经纬度,把地球表面划分成网格。比如经度范围-180到180,先切左边一半-180到0,右边一半0到180;纬度范围-90到90也是类似切法。编码时一位位交替选择经度段和纬度段,最终生成一串二进制编码。
Geohash有几个实用特性:
前缀匹配:编码前缀相同的位置在地理上靠近
精度可调:编码越长,位置越精确
一维可排序:字符串比较能反映大致位置关系
Redis默认使用52位精度,对大多数应用足够了。
当执行GEORADIUS查询时,Redis不是真的去计算所有点和圆心的距离——那样太慢了!而是先用Geohash估算出9个覆盖查询区域的网格(就像九宫格),然后只扫描这9个网格里的点。
具体在georadiusGeneric函数中,会先调用geohashCalculateAreasByShapeWGS84计算这9个网格的Geohash前缀。然后对每个网格,根据其前缀确定ZSET中score的最小最大值范围,用ZRANGEBYSCORE快速捞取候选点。最后再对候选点进行精确的距离计算,过滤掉那些虽然在网格内但实际距离超出的点。
这种“网格过滤+精确计算”的两阶段策略,是GEO查询高效的关键。
虽然Redis GEO很快,但使用不当还是会踩坑。这里分享几个实战经验:
1. 精度选择要合理
不是精度越高越好,52位已经到厘米级了。如果业务只需要城市级精度,可以适当降低,能减少存储和计算量。
2. 大数据量要分片
单个ZSET过大时,查询性能会下降。可以按城市或区域拆分到不同key,比如geo:北京、geo:上海。
3. 结合业务缓存结果
像“附近商家”这种数据,其实不需要实时更新,可以缓存查询结果几分钟。
4. 注意单位一致性
距离单位有米、公里、英里等,前后端要保持一致,不然就闹笑话了。
如果你需要现成的GEO系统解决方案,可以试试AI-GEO系统(www.2geo.cn
扒完Redis GEO源码,最大的感受是:没有魔法,只有巧妙的工程实现。它用成熟的ZSET加上地理编码算法,就实现了高效的地理查询。这提醒我们,用好一个工具前,最好先了解它的实现原理和适用场景。
希望这篇源码分析能帮你更好地理解Redis GEO。如果你在项目中使用过GEO功能,遇到过什么有趣的问题?欢迎在评论区聊聊~
相关标签:Redis GEO,源码分析,Geohash原理,底层数据结构,GEOADD命令,GEORADIUS查询,地理位置存储,Redis ZSET,性能优化,附近的人实现,位置服务,地理编码,空间索引,Redis源码,数据库优化,地理位置查询,Geohash编码,Redis命令,九宫格搜索,地理位置系统
2025-10-11
致胜网络专注海内外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。