【求助】tidb_mem_quota_binding_cache生产配置参考,调大存在哪些隐患?

各位大佬好,想请教下关于 tidb_mem_quota_binding_cache 参数线上调优相关经验:
1. 生产环境中配的多大?
2. 如果把这个绑定计划缓存调大,会有什么隐性隐患?比如 OOM、锁竞争、SQL解析变慢?
3. 实际运维中,是怎么实现的binding_cache监控?(我们的监控平台只支持select开头的查询,SHOW binding_cache status命令无法放到监控里。)

其实原因很简单,因为SHOW命令没法被你们的监控平台直接抓取,所以得换个思路,用SELECT去查系统表 来曲线救国。

1 个赞

搜了半天,没找到哪个系统视图存了binding_cache的使用大小。

tidb_mem_quota_binding_cache 控制的是 binding 计划缓存的内存上限,默认 64MB。这个值只影响 binding(SQL 绑定)的缓存,不是 SQL 执行内存,所以调大它本身不会直接导致执行阶段 OOM,主要影响是能缓存更多 binding。几点建议:1)生产上除非 binding 数量特别多(成千上万条)导致缓存放不下、频繁淘汰,否则默认 64MB 通常够用,先确认是否真有淘汰再调;2)判断依据看 SHOW GLOBAL BINDINGS 的条数和 binding_cache 的命中/淘汰情况,如果 binding 不多就没必要调大;3)监控问题:你说只能跑 select,可以查 INFORMATION_SCHEMA 里的相关表,binding 相关信息在系统表 mysql.bind_info 里,也可以用 SELECT 查 information_schema.cluster_* 相关视图,把这些接入监控,绕开 SHOW 命令。调大的隐患主要是占用 TiDB server 内存,量级不大,比起 SQL 执行内存(tidb_mem_quota_query)风险小很多。

关于tidb_mem_quota_binding_cache,建议先看看当前命中率:SHOW binding_cache status。如果命中率低,调大意义不大。

  1. 生产我们一般设4GB-8GB,具体看binding数量。建议先设4GB,观察后再调整。
  2. 调大主要风险是OOM,因为这块内存是TiDB进程共享的,不会自动释放。另外binding过多会增加解析开销,建议控制binding数量在1万以内。

设到4g,你们绑定了多少条?

社区 topic/1057681 综合分析报告

问题tidb_mem_quota_binding_cache 生产配置参考、调大隐患、监控方案
版本:v7.5.3


一、参数机制(源码确认)

tidb_mem_quota_binding_cache 控制 binding 计划缓存的字节级内存配额,默认 64MB。底层是 kvcache.SimpleLRUCache,条目数无上限,纯按字节触发 LRU 淘汰。通过 memory.Tracker 挂到 TiDB 全局内存树,受 server 总 OOM 管控。

二、核心澄清:调大不会让 SQL 匹配变慢

这是社区最常见的误解。源码确认 binding 匹配是 O(1) hash lookupbind_cache.go:137),通过 SQL digest 哈希直接定位,与 cache 内 binding 总条数 N 无关。cache 里 100 条还是 10000 条,单 SQL 匹配开销一样。

真正受 N 影响的操作(低频,不在 SQL 热路径上):

  • ADMIN RELOAD BINDINGS(全量重建 cache):O(N)
  • 后台 lease 周期 reload / baseline evolve 扫描:O(N),默认 3s/次
  • SHOW [GLOBAL] BINDINGS:O(N)

三、调大的真实风险

