redis/jedis虽然代码比较少,但是很难一篇文章概况所有设计及实现细节,所以还是抓取日常工作中可能的疑问,带着问题去翻代码:
1 假设当前内存占用是10G,那么落到磁盘rdb时,是否一定也是10G?
不一定,因为一方面可以设置压缩(默认开启:rdbcompression yes),另外一方面,假设内存中存在大量已过期数据,则也过滤掉这部分数据, dump的实现上,会遍历所有数据库(0-默认16),遍历所有数据然后保存:
int rdbSaveKeyValuePair(rio *rdb, robj *key, robj *val,
long long expiretime, long long now)
{
/* Save the expire time */
if (expiretime != -1) {
/* If this key is already expired skip it */
if (expiretime < now) return 0;
if (rdbSaveType(rdb,RDB_OPCODE_EXPIRETIME_MS) == -1) return -1;
if (rdbSaveMillisecondTime(rdb,expiretime) == -1) return -1;
}
/* Save type, key, value */
if (rdbSaveObjectType(rdb,val) == -1) return -1;
if (rdbSaveStringObject(rdb,key) == -1) return -1;
if (rdbSaveObject(rdb,val) == -1) return -1;
return 1;
}
2 monitor实现
void monitorCommand(client *c) {
/* ignore MONITOR if already slave or in monitor mode */
if (c->flags & CLIENT_SLAVE) return;
c->flags |= (CLIENT_SLAVE|CLIENT_MONITOR);
listAddNodeTail(server.monitors,c); //把整个客户端增加到server.monitors里面去
addReply(c,shared.ok);
}
执行命令时:
void call(client *c, int flags) {
long long dirty, start, duration;
int client_old_flags = c->flags;
/* Sent the command to clients in MONITOR mode, only if the commands are
* not generated from reading an AOF. */
if (listLength(server.monitors) &&
!server.loading &&
!(c->cmd->flags & (CMD_SKIP_MONITOR|CMD_ADMIN)))
{
replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc); //把命令发到client去
}
可以根据info来查询输出list的最大值。或者根据client list也可以排查问题
client_longes_output_list信息获取的方法,遍历所有client,获许对应的值,取最大值。
void getClientsMaxBuffers(unsigned long *longest_output_list,
unsigned long *biggest_input_buffer) {
client *c;
listNode *ln;
listIter li;
unsigned long lol = 0, bib = 0;
listRewind(server.clients,&li);
while ((ln = listNext(&li)) != NULL) {
c = listNodeValue(ln);
if (listLength(c->reply) > lol) lol = listLength(c->reply);
if (sdslen(c->querybuf) > bib) bib = sdslen(c->querybuf);
}
*longest_output_list = lol;
*biggest_input_buffer = bib;
}