提交 36a3b753 编写于 作者: M Matt Stancliff

Supervise redis processes only if configured

Adds configuration option 'supervised [no | upstart | systemd | auto]'

Also removed 'bzero' from the previous implementation because it's 2015.
(We could actually statically initialize those structs, but clang
throws an invalid warning when we try, so it looks bad even though it
isn't bad.)

Fixes #2264
上级 5e8b7e4f
......@@ -36,6 +36,17 @@
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize no
# If you run Redis from upstart or systemd, Redis can interact with your
# supervision tree. Options:
# supervised no - no supervision interaction
# supervised upstart - signal upstart by putting Redis into SIGSTOP mode
# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET
# supervised auto - detect upstart or systemd method based on
# UPSTART_JOB or NOTIFY_SOCKET environment variables
# Note: these supervision methods only signal "process is ready."
# They do not enable continuous liveness pings back to your supervisor.
supervised no
# When running daemonized, Redis writes a pid file in /var/run/redis.pid by
# default. You can specify a custom pid file location here.
pidfile /var/run/redis.pid
......
......@@ -60,6 +60,8 @@ clientBufferLimitsConfig clientBufferLimitsDefaults[REDIS_CLIENT_TYPE_COUNT] = {
* Config file parsing
*----------------------------------------------------------------------------*/
int supervisedToMode(const char *str);
int yesnotoi(char *s) {
if (!strcasecmp(s,"yes")) return 1;
else if (!strcasecmp(s,"no")) return 0;
......@@ -533,6 +535,15 @@ void loadServerConfigFromString(char *config) {
goto loaderr;
}
server.notify_keyspace_events = flags;
} else if (!strcasecmp(argv[0],"supervised") && argc == 2) {
int mode = supervisedToMode(argv[1]);
if (mode == -1) {
err = "Invalid option for 'supervised'. "
"Allowed values: 'upstart', 'systemd', 'auto', or 'no'";
goto loaderr;
}
server.supervised_mode = mode;
} else if (!strcasecmp(argv[0],"sentinel")) {
/* argc == 1 is handled by main() as we need to enter the sentinel
* mode ASAP. */
......@@ -1022,6 +1033,33 @@ char *maxmemoryToString() {
return s;
}
int supervisedToMode(const char *str) {
int mode;
if (!strcasecmp(str,"upstart")) {
mode = REDIS_SUPERVISED_UPSTART;
} else if (!strcasecmp(str,"systemd")) {
mode = REDIS_SUPERVISED_SYSTEMD;
} else if (!strcasecmp(str,"auto")) {
mode = REDIS_SUPERVISED_AUTODETECT;
} else if (!strcasecmp(str,"no")) {
mode = REDIS_SUPERVISED_NONE;
} else {
mode = -1;
}
return mode;
}
char *supervisedToString(void) {
char *s;
switch(server.supervised_mode) {
case REDIS_SUPERVISED_UPSTART: s = "upstart"; break;
case REDIS_SUPERVISED_SYSTEMD: s = "systemd"; break;
case REDIS_SUPERVISED_AUTODETECT: s = "auto"; break;
case REDIS_SUPERVISED_NONE: s = "no"; break;
default: s = "no"; break;
}
return s;
}
void configGetCommand(redisClient *c) {
robj *o = c->argv[2];
void *replylen = addDeferredMultiBulkLength(c);
......@@ -1177,6 +1215,11 @@ void configGetCommand(redisClient *c) {
addReplyBulkCString(c,s);
matches++;
}
if (stringmatch(pattern,"supervised",0)) {
addReplyBulkCString(c,"supervised");
addReplyBulkCString(c,supervisedToString());
matches++;
}
if (stringmatch(pattern,"client-output-buffer-limit",0)) {
sds buf = sdsempty();
int j;
......@@ -1872,6 +1915,12 @@ int rewriteConfig(char *path) {
rewriteConfigNumericalOption(state,"hz",server.hz,REDIS_DEFAULT_HZ);
rewriteConfigYesNoOption(state,"aof-rewrite-incremental-fsync",server.aof_rewrite_incremental_fsync,REDIS_DEFAULT_AOF_REWRITE_INCREMENTAL_FSYNC);
rewriteConfigYesNoOption(state,"aof-load-truncated",server.aof_load_truncated,REDIS_DEFAULT_AOF_LOAD_TRUNCATED);
rewriteConfigEnumOption(state,"supervised",server.supervised_mode,
"upstart", REDIS_SUPERVISED_UPSTART,
"systemd", REDIS_SUPERVISED_SYSTEMD,
"auto", REDIS_SUPERVISED_AUTODETECT,
"no", REDIS_SUPERVISED_NONE,
NULL, REDIS_SUPERVISED_NONE);
if (server.sentinel_mode) rewriteConfigSentinelOption(state);
/* Step 3: remove all the orphaned lines in the old file, that is, lines
......
......@@ -1416,6 +1416,7 @@ void initServerConfig(void) {
server.syslog_facility = LOG_LOCAL0;
server.daemonize = REDIS_DEFAULT_DAEMONIZE;
server.supervised = 0;
server.supervised_mode = REDIS_SUPERVISED_NONE;
server.aof_state = REDIS_AOF_OFF;
server.aof_fsync = REDIS_DEFAULT_AOF_FSYNC;
server.aof_no_fsync_on_rewrite = REDIS_DEFAULT_AOF_NO_FSYNC_ON_REWRITE;
......@@ -3591,8 +3592,23 @@ void redisSetProcTitle(char *title) {
/*
* Check whether systemd or upstart have been used to start redis.
*/
int redisIsSupervised(void) {
int redisSupervisedUpstart(void) {
const char *upstart_job = getenv("UPSTART_JOB");
if (!upstart_job) {
redisLog(REDIS_WARNING,
"upstart supervision requested, but UPSTART_JOB not found");
return 0;
}
redisLog(REDIS_NOTICE, "supervised by upstart, will stop to signal readyness");
raise(SIGSTOP);
unsetenv("UPSTART_JOB");
return 1;
}
int redisSupervisedSystemd(void) {
const char *notify_socket = getenv("NOTIFY_SOCKET");
int fd = 1;
struct sockaddr_un su;
......@@ -3600,31 +3616,24 @@ int redisIsSupervised(void) {
struct msghdr hdr;
int sendto_flags = 0;
if (upstart_job == NULL && notify_socket == NULL)
if (!notify_socket) {
redisLog(REDIS_WARNING,
"systemd supervision requested, but NOTIFY_SOCKET not found");
return 0;
if (upstart_job != NULL) {
redisLog(REDIS_NOTICE, "supervised by upstart, will stop to signal readyness");
raise(SIGSTOP);
unsetenv("UPSTART_JOB");
return 1;
}
/*
* If we got here, we're supervised by systemd.
*/
if ((strchr("@/", notify_socket[0])) == NULL ||
strlen(notify_socket) < 2)
if ((strchr("@/", notify_socket[0])) == NULL || strlen(notify_socket) < 2) {
return 0;
}
redisLog(REDIS_NOTICE, "supervised by systemd, will signal readyness");
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
redisLog(REDIS_WARNING, "cannot contact systemd socket %s", notify_socket);
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
redisLog(REDIS_WARNING,
"Can't connect to systemd socket %s", notify_socket);
return 0;
}
bzero(&su, sizeof(su));
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';
......@@ -3632,11 +3641,11 @@ int redisIsSupervised(void) {
if (notify_socket[0] == '@')
su.sun_path[0] = '\0';
bzero(&iov, sizeof(iov));
memset(&iov, 0, sizeof(iov));
iov.iov_base = "READY=1";
iov.iov_len = strlen("READY=1");
bzero(&hdr, sizeof(hdr));
memset(&hdr, 0, sizeof(hdr));
hdr.msg_name = &su;
hdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) +
strlen(notify_socket);
......@@ -3648,7 +3657,7 @@ int redisIsSupervised(void) {
sendto_flags |= MSG_NOSIGNAL;
#endif
if (sendmsg(fd, &hdr, sendto_flags) < 0) {
redisLog(REDIS_WARNING, "Cannot send notification to systemd");
redisLog(REDIS_WARNING, "Can't send notification to systemd");
close(fd);
return 0;
}
......@@ -3656,6 +3665,26 @@ int redisIsSupervised(void) {
return 1;
}
int redisIsSupervised(int mode) {
if (mode == REDIS_SUPERVISED_AUTODETECT) {
const char *upstart_job = getenv("UPSTART_JOB");
const char *notify_socket = getenv("NOTIFY_SOCKET");
if (upstart_job) {
redisSupervisedUpstart();
} else if (notify_socket) {
redisSupervisedSystemd();
}
} else if (mode == REDIS_SUPERVISED_UPSTART) {
return redisSupervisedUpstart();
} else if (mode == REDIS_SUPERVISED_SYSTEMD) {
return redisSupervisedSystemd();
}
return 0;
}
int main(int argc, char **argv) {
struct timeval tv;
......@@ -3762,8 +3791,8 @@ int main(int argc, char **argv) {
redisLog(REDIS_WARNING, "Warning: no config file specified, using the default config. In order to specify a config file use %s /path/to/%s.conf", argv[0], server.sentinel_mode ? "sentinel" : "redis");
}
server.supervised = redisIsSupervised();
int background = server.daemonize && server.supervised == 0;
server.supervised = redisIsSupervised(server.supervised_mode);
int background = server.daemonize && !server.supervised;
if (background) daemonize();
initServer();
if (background || server.pidfile) createPidFile();
......
......@@ -313,6 +313,12 @@ typedef long long mstime_t; /* millisecond time type. */
#define REDIS_LOG_RAW (1<<10) /* Modifier to log without timestamp */
#define REDIS_DEFAULT_VERBOSITY REDIS_NOTICE
/* Supervision options */
#define REDIS_SUPERVISED_NONE 0
#define REDIS_SUPERVISED_AUTODETECT 1
#define REDIS_SUPERVISED_SYSTEMD 2
#define REDIS_SUPERVISED_UPSTART 3
/* Anti-warning macro... */
#define REDIS_NOTUSED(V) ((void) V)
......@@ -740,7 +746,8 @@ struct redisServer {
int active_expire_enabled; /* Can be disabled for testing purposes. */
size_t client_max_querybuf_len; /* Limit for client query buffer length */
int dbnum; /* Total number of configured DBs */
int supervised; /* True if supervised by upstart or systemd */
int supervised; /* 1 if supervised, 0 otherwise. */
int supervised_mode; /* See REDIS_SUPERVISED_* */
int daemonize; /* True if running as a daemon */
clientBufferLimitsConfig client_obuf_limits[REDIS_CLIENT_TYPE_COUNT];
/* AOF persistence */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册