破玩意 | Redis 为什么那么快
./redis-server
宏观上看下我的流程
int main(int argc, char **argv) {
...
initServer();
...
aeCreateFileEvent(fd, acceptHandler, ...);
...
aeMain();
...
}
void aeMain(aeEventLoop *eventLoop)
{
eventLoop->stop = 0;
while (!eventLoop->stop)
aeProcessEvents(eventLoop, AE_ALL_EVENTS);
}
展开体验下我的具体工作
redis-cli -h host -p port
static void acceptHandler(...) {
...
cfd = anetAccept(...);
...
c = createClient(cfd))
...
}
static redisClient *createClient(int fd) {
...
aeCreateFileEvent(c->fd, readQueryFromClient, ...);
...
}
void aeMain(aeEventLoop *eventLoop)
{
eventLoop->stop = 0;
while (!eventLoop->stop)
aeProcessEvents(eventLoop, AE_ALL_EVENTS);
}
为了方便大家吹牛,我来拔高一下
具体怎么执行一个 Redis 命令
<client 6379> set dibingfa niubi
static struct redisCommand cmdTable[] = {
{"get",getCommand,2,REDIS_CMD_INLINE},
{"set",setCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
{"setnx",setnxCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
{"del",delCommand,-2,REDIS_CMD_INLINE},
{"exists",existsCommand,2,REDIS_CMD_INLINE},
...
}
static void setCommand(redisClient *c) {
...
addReply(c, nx ? shared.cone : shared.ok);
}
static void addReply(redisClient *c, robj *obj) {
...
aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,
sendReplyToClient, c, NULL) == AE_ERR);
}
后记
后记
整篇文章我好像没讲 Redis 为啥那么快,因为我感觉这个问题问得不好。
你可以从接收网络请求的 IO 多路复用角度说起,也可以从事件处理器驱动的 Reactor 模式说起,还可以从具体处理命令时的数据结构说起,比如单单是字符串背后的 sds 其实就做了很多的巧妙设计。
如果我是面试官,我会具体让面试者聊聊 Redis 的启动流程,或者 Redis 处理命令的整个流程。
这里面可挖的点挺多的,如果能谈笑风生,那自然是技术水平还不错。
另外,你会发现本文出现的很多唬人的术语,比如 Reactor 模式,事件处理器等,看一遍 Redis 源码后你会发现真的非常简单。
毫不客气地说,一切丝毫不谈具体实现,和你堆砌一大堆唬人名词的文章或者人,都是在耍流氓。
本文我参考的是 Redis3.0.0 源码,但成文时用的讲解代码是 Redis1.0.0,整个网络模块的设计是完全一样的。
专属附赠
我整理了一份 Redis 启动流程的极简版附注释代码的精美 PDF。
大家可以加我好友获取(低并发编程 菜单栏),由于我比较懒,直接把它放在朋友圈第一条了,大家直接看我朋友圈获取即可,哈哈哈。
评论