Commit be1b4aa9 authored by Oran Agra's avatar Oran Agra
Browse files

active defrag v2

- big keys are not defragged in one go from within the dict scan
  instead they are scanned in parts after the main dict hash bucket is done.
- add latency monitor sample for defrag
- change default active-defrag-cycle-min to induce lower latency
- make active defrag start a new scan right away if needed, so it's easier
  (for the test suite) to detect when it's done
- make active defrag quick the current cycle after each db / big key
- defrag  some non key long term global allocations
- some refactoring for smaller functions and more reusable code
- during dict rehashing, one scan iteration of the dict, can end up scanning
  one bucket in the smaller dict and many many buckets in the larger dict.
  so waiting for 16 scan iterations before checking the time, may be much too long.
parent aa57481d
...@@ -1302,8 +1302,12 @@ aof-rewrite-incremental-fsync yes ...@@ -1302,8 +1302,12 @@ aof-rewrite-incremental-fsync yes
# active-defrag-threshold-upper 100 # active-defrag-threshold-upper 100
# Minimal effort for defrag in CPU percentage # Minimal effort for defrag in CPU percentage
# active-defrag-cycle-min 25 # active-defrag-cycle-min 5
# Maximal effort for defrag in CPU percentage # Maximal effort for defrag in CPU percentage
# active-defrag-cycle-max 75 # active-defrag-cycle-max 75
# Maximum number of set/hash/zset/list fields that will be processed from
# the main dictionary scan
# active-defrag-max-scan-fields 1000
...@@ -537,6 +537,12 @@ void loadServerConfigFromString(char *config) { ...@@ -537,6 +537,12 @@ void loadServerConfigFromString(char *config) {
err = "active-defrag-cycle-max must be between 1 and 99"; err = "active-defrag-cycle-max must be between 1 and 99";
goto loaderr; goto loaderr;
} }
} else if (!strcasecmp(argv[0],"active-defrag-max-scan-fields") && argc == 2) {
server.active_defrag_max_scan_fields = strtoll(argv[1],NULL,10);
if (server.active_defrag_max_scan_fields < 1) {
err = "active-defrag-max-scan-fields must be positive";
goto loaderr;
}
} else if (!strcasecmp(argv[0],"hash-max-ziplist-entries") && argc == 2) { } else if (!strcasecmp(argv[0],"hash-max-ziplist-entries") && argc == 2) {
server.hash_max_ziplist_entries = memtoll(argv[1], NULL); server.hash_max_ziplist_entries = memtoll(argv[1], NULL);
} else if (!strcasecmp(argv[0],"hash-max-ziplist-value") && argc == 2) { } else if (!strcasecmp(argv[0],"hash-max-ziplist-value") && argc == 2) {
...@@ -1058,6 +1064,8 @@ void configSetCommand(client *c) { ...@@ -1058,6 +1064,8 @@ void configSetCommand(client *c) {
"active-defrag-cycle-min",server.active_defrag_cycle_min,1,99) { "active-defrag-cycle-min",server.active_defrag_cycle_min,1,99) {
} config_set_numerical_field( } config_set_numerical_field(
"active-defrag-cycle-max",server.active_defrag_cycle_max,1,99) { "active-defrag-cycle-max",server.active_defrag_cycle_max,1,99) {
} config_set_numerical_field(
"active-defrag-max-scan-fields",server.active_defrag_max_scan_fields,1,LLONG_MAX) {
} config_set_numerical_field( } config_set_numerical_field(
"auto-aof-rewrite-percentage",server.aof_rewrite_perc,0,LLONG_MAX){ "auto-aof-rewrite-percentage",server.aof_rewrite_perc,0,LLONG_MAX){
} config_set_numerical_field( } config_set_numerical_field(
...@@ -1239,6 +1247,7 @@ void configGetCommand(client *c) { ...@@ -1239,6 +1247,7 @@ void configGetCommand(client *c) {
config_get_numerical_field("active-defrag-ignore-bytes",server.active_defrag_ignore_bytes); config_get_numerical_field("active-defrag-ignore-bytes",server.active_defrag_ignore_bytes);
config_get_numerical_field("active-defrag-cycle-min",server.active_defrag_cycle_min); config_get_numerical_field("active-defrag-cycle-min",server.active_defrag_cycle_min);
config_get_numerical_field("active-defrag-cycle-max",server.active_defrag_cycle_max); config_get_numerical_field("active-defrag-cycle-max",server.active_defrag_cycle_max);
config_get_numerical_field("active-defrag-max-scan-fields",server.active_defrag_max_scan_fields);
config_get_numerical_field("auto-aof-rewrite-percentage", config_get_numerical_field("auto-aof-rewrite-percentage",
server.aof_rewrite_perc); server.aof_rewrite_perc);
config_get_numerical_field("auto-aof-rewrite-min-size", config_get_numerical_field("auto-aof-rewrite-min-size",
...@@ -2013,6 +2022,7 @@ int rewriteConfig(char *path) { ...@@ -2013,6 +2022,7 @@ int rewriteConfig(char *path) {
rewriteConfigBytesOption(state,"active-defrag-ignore-bytes",server.active_defrag_ignore_bytes,CONFIG_DEFAULT_DEFRAG_IGNORE_BYTES); rewriteConfigBytesOption(state,"active-defrag-ignore-bytes",server.active_defrag_ignore_bytes,CONFIG_DEFAULT_DEFRAG_IGNORE_BYTES);
rewriteConfigNumericalOption(state,"active-defrag-cycle-min",server.active_defrag_cycle_min,CONFIG_DEFAULT_DEFRAG_CYCLE_MIN); rewriteConfigNumericalOption(state,"active-defrag-cycle-min",server.active_defrag_cycle_min,CONFIG_DEFAULT_DEFRAG_CYCLE_MIN);
rewriteConfigNumericalOption(state,"active-defrag-cycle-max",server.active_defrag_cycle_max,CONFIG_DEFAULT_DEFRAG_CYCLE_MAX); rewriteConfigNumericalOption(state,"active-defrag-cycle-max",server.active_defrag_cycle_max,CONFIG_DEFAULT_DEFRAG_CYCLE_MAX);
rewriteConfigNumericalOption(state,"active-defrag-max-scan-fields",server.active_defrag_max_scan_fields,CONFIG_DEFAULT_DEFRAG_MAX_SCAN_FIELDS);
rewriteConfigYesNoOption(state,"appendonly",server.aof_state != AOF_OFF,0); rewriteConfigYesNoOption(state,"appendonly",server.aof_state != AOF_OFF,0);
rewriteConfigStringOption(state,"appendfilename",server.aof_filename,CONFIG_DEFAULT_AOF_FILENAME); rewriteConfigStringOption(state,"appendfilename",server.aof_filename,CONFIG_DEFAULT_AOF_FILENAME);
rewriteConfigEnumOption(state,"appendfsync",server.aof_fsync,aof_fsync_enum,CONFIG_DEFAULT_AOF_FSYNC); rewriteConfigEnumOption(state,"appendfsync",server.aof_fsync,aof_fsync_enum,CONFIG_DEFAULT_AOF_FSYNC);
......
This diff is collapsed.
...@@ -1389,6 +1389,7 @@ void initServerConfig(void) { ...@@ -1389,6 +1389,7 @@ void initServerConfig(void) {
server.active_defrag_threshold_upper = CONFIG_DEFAULT_DEFRAG_THRESHOLD_UPPER; server.active_defrag_threshold_upper = CONFIG_DEFAULT_DEFRAG_THRESHOLD_UPPER;
server.active_defrag_cycle_min = CONFIG_DEFAULT_DEFRAG_CYCLE_MIN; server.active_defrag_cycle_min = CONFIG_DEFAULT_DEFRAG_CYCLE_MIN;
server.active_defrag_cycle_max = CONFIG_DEFAULT_DEFRAG_CYCLE_MAX; server.active_defrag_cycle_max = CONFIG_DEFAULT_DEFRAG_CYCLE_MAX;
server.active_defrag_max_scan_fields = CONFIG_DEFAULT_DEFRAG_MAX_SCAN_FIELDS;
server.proto_max_bulk_len = CONFIG_DEFAULT_PROTO_MAX_BULK_LEN; server.proto_max_bulk_len = CONFIG_DEFAULT_PROTO_MAX_BULK_LEN;
server.client_max_querybuf_len = PROTO_MAX_QUERYBUF_LEN; server.client_max_querybuf_len = PROTO_MAX_QUERYBUF_LEN;
server.saveparams = NULL; server.saveparams = NULL;
...@@ -1806,6 +1807,7 @@ void resetServerStats(void) { ...@@ -1806,6 +1807,7 @@ void resetServerStats(void) {
server.stat_active_defrag_misses = 0; server.stat_active_defrag_misses = 0;
server.stat_active_defrag_key_hits = 0; server.stat_active_defrag_key_hits = 0;
server.stat_active_defrag_key_misses = 0; server.stat_active_defrag_key_misses = 0;
server.stat_active_defrag_scanned = 0;
server.stat_fork_time = 0; server.stat_fork_time = 0;
server.stat_fork_rate = 0; server.stat_fork_rate = 0;
server.stat_rejected_conn = 0; server.stat_rejected_conn = 0;
...@@ -1894,6 +1896,7 @@ void initServer(void) { ...@@ -1894,6 +1896,7 @@ void initServer(void) {
server.db[j].watched_keys = dictCreate(&keylistDictType,NULL); server.db[j].watched_keys = dictCreate(&keylistDictType,NULL);
server.db[j].id = j; server.db[j].id = j;
server.db[j].avg_ttl = 0; server.db[j].avg_ttl = 0;
server.db[j].defrag_later = listCreate();
} }
evictionPoolAlloc(); /* Initialize the LRU keys pool. */ evictionPoolAlloc(); /* Initialize the LRU keys pool. */
server.pubsub_channels = dictCreate(&keylistDictType,NULL); server.pubsub_channels = dictCreate(&keylistDictType,NULL);
......
...@@ -159,8 +159,9 @@ typedef long long mstime_t; /* millisecond time type. */ ...@@ -159,8 +159,9 @@ typedef long long mstime_t; /* millisecond time type. */
#define CONFIG_DEFAULT_DEFRAG_THRESHOLD_LOWER 10 /* don't defrag when fragmentation is below 10% */ #define CONFIG_DEFAULT_DEFRAG_THRESHOLD_LOWER 10 /* don't defrag when fragmentation is below 10% */
#define CONFIG_DEFAULT_DEFRAG_THRESHOLD_UPPER 100 /* maximum defrag force at 100% fragmentation */ #define CONFIG_DEFAULT_DEFRAG_THRESHOLD_UPPER 100 /* maximum defrag force at 100% fragmentation */
#define CONFIG_DEFAULT_DEFRAG_IGNORE_BYTES (100<<20) /* don't defrag if frag overhead is below 100mb */ #define CONFIG_DEFAULT_DEFRAG_IGNORE_BYTES (100<<20) /* don't defrag if frag overhead is below 100mb */
#define CONFIG_DEFAULT_DEFRAG_CYCLE_MIN 25 /* 25% CPU min (at lower threshold) */ #define CONFIG_DEFAULT_DEFRAG_CYCLE_MIN 5 /* 5% CPU min (at lower threshold) */
#define CONFIG_DEFAULT_DEFRAG_CYCLE_MAX 75 /* 75% CPU max (at upper threshold) */ #define CONFIG_DEFAULT_DEFRAG_CYCLE_MAX 75 /* 75% CPU max (at upper threshold) */
#define CONFIG_DEFAULT_DEFRAG_MAX_SCAN_FIELDS 1000 /* keys with more than 1000 fields will be processed separately */
#define CONFIG_DEFAULT_PROTO_MAX_BULK_LEN (512ll*1024*1024) /* Bulk request max size */ #define CONFIG_DEFAULT_PROTO_MAX_BULK_LEN (512ll*1024*1024) /* Bulk request max size */
#define ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 20 /* Loopkups per loop. */ #define ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 20 /* Loopkups per loop. */
...@@ -622,6 +623,7 @@ typedef struct redisDb { ...@@ -622,6 +623,7 @@ typedef struct redisDb {
dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */ dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */
int id; /* Database ID */ int id; /* Database ID */
long long avg_ttl; /* Average TTL, just for stats */ long long avg_ttl; /* Average TTL, just for stats */
list *defrag_later; /* List of key names to attempt to defrag one by one, gradually. */
} redisDb; } redisDb;
/* Client MULTI/EXEC state */ /* Client MULTI/EXEC state */
...@@ -957,6 +959,7 @@ struct redisServer { ...@@ -957,6 +959,7 @@ struct redisServer {
long long stat_active_defrag_misses; /* number of allocations scanned but not moved */ long long stat_active_defrag_misses; /* number of allocations scanned but not moved */
long long stat_active_defrag_key_hits; /* number of keys with moved allocations */ long long stat_active_defrag_key_hits; /* number of keys with moved allocations */
long long stat_active_defrag_key_misses;/* number of keys scanned and not moved */ long long stat_active_defrag_key_misses;/* number of keys scanned and not moved */
long long stat_active_defrag_scanned; /* number of dictEntries scanned */
size_t stat_peak_memory; /* Max used memory record */ size_t stat_peak_memory; /* Max used memory record */
long long stat_fork_time; /* Time needed to perform latest fork() */ long long stat_fork_time; /* Time needed to perform latest fork() */
double stat_fork_rate; /* Fork rate in GB/sec. */ double stat_fork_rate; /* Fork rate in GB/sec. */
...@@ -992,6 +995,7 @@ struct redisServer { ...@@ -992,6 +995,7 @@ struct redisServer {
int active_defrag_threshold_upper; /* maximum percentage of fragmentation at which we use maximum effort */ int active_defrag_threshold_upper; /* maximum percentage of fragmentation at which we use maximum effort */
int active_defrag_cycle_min; /* minimal effort for defrag in CPU percentage */ int active_defrag_cycle_min; /* minimal effort for defrag in CPU percentage */
int active_defrag_cycle_max; /* maximal effort for defrag in CPU percentage */ int active_defrag_cycle_max; /* maximal effort for defrag in CPU percentage */
unsigned long active_defrag_max_scan_fields; /* maximum number of fields of set/hash/zset/list to process from within the main dict scan */
size_t client_max_querybuf_len; /* Limit for client query buffer length */ size_t client_max_querybuf_len; /* Limit for client query buffer length */
int dbnum; /* Total number of configured DBs */ int dbnum; /* Total number of configured DBs */
int supervised; /* 1 if supervised, 0 otherwise. */ int supervised; /* 1 if supervised, 0 otherwise. */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment