github.com/thanos-io/thanos@v0.32.5/internal/cortex/chunk/cache/redis_cache.go (about)

     1  // Copyright (c) The Cortex Authors.
     2  // Licensed under the Apache License 2.0.
     3  
     4  package cache
     5  
     6  import (
     7  	"context"
     8  
     9  	"github.com/go-kit/log"
    10  	"github.com/go-kit/log/level"
    11  	otlog "github.com/opentracing/opentracing-go/log"
    12  	"github.com/prometheus/client_golang/prometheus"
    13  	"github.com/prometheus/client_golang/prometheus/promauto"
    14  	instr "github.com/weaveworks/common/instrument"
    15  
    16  	"github.com/thanos-io/thanos/internal/cortex/util/spanlogger"
    17  )
    18  
    19  // RedisCache type caches chunks in redis
    20  type RedisCache struct {
    21  	name            string
    22  	redis           *RedisClient
    23  	logger          log.Logger
    24  	requestDuration *instr.HistogramCollector
    25  }
    26  
    27  // NewRedisCache creates a new RedisCache
    28  func NewRedisCache(name string, redisClient *RedisClient, reg prometheus.Registerer, logger log.Logger) *RedisCache {
    29  	cache := &RedisCache{
    30  		name:   name,
    31  		redis:  redisClient,
    32  		logger: logger,
    33  		requestDuration: instr.NewHistogramCollector(
    34  			promauto.With(reg).NewHistogramVec(prometheus.HistogramOpts{
    35  				Namespace:   "cortex",
    36  				Name:        "rediscache_request_duration_seconds",
    37  				Help:        "Total time spent in seconds doing Redis requests.",
    38  				Buckets:     prometheus.ExponentialBuckets(0.000016, 4, 8),
    39  				ConstLabels: prometheus.Labels{"name": name},
    40  			}, []string{"method", "status_code"}),
    41  		),
    42  	}
    43  	if err := cache.redis.Ping(context.Background()); err != nil {
    44  		level.Error(logger).Log("msg", "error connecting to redis", "name", name, "err", err)
    45  	}
    46  	return cache
    47  }
    48  
    49  func redisStatusCode(err error) string {
    50  	// TODO: Figure out if there are more error types returned by Redis
    51  	switch err {
    52  	case nil:
    53  		return "200"
    54  	default:
    55  		return "500"
    56  	}
    57  }
    58  
    59  // Fetch gets keys from the cache. The keys that are found must be in the order of the keys requested.
    60  func (c *RedisCache) Fetch(ctx context.Context, keys []string) (found []string, bufs [][]byte, missed []string) {
    61  	const method = "RedisCache.MGet"
    62  	var items [][]byte
    63  	// Run a tracked request, using c.requestDuration to monitor requests.
    64  	err := instr.CollectedRequest(ctx, method, c.requestDuration, redisStatusCode, func(ctx context.Context) error {
    65  		log, _ := spanlogger.New(ctx, method)
    66  		defer log.Finish()
    67  		log.LogFields(otlog.Int("keys requested", len(keys)))
    68  
    69  		var err error
    70  		items, err = c.redis.MGet(ctx, keys)
    71  		if err != nil {
    72  			log.Error(err)
    73  			level.Error(c.logger).Log("msg", "failed to get from redis", "name", c.name, "err", err)
    74  			return err
    75  		}
    76  
    77  		log.LogFields(otlog.Int("keys found", len(items)))
    78  
    79  		return nil
    80  	})
    81  	if err != nil {
    82  		return found, bufs, keys
    83  	}
    84  
    85  	for i, key := range keys {
    86  		if items[i] != nil {
    87  			found = append(found, key)
    88  			bufs = append(bufs, items[i])
    89  		} else {
    90  			missed = append(missed, key)
    91  		}
    92  	}
    93  
    94  	return
    95  }
    96  
    97  // Store stores the key in the cache.
    98  func (c *RedisCache) Store(ctx context.Context, keys []string, bufs [][]byte) {
    99  	err := c.redis.MSet(ctx, keys, bufs)
   100  	if err != nil {
   101  		level.Error(c.logger).Log("msg", "failed to put to redis", "name", c.name, "err", err)
   102  	}
   103  }
   104  
   105  // Stop stops the redis client.
   106  func (c *RedisCache) Stop() {
   107  	_ = c.redis.Close()
   108  }