为了省地图 API 费用,我们把缓存做到极致,最后还是重构了整个位置服务
2026/6/10 17:36:04 网站建设 项目流程

一个月后,我们发现 Redis 比地图服务还忙

去年做本地生活项目的时候。

有段时间地图服务账单涨得特别快。

第一反应当然不是换服务商。

而是优化。

毕竟程序员的本能就是:

能靠技术解决的问题,不要靠采购解决。

于是我们开始疯狂加缓存。

第一版缓存

最简单。

逆地址解析结果直接缓存。

const key = `geo:${lat}:${lng}` const cache = await redis.get(key) if (cache) { return JSON.parse(cache) } const data = await reverseGeocode(lat, lng) await redis.set( key, JSON.stringify(data), 'EX', 86400 ) return data

上线第一天效果不错。

调用量明显下降。

大家都觉得找到了正确方向。

很快发现缓存命中率低得离谱

原因很简单。

GPS 坐标不是整数。

骑手位置:

30.658231 104.072891

下一秒:

30.658236 104.072895

肉眼看几乎没区别。

系统看来却是两个 Key。

缓存根本命不中。

第二版缓存

坐标网格化。

保留四位小数。

const lat = Number(rawLat.toFixed(4)) const lng = Number(rawLng.toFixed(4))

效果确实提升不少。

命中率从个位数来到 40% 左右。

但还是不够。

第三个问题出现了

POI 搜索。

用户搜索:

奶茶

下一位用户搜索:

奶茶店

再下一位:

附近奶茶

结果其实差不多。

但缓存看来完全不同。

为了缓存,我们写了很多奇怪逻辑

同义词归一化。

关键词预处理。

区域缓存。

热门词缓存。

甚至搞了搜索结果预热。

代码越来越复杂。

某天我看监控发现

Redis CPU:

75%

地图接口调用:

下降30%

但账单:

下降不到20%

那一刻突然意识到:

我们可能在优化错误的问题。

真正的问题

后来把调用链全部梳理了一遍。

发现大量请求根本不应该发生。

例如:

用户打开订单页。

调一次逆解析。

进入详情页。

再调一次。

刷新页面。

再调一次。

客服后台打开订单。

又调一次。

同一组坐标。

一天能被解析十几次。

调整思路

不再研究怎么缓存。

而是研究怎么减少调用。

例如:

位置上报时直接完成解析。

await save({ lat, lng, address })

查询直接读库。

SELECT address FROM order_location

整个链路简单很多。

顺手重新评估地图能力

既然都在改架构。

干脆把地图服务也重新看了一遍。

我们需要的其实很少:

  • POI 搜索
  • 正逆地址解析
  • 坐标转换

并不需要全家桶。

于是开始测试不同方案。

一个很现实的问题

很多团队选地图服务时只看:

功能多不多

实际上应该看:

我真正用了多少

很多接口一年都调不了几次。

真正花钱的永远是那几个高频接口。

后来的架构

客户端 ↓ 位置服务层 ↓ POI 逆解析 坐标转换 ↓ LTS

统一封装。

业务侧不再直接调用第三方接口。

以后换服务商只改一层。

最终结果

这次优化没有什么黑科技。

做的事情很朴素:

  • 删除重复调用
  • 调整数据流向
  • 重构位置服务
  • 重新评估供应商

最终:

  • 调用量下降约 70%
  • Redis 压力下降
  • 地图成本明显降低
  • 不再需要研究各种缓存骚操作

写在最后

很多时候技术人容易陷入一个误区:

出现成本问题,就开始研究缓存。

出现性能问题,就开始研究并发。

出现账单问题,就开始研究限流。

但真正应该问的是:

这个请求真的有必要发生吗?

当年我们花了很长时间研究缓存策略。

最后发现最值钱的一行代码其实是:

删除一次不必要的调用

如果你也在做位置服务、地图服务或者 POI 检索系统,可以先看看调用链,而不是先看 Redis。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询