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
Better systemd integration #5963
Conversation
dlopen() and use libsystemd.so's sd_notify() to signal the systemd service manager what state redis-server is in. Also, if redis-server has been configured to be supervised by systemd explicitly (i.e. systemd supervision wasn't auto-detected by looking at the environment), report server status to systemd more correctly: The service status will be switched from "loading" to "ready" after redis-server is ready to actually serve client requests. TODO: Make sure redis-server correctly reports service readiness if configured as a replica.
I'm not 100% sure that having a "server.masterhost" alone is enough to make this decision, but all usage scenarios that I personally know and have operated should be covered by this, according to my testing.
Good one! The use of However, I strongly disagree with the differing behavior of Still, this PR is a good step towards fixing #5826 and I'd love to see what @antirez has to say about it. |
Thanks, I wonder if @lamby has some wisdom about that. |
Could you explain all this in terms of systemd illiterate persons? That would help, thanks! |
Nothing particular from me, but +1 for generally better systemd integration but also +1 the -1 (hah!) regarding different behaviour... far too magical. :) |
@jtru in light of two people saying -1 to the change of the behavior, would you be open to change the patch in that regard? (here I'm working as mediator because I know zero about systemd, yet want to merge that). |
Bonus points for minimising the whitespace changes in the diff too! |
Thank you all for chiming in on the matter! :) I apologize for my lenghty response, but I think it's necessary, in order to not make redis users potentially shoot themsevles in the foot... @lamby and @antirez - I'm very open to make the changes you requested. I'd just like to have clarification on this - you would want the changed behaviour implemented, not the current behaviour (where "current" is "signal systemd that redis is ready to go without actually having loaded the dataset yet") while merely The original concern that caused me to stick to the split behaviour between auto-detection and explicit configuration is the following: systemd services have a property named However, with the new approach that my patch implements, redis won't progress to the ready state until the dataset has loaded (which, imo, is the correct way to behave). On our systems at work, bigger instances actually take more than 120 seconds to do that pretty regularly. With the default Now suppose a user has redis in operation with Since (And now, some optional reading about systemd-related stuff, since @antirez requested it :)) systemd defines a protocol where a service can tell systemd what state (loading, ready, stopping, failed, ...) it's in its lifecycle, so that systemd can initiate or defer other actions (i.e. begin starting or stopping other service) based on that information.
|
I'm afraid this has very quickly got above what I know about systemd so will be unable to comment/review/etc. :) |
Hm, I didn't mean to scare anyone away :/ I'll try to give a quick tl;dr overview: My patch makes it possible for redis to correctly inform systemd to start services that depend on it. However, for users where redis startup (= the time until clients can meaningfully be served after spawning) is slow, there's a config option in systemd (not redis) that might get the redis service killed during startup. That possible interaction should be hinted at somewhere. |
Don't worry, I didn't take it that way. I just lack the systemd knowledge and, alas, I lack the time to invest in learning it to have any kind of +0 or -0 here. Good luck. :) |
sd_notify crash courseSo we want to deploy an application which uses Redis, let's call that Both systemd units & initscripts can have service dependencies, whereby So all is fine and dandy, services can depend on each other, some order can be instilled into the chaotic and unpredictable boot process, and big swaths of reconnection&readiness-waiting crapcode can be not written in That's the crucial question, and the answer has two cases: Type=simple (Type=oneshot, Type=forking, Type=exec)In this case, systemd has no choice but assume that service is ready as soon as its main process has started. This sort-of works, except sometimes it doesn't. There's a scheduling race between mogrifier main() and redis main(). Said another way, there's a small window of time (hit by chance only sometimes) when Type=notifyHopefully, you can see the race problem above. The In this case, the service itself tells to the supervisor when initial startup has completed — via sending Assuming service dependencies were configured correctly, this feature allows to completely eliminate the startup race problem, so @antirez @lamby please see the above, I wrote it specifically to help you review the PR. Questions welcome of course. |
I see your point; let me counter it like this:
I do recognize there are situations when correctness has to be sacrificed for backward compatibility. But this isn't one of those cases. Just choose your nightmare: explaining |
I'm not sure why I'm being asked to review this. It should not block on me. |
Hey @jtru, just to make it clear: looks like this PR is currently blocked on you.
I.e. the As I see, there's no complaints about |
@antirez if you tell me to make the If you'd like, I would also include a word of warning in the default/sample |
A sample |
I'll have some time to work on this over the upcoming weekend (UTC+2 here) - I'll try my best to make everyone involved in this ticket happy ;) |
Thanks, just want to say that as @lamby I also lack the necessary systemd skill, so it's better to handle that in a "most of the community should be happy". Of course trying always to make simple stuff in the Redis style when possible. Thank you. |
This commit fixes bug reported at redis#5998. Thanks to @tomcat1102.
…ge reply (or POSTPONED_ARRAY) when redis appends the blocked client reply list to the real client, it didn't bother to check if it is in fact the master client. so a slave executing that module command will send replies to the master, causing the master to send the slave error responses, which will mess up the replication offset (slave will advance it's replication offset, and the master does not)
Always make redis communicate its actual status to systemd according to the Type=Notify service readiness protocol (refer to sd_notify(3) for details), no matter if systemd supervision was configured or auto-detected.
Hrmm... as you can probably tell, I'm not very familiar with github's git workflow practises ;) I'm not sure how my history (actually, my PR's series of commits to apply) ended up like this, but I'll try to sort it out (if all else fails, I'd just create a new branch from current unstable with my changes and create a new PR, if that is acceptable?) asap. As for the content of my changeset, this is what I intend to provide:
|
@jtru yea, I think you just did I highly recommend people to
|
Hey, @jtru and @ulidtko have you considered sending EXTEND_TIMEOUT_USEC= notifications? That could be a way to perhaps solve the timeout control from the redis side. This is also one of the events supported too now by start-stop-daemon on sysvinit-based systems (see https://manpages.debian.org/unstable/start-stop-daemon). |
|
||
serverLog(LL_NOTICE, "supervised by systemd, will signal readiness"); | ||
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) { | ||
handle = dlopen("libsystemd.so", RTLD_LAZY); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not a very good idea for various reasons. It will require systems to install the development packages to get the .so symlink to the current SONAME (say libsystemd.so.0). This also disregards any ABI, as we are using the non-versioned filename, which once libsystemd bumps its SOVERSION to say 1, it can happily crash or misbehave, etc. It also makes it very hard to spot when this needs to be updated, and no way to prevent loading the wrong library.
The only sane and safe way to use an external library in an optional way would be to create some kind of redis plugin which dynamically links at build-time against libsystemd.so, and then redis can safely use dlopen on its own plugin, because its ABI is guaranteed to match when built together, and the libsystemd ABI is respected because we are always linking against a versioned shared library.
Hey @guillemj,
Ah yes, please see #6052, it's a re-make of this PR. Also, your comment on @jtru see? This is the reason I'd use |
Please look at #6052 instead. I'm sorry for the confusion caused :/ |
I believe this fixes #5826 while also reducing implementation complexity by dynamically re-using
libsystemd.so
components.The patch as implemented only changes behaviour if the configuration specifies redis to be supervised by systemd explicitly. If the server is supervised by systemd "accidentally" only (i.e. by
supervised auto
being set and the redis unit file specifyingType=notify
for the service), the current behaviour of reporting readiness very early after startup is preserved. This should prevent users who aren't aware of the concequences of having a systemdType=notify
service in operation from having to deal with any changes.