设为首页 收藏本站
查看: 680|回复: 0

[经验分享] Redis系列(一)---启动流程分析

[复制链接]

尚未签到

发表于 2015-7-21 07:41:45 | 显示全部楼层 |阅读模式
  我们知道,Redis是一个性能非常优异的kv服务器,有关redis的性能及适用场景,在后期做介绍,这里重点介绍下redis的启动流程,也是对近期对redis代码阅读的一点总结,有不足之处,欢迎拍砖.
  阅读c/c++项目的源码,一般情况下,都将从main函数,那么对于redis的启动流程,下边也从main函数开始说起.
  首先,main函数里边声明了一个time_t start 变量, 用来对一些操作进行时间统计,如从AOF文件中加载数据,从redisdb中加载数据。
  接下来,调用initServerConfig() 对struct redisServer server 这一个全部变量进行默认初始化.(如果启动redis时指定了redis.conf,后边会用配置文件中的配置覆盖这里初始化的值)。 然后是对命令行参数的读取,参数个数不能超过3个, 可以以test-memory指定内存数运行redis;
  如果启动参数指定了redis.conf, 那么首先调用resetServerSaveParams() 重置server.saveparams(释放该指针指向的内存单元并设置为NULL, 同时将server.saveparamslen置为0):
  
  



void resetServerSaveParams() {
zfree(server.saveparams);
server.saveparams = NULL;
server.saveparamslen = 0;
}
  
  然后调用loadServerConfig(char *filename) 对 server 全局变量重新初始化。(具体实现方式暂时不做具体分析)
  判断 server.daemonize,已决定是否一daemon方式启动redis.



if (server.daemonize) daemonize();
  接下来调用 initServer(), 初始化服务器,初略来说,这个函数完成的工作有:
  调用 createSharedObjects() 初始化 全局的shared对象
  调用 aeCreateEventLoop() 创建事件轮询:
  

server.el = aeCreateEventLoop();
      aeCreateEventLoop完成的工作:
      1:为aeEventLoop分配内存: eventLoop = zmalloc(sizeof(*eventLoop));
      2:调用aeApiCreate(aeEventLoop) 对eventLoop进行初始化,在这个函数里边, 首先调用zmalloc为aeApiState 分配内存, 然后调用epoll_create创建一个fd, 并将其赋值给 aeApiState的epfd, 然后整个aeApiState 赋值给eventLoop的apidata.



typedef struct aeApiState {
int epfd;
struct epoll_event events[AE_SETSIZE];
} aeApiState;
static int aeApiCreate(aeEventLoop *eventLoop) {
aeApiState *state = zmalloc(sizeof(aeApiState));
if (!state) return -1;
state->epfd = epoll_create(1024); /* 1024 is just an hint for the kernel */
if (state->epfd == -1) return -1;
eventLoop->apidata = state;
return 0;
}
aeEventLoop *aeCreateEventLoop(void) {
aeEventLoop *eventLoop;
int i;
eventLoop = zmalloc(sizeof(*eventLoop));
if (!eventLoop) return NULL;
eventLoop->timeEventHead = NULL;
eventLoop->timeEventNextId = 0;
eventLoop->stop = 0;
eventLoop->maxfd = -1;
eventLoop->beforesleep = NULL;
if (aeApiCreate(eventLoop) == -1) {
zfree(eventLoop);
return NULL;
}
/* Events with mask == AE_NONE are not set. So let's initialize the
* vector with it. */
for (i = 0; i < AE_SETSIZE; i++)
eventLoop->events.mask = AE_NONE;
return eventLoop;
}
  
  然后调用anetTcpServer和anetUnixServer 创建对端口和unix域套接字的监听, 并将返回值赋值给 server.ipfd和server.sofd。通知给这两个套接字设置AE_READABLE事件,并设置相应的处理函数
    



if (server.port != 0) {
server.ipfd = anetTcpServer(server.neterr,server.port,server.bindaddr);
if (server.ipfd == ANET_ERR) {
redisLog(REDIS_WARNING, "Opening port %d: %s",
server.port, server.neterr);
exit(1);
}
}
if (server.unixsocket != NULL) {
unlink(server.unixsocket); /* don't care if this fails */
server.sofd = anetUnixServer(server.neterr,server.unixsocket,server.unixsocketperm);
if (server.sofd == ANET_ERR) {
redisLog(REDIS_WARNING, "Opening socket: %s", server.neterr);
exit(1);
}
}
if (server.ipfd > 0 && aeCreateFileEvent(server.el,server.ipfd,AE_READABLE,
acceptTcpHandler,NULL) == AE_ERR) oom("creating file event");
if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE,
acceptUnixHandler,NULL) == AE_ERR) oom("creating file event");
  
  判断是否需要打开aof文件。
  



if (server.appendonly) {
server.appendfd = open(server.appendfilename,O_WRONLY|O_APPEND|O_CREAT,0644);
if (server.appendfd == -1) {
redisLog(REDIS_WARNING, "Can't open the append-only file: %s",
strerror(errno));
exit(1);
}
}
  
  initServer 函数返回后, 根据server.appendonly的值判断是否需要从aof文件或者rdb装载数据。
  



start = time(NULL);
if (server.appendonly) {
if (loadAppendOnlyFile(server.appendfilename) == REDIS_OK)
redisLog(REDIS_NOTICE,"DB loaded from append only file: %ld seconds",time(NULL)-start);
} else {
if (rdbLoad(server.dbfilename) == REDIS_OK) {
redisLog(REDIS_NOTICE,"DB loaded from disk: %ld seconds",
time(NULL)-start);
} else if (errno != ENOENT) {
redisLog(REDIS_WARNING,"Fatal error loading the DB. Exiting.");
exit(1);
}
}
  
  然后就设置每次进入事件处理函数之前需要执行的函数



aeSetBeforeSleepProc(server.el,beforeSleep);
  然后调用aeMain(server.el);开始事件循环。
  





aeMain(server.el);
void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = 0;
while (!eventLoop->stop) {
if (eventLoop->beforesleep != NULL)
eventLoop->beforesleep(eventLoop);
aeProcessEvents(eventLoop, AE_ALL_EVENTS);
}
}
  如果事件轮询结束(acMain返回),则调用aeDeleteEventLoop(server.el);删除eventLoop
  



void aeDeleteEventLoop(aeEventLoop *eventLoop) {
aeApiFree(eventLoop);
zfree(eventLoop);
}
  至此 main函数结束,服务器退出。
  
  
  
  
  
  
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-88820-1-1.html 上篇帖子: redis 配置文件解读 下篇帖子: SignalR Scaleout with Redis
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表