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  }