欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  数据库

Redis configuration rewriting

程序员文章站 2022-05-22 12:28:19
...

Lately I'm trying to push forward Redis 2.8 enough to reach the feature freeze and release it as a stable release as soon as possible. Redis 2.8 will not contain Redis Cluster, and its implementation of Redis Sentinel is the same as 2.6 an

Lately I'm trying to push forward Redis 2.8 enough to reach the feature freeze and release it as a stable release as soon as possible.
Redis 2.8 will not contain Redis Cluster, and its implementation of Redis Sentinel is the same as 2.6 and unstable branches, (Sentinel is taken mostly in sync in all the branches being fundamentally a different project using Redis just as framework).

However there are many new interesting features in Redis 2.8 that are back ported from the unstable branch. Basically 2.8 it's our usual "in the middle" release, like 2.4 was: waiting for Redis 3.0 that will feature Redis Cluster (we have great progresses about it! See https://vimeo.com/63672368), we'll have a 2.8 release with everything that is ready to be released into the unstable branch. The goal is of course to put more things in the hands of users ASAP.

The big three new entries into Redis 2.8 are replication partial resynchronizations (already covered in this blog), keyspace events notifications via Pub/Sub, and finally CONFIG REWRITE, a feature I just finished to implement (you can find it in the config-rewrite branch at Github). The post explains what CONFIG REWRITE is.

An inverted workflow
===

Almost every unix daemon works like that:

1) You have a configuration file.
2) When you need to hack the configuration, you modify it and either restart the daemon, or send it a signal to reload the config.

It's been this way forever, but with Redis I took a different path since the start: as long as I understood people created "farms" of Redis servers either to provision them on-demand, or for internal usage where a big number of Redis servers are used, I really wanted to provide a different paradigm that was more "network oriented".

This is why I introduced the CONFIG command, with its sub commands GET and SET. At the start the ability of CONFIG was pretty basic, but now you can reconfigure almost every aspect of Redis on the fly, just sending commands to the server. This is extreme enough you can change persistence type when an instance is running. For example just typing:

CONFIG SET appendonly yes

Will switch on the Append Only File, will start a rewrite process to create the first AOF, and so forth. Similarly it is possible to alter from replication to memory limits and policy while the server is running, just interacting with the server with normal commands without any "hook" inside the operating system running Redis.

The symmetrical command CONFIG GET is used to query the configuration. Some users are more conservative in how they handle their servers and may want to always touch the configurations manually, but my idea was that the two commands provided quite a powerful system to handle a large number of instances in a scriptable way without the use of additional software layers, and avoiding restarts of the server that are costly, especially in the case of an in memory database.

However there was a major issue, after you modified an important configuration parameter with CONFIG SET, later you had to report the change into the redis.conf file manually, so that after the restart Redis would use the new config. As you can guess this was a huge limitation, basically the CONFIG API was only useful to hack the config live and avoid a reboot, but manual intervention or some other software layer to handle the configuration of your servers was needed anyway.

So the idea to solve this issue was to add as soon as possible a new command, CONFIG REWRITE, that would rewrite the Redis configuration to report the changes in memory.
So the new work flow would be like that:

CONFIG SET appendonly yes
CONFIG REWRITE

However I was trying to do a complete refactoring of the config.c file in order to implement this feature easily, but this was the best recipe to delay the feature forever… Finally I decided to implement it before the 2.8 release, without waiting for a refactoring, but implementing the new feature in a way that is refactor-friendly. So basically, we finally have it!

I believe that now that CONFIG REWRITE somewhat completes the triad of the configuration API, users will greatly benefit from that, both in the case of small users that will do configuration changes from redis-cli in a very reliable way, without a restart, without the possibility of configuration errors in redis.conf, and for big users of course where scripting a large farm of Redis instances can be very useful.

Before to continue: If you want to play with config rewrite, clone the config-rewrite branch at Github (but the feature will be merged into 2.8 and unstable soon), and play with it.

A gentle rewrite
===

Rewriting a configuration file is harder than it seems at first. Actually to do a brutal rewrite is trivial, you just write every configuration parameter with the current value in the new file, and you are done, but this has a number of side effects:

1) User comments and overall redis.conf structure go away, lost forever.
2) You get a number of things set explicitly to its default value.
3) After a server upgrade, because of "2", maybe you'll run an old default value that now changed.

So CONFIG REWRITE tries to follow a set of rules to make the rewriting more gentle, touching only the minimum possible, and preserving everything else.

This is how it works:

1) Comments are always preserved.
2) If an option was already present in the old redis.conf, the same line is used for the same option in the new file.
3) If an option was not present and is set at its default value, it is not added.
4) If an option was not present, but the new value is no longer its default, the option is appended at the end of the file.
5) All the no longer useful lines in the old configuration file are blanked (for example if there were three "save" options, but only two are used in the new config).

However if the configuration file for some reason no longer exists, CONFIG REWRITE will create it from scratch. The rules followed are the above anyway, just assuming an empty old configuration file, so the effect is to just produce a configuration file with every option not set to the default value.

An example
===

Just to make everything a bit more real, that's an example.

I start Redis with the following configuration file:

---
# This is a comment
save 3600 10
save 60 10000

# Hello world
dir .
---

After a CONFIG REWRITE without changing any parameter what I see is:

---
# This is a comment
save 3600 10
save 60 10000

# Hello world
dir "/Users/antirez/hack/redis/src"
---

As you can see the only difference is that "dir" was turned into an absolute path in that case, only because it was not already. The path is also quoted inside "" as certain options are rewritten in order to support special characters.

At this point I use the following commands:

redis 127.0.0.1:6379> config set appendonly yes
OK
redis 127.0.0.1:6379> config set maxmemory 10000000
OK
redis 127.0.0.1:6379> config rewrite
OK

Now the configuration file looks like that:

---
# This is a comment
save 3600 10
save 60 10000

# Hello world
dir "/Users/antirez/hack/redis/src"

# Generated by CONFIG REWRITE
maxmemory 10000000
appendonly yes
---

As you can see new configurations are appended at the end.

Finally I make a change that requires deleting some previous line:

redis 127.0.0.1:6379> config set save ""
OK
redis 127.0.0.1:6379> config rewrite
OK

The new config file is the following:

---
# This is a comment

# Hello world
dir "/Users/antirez/hack/redis/src"

# Generated by CONFIG REWRITE
maxmemory 10000000
appendonly yes
---

Comments are preserved but multiple blank lines are squeezed to a single one.

Thanks for reading! Comments