From e6ea603ad3ae53d4d33c48ec94699912dcfac716 Mon Sep 17 00:00:00 2001 From: antirez Date: Mon, 23 Jul 2018 14:13:58 +0200 Subject: [PATCH 1/2] Dynamic HZ: separate hz from the configured hz. This way we can remember what the user configured HZ is, but change the actual HZ dynamically if needed in the dynamic HZ feature implementation. --- src/config.c | 16 ++++++++-------- src/server.c | 5 ++++- src/server.h | 3 +++ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/config.c b/src/config.c index 54494c8e..5acea06d 100644 --- a/src/config.c +++ b/src/config.c @@ -441,9 +441,9 @@ void loadServerConfigFromString(char *config) { err = "argument must be 'yes' or 'no'"; goto loaderr; } } else if (!strcasecmp(argv[0],"hz") && argc == 2) { - server.hz = atoi(argv[1]); - if (server.hz < CONFIG_MIN_HZ) server.hz = CONFIG_MIN_HZ; - if (server.hz > CONFIG_MAX_HZ) server.hz = CONFIG_MAX_HZ; + server.config_hz = atoi(argv[1]); + if (server.config_hz < CONFIG_MIN_HZ) server.config_hz = CONFIG_MIN_HZ; + if (server.config_hz > CONFIG_MAX_HZ) server.config_hz = CONFIG_MAX_HZ; } else if (!strcasecmp(argv[0],"appendonly") && argc == 2) { int yes; @@ -1158,11 +1158,11 @@ void configSetCommand(client *c) { } config_set_numerical_field( "cluster-slave-validity-factor",server.cluster_slave_validity_factor,0,INT_MAX) { } config_set_numerical_field( - "hz",server.hz,0,INT_MAX) { + "hz",server.config_hz,0,INT_MAX) { /* Hz is more an hint from the user, so we accept values out of range * but cap them to reasonable values. */ - if (server.hz < CONFIG_MIN_HZ) server.hz = CONFIG_MIN_HZ; - if (server.hz > CONFIG_MAX_HZ) server.hz = CONFIG_MAX_HZ; + if (server.config_hz < CONFIG_MIN_HZ) server.config_hz = CONFIG_MIN_HZ; + if (server.config_hz > CONFIG_MAX_HZ) server.config_hz = CONFIG_MAX_HZ; } config_set_numerical_field( "watchdog-period",ll,0,INT_MAX) { if (ll) @@ -1329,7 +1329,7 @@ void configGetCommand(client *c) { config_get_numerical_field("slave-announce-port",server.slave_announce_port); config_get_numerical_field("min-slaves-to-write",server.repl_min_slaves_to_write); config_get_numerical_field("min-slaves-max-lag",server.repl_min_slaves_max_lag); - config_get_numerical_field("hz",server.hz); + config_get_numerical_field("hz",server.config_hz); config_get_numerical_field("cluster-node-timeout",server.cluster_node_timeout); config_get_numerical_field("cluster-migration-barrier",server.cluster_migration_barrier); config_get_numerical_field("cluster-slave-validity-factor",server.cluster_slave_validity_factor); @@ -2098,7 +2098,7 @@ int rewriteConfig(char *path) { rewriteConfigYesNoOption(state,"activedefrag",server.active_defrag_enabled,CONFIG_DEFAULT_ACTIVE_DEFRAG); rewriteConfigYesNoOption(state,"protected-mode",server.protected_mode,CONFIG_DEFAULT_PROTECTED_MODE); rewriteConfigClientoutputbufferlimitOption(state); - rewriteConfigNumericalOption(state,"hz",server.hz,CONFIG_DEFAULT_HZ); + rewriteConfigNumericalOption(state,"hz",server.config_hz,CONFIG_DEFAULT_HZ); rewriteConfigYesNoOption(state,"aof-rewrite-incremental-fsync",server.aof_rewrite_incremental_fsync,CONFIG_DEFAULT_AOF_REWRITE_INCREMENTAL_FSYNC); rewriteConfigYesNoOption(state,"rdb-save-incremental-fsync",server.rdb_save_incremental_fsync,CONFIG_DEFAULT_RDB_SAVE_INCREMENTAL_FSYNC); rewriteConfigYesNoOption(state,"aof-load-truncated",server.aof_load_truncated,CONFIG_DEFAULT_AOF_LOAD_TRUNCATED); diff --git a/src/server.c b/src/server.c index 93c0a46f..557af84d 100644 --- a/src/server.c +++ b/src/server.c @@ -1512,7 +1512,7 @@ void initServerConfig(void) { server.timezone = timezone; /* Initialized by tzset(). */ server.configfile = NULL; server.executable = NULL; - server.hz = CONFIG_DEFAULT_HZ; + server.config_hz = CONFIG_DEFAULT_HZ; server.arch_bits = (sizeof(long) == 8) ? 64 : 32; server.port = CONFIG_DEFAULT_SERVER_PORT; server.tcp_backlog = CONFIG_DEFAULT_TCP_BACKLOG; @@ -1991,6 +1991,7 @@ void initServer(void) { server.syslog_facility); } + server.hz = server.config_hz; server.pid = getpid(); server.current_client = NULL; server.clients = listCreate(); @@ -3074,6 +3075,7 @@ sds genRedisInfoString(char *section) { "uptime_in_seconds:%jd\r\n" "uptime_in_days:%jd\r\n" "hz:%d\r\n" + "configured_hz:%d\r\n" "lru_clock:%ld\r\n" "executable:%s\r\n" "config_file:%s\r\n", @@ -3097,6 +3099,7 @@ sds genRedisInfoString(char *section) { (intmax_t)uptime, (intmax_t)(uptime/(3600*24)), server.hz, + server.config_hz, (unsigned long) lruclock, server.executable ? server.executable : "", server.configfile ? server.configfile : ""); diff --git a/src/server.h b/src/server.h index dae7561d..4ac323da 100644 --- a/src/server.h +++ b/src/server.h @@ -923,6 +923,9 @@ struct redisServer { char *configfile; /* Absolute config file path, or NULL */ char *executable; /* Absolute executable file path. */ char **exec_argv; /* Executable argv vector (copy). */ + int config_hz; /* Configured HZ value. May be different than + the actual 'hz' field value if dynamic-hz + is enabled. */ int hz; /* serverCron() calls frequency in hertz */ redisDb *db; dict *commands; /* Command table */ From b65ddfb16a7060a543b523feadeca1234cffd323 Mon Sep 17 00:00:00 2001 From: antirez Date: Mon, 23 Jul 2018 14:21:04 +0200 Subject: [PATCH 2/2] Dynamic HZ: adapt cron frequency to number of clients. --- src/server.c | 11 +++++++++++ src/server.h | 11 ++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/server.c b/src/server.c index 557af84d..aff7911e 100644 --- a/src/server.c +++ b/src/server.c @@ -1096,6 +1096,17 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { /* Update the time cache. */ updateCachedTime(); + /* Adapt the server.hz value to the number of configured clients. If we have + * many clients, we want to call serverCron() with an higher frequency. */ + server.hz = server.config_hz; + while (listLength(server.clients) / server.hz > MAX_CLIENTS_PER_CLOCK_TICK) { + server.hz *= 2; + if (server.hz > CONFIG_MAX_HZ) { + server.hz = CONFIG_MAX_HZ; + break; + } + } + run_with_period(100) { trackInstantaneousMetric(STATS_METRIC_COMMAND,server.stat_numcommands); trackInstantaneousMetric(STATS_METRIC_NET_INPUT, diff --git a/src/server.h b/src/server.h index 4ac323da..a139b544 100644 --- a/src/server.h +++ b/src/server.h @@ -78,12 +78,13 @@ typedef long long mstime_t; /* millisecond time type. */ #define C_ERR -1 /* Static server configuration */ -#define CONFIG_DEFAULT_HZ 10 /* Time interrupt calls/sec. */ +#define CONFIG_DEFAULT_HZ 10 /* Time interrupt calls/sec. */ #define CONFIG_MIN_HZ 1 #define CONFIG_MAX_HZ 500 -#define CONFIG_DEFAULT_SERVER_PORT 6379 /* TCP port */ -#define CONFIG_DEFAULT_TCP_BACKLOG 511 /* TCP listen backlog */ -#define CONFIG_DEFAULT_CLIENT_TIMEOUT 0 /* default client timeout: infinite */ +#define MAX_CLIENTS_PER_CLOCK_TICK 200 /* HZ is adapted based on that. */ +#define CONFIG_DEFAULT_SERVER_PORT 6379 /* TCP port. */ +#define CONFIG_DEFAULT_TCP_BACKLOG 511 /* TCP listen backlog. */ +#define CONFIG_DEFAULT_CLIENT_TIMEOUT 0 /* Default client timeout: infinite */ #define CONFIG_DEFAULT_DBNUM 16 #define CONFIG_MAX_LINE 1024 #define CRON_DBS_PER_CALL 16 @@ -91,7 +92,7 @@ typedef long long mstime_t; /* millisecond time type. */ #define PROTO_SHARED_SELECT_CMDS 10 #define OBJ_SHARED_INTEGERS 10000 #define OBJ_SHARED_BULKHDR_LEN 32 -#define LOG_MAX_LEN 1024 /* Default maximum length of syslog messages */ +#define LOG_MAX_LEN 1024 /* Default maximum length of syslog messages.*/ #define AOF_REWRITE_PERC 100 #define AOF_REWRITE_MIN_SIZE (64*1024*1024) #define AOF_REWRITE_ITEMS_PER_CMD 64