Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cache: switch to Rueidis client for Redis #5593

Merged
merged 3 commits into from Dec 20, 2022

Conversation

GiedriusS
Copy link
Member

@GiedriusS GiedriusS commented Aug 12, 2022

Add support for the Rueidis client. It has been instrumental for us in
avoiding an incident in production from too much network load on the
servers. Since we have lots of alerting/recording rules that use
historical data i.e. from Thanos Store, it means that without
client-side caching the same data is retrieved repeatedly.
Rueidis sends a PTTL command to Redis after retrieving data from Redis
to know what the TTL is.

I contemplated sending a design doc for this but the design doc ended up
very slim. It's either something like this or:

  • Adding client-side caching support to go-redis (it's probably a huge
    undertaking);
  • Using the type field to differentiate clients.

I think it's ready to go except for two things:

  • There's no way to disable local cache in Rueidis for now due to
    limitation in the Rueidis library;
  • There's no way to disable the default TTL in case PTTL fails - we
    probably don't want to cache sensitive things like index data for longer
    then we're supposed to.

I'll try to work on these things if this whole idea of having different
clients look good to you.

Signed-off-by: Giedrius Statkevičius giedrius.statkevicius@vinted.com

bwplotka
bwplotka previously approved these changes Aug 17, 2022
Copy link
Member

@bwplotka bwplotka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot! One sentence to fix in docs, otherwise LGTM!

* `GOREDIS` (the default one)
* `RUEIDIS`

The main difference is that [Rueidis](https://github.com/rueian/rueidis) supports [client-side caching](https://redis.io/docs/manual/client-side-caching/) which is really important. If you have high cardinality metrics then it means that it is no longer necessary to go to remote-object storage to get information about potentially thousands or millions of metrics.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you have high cardinality metrics then it means that it is no longer necessary to go to remote-object storage to get information about potentially thousands or millions of metrics.

I think this is wrong. The client caching is for Redis client NOT object storage. Also how it helps with cardinality in particular?

Client side caching to me sounds like extra in-mem cache that is checked first before accessing shared cache in REDIS, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I am also a little bit confused. What's the benefits of client side caching over server side caching. Less network calls?

@matej-g
Copy link
Collaborator

matej-g commented Aug 26, 2022

What's the status on this? Will we proceed with single client as we discussed?

@GiedriusS
Copy link
Member Author

I talked with @hanjm in private and they depend on RESP2 support in the Redis client so unfortunately we cannot easily from go-redis to Rueidis. So, I propose moving forward with this custom client support if that sounds good. Our discussion still stands though - we shouldn't add support for custom clients without good rationale. Let me update the PR and fix the docs.

@rueian
Copy link
Contributor

rueian commented Oct 13, 2022

I talked with @hanjm in private and they depend on RESP2 support in the Redis client so unfortunately we cannot easily from go-redis to Rueidis. So, I propose moving forward with this custom client support if that sounds good. Our discussion still stands though - we shouldn't add support for custom clients without good rationale. Let me update the PR and fix the docs.

Hi @GiedriusS, just let you know that rueidis now also works in RESP2 with client-side cache disabled.

@hanjm
Copy link
Member

hanjm commented Oct 14, 2022

Hi @GiedriusS, just let you know that rueidis now also works in RESP2 with client-side cache disabled.

Cool.

@matej-g
Copy link
Collaborator

matej-g commented Oct 17, 2022

@GiedriusS @hanjm does this mean we can go forward with the original suggestion, i.e. replace clients?

@GiedriusS
Copy link
Member Author

I think so. I'll update this PR soon.

@GiedriusS
Copy link
Member Author

Testing out the newest Rueidis client before updating this PR (:

@bwplotka
Copy link
Member

bwplotka commented Dec 7, 2022

We are looking forward to this change, sounds like deadlock is over (:

@GiedriusS GiedriusS force-pushed the add_rueidis_client_support branch 4 times, most recently from 8c84c55 to 12699e4 Compare December 8, 2022 12:04
@GiedriusS
Copy link
Member Author

Replaced go-redis with rueidis and simplified everything since rueidis now supports RESP2 as well. Most notably, this includes support for Redis Enterprise. Also, support for disabling client-side caching has been added so I've adjusted the code for that too. I've been testing this in prod for 3 months+ if not more so I think this should be good to go 💪 huge thank you goes to @rueian for all of the development and support, and a great library ❤️

Switch client to rueidis because it is faster and supports client-side
caching. Tested it in production for a few months.

Signed-off-by: Giedrius Statkevičius <giedrius.statkevicius@vinted.com>
return errors.New("both client key and certificate must be provided")
}
}

return nil
}

