github.com/thanos-io/thanos@v0.32.5/pkg/store/cache/caching_bucket_factory.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package storecache 5 6 import ( 7 "regexp" 8 "strings" 9 "time" 10 11 "github.com/go-kit/log" 12 "github.com/go-kit/log/level" 13 "github.com/pkg/errors" 14 "github.com/prometheus/client_golang/prometheus" 15 "github.com/prometheus/common/route" 16 "gopkg.in/yaml.v2" 17 18 "github.com/thanos-io/objstore" 19 20 "github.com/thanos-io/thanos/pkg/block/metadata" 21 "github.com/thanos-io/thanos/pkg/cache" 22 "github.com/thanos-io/thanos/pkg/cacheutil" 23 "github.com/thanos-io/thanos/pkg/model" 24 ) 25 26 // BucketCacheProvider is a type used to evaluate all bucket cache providers. 27 type BucketCacheProvider string 28 29 const ( 30 InMemoryBucketCacheProvider BucketCacheProvider = "IN-MEMORY" // In-memory cache-provider for caching bucket. 31 MemcachedBucketCacheProvider BucketCacheProvider = "MEMCACHED" // Memcached cache-provider for caching bucket. 32 RedisBucketCacheProvider BucketCacheProvider = "REDIS" // Redis cache-provider for caching bucket. 33 GroupcacheBucketCacheProvider BucketCacheProvider = "GROUPCACHE" // Groupcache cache-provider for caching bucket. 34 ) 35 36 // CachingWithBackendConfig is a configuration of caching bucket used by Store component. 37 type CachingWithBackendConfig struct { 38 Type BucketCacheProvider `yaml:"type"` 39 BackendConfig interface{} `yaml:"config"` 40 41 // Basic unit used to cache chunks. 42 ChunkSubrangeSize int64 `yaml:"chunk_subrange_size"` 43 44 // Maximum number of GetRange requests issued by this bucket for single GetRange call. Zero or negative value = unlimited. 45 MaxChunksGetRangeRequests int `yaml:"max_chunks_get_range_requests"` 46 47 MetafileMaxSize model.Bytes `yaml:"metafile_max_size"` 48 49 // TTLs for various cache items. 50 ChunkObjectAttrsTTL time.Duration `yaml:"chunk_object_attrs_ttl"` 51 ChunkSubrangeTTL time.Duration `yaml:"chunk_subrange_ttl"` 52 53 // How long to cache result of Iter call in root directory. 54 BlocksIterTTL time.Duration `yaml:"blocks_iter_ttl"` 55 56 // Config for Exists and Get operations for metadata files. 57 MetafileExistsTTL time.Duration `yaml:"metafile_exists_ttl"` 58 MetafileDoesntExistTTL time.Duration `yaml:"metafile_doesnt_exist_ttl"` 59 MetafileContentTTL time.Duration `yaml:"metafile_content_ttl"` 60 } 61 62 func (cfg *CachingWithBackendConfig) Defaults() { 63 cfg.ChunkSubrangeSize = 16000 // Equal to max chunk size. 64 cfg.ChunkObjectAttrsTTL = 24 * time.Hour 65 cfg.ChunkSubrangeTTL = 24 * time.Hour 66 cfg.MaxChunksGetRangeRequests = 3 67 cfg.BlocksIterTTL = 5 * time.Minute 68 cfg.MetafileExistsTTL = 2 * time.Hour 69 cfg.MetafileDoesntExistTTL = 15 * time.Minute 70 cfg.MetafileContentTTL = 24 * time.Hour 71 cfg.MetafileMaxSize = 1024 * 1024 // Equal to default MaxItemSize in memcached client. 72 } 73 74 // NewCachingBucketFromYaml uses YAML configuration to create new caching bucket. 75 func NewCachingBucketFromYaml(yamlContent []byte, bucket objstore.Bucket, logger log.Logger, reg prometheus.Registerer, r *route.Router) (objstore.InstrumentedBucket, error) { 76 level.Info(logger).Log("msg", "loading caching bucket configuration") 77 78 config := &CachingWithBackendConfig{} 79 config.Defaults() 80 81 if err := yaml.UnmarshalStrict(yamlContent, config); err != nil { 82 return nil, errors.Wrap(err, "parsing config YAML file") 83 } 84 85 backendConfig, err := yaml.Marshal(config.BackendConfig) 86 if err != nil { 87 return nil, errors.Wrap(err, "marshal content of cache backend configuration") 88 } 89 90 var c cache.Cache 91 cfg := cache.NewCachingBucketConfig() 92 93 // Configure cache paths. 94 cfg.CacheAttributes("chunks", nil, isTSDBChunkFile, config.ChunkObjectAttrsTTL) 95 cfg.CacheGetRange("chunks", nil, isTSDBChunkFile, config.ChunkSubrangeSize, config.ChunkObjectAttrsTTL, config.ChunkSubrangeTTL, config.MaxChunksGetRangeRequests) 96 cfg.CacheExists("meta.jsons", nil, isMetaFile, config.MetafileExistsTTL, config.MetafileDoesntExistTTL) 97 cfg.CacheGet("meta.jsons", nil, isMetaFile, int(config.MetafileMaxSize), config.MetafileContentTTL, config.MetafileExistsTTL, config.MetafileDoesntExistTTL) 98 99 // Cache Iter requests for root. 100 cfg.CacheIter("blocks-iter", nil, isBlocksRootDir, config.BlocksIterTTL, JSONIterCodec{}) 101 102 switch strings.ToUpper(string(config.Type)) { 103 case string(MemcachedBucketCacheProvider): 104 var memcached cacheutil.RemoteCacheClient 105 memcached, err := cacheutil.NewMemcachedClient(logger, "caching-bucket", backendConfig, reg) 106 if err != nil { 107 return nil, errors.Wrapf(err, "failed to create memcached client") 108 } 109 c = cache.NewMemcachedCache("caching-bucket", logger, memcached, reg) 110 case string(InMemoryBucketCacheProvider): 111 c, err = cache.NewInMemoryCache("caching-bucket", logger, reg, backendConfig) 112 if err != nil { 113 return nil, errors.Wrapf(err, "failed to create inmemory cache") 114 } 115 case string(GroupcacheBucketCacheProvider): 116 const basePath = "/_galaxycache/" 117 118 c, err = cache.NewGroupcache(logger, reg, backendConfig, basePath, r, bucket, cfg) 119 if err != nil { 120 return nil, errors.Wrap(err, "failed to create groupcache") 121 } 122 123 case string(RedisBucketCacheProvider): 124 redisCache, err := cacheutil.NewRedisClient(logger, "caching-bucket", backendConfig, reg) 125 if err != nil { 126 return nil, errors.Wrapf(err, "failed to create redis client") 127 } 128 c = cache.NewRedisCache("caching-bucket", logger, redisCache, reg) 129 default: 130 return nil, errors.Errorf("unsupported cache type: %s", config.Type) 131 } 132 133 // Include interactions with cache in the traces. 134 c = cache.NewTracingCache(c) 135 cfg.SetCacheImplementation(c) 136 137 cb, err := NewCachingBucket(bucket, cfg, logger, reg) 138 if err != nil { 139 return nil, err 140 } 141 142 return cb, nil 143 } 144 145 var chunksMatcher = regexp.MustCompile(`^.*/chunks/\d+$`) 146 147 func isTSDBChunkFile(name string) bool { return chunksMatcher.MatchString(name) } 148 149 func isMetaFile(name string) bool { 150 return strings.HasSuffix(name, "/"+metadata.MetaFilename) || strings.HasSuffix(name, "/"+metadata.DeletionMarkFilename) 151 } 152 153 func isBlocksRootDir(name string) bool { 154 return name == "" 155 }