redis在进行持久化(aof或者rdb,这个以后会讲到,暂时理解是两种不同的方式将内存中的数据同步到磁盘)的时候,开始都是直接fork一个子进程出来,然后让这个子进程取进行持久化工作,在这期间,父进程照样工作,对外提供服务,接收到的命令也都缓存起来,子进程执行完任务之后,通知父进程,父进程收割,将缓存的命令同步到磁盘,最后OK。但是这样会出现一个问题,就是在子进程执行任务期间,如果父进程中缓存过多的数据就会造成性能下降,redis的大佬们就想出了利用管道来进行父子进程之间通信的方式来优化,就是子进程执行期间,将父进程接收到的命令通过管道来写给子进程,这样能够减少父进程收割完子进程之后,写入磁盘的数据的数目。
在redis当中简单的管道实现如下:
1. 打开:
void openChildInfoPipe(void) { if (pipe(server.child_info_pipe) == -1) { /* On error our two file descriptors should be still set to -1, * but we call anyway cloesChildInfoPipe() since can't hurt. */ closeChildInfoPipe(); } else if (anetNonBlock(NULL,server.child_info_pipe[0]) != ANET_OK) { closeChildInfoPipe(); } else { memset(&server.child_info_data,0,sizeof(server.child_info_data)); } }
2. 关闭:
/* Close the pipes opened with openChildInfoPipe(). */ void closeChildInfoPipe(void) { if (server.child_info_pipe[0] != -1 || server.child_info_pipe[1] != -1) { close(server.child_info_pipe[0]); close(server.child_info_pipe[1]); server.child_info_pipe[0] = -1; server.child_info_pipe[1] = -1; } }
3. 发送数据给parent
/* Send COW data to parent. The child should call this function after populating * the corresponding fields it want to sent (according to the process type). */ void sendChildInfo(int ptype) { if (server.child_info_pipe[1] == -1) return; server.child_info_data.magic = CHILD_INFO_MAGIC; server.child_info_data.process_type = ptype; ssize_t wlen = sizeof(server.child_info_data); if (write(server.child_info_pipe[1],&server.child_info_data,wlen) != wlen) { /* Nothing to do on error, this will be detected by the other side. */ } }
4. 接收parent的数据
/* Receive COW data from parent. */ void receiveChildInfo(void) { if (server.child_info_pipe[0] == -1) return; ssize_t wlen = sizeof(server.child_info_data); if (read(server.child_info_pipe[0],&server.child_info_data,wlen) == wlen && server.child_info_data.magic == CHILD_INFO_MAGIC) { if (server.child_info_data.process_type == CHILD_INFO_TYPE_RDB) { server.stat_rdb_cow_bytes = server.child_info_data.cow_size; } else if (server.child_info_data.process_type == CHILD_INFO_TYPE_AOF) { server.stat_aof_cow_bytes = server.child_info_data.cow_size; } } }