风险 说明 严重度
进程内存常驻增加 1 万条 binding ~10-30MB,与 query cache / session pool 抢 TiDB 进程内存
bind_info 表查询变慢 N 过大 → mysql.bind_info 内部查询开销增加(TICKET-810 先例)
baseline evolve CPU 开销 启用 tidb_evolve_plan_baselines 时,N 越多后台 CPU 越高
bug 影响面放大 v8.5.6 曾出现 LRU 非线程安全导致 OOM(tidb#68015,TICKET-8523)——cache 越大 bug 触发时膨胀越快。v7.5.3 不受此 bug 影响(仍用 Mutex 非 RWLock),但教训:quota 越大未来出现类似 bug 时影响面越大 参考级

注意:v7.5.3 使用 sync.Mutex 保护所有 cache 操作(bind_cache.go:32),不存在 v8.5.6 的并发 Get 改坏 LRU 链表问题,锁竞争风险极低

四、生产配置建议

binding 数量 建议配置 理由
< 1000 条 保持默认 64MB 足够,调大无收益
1000-5000 条 256MB-1GB 按需调,观察进程内存
> 5000 条 1-4GB 先控制 binding 数量,再考虑调大

建议先查 binding 数量再决策

SELECT COUNT(*) FROM mysql.bind_info WHERE status = 'enabled';

五、监控方案(SELECT-only 兼容)

-- 1. binding 总条数和趋势(唯一可信方式,SHOW 有截断 bug,见 TICKET-8148)
SELECT COUNT(*), SUM(LENGTH(original_sql) + LENGTH(bind_sql))
FROM mysql.bind_info WHERE status = 'enabled';

-- 2. 各库 binding 分布
SELECT original_db, COUNT(*)
FROM mysql.bind_info WHERE status = 'enabled'
GROUP BY original_db ORDER BY COUNT(*) DESC;

-- 3. 最近创建/更新的 binding
SELECT original_db, original_sql, bind_sql, create_time, update_time
FROM mysql.bind_info WHERE status = 'enabled'
ORDER BY update_time DESC LIMIT 20;

监控盲区:TiDB 未暴露 binding cache hit/miss ratio 的 Prometheus metric(源码确认),无法直接量化调大后的命中率收益。只能通过 TiDB 进程总内存趋势间接判断。

六、建议对客回复

tidb_mem_quota_binding_cache 默认 64MB 控制的是 binding 计划缓存的内存上限。调大不会让 SQL 匹配/解析变慢(匹配是 O(1) 哈希查找,与 binding 总数无关),主要影响是 TiDB 进程常驻内存增加。

生产建议:

  1. 先用 SELECT COUNT(*) FROM mysql.bind_info WHERE status='enabled' 查当前 binding 数量
  2. binding < 1000 条保持默认即可;数千条以上可酌情调到 256MB-1GB
  3. 监控用 SELECT FROM mysql.bind_info(不要用 SHOW GLOBAL BINDINGS,长 SQL 会被截断)
  4. 调大后关注 TiDB 进程总内存趋势

风险方面:v7.5.3 的 binding cache 使用 Mutex 保护,不存在并发安全问题;主要风险是占用进程内存导致与其他内存区域(query cache、session pool)竞争。建议 binding 总数控制在 1 万条以内。


分析基于:bind_cache.go / optimize.go release-7.5 源码 + KB 历史工单

tidb_mem_quota_binding_cache:SQL Binding 计划缓存内存上限,单位字节,控制所有绑定规则缓存执行计划占用总内存; 每条 Binding 会缓存优化后的物理执行计划,频繁更新 / 大量绑定语句会持续占用这块内存,达到阈值后会淘汰最久未使用的 Binding 缓存计划,不会直接删除绑定规则(规则持久化在 mysql.bind_info 表,只是缓存失效,下次执行重新生成计划)。

1)通用中小集群(TP 业务,绑定条数<500)

  • 标配:268435456(256MB) 适用:在线 OLTP,单 TiDB 节点绑定 SQL 不超过 500 条,QPS 1~3w,无大量复杂多表 JOIN、CTE、窗口函数。

2)中大型 TP / 混合负载(绑定 500~2000 条,复杂 SQL 多)

  • 标配:536870912(512MB) 适用:金融、政务系统,大量慢 SQL 绑定,报表复杂查询多,单节点绑定上千条。

3)重报表 / 复杂 OLAP 混合集群(绑定>2000 条,大 JOIN、子查询多)

  • 标配:1073741824(1GB) 上限不建议超过 2GB(2147483648),极少场景用到。