Skip to content

Commit ea70f2c

Browse files
committed
Add in-memory chunk cache
Signed-off-by: SungJin1212 <[email protected]>
1 parent fbe118b commit ea70f2c

File tree

6 files changed

+129
-14
lines changed

6 files changed

+129
-14
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
## master / unreleased
44

5-
* [FEATURE] Query Frontend/Querier: Add protobuf codec `-api.querier-default-codec` and the option to choose response compression type `-querier.response-compression`. #5527
65
* [CHANGE] Enable Compactor and Alertmanager in target all. #6204
6+
* [FEATURE] Query Frontend/Querier: Add protobuf codec `-api.querier-default-codec` and the option to choose response compression type `-querier.response-compression`. #5527
77
* [FEATURE] Ruler: Experimental: Add `ruler.frontend-address` to allow query to query frontends instead of ingesters. #6151
88
* [FEATURE] Ruler: Minimize chances of missed rule group evaluations that can occur due to OOM kills, bad underlying nodes, or due to an unhealthy ruler that appears in the ring as healthy. This feature is enabled via `-ruler.enable-ha-evaluation` flag. #6129
9+
* [FEATURE] Store Gateway: Add an in-memory chunk cache. #6245
910
* [ENHANCEMENT] Ingester: Add `blocks-storage.tsdb.wal-compression-type` to support zstd wal compression type. #6232
1011
* [ENHANCEMENT] Query Frontend: Add info field to query response. #6207
1112
* [ENHANCEMENT] Query Frontend: Add peakSample in query stats response. #6188

docs/blocks-storage/querier.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -788,10 +788,17 @@ blocks_storage:
788788
[max_backfill_items: <int> | default = 10000]
789789

790790
chunks_cache:
791-
# Backend for chunks cache, if not empty. Supported values: memcached.
791+
# Backend for chunks cache, if not empty. Supported values: memcached,
792+
# redis, inmemory and '' (disable).
792793
# CLI flag: -blocks-storage.bucket-store.chunks-cache.backend
793794
[backend: <string> | default = ""]
794795

796+
inmemory:
797+
# Maximum size in bytes of in-memory chunk cache used to speed up chunk
798+
# lookups (shared between all tenants).
799+
# CLI flag: -blocks-storage.bucket-store.chunks-cache.inmemory.max-size-bytes
800+
[max_size_bytes: <int> | default = 1073741824]
801+
795802
memcached:
796803
# Comma separated list of memcached addresses. Supported prefixes are:
797804
# dns+ (looked up as an A/AAAA query), dnssrv+ (looked up as a SRV

docs/blocks-storage/store-gateway.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -903,10 +903,17 @@ blocks_storage:
903903
[max_backfill_items: <int> | default = 10000]
904904

905905
chunks_cache:
906-
# Backend for chunks cache, if not empty. Supported values: memcached.
906+
# Backend for chunks cache, if not empty. Supported values: memcached,
907+
# redis, inmemory and '' (disable).
907908
# CLI flag: -blocks-storage.bucket-store.chunks-cache.backend
908909
[backend: <string> | default = ""]
909910

911+
inmemory:
912+
# Maximum size in bytes of in-memory chunk cache used to speed up chunk
913+
# lookups (shared between all tenants).
914+
# CLI flag: -blocks-storage.bucket-store.chunks-cache.inmemory.max-size-bytes
915+
[max_size_bytes: <int> | default = 1073741824]
916+
910917
memcached:
911918
# Comma separated list of memcached addresses. Supported prefixes are:
912919
# dns+ (looked up as an A/AAAA query), dnssrv+ (looked up as a SRV

docs/configuration/config-file-reference.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1339,10 +1339,17 @@ bucket_store:
13391339
[max_backfill_items: <int> | default = 10000]
13401340

13411341
chunks_cache:
1342-
# Backend for chunks cache, if not empty. Supported values: memcached.
1342+
# Backend for chunks cache, if not empty. Supported values: memcached,
1343+
# redis, inmemory and '' (disable).
13431344
# CLI flag: -blocks-storage.bucket-store.chunks-cache.backend
13441345
[backend: <string> | default = ""]
13451346

