Redis服务端执行命令基本流程
2016-05-31 22:41
1096 查看
服务端执行命令基本流程:
如 set a "100" 这样的命令,在客户端被转换成redis协议格式发送至服务端,服务端收到后,解析字符串,得到三个RedisObject,object内部内容分别为set ,a ,100
对于100这样的数字,redis初始时会建立redis.h/REDIS_SHARED_INTEGERS个常量对象,默认0-10000,如100这样的直接在原本建立好的redisobject的引用上+1,这样子引用计数+对象共享,避免了反复分配内存的消耗。
对于其他字符串,和其他类型,如果每个object都进行引用计数和对象共享,则会消耗大量CPU时间,所以Redis只对整数值的字符串对象进行初始化和引用计数
struct sharedObjectsStruct { robj *crlf, *ok, *err, *emptybulk, *czero, *cone, *cnegone, *pong, *space, *colon, *nullbulk, *nullmultibulk, *queued, *emptymultibulk, *wrongtypeerr, *nokeyerr, *syntaxerr, *sameobjecterr, *outofrangeerr, *noscripterr, *loadingerr, *slowscripterr, *bgsaveerr, *masterdownerr, *roslaveerr, *execaborterr, *noautherr, *noreplicaserr, *busykeyerr, *oomerr, *plus, *messagebulk, *pmessagebulk, *subscribebulk, *unsubscribebulk, *psubscribebulk, *punsubscribebulk, *del, *rpop, *lpop, *lpush, *emptyscan, *minstring, *maxstring, *select[REDIS_SHARED_SELECT_CMDS], *integers[REDIS_SHARED_INTEGERS],//here<------------------- *mbulkhdr[REDIS_SHARED_BULKHDR_LEN], /* "*<value>\r\n" */ *bulkhdr[REDIS_SHARED_BULKHDR_LEN]; /* "$<value>\r\n" */ };
且服务端会为每个redis连接维护一个redisClient对象,
/* redis.h With multiplexing we need to take per-client state. * Clients are taken in a liked list. * * 因为 I/O 复用的缘故,需要为每个客户端维持一个状态。 * * 多个客户端状态被服务器用链表连接起来。 */ typedef struct redisClient { // 套接字描述符 int fd; // 当前正在使用的数据库 redisDb *db; // 当前正在使用的数据库的 id (号码) int dictid; // 客户端的名字 robj *name; /* As set by CLIENT SETNAME */ // 查询缓冲区 sds querybuf; // 查询缓冲区长度峰值 size_t querybuf_peak; /* Recent (100ms or more) peak of querybuf size */ // 参数数量 int argc; // 参数对象数组 robj **argv; // 记录被客户端执行的命令 struct redisCommand *cmd, *lastcmd; // 请求的类型:内联命令还是多条命令 int reqtype; // 剩余未读取的命令内容数量 int multibulklen; /* number of multi bulk arguments left to read */ // 命令内容的长度 long bulklen; /* length of bulk argument in multi bulk request */ // 回复链表 list *reply; // 回复链表中对象的总大小 unsigned long reply_bytes; /* Tot bytes of objects in reply list */ // 已发送字节,处理 short write 用 int sentlen; /* Amount of bytes already sent in the current buffer or object being sent. */ // 创建客户端的时间 time_t ctime; /* Client creation time */ // 客户端最后一次和服务器互动的时间 time_t lastinteraction; /* time of the last interaction, used for timeout */ // 客户端的输出缓冲区超过软性限制的时间 time_t obuf_soft_limit_reached_time; // 客户端状态标志 int flags; /* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... */ .............. ............... /* Response buffer */ // 回复偏移量 int bufpos; // 回复缓冲区 char buf[REDIS_REPLY_CHUNK_BYTES]; } redisClient;
根据字符串set查找命令表
//redis.h struct redisCommand redisCommandTable[] = { {"get",getCommand,2,"r",0,NULL,1,1,1,0,0}, {"set",setCommand,-3,"wm",0,NULL,1,1,1,0,0}, {"setnx",setnxCommand,3,"wm",0,NULL,1,1,1,0,0}, {"setex",setexCommand,4,"wm",0,NULL,1,1,1,0,0}, {"psetex",psetexCommand,4,"wm",0,NULL,1,1,1,0,0}, {"append",appendCommand,3,"wm",0,NULL,1,1,1,0,0}, {"strlen",strlenCommand,2,"r",0,NULL,1,1,1,0,0}, {"del",delCommand,-2,"w",0,NULL,1,-1,1,0,0}, {"exists",existsCommand,2,"r",0,NULL,1,1,1,0,0}, {"setbit",setbitCommand,4,"wm",0,NULL,1,1,1,0,0}, {"getbit",getbitCommand,3,"r",0,NULL,1,1,1,0,0}, .... };
//redis.h struct redisCommand { // 命令名字 char *name; // 实现函数 redisCommandProc *proc; // 参数个数 int arity; // 字符串表示的 FLAG char *sflags; /* Flags as string representation, one char per flag. */ // 实际 FLAG int flags; /* The actual flags, obtained from the 'sflags' field. */ /* Use a function to determine keys arguments in a command line. * Used for Redis Cluster redirect. */ // 从命令中判断命令的键参数。在 Redis 集群转向时使用。 redisGetKeysProc *getkeys_proc; /* What keys should be loaded in background when calling this command? */ // 指定哪些参数是 key int firstkey; /* The first argument that's a key (0 = no keys) */ int lastkey; /* The last argument that's a key */ int keystep; /* The step between first and last key */ // 统计信息 // microseconds 记录了命令执行耗费的总毫微秒数 // calls 是命令被执行的总次数 long long microseconds, calls; };
查表得到setCommand,令redisClient中的cm指向它,client->cmd->proc(client)执行命令,调用setCommand,处理redisCommadn中其他选项参数,最后调用setGenericCommand处理set key value的指令
相关文章推荐
- 从源码安装Mysql/Percona 5.5
- redis安装问题小结
- 使用 Redis 和 Python 构建一个共享单车的应用程序
- Redis偶发连接失败案例实战记录
- Redis中实现查找某个值的范围
- win 7 安装redis服务【笔记】
- redis的hGetAll函数的性能问题(记Redis那坑人的HGETALL)
- Redis和Memcached的区别详解
- 分割超大Redis数据库例子
- Redis总结笔记(一):安装和常用命令
- Redis sort 排序命令详解
- 用Redis实现微博关注关系
- Redis实现信息已读未读状态提示
- redis中修改配置文件中的端口号 密码方法
- 在Ruby on Rails上使用Redis Store的方法
- 浅析Ruby的源代码布局及其编程风格
- Redis和Memcache的区别总结
- 在Node.js应用中使用Redis的方法简介
- Redis服务器的启动过程分析
- web 应用中常用的各种 cache详解