Redis源代码重要目录
dict.c:也是很重要的两个文件,主要对于内存中的hash进行管理:
adlist.c:用于对list的定义,它是个双向链表结构
sds.c:用于对字符串的定义,从头文件可以找到:
object.c:用于创建和释放redisObject对象
sort.c:关于排序算法,sort.c具体作为Redis场景下的排序实现。

multi.c:用于事务处理操作。
rdb.c:对于Redis本地数据库的相关操作,默认文件是dump.rdb(通过配置文件获得),包括的操作包括保存,移除,查询等等。
redis.c:服务端程序的实现。具体会在后面的文章详细介绍。
ae.c:用于Redis的事件处理,包括句柄事件和超时事件。
anet.c:这两个文件非常重要,作为Server/Client通信的基础封装,包括anetTcpServer,anetTcpConnect,anetTcpAccept,anetRead,anetWrite等等方法。
aof.c:aof,全称为append only file,作用就是记录每次的写操作,在遇到断电等问题时可以用它来恢复数据库状态。但是他不是bin的,而是text的。一行一行,写得很规范.如果你是一台redis,那你也能人肉通过它恢复数据。
db.c:对于Redis内存数据库的相关操作。
zmalloc.c:关于Redis的内存分配的封装实现。
 
 
 

http://www.cnblogs.com/liuhao/archive/2012/06/06/2538751.html

serverCron是redis每隔100ms执行的一个循环事件,由ae事件框架驱动。其主要执行如下任务:

1.记录循环时间:

  1. server.unixtime = time(NULL)

redis使用全局状态cache了当前的时间值。在vm实现以及lru实现中,均需要对每一个对象的访问记录其时间,在这种情况下,对精度的要求并不高(100ms内的访问值一样是没有问题的)。使用cache的时间值,其代价要远远低于每次均调用time()系统调用

2.更新LRUClock值:

  1. updateLRUClock()

