一、服务器中的数据库和键空间
1、数据库
Redis服务器将所有数据库都保存在服务器状态的db数组中,db数组的每个项都是一个redis.h/redis结构,每个redisDB结构代表一个数据库。structredisServer{redisDb*db;//一个数组,保存着服务器中的所有数据库,标识当前的目标数据库,切换数据库即指针切换intdbnum;//数据库的数量,默认=16,可设置};
typedefstructredisDb{dict*dict;//数据库键空间,保存着数据库中的所有键值对dict*expires;//过期字典,保存着键的过期时间};redisDb2、键空间的操作1.1、额外维护操作当使用Redis命令对数据库进行读写时,服务器会对键空间执行指定的读写操作,除此之外,还会执行一些额外的维护操作,包括
读取键之后,服务器会根据键是否存在来更新服务的键空间命中hit次数或键空间不命中miss次数;
读取键之后,服务器会更新键的最后一次使用时间LRU,后面用于计算键的闲置时间;
读取键时会先判断该键是否过期,若过期则先删除,过期键后面会写;
如果有客户端使用WATCH命令监视某键,如果服务器对该键修改后,会将该键标记为脏dirty,从而让事务程序识别;
服务器每次修改一个键之后,都会对脏键计数器的值增1,这个计数器会触发服务器的持久化以及复制操作;
如果服务器开启了数据库通知功能,那么对键修改后,服务器将按配置发送相应的数据库通知;
1.2、设置键的生存时间或过期时间
设置时间:使用EXPIRE和PEXPIRE命令,客户端以秒或者毫秒精度为数据库中的某键设置生存时间TTL(TimetoLive),经过指定时间后,服务器会自动删除生存时间为0的键。同理,使用EXPIREAT和PEXPIREAT命令,设置过期时间。另外SETEX命令可以在设置字符串键的同时为键设置过期时间,只有用于字符串,原理同EXPIRE命令。
EXPIREkeyttl命令用于将键key的生存时间设置为ttl秒;PEXPIREkeyttl命令用于将键key的生存时间设置为ttl毫秒;EXPIREATkeytimestamp命令用于将键key的过期时间设置为timestamp所指定的秒数时间戳;PEXPIREATkeytimestamp命令用于将键key的过期时间设置为timestamp所指定的毫秒数时间戳;
实际上EXPIRE、PEXPIRE、EXPIREAT三个命令都是使用PEXPIREAT命令来实现的,无论客户端执行哪个,最终都会转化成PEXPIREAT命令。
EXPIRE先转化成PEXPIRE,再转化成PEXPIREAT;EXPIREAT转化成PEXPIREAT;
查看时间:
使用TTL和PTTL查看生存或过期时间,返回这个键的剩余生存时间,也就是这个键距离被服务器自动删除还有多长时间。移除时间:PERSISTKey检查时间:is_expired(Key)----直接访问字典TTL或PTTLKey0过期----命令,比访问字典慢一些1.3、键的删除策略键的删除策略有三种:定时删除:设置键的过期时间的同时,创建一个定时器,时间到了立即删除,内存友好,CPU不友好;
惰性删除:放任键不管,每次获取键时,都检查键是否过期,若过期则删除,内存不友好,CPU友好;
定期删除:每隔一段时间检查一次,删除到期的键,需要合理设置执行时长和执行频率;
Redis里配合使用惰性删除和定期删除两种策略惰性删除由db.c/expireIfNeeded函数实现,所有读写数据库的Redis命令在执行之前都会调用检查,因为每个被访问的键都可能因为过期而被expireIfNeeded函数删除,所以每个命令的实现函数都必须能同时处理键存在以及键不存在两种情况;
定期删除由redis.c/activeExpireCycle函数实现,每当Redis的服务器周期性操作redis.c/serverCron函数执行时,activeExpireCycle就会被调用,分多次遍历服务器中的各个数据库,检查expires字典,删除其中的过期键。其中使用全局变量current_db记录当前的检查进度,都检查完成后重置为0;
作者本人是一枚小小的百度研发RD,如文章中出现表述不清、表达不准确、错别字、排版不友好等等问题,欢迎大家留言指正!
预览时标签不可点收录于话题#个上一篇下一篇