// RedisClient is a wrap of redis.Client.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is now outdated.

redisClient := redis.NewClient(opts)
if reg != nil {
reg = prometheus.WrapRegistererWith(prometheus.Labels{"name": name}, reg)
var disableCaching = false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not disableCaching := false? I thought we used var only to declare variables and use their type's zero-value.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, this is client-side caching, right? Could the variable be named clientSideCacheEnabled then? It is more concise with what it really is and avoids the "negative thinking" (which causes double negation when disableCaching = false.

if _, err := c.Set(ctx, key, value, ttl).Result(); err != nil {
level.Warn(c.logger).Log("msg", "failed to set item into redis", "err", err, "key", key,
"value_size", len(value))
if err := c.client.Do(ctx, c.client.B().Set().Key(key).Value(rueidis.BinaryString(value)).ExSeconds(int64(ttl.Seconds())).Build()).Error(); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why here we use Set with ExSeconds being added later instead of Setex, like in the SetMulti function? Would be cool to be consistent.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, wouldn't it be wise to use DoCache here to populate the client side cache too? I don't see DoCache or DoMultiCache being used anymore and from what I understand from Rueidis' README those are functions that will also populate client side cache.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed there is MGetCache for getting through client side cache, but I fail to see where we write to the client side cache.

Copy link
Contributor

@rueian rueian Dec 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @douglascamata,

The population of client side cache is done by rueidis when you get successful responses from DoCache and DoMultiCache with supported commands, such as GET and MGET.

SET is not supported by DoCache by design, because the client must be tracked by redis server via cacheable requests to receive related invalidation notifications later.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rueian gotcha, thanks for the clarification!

I thought it would be useful for us to populate the client side cache whenever we SET something, but it if the cost is another GET and by consequence of the design, might not be a good idea.

Signed-off-by: Giedrius Statkevičius <giedrius.statkevicius@vinted.com>
@GiedriusS
Copy link
Member Author

Thanks for the review @douglascamata, I've updated the PR.

@GiedriusS GiedriusS changed the title cache: add Rueidis client support cache: switch to Rueidis client for Redis Dec 15, 2022
yeya24
yeya24 previously approved these changes Dec 19, 2022
Copy link
Contributor

@yeya24 yeya24 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this looks good. Looking forward to merge it!

pkg/cacheutil/redis_client.go Show resolved Hide resolved
@yeya24
Copy link
Contributor

yeya24 commented Dec 19, 2022

Btw let's fix the changelog.

Signed-off-by: Bartlomiej Plotka <bwplotka@gmail.com>
Copy link
Member

@bwplotka bwplotka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work! Worth taking it to 0.30 release as well.

@bwplotka bwplotka enabled auto-merge (squash) December 20, 2022 13:41
@bwplotka bwplotka merged commit e85bc1f into thanos-io:main Dec 20, 2022
@GiedriusS GiedriusS deleted the add_rueidis_client_support branch December 20, 2022 15:08
ngraham20 pushed a commit to ngraham20/thanos that referenced this pull request May 18, 2023
* cacheutil: replace go-redis with rueidis client

Switch client to rueidis because it is faster and supports client-side
caching. Tested it in production for a few months.

Signed-off-by: Giedrius Statkevičius <giedrius.statkevicius@vinted.com>

* cacheutil: fix according to review

Signed-off-by: Giedrius Statkevičius <giedrius.statkevicius@vinted.com>

Signed-off-by: Giedrius Statkevičius <giedrius.statkevicius@vinted.com>
Signed-off-by: Bartlomiej Plotka <bwplotka@gmail.com>
Co-authored-by: Bartlomiej Plotka <bwplotka@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants