您的位置:首页 > 数据库 > Redis

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的指令
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  redis 源码