1347+
inmemory:
1348+
# Maximum size in bytes of in-memory chunk cache used to speed up chunk
1349+
# lookups (shared between all tenants).
1350+
# CLI flag: -blocks-storage.bucket-store.chunks-cache.inmemory.max-size-bytes
1351+
[max_size_bytes: <int> | default = 1073741824]
1352+
13461353
memcached:
13471354
# Comma separated list of memcached addresses. Supported prefixes are:
13481355
# dns+ (looked up as an A/AAAA query), dnssrv+ (looked up as a SRV query,

integration/querier_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,19 @@ func TestQuerierWithBlocksStorageRunningInMicroservicesMode(t *testing.T) {
9797
chunkCacheBackend: tsdb.CacheBackendRedis,
9898
bucketIndexEnabled: true,
9999
},
100+
"blocks default sharding, in-memory chunk cache": {
101+
blocksShardingStrategy: "default",
102+
indexCacheBackend: tsdb.IndexCacheBackendRedis,
103+
chunkCacheBackend: tsdb.CacheBackendInMemory,
104+
bucketIndexEnabled: true,
105+
},
106+
"blocks shuffle sharding, in-memory chunk cache": {
107+
blocksShardingStrategy: "shuffle-sharding",
108+
tenantShardSize: 1,
109+
indexCacheBackend: tsdb.IndexCacheBackendRedis,
110+
chunkCacheBackend: tsdb.CacheBackendInMemory,
111+
bucketIndexEnabled: true,
112+
},
100113
}
101114