后续在执行lru淘汰策略时,作为比较的基准值。redis默认的时间精度是10s(#define REDIS_LRU_CLOCK_RESOLUTION 10),保存lru clock的变量共有22bit。换算成总的时间为1.5 year(每隔1.5年循环一次)。

不知为何在最初设计的时候,为lru clock只给了22bit的空间。

3.更新峰值内存占用:

  1. 550if (zmalloc_used_memory() > server.stat_peak_memory)
  2. 551 server.stat_peak_memory = zmalloc_used_memory();

4.处理shutdown_asap

在上一篇blog中,介绍了redis对SIG_TERM信号的处理。其信号处理函数中并没有立即终止进程的执行,而是选择了标记shutdown_asap flag,然后在serverCron中通过执行prepareForShutdown函数,优雅的退出。

  1. 555if (server.shutdown_asap) {
  2. 556if (prepareForShutdown() == REDIS_OK) exit(0);
  3. 557 redisLog(REDIS_WARNING,"SIGTERM received but errors trying to shut down the server, check the logs for more information");
  4. 558 }

在prepareForShutdown函数中,redis处理了rdb、aof记录文件退出的情况,最后保存了一次rdb文件,关闭了相关的文件描述符以及删除了保存pid的文件(server.pidfile).

5.打印统计信息

统计信息分为两类,两类统计信息均为每5s输出一次。第一类是key数目、设置了超时值的key数目、以及当前的hashtable的槽位数:

  1. 561for (j = 0; j < server.dbnum; j++) {
  2. 562longlong size, used, vkeys;
  3. 563564 size = dictSlots(server.db[j].dict);
  4. 565 used = dictSize(server.db[j].dict);
  5. 566 vkeys = dictSize(server.db[j].expires);
  6. 567if (!(loops % 50) && (used || vkeys)) {
  7. 568 redisLog(REDIS_VERBOSE,"DB %d: %lld keys (%lld volatile) in %lld slots HT.",j,used,vkeys,size);
  8. 569/* dictPrintStats(server.dict); */570 }
  9. 571 }

第二类是当前的client数目,slaves数目,以及总体的内存使用情况:

  1. 585if (!(loops % 50)) {
  2. 586 redisLog(REDIS_VERBOSE,"%d clients connected (%d slaves), %zu bytes in use",
  3. 587 listLength(server.clients)-listLength(server.slaves),
  4. 588 listLength(server.slaves),
  5. 589 zmalloc_used_memory());
  6. 590 }

6.尝试resize hash表

因为现在的操作系统fork进程均大多数采用的是copy-on-write,为了避免resize哈希表造成的无谓的页面拷贝,在有后台的rdb save进程或是rdb rewrite进程时,不会尝试resize哈希表。

否则,将会每隔1s,进行一次resize哈希表的尝试;同时,如果设置了递增式rehash(redis默认是设置的),每次serverCron执行,均会尝试执行一次递增式rehash操作(占用1ms的CPU时间);

  1. 579if (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1) {
  2. 580if (!(loops % 10)) tryResizeHashTables();
  3. 581if (server.activerehashing) incrementallyRehash();
  4. 582 }

7.关闭超时的客户端

每隔10s进行一次尝试

  1. 593if ((server.maxidletime && !(loops % 100)) || server.bpop_blocked_clients)
  2. 594 closeTimedoutClients();

8.如果用户在此期间,请求进行aof的rewrite操作,调度执行rewrite

  1. 598if (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1 &&
  2. 599 server.aofrewrite_scheduled)
  3. 600 {
  4. 601 rewriteAppendOnlyFileBackground();
  5. 602 }

9.如果有后台的save rdb操作或是rewrite操作:

调用wait3获取子进程状态。此wait3为非阻塞(设置了WNOHANG flag)。注意:APUE2在进程控制章节其实挺不提倡用wait3和wait4接口的,不过redis的作者貌似对这个情有独钟。如果后台进程刚好退出,调用backgroundSaveDoneHandler或backgroundRewriteDoneHandler进行必要的善后工作,并更新dict resize policy(如果已经没有后台进程了,就可以允许执行resize操作了)。

  1. 605if (server.bgsavechildpid != -1 || server.bgrewritechildpid != -1) {
  2. 606int statloc;
  3. 607 pid_t pid;
  4. 608609if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) {
  5. 610if (pid == server.bgsavechildpid) {
  6. 611 backgroundSaveDoneHandler(statloc);
  7. 612 } else {
  8. 613 backgroundRewriteDoneHandler(statloc);
  9. 614 }
  10. 615 updateDictResizePolicy();
  11. 616 }

10.否则,如果没有后台的save rdb操作及rewrite操作:

首先,根据saveparams规定的rdb save策略,如果满足条件,执行后台rdbSave操作;

其次,根据aofrewrite策略,如果当前aof文件增长的规模,要求触发rewrite操作,则执行后台的rewrite操作。

  1. 622for (j = 0; j < server.saveparamslen; j++) {
  2. 623struct saveparam *sp = server.saveparams+j;
  3. 624625if (server.dirty >= sp->changes &&
  4. 626 now-server.lastsave > sp->seconds) {
  5. 627 redisLog(REDIS_NOTICE,"%d changes in %d seconds. Saving...",
  6. 628 sp->changes, sp->seconds);
  7. 629 rdbSaveBackground(server.dbfilename);
  8. 630break;
  9. 631 }
  10. 632 }
  11. 633634/* Trigger an AOF rewrite if needed */635if (server.bgsavechildpid == -1 &&
  12. 636 server.bgrewritechildpid == -1 &&
  13. 637 server.auto_aofrewrite_perc &&
  14. 638 server.appendonly_current_size > server.auto_aofrewrite_min_size)
  15. 639 {
  16. 640longlongbase = server.auto_aofrewrite_base_size ?
  17. 641 server.auto_aofrewrite_base_size : 1;
  18. 642longlong growth = (server.appendonly_current_size*100/base) - 100;
  19. 643if (growth >= server.auto_aofrewrite_perc) {
  20. 644 redisLog(REDIS_NOTICE,"Starting automatic rewriting of AOF on %lld%% growth",growth);
  21. 645 rewriteAppendOnlyFileBackground();
  22. 646 }
  23. 647 }

11.如果推迟执行aof flush,则进行flush操作,调用flushAppendOnlyFile函数;

12.如果此redis instance为master,则调用activeExpireCycle,对过期值进行处理(slave只等待master的DEL,保持slave和master的严格一致);

13.最后,每隔1s,调用replicationCron,执行与replication相关的操作。

在blog的最后,对serverCron的开头结尾进行简单的探讨;

serverCron开头,有这样几行代码:

  1. 525 REDIS_NOTUSED(eventLoop);
  2. 526 REDIS_NOTUSED(id);
  3. 527 REDIS_NOTUSED(clientData);

表明,这个时间处理例程内部,对aeCreateTimeEvent规定的函数原型所传的参数,均没有使用。redis的ae库据作者所说,是参考libevent的实现精简再精简得到的,猜测其接口的设计也是借鉴了很多libevent的接口设计风格。

serverCron最后,return 100。表明server将会在100ms后重新调用这个例程的执行。

Redis源码分析:serverCron - redis源码笔记的更多相关文章

  1. NIO 源码分析(05) Channel 源码分析

    目录 一.Channel 类图 二.begin 和 close 是什么 2.1 AbstractInterruptibleChannel 中的 begin 和 close 2.2 Selector 中 ...

  2. NIO 源码分析(02-2) BIO 源码分析 Socket

    目录 一.BIO 最简使用姿势 二.connect 方法 2.1 Socket.connect 方法 2.2 AbstractPlainSocketImpl.connect 方法 2.3 DualSt ...

  3. NIO 源码分析(02-1) BIO 源码分析

    目录 一.BIO 最简使用姿势 二.ServerSocket 源码分析 2.1 相关类图 2.2 主要属性 2.3 构造函数 2.4 bind 方法 2.5 accept 方法 2.6 总结 NIO ...

  4. [源码分析] 从实例和源码入手看 Flink 之广播 Broadcast

    [源码分析] 从实例和源码入手看 Flink 之广播 Broadcast 0x00 摘要 本文将通过源码分析和实例讲解,带领大家熟悉Flink的广播变量机制. 0x01 业务需求 1. 场景需求 对黑 ...

  5. drf的基本使用、APIView源码分析和CBV源码拓展

    cbv源码拓展 扩展,如果我在Book视图类中重写dispatch方法 -可以实现,在get,post方法执行之前或者之后执行代码,完成类似装饰器的效果 def dispatch(self, requ ...

  6. Spring Ioc源码分析系列--Ioc源码入口分析

    Spring Ioc源码分析系列--Ioc源码入口分析 本系列文章代码基于Spring Framework 5.2.x 前言 上一篇文章Spring Ioc源码分析系列--Ioc的基础知识准备介绍了I ...

  7. k8s client-go源码分析 informer源码分析(3)-Reflector源码分析

    k8s client-go源码分析 informer源码分析(3)-Reflector源码分析 1.Reflector概述 Reflector从kube-apiserver中list&watc ...

  8. jQuery1.11源码分析(1)-----Sizzle源码概览[原创]

    最近在啃jQuery1.11源码,上来就遇到Sizzle这个jQuery的大核心,虽然已经清楚了Sizzle的用途,先绕过去也没事,但明知山有虎偏向虎山行才是我们要做的. 本文面向的阅读对象:正在学习 ...

  9. 【MyBatis源码分析】select源码分析及小结

    示例代码 之前的文章说过,对于MyBatis来说insert.update.delete是一组的,因为对于MyBatis来说它们都是update:select是一组的,因为对于MyBatis来说它就是 ...

  10. 集合源码分析[3]-ArrayList 源码分析

    历史文章: Collection 源码分析 AbstractList 源码分析 介绍 ArrayList是一个数组队列,相当于动态数组,与Java的数组对比,他的容量可以动态改变. 继承关系 Arra ...

随机推荐

  1. 问题:Unable to find a 'userdata.img' file for ABI armeabi to copy into the AVD folder.

    创建AVD时,发现创建不成功,报错“Unable to find a 'userdata.img' file for ABIarmeabi to copy into the AVD folder.” ...

  2. SpringMVC流程架构图

    [组件说明] 以下组件通常使用框架提供实现: 1.DisPatcherServlet:前端控制器(不需要程序员开发) 用户请求到达前端控制器,它相当于MVC模式中的C(Controller),Disp ...

  3. 洛谷 P3393 逃离僵尸岛

    洛谷 这道题目其实是最短路裸题. 首先看到题目,要求的到"被占点"距离不大于S的点,自然想到了以"被占点"为源点,求一遍最短路,处理出"危险点&quo ...

  4. 阿里云RDS上的一些概念性记录

    刚接触RDS,只能对RDS上的一些特性做一些笔记,方便记忆,以下为RDS上的内容摘录,取自官方文档 1 数据备份 可使用命令行或图形界面进行逻辑数据备份.仅限通过 RDS 管理控制台 或 OPEN A ...

  5. 001infor record 计划时间取值增强-20150622

    ZMD_MRP_PARAMETERS 3000公司下工厂跑MRP时,如果为外购则通过外挂表取infor record计划交期. METHOD if_ex_md_mrp_parameters~adjus ...

  6. cn_office_professional_plus_2010_x86_515 安装激活方法解决方案64bit

    一:首先选择 Office 2010 Toolkit.exe 右键 选择属性 –兼容性 然后 选择以管理员身份运行此程序  然后 双击 Office 2010 Toolkit.exe 需要安装的工具及 ...

  7. 谷歌机器学习速成课程---3降低损失 (Reducing Loss):学习速率

    正如之前所述,梯度矢量具有方向和大小.梯度下降法算法用梯度乘以一个称为学习速率(有时也称为步长)的标量,以确定下一个点的位置.例如,如果梯度大小为 2.5,学习速率为 0.01,则梯度下降法算法会选择 ...

  8. $Java-json系列(一):用GSON解析Json格式数据

    GSON是谷歌提供的开源库,用来解析Json格式的数据,非常好用.如果要使用GSON的话,则要先下载gson-2.2.4.jar这个文件,如果是在Android项目中使用,则在Android项目的li ...

  9. 大数据架构之:Flume

    1. Flume是一个分布式.可靠.和高可用的海量日志聚合的系统,支持在系统中定制各类数据发送方,用于收集数据:同时,Flume提供对数据进行简单处理,并写到各种数据接受方(可定制)的能力. 2.一个 ...

  10. 物理分辨率与逻辑分辨率,pt与px

    有些小伙伴们,在使用chrome的移动端调试工具调试网页的时候,会发现iphone6上的尺寸为375*667,不禁差异,iphone6的分辨率不是750*1334吗? 实际上调试器上的大小单位不是px ...