Apache Druid 缓存配置实战指南:Local / Memcached / Hybrid 三种缓存类型深度解析
【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址: https://gitcode.com/gh_mirrors/druid7/druid
缓存是 Druid 查询链路中最重要的性能优化手段之一。在 Apache Druid 中,缓存可以按需在Broker、Historical 和 Realtime三类进程上开启,用于加速重复查询、降低底层 Segment 扫描压力。本文以仓库中的官方配置文档docs/content/configuration/caching.md为主体,结合server/src/main/java/io/druid/client/cache/下的源码实现与examples/conf/中的真实示例配置,完整讲解local、memcached、hybrid三种缓存类型的全部配置参数、底层工作原理、适用场景与常见实践,帮助你为自己的集群选择并落地正确的缓存方案。
一、缓存在哪里生效:Broker、Historical 与 Realtime
Druid 的查询缓存是一个可选项,需要在Broker、Historical以及 Realtime 处理节点上分别决定是否启用。官方文档给出了三份对应的配置说明:
- broker 缓存配置:Broker 负责接收查询请求、将其分发到各数据节点并合并结果,是缓存收益最明显的进程;
- historical 缓存配置:Historical 节点直接提供历史数据查询,开启缓存可大幅降低重复扫描;
- realtime 缓存配置:实时节点提供近实时数据,同样可参与缓存。
以 Broker 为例,其缓存开关在examples/conf/druid/broker/runtime.properties中有真实示例:
# Query cache druid.broker.cache.useCache=true druid.broker.cache.populateCache=true druid.cache.type=local druid.cache.sizeInBytes=2000000000druid.broker.cache.useCache与druid.broker.cache.populateCache分别控制“查询时是否读取缓存”和“查询结果是否写入缓存”,二者独立配置,默认均为false(见 CacheConfig.java 源码中private boolean useCache = false;与private boolean populateCache = false;)。因此“开启缓存”至少需要同时把这两个开关置为true,否则只会单向生效。
哪些查询类型默认不参与缓存
CacheConfig中还内置了一个默认不可缓存的查询类型列表:
private List<String> unCacheable = Arrays.asList(Query.GROUP_BY, Query.SELECT);也就是说,默认情况下 GroupBy 与 Select 查询不会被缓存,Timeseries、TopN 等查询类型则正常参与缓存。该列表可通过druid.cache.unCacheable配置覆盖。CacheConfig的isQueryCacheable(String queryType)方法正是通过判断查询类型是否落在该列表中来决定缓存的可用性。
二、缓存类型总览:druid.cache.type
Druid 默认使用本地 JVM 内存缓存(local),除非你显式指定了其他类型。全局缓存类型由公共配置文件(即examples/conf/druid/_common/common.runtime.properties)中的druid.cache.type决定,因此Broker 与 Historical 可以复用同一份缓存配置。
| Property | Possible Values | Description | Default |
|---|---|---|---|
druid.cache.type | local,memcached,hybrid | 查询使用的缓存类型。各类型的详细配置选项见下文 | local |
缓存类型通过CacheProvider接口工厂化注入:LocalCacheProvider、MemcachedCacheProvider、HybridCacheProvider分别对应上述三种类型,统一实现 CacheProvider.java 与 Cache.java 抽象出的get / put / getBulk / close / getStats等操作。
三、Local Cache:简单高效的进程内 LRU 缓存
3.1 原理
Local Cache 是一个简单的 JVM 堆内内存 LRU 缓存,其实现为MapCache包装的ByteCountingLRUMap(见 LocalCacheProvider.java):
@Override public Cache get() { return new MapCache(new ByteCountingLRUMap(initialSize, logEvictionCount, sizeInBytes)); }ByteCountingLRUMap继承自LinkedHashMap并以accessOrder = true构造(即按访问顺序排序),因此天然具备 LRU 淘汰语义;它额外用AtomicLong numBytes按字节精确统计缓存占用,并在超过sizeInBytes上限时按插入/访问顺序淘汰最久未使用的条目(详见 ByteCountingLRUMap.java)。
由于缓存驻留在 JVM 堆内存中,启用 Local Cache 后务必同步调大进程的堆内存(如
jvm.config中的-Xmx),否则缓存会与数据对象争抢堆空间。
3.2 配置参数
| Property | Description | Default |
|---|---|---|
druid.cache.sizeInBytes | 缓存最大字节数。设为0表示禁用缓存 | 0 |
druid.cache.initialSize | 缓存底层哈希表(hashtable)的初始大小 | 500000 |
druid.cache.logEvictionCount | 非零时,每淘汰logEvictionCount个条目记录一条日志 | 0 |
其中sizeInBytes与initialSize都带有@Min(0)校验约束;当logEvictionCount非零时,ByteCountingLRUMap会在淘汰计数达到该值的整数倍时输出日志,日志中同时打印当前大小与平均对象大小,便于排查缓存抖动。
3.3 实践示例
官方 Quickstart 配置(examples/conf/druid/broker/runtime.properties)给出的正是 Local Cache 的典型用法:
druid.broker.cache.useCache=true druid.broker.cache.populateCache=true druid.cache.type=local druid.cache.sizeInBytes=2000000000 # 2GB 堆内缓存四、Memcached:进程间共享的分布式缓存
4.1 原理
Memcached 模式使用memcached 作为缓存后端,所有节点共享同一个缓存实例,因此多 Broker / 多 Historical 之间可以共用缓存命中结果,避免各自为政的重复计算。底层通过 spymemcached 客户端(MemcachedCache+MemcacheClientPool)与 memcached 服务通信,LZ4Transcoder负责对象的 LZ4 压缩编解码。
与 Local Cache 不同,Memcached 缓存不占用 Druid 进程的堆内存,这是它适合大规模共享缓存的关键原因。
4.2 配置参数
| Property | Description | Default |
|---|---|---|
druid.cache.expiration | Memcached 缓存条目的过期时间(秒) | 2592000(30 天) |
druid.cache.timeout | 等待 memcached 响应的最大毫秒数 | 500 |
druid.cache.hosts | 逗号分隔的 memcached 主机列表<host:port> | 无(必填) |
druid.cache.maxObjectSize | 单个 memcached 对象的最大字节数 | 52428800(50 MB) |
druid.cache.memcachedPrefix | 所有 key 在 memcached 中的统一前缀 | druid |
druid.cache.numConnections | 使用的 memcached 连接数 | 1 |
对照源码 MemcachedCacheConfig.java,以下细节值得注意:
hosts为@NotNull必填项,格式为逗号分隔的host:port列表;expiration默认 30 天:超过 30 天的值会被 memcached 解释为绝对 POSIX 时间戳而非相对时长,因此如需更长保留期需小心换算;- 源码中还包含文档未列出的两个进阶参数:
druid.cache.readBufferSize(客户端读缓冲字节数,-1表示使用 spymemcached 默认值)与druid.cache.maxOperationQueueSize(客户端操作队列最大字节数,0表示无界),可按需微调。
4.3 实践示例
druid.cache.type=memcached druid.cache.hosts=memcache-1:11211,memcache-2:11211 druid.cache.expiration=86400 # 1 天 druid.cache.timeout=500 druid.cache.memcachedPrefix=druid_prod druid.cache.numConnections=4五、Hybrid Cache:Local + Memcached 两级 L1/L2 缓存
5.1 原理与读取流程
Hybrid 模式组合任意两种缓存构成 L1 / L2 两级缓存,最常见的是“本地内存(L1)+ 远端 memcached(L2)”的组合,兼顾本地命中的低延迟与远端共享的命中率。
读取流程由 HybridCache.java 的get/getBulk实现:
- 先查L1缓存;
- 若L1 未命中(miss),再查L2缓存;
- 若L2 命中,则同时回填写入 L1,下次相同查询即可在本地直接命中;
- 只有两级都未命中时才算整体 miss。
写入时则是两级同时put(level1.put(key, value); level2.put(key, value);),保证一致性。统计信息(命中、未命中、条目数、字节数、淘汰数、超时数、错误数)由两级分别统计后汇总。
从 HybridCacheProvider.java 可以看到,两级缓存通过依赖注入@Named("l1")与@Named("l2")绑定,任一缺失都会直接抛出 "l1/l2 cache not specified for hybrid cache" 异常。
5.2 配置参数
| Property | Description | Default |
|---|---|---|
druid.cache.l1.type | L1 缓存的类型,取值同druid.cache.type(local/memcached/hybrid) | local |
druid.cache.l2.type | L2 缓存的类型,取值同druid.cache.type | local |
druid.cache.l1.* | L1 缓存类型的任意合法属性,均可用此前缀覆盖。例如 L1 为local时,用druid.cache.l1.sizeInBytes设置其大小 | 与对应缓存类型的默认值一致 |
druid.cache.l2.* | L2 缓存设置前缀,语义同 L1 | 与对应缓存类型的默认值一致 |
即:druid.cache.l1.*与druid.cache.l2.*是各自层级的属性命名空间,其下的属性名与对应缓存类型在全局配置中的属性名一一对应。
5.3 实践示例
druid.cache.type=hybrid # L1:本地内存缓存,容量 1GB druid.cache.l1.type=local druid.cache.l1.sizeInBytes=1000000000 druid.cache.l1.initialSize=500000 # L2:共享 memcached druid.cache.l2.type=memcached druid.cache.l2.hosts=memcache-1:11211 druid.cache.l2.expiration=2592000 druid.cache.l2.memcachedPrefix=druid六、缓存类型的选型建议
结合上述原理与源码,三种缓存类型的适用场景可以归纳如下:
| 场景 | 推荐类型 | 理由 |
|---|---|---|
| 单机 / 小集群、查询重复度高、延迟敏感 | local | 零网络开销,命中延迟最低;注意同步增大 JVM 堆内存 |
| 多节点共享缓存、堆内存紧张、节点间结果可复用 | memcached | 缓存不占 Druid 堆内存,所有节点共享同一份结果 |
| 兼顾本地低延迟与远端高命中率 | hybrid | L1 承担热点、L2 兜底并回填,是生产环境最均衡的方案 |
无论选择哪种类型,都需要在公共配置文件中统一定义(如examples/conf/druid/_common/common.runtime.properties),从而让 Broker、Historical 等进程复用同一份缓存配置;同时配合各进程的druid.<process>.cache.useCache与druid.<process>.cache.populateCache开关控制具体行为。缓存命中率、淘汰数与内存占用等指标,可通过CacheStats与CacheMonitor上报到 Druid 的监控体系中进行观测与调优。
【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址: https://gitcode.com/gh_mirrors/druid7/druid
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考