Merge pull request #4883 from itamarhaber/lua_scripts-in-info-memory

Adds memory information about the scripts' cache to INFO
This commit is contained in:
Salvatore Sanfilippo 2018-07-23 18:43:05 +02:00 committed by GitHub
commit 445a2a2b1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 2 deletions

View File

@ -1017,6 +1017,18 @@ struct redisMemOverhead *getMemoryOverheadData(void) {
mh->aof_buffer = mem; mh->aof_buffer = mem;
mem_total+=mem; mem_total+=mem;
mem = 0;
mem += dictSize(server.lua_scripts) * sizeof(dictEntry) +
dictSlots(server.lua_scripts) * sizeof(dictEntry*);
mem += dictSize(server.repl_scriptcache_dict) * sizeof(dictEntry) +
dictSlots(server.repl_scriptcache_dict) * sizeof(dictEntry*);
if (listLength(server.repl_scriptcache_fifo) > 0) {
mem += listLength(server.repl_scriptcache_fifo) * (sizeof(listNode) +
sdsZmallocSize(listNodeValue(listFirst(server.repl_scriptcache_fifo))));
}
mh->lua_caches = mem;
mem_total+=mem;
for (j = 0; j < server.dbnum; j++) { for (j = 0; j < server.dbnum; j++) {
redisDb *db = server.db+j; redisDb *db = server.db+j;
long long keyscount = dictSize(db->dict); long long keyscount = dictSize(db->dict);
@ -1074,6 +1086,7 @@ sds getMemoryDoctorReport(void) {
int high_alloc_rss = 0; /* High rss overhead. */ int high_alloc_rss = 0; /* High rss overhead. */
int big_slave_buf = 0; /* Slave buffers are too big. */ int big_slave_buf = 0; /* Slave buffers are too big. */
int big_client_buf = 0; /* Client buffers are too big. */ int big_client_buf = 0; /* Client buffers are too big. */
int many_scripts = 0; /* Script cache has too many scripts. */
int num_reports = 0; int num_reports = 0;
struct redisMemOverhead *mh = getMemoryOverheadData(); struct redisMemOverhead *mh = getMemoryOverheadData();
@ -1124,6 +1137,12 @@ sds getMemoryDoctorReport(void) {
big_slave_buf = 1; big_slave_buf = 1;
num_reports++; num_reports++;
} }
/* Too many (over 42) scripts are cached? */
if (dictSize(server.lua_scripts) > 42) {
many_scripts = 1;
num_reports++;
}
} }
sds s; sds s;
@ -1153,7 +1172,7 @@ sds getMemoryDoctorReport(void) {
s = sdscatprintf(s," * High allocator RSS overhead: This instance has an RSS memory overhead is greater than 1.1 (this means that the Resident Set Size of the allocator is much larger than the sum what the allocator actually holds). This problem is usually due to a large peak memory (check if there is a peak memory entry above in the report), you can try the MEMORY PURGE command to reclaim it.\n\n"); s = sdscatprintf(s," * High allocator RSS overhead: This instance has an RSS memory overhead is greater than 1.1 (this means that the Resident Set Size of the allocator is much larger than the sum what the allocator actually holds). This problem is usually due to a large peak memory (check if there is a peak memory entry above in the report), you can try the MEMORY PURGE command to reclaim it.\n\n");
} }
if (high_proc_rss) { if (high_proc_rss) {
s = sdscatprintf(s," * High process RSS overhead: This instance has non-allocator RSS memory overhead is greater than 1.1 (this means that the Resident Set Size of the Redis process is much larger than the RSS the allocator holds). This problem may be due to LUA scripts or Modules.\n\n"); s = sdscatprintf(s," * High process RSS overhead: This instance has non-allocator RSS memory overhead is greater than 1.1 (this means that the Resident Set Size of the Redis process is much larger than the RSS the allocator holds). This problem may be due to Lua scripts or Modules.\n\n");
} }
if (big_slave_buf) { if (big_slave_buf) {
s = sdscat(s," * Big slave buffers: The slave output buffers in this instance are greater than 10MB for each slave (on average). This likely means that there is some slave instance that is struggling receiving data, either because it is too slow or because of networking issues. As a result, data piles on the master output buffers. Please try to identify what slave is not receiving data correctly and why. You can use the INFO output in order to check the slaves delays and the CLIENT LIST command to check the output buffers of each slave.\n\n"); s = sdscat(s," * Big slave buffers: The slave output buffers in this instance are greater than 10MB for each slave (on average). This likely means that there is some slave instance that is struggling receiving data, either because it is too slow or because of networking issues. As a result, data piles on the master output buffers. Please try to identify what slave is not receiving data correctly and why. You can use the INFO output in order to check the slaves delays and the CLIENT LIST command to check the output buffers of each slave.\n\n");
@ -1161,6 +1180,9 @@ sds getMemoryDoctorReport(void) {
if (big_client_buf) { if (big_client_buf) {
s = sdscat(s," * Big client buffers: The clients output buffers in this instance are greater than 200K per client (on average). This may result from different causes, like Pub/Sub clients subscribed to channels bot not receiving data fast enough, so that data piles on the Redis instance output buffer, or clients sending commands with large replies or very large sequences of commands in the same pipeline. Please use the CLIENT LIST command in order to investigate the issue if it causes problems in your instance, or to understand better why certain clients are using a big amount of memory.\n\n"); s = sdscat(s," * Big client buffers: The clients output buffers in this instance are greater than 200K per client (on average). This may result from different causes, like Pub/Sub clients subscribed to channels bot not receiving data fast enough, so that data piles on the Redis instance output buffer, or clients sending commands with large replies or very large sequences of commands in the same pipeline. Please use the CLIENT LIST command in order to investigate the issue if it causes problems in your instance, or to understand better why certain clients are using a big amount of memory.\n\n");
} }
if (many_scripts) {
s = sdscat(s," * Many scripts: There seem to be many cached scripts in this instance (more than 42). This may be because scripts are generated and `EVAL`ed, instead of being parameterized (with KEYS and ARGV), `SCRIPT LOAD`ed and `EVALSHA`ed. Unless `SCRIPT FLUSH` is called periodically, the scripts' caches may end up consuming most of your memory.\n\n");
}
s = sdscat(s,"I'm here to keep you safe, Sam. I want to help you.\n"); s = sdscat(s,"I'm here to keep you safe, Sam. I want to help you.\n");
} }
freeMemoryOverheadData(mh); freeMemoryOverheadData(mh);
@ -1293,7 +1315,7 @@ void memoryCommand(client *c) {
} else if (!strcasecmp(c->argv[1]->ptr,"stats") && c->argc == 2) { } else if (!strcasecmp(c->argv[1]->ptr,"stats") && c->argc == 2) {
struct redisMemOverhead *mh = getMemoryOverheadData(); struct redisMemOverhead *mh = getMemoryOverheadData();
addReplyMultiBulkLen(c,(24+mh->num_dbs)*2); addReplyMultiBulkLen(c,(25+mh->num_dbs)*2);
addReplyBulkCString(c,"peak.allocated"); addReplyBulkCString(c,"peak.allocated");
addReplyLongLong(c,mh->peak_allocated); addReplyLongLong(c,mh->peak_allocated);
@ -1316,6 +1338,9 @@ void memoryCommand(client *c) {
addReplyBulkCString(c,"aof.buffer"); addReplyBulkCString(c,"aof.buffer");
addReplyLongLong(c,mh->aof_buffer); addReplyLongLong(c,mh->aof_buffer);
addReplyBulkCString(c,"lua.caches");
addReplyLongLong(c,mh->lua_caches);
for (size_t j = 0; j < mh->num_dbs; j++) { for (size_t j = 0; j < mh->num_dbs; j++) {
char dbname[32]; char dbname[32];
snprintf(dbname,sizeof(dbname),"db.%zd",mh->db[j].dbid); snprintf(dbname,sizeof(dbname),"db.%zd",mh->db[j].dbid);

View File

@ -919,6 +919,7 @@ void scriptingInit(int setup) {
* This is useful for replication, as we need to replicate EVALSHA * This is useful for replication, as we need to replicate EVALSHA
* as EVAL, so we need to remember the associated script. */ * as EVAL, so we need to remember the associated script. */
server.lua_scripts = dictCreate(&shaScriptObjectDictType,NULL); server.lua_scripts = dictCreate(&shaScriptObjectDictType,NULL);
server.lua_scripts_mem = 0;
/* Register the redis commands table and fields */ /* Register the redis commands table and fields */
lua_newtable(lua); lua_newtable(lua);
@ -1073,6 +1074,7 @@ void scriptingInit(int setup) {
* This function is used in order to reset the scripting environment. */ * This function is used in order to reset the scripting environment. */
void scriptingRelease(void) { void scriptingRelease(void) {
dictRelease(server.lua_scripts); dictRelease(server.lua_scripts);
server.lua_scripts_mem = 0;
lua_close(server.lua); lua_close(server.lua);
} }
@ -1207,6 +1209,7 @@ sds luaCreateFunction(client *c, lua_State *lua, robj *body) {
* EVALSHA commands as EVAL using the original script. */ * EVALSHA commands as EVAL using the original script. */
int retval = dictAdd(server.lua_scripts,sha,body); int retval = dictAdd(server.lua_scripts,sha,body);
serverAssertWithInfo(c ? c : server.lua_client,NULL,retval == DICT_OK); serverAssertWithInfo(c ? c : server.lua_client,NULL,retval == DICT_OK);
server.lua_scripts_mem += sdsZmallocSize(sha) + sdsZmallocSize(body->ptr);
incrRefCount(body); incrRefCount(body);
return sha; return sha;
} }

View File

@ -3124,6 +3124,7 @@ sds genRedisInfoString(char *section) {
char peak_hmem[64]; char peak_hmem[64];
char total_system_hmem[64]; char total_system_hmem[64];
char used_memory_lua_hmem[64]; char used_memory_lua_hmem[64];
char used_memory_scripts_hmem[64];
char used_memory_rss_hmem[64]; char used_memory_rss_hmem[64];
char maxmemory_hmem[64]; char maxmemory_hmem[64];
size_t zmalloc_used = zmalloc_used_memory(); size_t zmalloc_used = zmalloc_used_memory();
@ -3143,6 +3144,7 @@ sds genRedisInfoString(char *section) {
bytesToHuman(peak_hmem,server.stat_peak_memory); bytesToHuman(peak_hmem,server.stat_peak_memory);
bytesToHuman(total_system_hmem,total_system_mem); bytesToHuman(total_system_hmem,total_system_mem);
bytesToHuman(used_memory_lua_hmem,memory_lua); bytesToHuman(used_memory_lua_hmem,memory_lua);
bytesToHuman(used_memory_scripts_hmem,server.lua_scripts_mem);
bytesToHuman(used_memory_rss_hmem,server.cron_malloc_stats.process_rss); bytesToHuman(used_memory_rss_hmem,server.cron_malloc_stats.process_rss);
bytesToHuman(maxmemory_hmem,server.maxmemory); bytesToHuman(maxmemory_hmem,server.maxmemory);
@ -3167,6 +3169,9 @@ sds genRedisInfoString(char *section) {
"total_system_memory_human:%s\r\n" "total_system_memory_human:%s\r\n"
"used_memory_lua:%lld\r\n" "used_memory_lua:%lld\r\n"
"used_memory_lua_human:%s\r\n" "used_memory_lua_human:%s\r\n"
"used_memory_scripts:%lld\r\n"
"used_memory_scripts_human:%s\r\n"
"number_of_cached_scripts:%lu\r\n"
"maxmemory:%lld\r\n" "maxmemory:%lld\r\n"
"maxmemory_human:%s\r\n" "maxmemory_human:%s\r\n"
"maxmemory_policy:%s\r\n" "maxmemory_policy:%s\r\n"
@ -3204,6 +3209,9 @@ sds genRedisInfoString(char *section) {
total_system_hmem, total_system_hmem,
memory_lua, memory_lua,
used_memory_lua_hmem, used_memory_lua_hmem,
server.lua_scripts_mem,
used_memory_scripts_hmem,
dictSize(server.lua_scripts),
server.maxmemory, server.maxmemory,
maxmemory_hmem, maxmemory_hmem,
evict_policy, evict_policy,

View File

@ -851,6 +851,7 @@ struct redisMemOverhead {
size_t clients_slaves; size_t clients_slaves;
size_t clients_normal; size_t clients_normal;
size_t aof_buffer; size_t aof_buffer;
size_t lua_caches;
size_t overhead_total; size_t overhead_total;
size_t dataset; size_t dataset;
size_t total_keys; size_t total_keys;
@ -1227,6 +1228,7 @@ struct redisServer {
client *lua_client; /* The "fake client" to query Redis from Lua */ client *lua_client; /* The "fake client" to query Redis from Lua */
client *lua_caller; /* The client running EVAL right now, or NULL */ client *lua_caller; /* The client running EVAL right now, or NULL */
dict *lua_scripts; /* A dictionary of SHA1 -> Lua scripts */ dict *lua_scripts; /* A dictionary of SHA1 -> Lua scripts */
unsigned long long lua_scripts_mem; /* Cached scripts' memory + oh */
mstime_t lua_time_limit; /* Script timeout in milliseconds */ mstime_t lua_time_limit; /* Script timeout in milliseconds */
mstime_t lua_time_start; /* Start time of script, milliseconds time */ mstime_t lua_time_start; /* Start time of script, milliseconds time */
int lua_write_dirty; /* True if a write command was called during the int lua_write_dirty; /* True if a write command was called during the