102115
for testName, testCfg := range tests {

pkg/storage/tsdb/caching_bucket.go

Lines changed: 90 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strings"
99
"time"
1010

11+
"github.com/alecthomas/units"
1112
"github.com/go-kit/log"
1213
"github.com/golang/snappy"
1314
"github.com/oklog/ulid"
@@ -18,22 +19,24 @@ import (
1819
"github.com/thanos-io/thanos/pkg/block/metadata"
1920
"github.com/thanos-io/thanos/pkg/cache"
2021
"github.com/thanos-io/thanos/pkg/cacheutil"
22+
"github.com/thanos-io/thanos/pkg/model"
2123
storecache "github.com/thanos-io/thanos/pkg/store/cache"
2224
)
2325

2426
const (
2527
CacheBackendMemcached = "memcached"
2628
CacheBackendRedis = "redis"
29+
CacheBackendInMemory = "inmemory"
2730
)
2831

29-
type CacheBackend struct {
32+
type MetadataCacheBackend struct {
3033
Backend string `yaml:"backend"`
3134
Memcached MemcachedClientConfig `yaml:"memcached"`
3235
Redis RedisClientConfig `yaml:"redis"`
3336
}
3437

3538
// Validate the config.
36-
func (cfg *CacheBackend) Validate() error {
39+
func (cfg *MetadataCacheBackend) Validate() error {
3740
switch cfg.Backend {
3841
case CacheBackendMemcached:
3942
return cfg.Memcached.Validate()
@@ -46,8 +49,31 @@ func (cfg *CacheBackend) Validate() error {
4649
return nil
4750
}
4851

52+
type ChunkCacheBackend struct {
53+
Backend string `yaml:"backend"`
54+
InMemory InMemoryChunkCacheConfig `yaml:"inmemory"`
55+
Memcached MemcachedClientConfig `yaml:"memcached"`
56+
Redis RedisClientConfig `yaml:"redis"`
57+
}
58+
59+
// Validate the config.
60+
func (cfg *ChunkCacheBackend) Validate() error {
61+
switch cfg.Backend {
62+
case CacheBackendMemcached:
63+
return cfg.Memcached.Validate()
64+
case CacheBackendRedis:
65+
return cfg.Redis.Validate()
66+
case CacheBackendInMemory:
67+
return nil
68+
case "":
69+
default:
70+
return fmt.Errorf("unsupported cache backend: %s", cfg.Backend)
71+
}
72+
return nil
73+
}
74+
4975
type ChunksCacheConfig struct {
50-
CacheBackend `yaml:",inline"`
76+
ChunkCacheBackend `yaml:",inline"`
5177

5278
SubrangeSize int64 `yaml:"subrange_size"`
5379
MaxGetRangeRequests int `yaml:"max_get_range_requests"`
@@ -56,10 +82,11 @@ type ChunksCacheConfig struct {
5682
}
5783

5884
func (cfg *ChunksCacheConfig) RegisterFlagsWithPrefix(f *flag.FlagSet, prefix string) {
59-
f.StringVar(&cfg.Backend, prefix+"backend", "", fmt.Sprintf("Backend for chunks cache, if not empty. Supported values: %s.", CacheBackendMemcached))
85+
f.StringVar(&cfg.Backend, prefix+"backend", "", fmt.Sprintf("Backend for chunks cache, if not empty. Supported values: %s, %s, %s and '' (disable).", CacheBackendMemcached, CacheBackendRedis, CacheBackendInMemory))
6086

6187
cfg.Memcached.RegisterFlagsWithPrefix(f, prefix+"memcached.")
6288
cfg.Redis.RegisterFlagsWithPrefix(f, prefix+"redis.")
89+
cfg.InMemory.RegisterFlagsWithPrefix(f, prefix+"inmemory.")
6390

6491
f.Int64Var(&cfg.SubrangeSize, prefix+"subrange-size", 16000, "Size of each subrange that bucket object is split into for better caching.")
6592
f.IntVar(&cfg.MaxGetRangeRequests, prefix+"max-get-range-requests", 3, "Maximum number of sub-GetRange requests that a single GetRange request can be split into when fetching chunks. Zero or negative value = unlimited number of sub-requests.")
@@ -68,11 +95,34 @@ func (cfg *ChunksCacheConfig) RegisterFlagsWithPrefix(f *flag.FlagSet, prefix st
6895
}
6996

7097
func (cfg *ChunksCacheConfig) Validate() error {
71-
return cfg.CacheBackend.Validate()
98+
return cfg.ChunkCacheBackend.Validate()
99+
}
100+
101+
type InMemoryChunkCacheConfig struct {
102+
MaxSizeBytes uint64 `yaml:"max_size_bytes"`
103+
}
104+
105+
func (cfg *InMemoryChunkCacheConfig) RegisterFlagsWithPrefix(f *flag.FlagSet, prefix string) {
106+
f.Uint64Var(&cfg.MaxSizeBytes, prefix+"max-size-bytes", uint64(1*units.Gibibyte), "Maximum size in bytes of in-memory chunk cache used to speed up chunk lookups (shared between all tenants).")
107+
}
108+
109+
func (cfg *InMemoryChunkCacheConfig) toInMemoryChunkCacheConfig() cache.InMemoryCacheConfig {
110+
maxCacheSize := model.Bytes(cfg.MaxSizeBytes)
111+
112+
// Calculate the max item size.
113+
maxItemSize := defaultMaxItemSize
114+
if maxItemSize > maxCacheSize {
115+
maxItemSize = maxCacheSize
116+
}
117+
118+
return cache.InMemoryCacheConfig{
119+
MaxSize: maxCacheSize,
120+
MaxItemSize: maxItemSize,
121+
}
72122
}
73123

74124
type MetadataCacheConfig struct {
75-
CacheBackend `yaml:",inline"`
125+
MetadataCacheBackend `yaml:",inline"`
76126

77127
TenantsListTTL time.Duration `yaml:"tenants_list_ttl"`
78128
TenantBlocksListTTL time.Duration `yaml:"tenant_blocks_list_ttl"`
@@ -107,14 +157,14 @@ func (cfg *MetadataCacheConfig) RegisterFlagsWithPrefix(f *flag.FlagSet, prefix
107157
}
108158

109159
func (cfg *MetadataCacheConfig) Validate() error {
110-
return cfg.CacheBackend.Validate()
160+
return cfg.MetadataCacheBackend.Validate()
111161
}
112162

113163
func CreateCachingBucket(chunksConfig ChunksCacheConfig, metadataConfig MetadataCacheConfig, matchers Matchers, bkt objstore.InstrumentedBucket, logger log.Logger, reg prometheus.Registerer) (objstore.InstrumentedBucket, error) {
114164
cfg := cache.NewCachingBucketConfig()
115165
cachingConfigured := false
116166

117-
chunksCache, err := createCache("chunks-cache", &chunksConfig.CacheBackend, logger, reg)
167+
chunksCache, err := createChunkCache("chunks-cache", &chunksConfig.ChunkCacheBackend, logger, reg)
118168
if err != nil {
119169
return nil, errors.Wrapf(err, "chunks-cache")
120170
}
@@ -124,7 +174,7 @@ func CreateCachingBucket(chunksConfig ChunksCacheConfig, metadataConfig Metadata
124174
cfg.CacheGetRange("chunks", chunksCache, matchers.GetChunksMatcher(), chunksConfig.SubrangeSize, chunksConfig.AttributesTTL, chunksConfig.SubrangeTTL, chunksConfig.MaxGetRangeRequests)
125175
}
126176

127-
metadataCache, err := createCache("metadata-cache", &metadataConfig.CacheBackend, logger, reg)
177+
metadataCache, err := createMetadataCache("metadata-cache", &metadataConfig.MetadataCacheBackend, logger, reg)
128178
if err != nil {
129179
return nil, errors.Wrapf(err, "metadata-cache")
130180
}
@@ -152,12 +202,42 @@ func CreateCachingBucket(chunksConfig ChunksCacheConfig, metadataConfig Metadata
152202
return storecache.NewCachingBucket(bkt, cfg, logger, reg)
153203
}
154204

155-
func createCache(cacheName string, cacheBackend *CacheBackend, logger log.Logger, reg prometheus.Registerer) (cache.Cache, error) {
205+
func createMetadataCache(cacheName string, cacheBackend *MetadataCacheBackend, logger log.Logger, reg prometheus.Registerer) (cache.Cache, error) {
156206
switch cacheBackend.Backend {
157207
case "":
158208
// No caching.
159209
return nil, nil
210+
case CacheBackendMemcached:
211+
var client cacheutil.MemcachedClient
212+
client, err := cacheutil.NewMemcachedClientWithConfig(logger, cacheName, cacheBackend.Memcached.ToMemcachedClientConfig(), reg)
213+
if err != nil {
214+
return nil, errors.Wrapf(err, "failed to create memcached client")
215+
}
216+
return cache.NewMemcachedCache(cacheName, logger, client, reg), nil
160217

218+
case CacheBackendRedis:
219+
redisCache, err := cacheutil.NewRedisClientWithConfig(logger, cacheName, cacheBackend.Redis.ToRedisClientConfig(), reg)
220+
if err != nil {
221+
return nil, errors.Wrapf(err, "failed to create redis client")
222+
}
223+
return cache.NewRedisCache(cacheName, logger, redisCache, reg), nil
224+
225+
default:
226+
return nil, errors.Errorf("unsupported cache type for cache %s: %s", cacheName, cacheBackend.Backend)
227+
}
228+
}
229+
230+
func createChunkCache(cacheName string, cacheBackend *ChunkCacheBackend, logger log.Logger, reg prometheus.Registerer) (cache.Cache, error) {
231+
switch cacheBackend.Backend {
232+
case "":
233+
// No caching.
234+
return nil, nil
235+
case CacheBackendInMemory:
236+
inMemoryCache, err := cache.NewInMemoryCacheWithConfig(cacheName, logger, reg, cacheBackend.InMemory.toInMemoryChunkCacheConfig())
237+
if err != nil {
238+
return nil, errors.Wrapf(err, "failed to create in-memory chunk cache")
239+
}
240+
return inMemoryCache, nil
161241
case CacheBackendMemcached:
162242
var client cacheutil.MemcachedClient
163243
client, err := cacheutil.NewMemcachedClientWithConfig(logger, cacheName, cacheBackend.Memcached.ToMemcachedClientConfig(), reg)

0 commit comments

Comments
 (0)