Redis数据库定义:
typedef struct redisDb
int id;
redisDb;
dict
dict数组保存所有的数据库,Redis初始化的时候,默认会创建16个数据库
默认情况下,Redis客户端的目标数据库是0 号数据库,可以通过select命令切换。 注意,由于Redis缺少获取当前操作的数据库命令,使用select切换需要特别注意
读写数据库中的键值对的时候,Redis除了对键空间执行指定操作外,还有一些额外的操作:
- 读取键之后(读和写操作都会先读取),记录键空间命中或不命中次数
- 读取键之后,更新键的LRU
- 读取时发现已经过期,会先删除过期键
- 如果有客户端使用watch命令监视了key,会在修改后标记为dirty
- 修改之后,会对dirty键计数器加1,用于持久化和复制
- 如果开启了数据库通知,修改之后会发送相应通知
robj *
robj *o =
c->db, key);
if !o) c,reply);
return o;
}
robj *
robj *val;
db,key);
val =
db,key);
if val == NULL)
server.stat_keyspace_misses++;
server.stat_keyspace_hits++;
return val;
}
robj *
dictEntry *de =
db->dict,key->ptr);
robj *val =
de);
* Don’t do it if we have a saving child, as this will trigger
if server.rdb_child_pid == –1 && server.aof_child_pid == –1)
val->lru = server.lruclock;
return val;
return NULL;
}
expires
通过exprire或者pexpire命令,可以设置键的TTL,如果键的TTL为0,会被自动删除。
expires字典保存了数据库中所有键的过期时间。
- 过期字典的键是指向某个数据中的键对象
- 过期字段的值是long long类型的整数,保存这个键的过期时间
voidc, ),UNIT_SECONDS);}voidrobj *key = c->argv[1], *param = c->argv[2];if c, param, &when, NULL) != REDIS_OK)return;if unit == UNIT_SECONDS) when *= 1000;when += basetime;.czero); c,sharedreturn;* should never be executed as a DEL when load the AOF or in the context* of a slave instance.** Instead we take the other branch of the IF statement setting an expirerobj *aux;c,key, c->db,key));server.dirty++;aux =“DEL“,3);2,aux,key); c,aux);c->db,key);“del“,key,c->db->id); REDIS_NOTIFY_GENERIC,.cone); c, sharedreturn;c->db,key,when);.cone); c,sharedc->db,key);“expire“,key,c->db->id); REDIS_NOTIFY_GENERIC,server.dirty++;return;}
过期键删除策略
- 惰性删除:每次执行命令前,都会调用expireIfNeeded函数检查是否过期,如果已经过期,改函数会删除过期键
- 定时删除:定时执行activeExpireCycleTryExpire函数
expireIfNeeded
intmstime_t when = db,key);mstime_t now;if server.loading) return 0;* blocked to when the Lua script started. This way a key can expire* only the first time it is accessed and not in the middle of the* script execution, making propagation to slaves / AOF consistent.now = server.lua_caller ? server.lua_time_start : );* the slave key expiration is controlled by the master that will* send us synthesized DEL operations for expired keys.** Still we try to return the right information to the caller,* that is, 0 if we think the key should be still valid, 1 ifif server.masterhost != NULL) return now > when;if now <= when) return 0;server.stat_expiredkeys++;db,key);REDIS_NOTIFY_EXPIRED,“expired“,key,db->id);return db,key);}activeExpireCycleTryExpire
while (num–)dictEntry *de;long long ttl;if (de = db->expires)) == NULL) break;ttl = de)-now;if db,de,now)) expired++;if ttl < 0) ttl = 0;ttl_sum += ttl;ttl_samples++;}AOF、RDB和复制功能对过期键的处理
- 生成RDB文件时,已过期的键不会被保存到新的RDB文件中
- 载入RDB文件:
- 主服务器载入时,会忽略过期键
- 从服务器载入时,都会被载入(但是很快会因为同步被覆盖)
- AOF写入,已过期未删除的键没有影响,被删除后,会追加一条del命令
- AOF重写,会对键进行检查,过期键不会保存到重写后的AOF文件
- 复制:
- 主服务器删除一个过期键后,会显式向所有从服务器发送DEL命令
- 从服务器执行读命令,及时过期也不会删除,只有接受到主服务器DEL命令才会删除
转载自:https://coolex.info/blog/459.html