Merge pull request #6052 from jtru/better-systemd-integration-v2
Better systemd integration v2
This commit is contained in:
commit
f4b8197060
25
src/Makefile
25
src/Makefile
@ -32,6 +32,7 @@ OPT=$(OPTIMIZATION)
|
|||||||
PREFIX?=/usr/local
|
PREFIX?=/usr/local
|
||||||
INSTALL_BIN=$(PREFIX)/bin
|
INSTALL_BIN=$(PREFIX)/bin
|
||||||
INSTALL=install
|
INSTALL=install
|
||||||
|
PKG_CONFIG?=pkg-config
|
||||||
|
|
||||||
# Default allocator defaults to Jemalloc if it's not an ARM
|
# Default allocator defaults to Jemalloc if it's not an ARM
|
||||||
MALLOC=libc
|
MALLOC=libc
|
||||||
@ -140,6 +141,30 @@ endif
|
|||||||
# Include paths to dependencies
|
# Include paths to dependencies
|
||||||
FINAL_CFLAGS+= -I../deps/hiredis -I../deps/linenoise -I../deps/lua/src
|
FINAL_CFLAGS+= -I../deps/hiredis -I../deps/linenoise -I../deps/lua/src
|
||||||
|
|
||||||
|
# Determine systemd support and/or build preference (defaulting to auto-detection)
|
||||||
|
BUILD_WITH_SYSTEMD=no
|
||||||
|
# If 'USE_SYSTEMD' in the environment is neither "no" nor "yes", try to
|
||||||
|
# auto-detect libsystemd's presence and link accordingly.
|
||||||
|
ifneq ($(USE_SYSTEMD),no)
|
||||||
|
LIBSYSTEMD_PKGCONFIG := $(shell $(PKG_CONFIG) --exists libsystemd && echo $$?)
|
||||||
|
# If libsystemd cannot be detected, continue building without support for it
|
||||||
|
# (unless a later check tells us otherwise)
|
||||||
|
ifeq ($(LIBSYSTEMD_PKGCONFIG),0)
|
||||||
|
BUILD_WITH_SYSTEMD=yes
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
ifeq ($(USE_SYSTEMD),yes)
|
||||||
|
ifneq ($(LIBSYSTEMD_PKGCONFIG),0)
|
||||||
|
$(error USE_SYSTEMD is set to "$(USE_SYSTEMD)", but $(PKG_CONFIG) cannot find libsystemd)
|
||||||
|
endif
|
||||||
|
# Force building with libsystemd
|
||||||
|
BUILD_WITH_SYSTEMD=yes
|
||||||
|
endif
|
||||||
|
ifeq ($(BUILD_WITH_SYSTEMD),yes)
|
||||||
|
FINAL_LIBS+=$(shell $(PKG_CONFIG) --libs libsystemd)
|
||||||
|
FINAL_CFLAGS+= -DHAVE_LIBSYSTEMD
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(MALLOC),tcmalloc)
|
ifeq ($(MALLOC),tcmalloc)
|
||||||
FINAL_CFLAGS+= -DUSE_TCMALLOC
|
FINAL_CFLAGS+= -DUSE_TCMALLOC
|
||||||
FINAL_LIBS+= -ltcmalloc
|
FINAL_LIBS+= -ltcmalloc
|
||||||
|
@ -1665,6 +1665,11 @@ void readSyncBulkPayload(connection *conn) {
|
|||||||
if (server.repl_backlog == NULL) createReplicationBacklog();
|
if (server.repl_backlog == NULL) createReplicationBacklog();
|
||||||
serverLog(LL_NOTICE, "MASTER <-> REPLICA sync: Finished with success");
|
serverLog(LL_NOTICE, "MASTER <-> REPLICA sync: Finished with success");
|
||||||
|
|
||||||
|
if (server.supervised_mode == SUPERVISED_SYSTEMD) {
|
||||||
|
redisCommunicateSystemd("STATUS=MASTER <-> REPLICA sync: Finished with success. Ready to accept connections.\n");
|
||||||
|
redisCommunicateSystemd("READY=1\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* Restart the AOF subsystem now that we finished the sync. This
|
/* Restart the AOF subsystem now that we finished the sync. This
|
||||||
* will trigger an AOF rewrite, and when done will start appending
|
* will trigger an AOF rewrite, and when done will start appending
|
||||||
* to the new file. */
|
* to the new file. */
|
||||||
|
79
src/server.c
79
src/server.c
@ -3558,6 +3558,8 @@ int prepareForShutdown(int flags) {
|
|||||||
int nosave = flags & SHUTDOWN_NOSAVE;
|
int nosave = flags & SHUTDOWN_NOSAVE;
|
||||||
|
|
||||||
serverLog(LL_WARNING,"User requested shutdown...");
|
serverLog(LL_WARNING,"User requested shutdown...");
|
||||||
|
if (server.supervised_mode == SUPERVISED_SYSTEMD)
|
||||||
|
redisCommunicateSystemd("STOPPING=1\n");
|
||||||
|
|
||||||
/* Kill all the Lua debugger forked sessions. */
|
/* Kill all the Lua debugger forked sessions. */
|
||||||
ldbKillForkedSessions();
|
ldbKillForkedSessions();
|
||||||
@ -3599,6 +3601,8 @@ int prepareForShutdown(int flags) {
|
|||||||
/* Create a new RDB file before exiting. */
|
/* Create a new RDB file before exiting. */
|
||||||
if ((server.saveparamslen > 0 && !nosave) || save) {
|
if ((server.saveparamslen > 0 && !nosave) || save) {
|
||||||
serverLog(LL_NOTICE,"Saving the final RDB snapshot before exiting.");
|
serverLog(LL_NOTICE,"Saving the final RDB snapshot before exiting.");
|
||||||
|
if (server.supervised_mode == SUPERVISED_SYSTEMD)
|
||||||
|
redisCommunicateSystemd("STATUS=Saving the final RDB snapshot\n");
|
||||||
/* Snapshotting. Perform a SYNC SAVE and exit */
|
/* Snapshotting. Perform a SYNC SAVE and exit */
|
||||||
rdbSaveInfo rsi, *rsiptr;
|
rdbSaveInfo rsi, *rsiptr;
|
||||||
rsiptr = rdbPopulateSaveInfo(&rsi);
|
rsiptr = rdbPopulateSaveInfo(&rsi);
|
||||||
@ -3609,6 +3613,8 @@ int prepareForShutdown(int flags) {
|
|||||||
* saving aborted, handling special stuff like slaves pending for
|
* saving aborted, handling special stuff like slaves pending for
|
||||||
* synchronization... */
|
* synchronization... */
|
||||||
serverLog(LL_WARNING,"Error trying to save the DB, can't exit.");
|
serverLog(LL_WARNING,"Error trying to save the DB, can't exit.");
|
||||||
|
if (server.supervised_mode == SUPERVISED_SYSTEMD)
|
||||||
|
redisCommunicateSystemd("STATUS=Error trying to save the DB, can't exit.\n");
|
||||||
return C_ERR;
|
return C_ERR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4774,61 +4780,19 @@ int redisSupervisedUpstart(void) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int redisSupervisedSystemd(void) {
|
int redisCommunicateSystemd(const char *sd_notify_msg) {
|
||||||
const char *notify_socket = getenv("NOTIFY_SOCKET");
|
const char *notify_socket = getenv("NOTIFY_SOCKET");
|
||||||
int fd = 1;
|
|
||||||
struct sockaddr_un su;
|
|
||||||
struct iovec iov;
|
|
||||||
struct msghdr hdr;
|
|
||||||
int sendto_flags = 0;
|
|
||||||
|
|
||||||
if (!notify_socket) {
|
if (!notify_socket) {
|
||||||
serverLog(LL_WARNING,
|
serverLog(LL_WARNING,
|
||||||
"systemd supervision requested, but NOTIFY_SOCKET not found");
|
"systemd supervision requested, but NOTIFY_SOCKET not found");
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((strchr("@/", notify_socket[0])) == NULL || strlen(notify_socket) < 2) {
|
#ifdef HAVE_LIBSYSTEMD
|
||||||
return 0;
|
(void) sd_notify(0, sd_notify_msg);
|
||||||
}
|
#else
|
||||||
|
UNUSED(sd_notify_msg);
|
||||||
serverLog(LL_NOTICE, "supervised by systemd, will signal readiness");
|
#endif
|
||||||
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
|
return 0;
|
||||||
serverLog(LL_WARNING,
|
|
||||||
"Can't connect to systemd socket %s", notify_socket);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&su, 0, sizeof(su));
|
|
||||||
su.sun_family = AF_UNIX;
|
|
||||||
strncpy (su.sun_path, notify_socket, sizeof(su.sun_path) -1);
|
|
||||||
su.sun_path[sizeof(su.sun_path) - 1] = '\0';
|
|
||||||
|
|
||||||
if (notify_socket[0] == '@')
|
|
||||||
su.sun_path[0] = '\0';
|
|
||||||
|
|
||||||
memset(&iov, 0, sizeof(iov));
|
|
||||||
iov.iov_base = "READY=1";
|
|
||||||
iov.iov_len = strlen("READY=1");
|
|
||||||
|
|
||||||
memset(&hdr, 0, sizeof(hdr));
|
|
||||||
hdr.msg_name = &su;
|
|
||||||
hdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) +
|
|
||||||
strlen(notify_socket);
|
|
||||||
hdr.msg_iov = &iov;
|
|
||||||
hdr.msg_iovlen = 1;
|
|
||||||
|
|
||||||
unsetenv("NOTIFY_SOCKET");
|
|
||||||
#ifdef HAVE_MSG_NOSIGNAL
|
|
||||||
sendto_flags |= MSG_NOSIGNAL;
|
|
||||||
#endif
|
|
||||||
if (sendmsg(fd, &hdr, sendto_flags) < 0) {
|
|
||||||
serverLog(LL_WARNING, "Can't send notification to systemd");
|
|
||||||
close(fd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int redisIsSupervised(int mode) {
|
int redisIsSupervised(int mode) {
|
||||||
@ -4839,12 +4803,17 @@ int redisIsSupervised(int mode) {
|
|||||||
if (upstart_job) {
|
if (upstart_job) {
|
||||||
redisSupervisedUpstart();
|
redisSupervisedUpstart();
|
||||||
} else if (notify_socket) {
|
} else if (notify_socket) {
|
||||||
redisSupervisedSystemd();
|
server.supervised_mode = SUPERVISED_SYSTEMD;
|
||||||
|
serverLog(LL_WARNING,
|
||||||
|
"WARNING auto-supervised by systemd - you MUST set appropriate values for TimeoutStartSec and TimeoutStopSec in your service unit.");
|
||||||
|
return redisCommunicateSystemd("STATUS=Redis is loading...\n");
|
||||||
}
|
}
|
||||||
} else if (mode == SUPERVISED_UPSTART) {
|
} else if (mode == SUPERVISED_UPSTART) {
|
||||||
return redisSupervisedUpstart();
|
return redisSupervisedUpstart();
|
||||||
} else if (mode == SUPERVISED_SYSTEMD) {
|
} else if (mode == SUPERVISED_SYSTEMD) {
|
||||||
return redisSupervisedSystemd();
|
serverLog(LL_WARNING,
|
||||||
|
"WARNING supervised by systemd - you MUST set appropriate values for TimeoutStartSec and TimeoutStopSec in your service unit.");
|
||||||
|
return redisCommunicateSystemd("STATUS=Redis is loading...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -5037,6 +5006,14 @@ int main(int argc, char **argv) {
|
|||||||
serverLog(LL_NOTICE,"Ready to accept connections");
|
serverLog(LL_NOTICE,"Ready to accept connections");
|
||||||
if (server.sofd > 0)
|
if (server.sofd > 0)
|
||||||
serverLog(LL_NOTICE,"The server is now ready to accept connections at %s", server.unixsocket);
|
serverLog(LL_NOTICE,"The server is now ready to accept connections at %s", server.unixsocket);
|
||||||
|
if (server.supervised_mode == SUPERVISED_SYSTEMD) {
|
||||||
|
if (!server.masterhost) {
|
||||||
|
redisCommunicateSystemd("STATUS=Ready to accept connections\n");
|
||||||
|
redisCommunicateSystemd("READY=1\n");
|
||||||
|
} else {
|
||||||
|
redisCommunicateSystemd("STATUS=Waiting for MASTER <-> REPLICA sync\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
InitServerLast();
|
InitServerLast();
|
||||||
sentinelIsRunning();
|
sentinelIsRunning();
|
||||||
|
@ -50,6 +50,10 @@
|
|||||||
#include <lua.h>
|
#include <lua.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSYSTEMD
|
||||||
|
#include <systemd/sd-daemon.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef long long mstime_t; /* millisecond time type. */
|
typedef long long mstime_t; /* millisecond time type. */
|
||||||
typedef long long ustime_t; /* microsecond time type. */
|
typedef long long ustime_t; /* microsecond time type. */
|
||||||
|
|
||||||
@ -1544,6 +1548,7 @@ uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l);
|
|||||||
void exitFromChild(int retcode);
|
void exitFromChild(int retcode);
|
||||||
size_t redisPopcount(void *s, long count);
|
size_t redisPopcount(void *s, long count);
|
||||||
void redisSetProcTitle(char *title);
|
void redisSetProcTitle(char *title);
|
||||||
|
int redisCommunicateSystemd(const char *sd_notify_msg);
|
||||||
|
|
||||||
/* networking.c -- Networking and Client related operations */
|
/* networking.c -- Networking and Client related operations */
|
||||||
client *createClient(connection *conn);
|
client *createClient(connection *conn);
|
||||||
|
@ -73,6 +73,16 @@ if [ "$(id -u)" -ne 0 ] ; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
#bail if this system is managed by systemd
|
||||||
|
_pid_1_exe="$(readlink -f /proc/1/exe)"
|
||||||
|
if [ "${_pid_1_exe##*/}" = systemd ]
|
||||||
|
then
|
||||||
|
echo "This systems seems to use systemd."
|
||||||
|
echo "Please take a look at the provided example service unit files in this directory, and adapt and install them. Sorry!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
unset _pid_1_exe
|
||||||
|
|
||||||
if ! echo $REDIS_PORT | egrep -q '^[0-9]+$' ; then
|
if ! echo $REDIS_PORT | egrep -q '^[0-9]+$' ; then
|
||||||
_MANUAL_EXECUTION=true
|
_MANUAL_EXECUTION=true
|
||||||
#Read the redis port
|
#Read the redis port
|
||||||
|
37
utils/systemd-redis_multiple_servers@.service
Normal file
37
utils/systemd-redis_multiple_servers@.service
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# example systemd template service unit file for multiple redis-servers
|
||||||
|
#
|
||||||
|
# You can use this file as a blueprint for your actual template service unit
|
||||||
|
# file, if you intend to run multiple independent redis-server instances in
|
||||||
|
# parallel using systemd's "template unit files" feature. If you do, you will
|
||||||
|
# want to choose a better basename for your service unit by renaming this file
|
||||||
|
# when copying it.
|
||||||
|
#
|
||||||
|
# Please take a look at the provided "systemd-redis_server.service" example
|
||||||
|
# service unit file, too, if you choose to use this approach at managing
|
||||||
|
# multiple redis-server instances via systemd.
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Redis data structure server - instance %i
|
||||||
|
Documentation=https://redis.io/documentation
|
||||||
|
# This template unit assumes your redis-server configuration file(s)
|
||||||
|
# to live at /etc/redis/redis_server_<INSTANCE_NAME>.conf
|
||||||
|
AssertPathExists=/etc/redis/redis_server_%i.conf
|
||||||
|
#Before=your_application.service another_example_application.service
|
||||||
|
#AssertPathExists=/var/lib/redis
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/local/bin/redis-server /etc/redis/redis_server_%i.conf
|
||||||
|
LimitNOFILE=10032
|
||||||
|
NoNewPrivileges=yes
|
||||||
|
#OOMScoreAdjust=-900
|
||||||
|
#PrivateTmp=yes
|
||||||
|
Type=notify
|
||||||
|
TimeoutStartSec=infinity
|
||||||
|
TimeoutStopSec=infinity
|
||||||
|
UMask=0077
|
||||||
|
#User=redis
|
||||||
|
#Group=redis
|
||||||
|
#WorkingDirectory=/var/lib/redis
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
41
utils/systemd-redis_server.service
Normal file
41
utils/systemd-redis_server.service
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# example systemd service unit file for redis-server
|
||||||
|
#
|
||||||
|
# In order to use this as a template for providing a redis service in your
|
||||||
|
# environment, _at the very least_ make sure to adapt the redis configuration
|
||||||
|
# file you intend to use as needed (make sure to set "supervised systemd"), and
|
||||||
|
# to set sane TimeoutStartSec and TimeoutStopSec property values in the unit's
|
||||||
|
# "[Service]" section to fit your needs.
|
||||||
|
#
|
||||||
|
# Some properties, such as User= and Group=, are highly desirable for virtually
|
||||||
|
# all deployments of redis, but cannot be provided in a manner that fits all
|
||||||
|
# expectable environments. Some of these properties have been commented out in
|
||||||
|
# this example service unit file, but you are highly encouraged to set them to
|
||||||
|
# fit your needs.
|
||||||
|
#
|
||||||
|
# Please refer to systemd.unit(5), systemd.service(5), and systemd.exec(5) for
|
||||||
|
# more information.
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Redis data structure server
|
||||||
|
Documentation=https://redis.io/documentation
|
||||||
|
#Before=your_application.service another_example_application.service
|
||||||
|
#AssertPathExists=/var/lib/redis
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/local/bin/redis-server --supervised systemd --daemonize no
|
||||||
|
## Alternatively, have redis-server load a configuration file:
|
||||||
|
#ExecStart=/usr/local/bin/redis-server /path/to/your/redis.conf
|
||||||
|
LimitNOFILE=10032
|
||||||
|
NoNewPrivileges=yes
|
||||||
|
#OOMScoreAdjust=-900
|
||||||
|
#PrivateTmp=yes
|
||||||
|
Type=notify
|
||||||
|
TimeoutStartSec=infinity
|
||||||
|
TimeoutStopSec=infinity
|
||||||
|
UMask=0077
|
||||||
|
#User=redis
|
||||||
|
#Group=redis
|
||||||
|
#WorkingDirectory=/var/lib/redis
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
Loading…
x
Reference in New Issue
Block a user