摘录些nosqlfans上看的资源(http://blog.nosqlfan.com/html/3537.html),用了一年了,只会安装、启动和get set,真的不好意思说会redis
REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统,他为VMWare 公司工作,主要就是进行Redis的开发。 Blizzard (暴雪)使用8节点的Redis来为 WoW (魔兽争霸)提供Avatar服务。
一、redis启动初探
http://pauladamsmith.com/blog/2011/03/redis_get_set.html 原文
Redis starts up by initializing a global server state variable, and reading in an optional configuration file to override any defaults. It sets up a global command table that connects command names with the actual function that implements the command. It creates an event loop using the best available underlying system library for event/readiness notification, and registers a handler function for when there is a new client socket connection to accept. It also registers a periodic (i.e., time-based) event handler for dealing with cron-like tasks like key expiry that need to be addressed outside the regular client-handling path. Once a client has connected, a function is registered on the event loop for being notified when the client has data to be read (i.e., a query for a command). The client’s query is parsed and a command handler is called to execute the command and write the response back to the client (the writing of data to the client is also handled by the event-notification loop). The client object is reset and server is ready to process more queries.
二、 使用gdb分析get set command
GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。 http://pauladamsmith.com/blog/2011/03/redis_get_set.html 介绍了使用gdb加断点跟踪GET和SET
redis-cli 使用 redisContext封装相关连接状态,hiredis.h(deps目录)定义了 redisContext, obuf 字段存放redis-cli输入的原生命令
redis_client.get('users:1234') 和 命令行指令 get users:1234 一样,会发送 *2\r\n$3\r\nget\r\n$10\r\nusers:1234\r\n 字节串到服务器
服务器端redis-server 为每个客户端创建buffer,将字节流扩展至buffer中,执行方法readQueryFromClient 接收数据。 然后根据请求方式 lookupCommand(c->argv[0]->ptr),
从command的定义中可找到get方法
struct redisCommand readonlyCommandTable[] = {
{"get",getCommand,2,0,NULL,1,1,1},
getCommand 是getGenericCommand方法的封装,找到对应方法后,执行,从数据库中查找key对应的value:
# db.c:58
robj *lookupKeyReadOrReply(redisClient *c, robj *key, robj *reply) {
robj *o = lookupKeyRead(c->db, key);
if (!o) addReply(c,reply);
return o;
}
redis使用自己的hash table在内存中存储key-value对,在db对象中,dict字段指向当前库的hash值(redis一个实例可以有16个库)
redis调用dictFind方法(dict.c)在数据库的hashtable中查找对应值。
SET流程与此类似,调用dictAdd方法设置key-value对。
三、redis源码分析
(1)redis replication (http://www.hoterran.info/redis_replication)
(2)redis 持久化(http://www.hoterran.info/redis_persistence)
redis有全量(save/bgsave)和增量(aof)的持久化命令。 全量的原理就是遍历里所有的DB,在每个bucket,读取链表的key和value并写入dump.rdb文件(rdb.c 405)。 save命令直接调度rdbSave函数,这会阻塞主线程的工作,通常我们使用bgsave。
sync:当master接收到slave发来的该命令的时候,会执行rdbSaveBackground
增量备份就是aof,原理有点类似redo log。每次执行命令后如出现数据变化,会调用feedAppendOnlyFile,把数据写到server.aofbuf里。aof最大的问题就是随着时间append file会变的很大,所以我们需要bgrewriteaof命令重新整理文件,只保留最新的kv数据。
(3)redis rehash(http://www.yiihsia.com/2011/04/redis源码分析-如何rehash/)
rehash有2种工作模式 lazy rehashing:在每次对dict进行操作的时候执行一个slot的rehash active rehashing:每100ms里面使用1ms时间进行rehash。 什么时候dict做扩容? 在数据插入的时候会调用dictKeyIndex,该方法里会调用_dictExpandIfNeeded,判断dict是否需要rehash,当dict中元素大于桶的个数时,调用dictExpand扩展hash。dictExpand的工作主要是初始化hash表,默认是扩大两倍(并不单纯是桶的两倍),然后赋值给ht[1],然后状态改为rehashing,此时该dict开始rehashing 四、redis基本结构