美团路径缓存淘汰策略全解析(性能 vs 精度 vs 成本的三难选择)

📌 一、背景:为什么需要路径缓存?

在美团骑手实时导航系统中,每天超过 5 亿次路径规划请求,如果每次都重新计算:

  • ❌ 地图服务调用次数剧增(高德/自研)
  • ❌ 响应延迟上升,影响 ETA 和调度时效
  • ❌ 多个相似订单浪费计算资源

所以我们引入了路径缓存服务 PathCache,用于加速以下场景:

  • 相似起终点订单(比如同小区商户 → 楼盘外卖点)
  • 骑手换单前后的路径尝试
  • 派单调度模拟(每个骑手尝试不同路径)

📌 二、路径缓存的基本结构

✅ 缓存 Key 设计

ts 复制代码
cacheKey = `${startLat}_${startLng}_${endLat}_${endLng}_${timeSlice}`

加入时间片段(例如 15分钟粒度)避免老路况影响精度。


✅ 缓存 Value 结构(简化)

ts 复制代码
interface PathCacheEntry {
  route: RouteSegment[];       // 路线分段信息
  score: number;               // 规划打分
  trafficLevel: string;        // 当时的路况等级
  createTime: number;          // 路径生成时间戳
  usedCount: number;           // 被命中次数
  etaSnapshot: number;         // 当时 ETA 值
}

📌 三、淘汰策略设计核心:缓存不能太旧,也不能太少

我们评估过以下淘汰算法:

策略 特点 是否使用
FIFO 简单,但命中率低 否 ❌
LRU 保活常用路径,适合骑手高频路线 是 ✅
LFU 命中频率优先,但会留"老废数据" 否 ❌
TTL+LRU LRU为主,超期也淘汰 是 ✅
自定义分级 热路网保留更久,冷路快淘汰 是 ✅

📦 四、核心实现片段(Node.js 伪代码)

✅ 路径缓存读写:

js 复制代码
const cacheMap = new Map()

function getPathFromCache(key) {
  const entry = cacheMap.get(key)
  if (!entry) return null

  const now = Date.now()
  if (now - entry.createTime > 10 * 60 * 1000) { // 超过10分钟失效
    cacheMap.delete(key)
    return null
  }

  entry.usedCount += 1
  return entry
}

function savePathToCache(key, data) {
  cacheMap.set(key, {
    ...data,
    createTime: Date.now(),
    usedCount: 1
  })
}

✅ 淘汰策略:定时任务 + 限制容量

js 复制代码
const MAX_CACHE_SIZE = 100000

setInterval(() => {
  const entries = Array.from(cacheMap.entries())

  // 超时 + 命中次数低 的组合淘汰策略
  entries.sort((a, b) => {
    return a[1].usedCount - b[1].usedCount
  })

  if (entries.length > MAX_CACHE_SIZE) {
    const dropCount = entries.length - MAX_CACHE_SIZE
    for (let i = 0; i < dropCount; i++) {
      cacheMap.delete(entries[i][0])
    }
  }
}, 60000)

📈 五、缓存命中率优化方案(真实策略)

✅ 1. 起终点"相似化"

通过对经纬度 hash 到格子区域:

ts 复制代码
function simplifyCoord(lat, lng) {
  return `${Math.round(lat * 1000)},${Math.round(lng * 1000)}`
}

命中率提升约 23.1%


✅ 2. 多路缓存(小批量候选)

为了防止主缓存被挤爆,我们引入 冷热分级策略

text 复制代码
一级缓存:热门路径(热门商圈配送) → Redis
二级缓存:普通路径 → LRU 本地缓存
三级备份:异步写入本地 LevelDB

✅ 3. 同区域同向缓存迁移

举例:

A小区 → 商场B 的路径,可应用到 A小区 → 商场B 门口快递点,只需增补尾段

这种近似路径继承策略 ,帮助我们降低路径规划调用约 14.7%


📊 六、实战效果对比

指标 未优化 使用 PathCache(全策略)
平均路径耗时 123ms 23ms
地图服务 QPS 降低 - 减少 67% 请求
缓存命中率 18% 64.5%
错误路径命中率 - < 0.9%(有 ETA 反查兜底)

📌 七、工程挑战总结

挑战 解决策略
异常旧路径未失效 TTL+并发清理
路况快速波动 加入时间片 hash
高峰缓存击穿 Redis 热点缓存 + fallback 兜底
多版本路径重复命中 增加 algo_version 区分 key

✅ 总结

路径缓存系统是一个低成本、高收益的优化方案,但做好它不简单:

  1. 要理解"骑手路径行为"和"地理分布模式"
  2. 要能高效设计缓存 key、淘汰策略、实时清理
  3. 要和 ETA 模型打通,确保预测数据不过时
  4. 要可观测、可复盘、可 Debug(日志审计 + 兜底机制)
相关推荐
ObjectX前端实验室14 分钟前
React Fiber 双缓冲树机制深度解析
前端·react.js
小蒜学长29 分钟前
springboot基于BS的小区家政服务预约平台(代码+数据库+LW)
java·数据库·spring boot·后端
我命由我1234538 分钟前
Git 暂存文件警告信息:warning: LF will be replaced by CRLF in XXX.java.
java·linux·笔记·git·后端·学习·java-ee
高斯林.神犇1 小时前
javaWeb基础
前端·chrome
简色1 小时前
预约优化方案全链路优化实践
java·spring boot·后端·mysql·spring·rabbitmq
用户21411832636021 小时前
dify案例分享-Qwen3-VL+Dify:从作业 OCR 到视频字幕,多模态识别工作流一步教,附体验链接
前端
南屿im2 小时前
把代码变成“可改的树”:一文读懂前端 AST 的原理与实战
前端·javascript
charlie1145141912 小时前
从《Life of A Pixel》来看Chrome的渲染机制
前端·chrome·学习·渲染·浏览器·原理分析
学编程的小鬼2 小时前
SpringBoot日志
java·后端·springboot
用户4099322502122 小时前
PostgreSQL备份不是复制文件?物理vs逻辑咋选?误删还能精准恢复到1分钟前?
后端·ai编程·trae