Giter Site home page Giter Site logo

redis's Introduction

redis's People

Watchers

Zhang Shilei avatar

redis's Issues

redis standalone

redis standalone

使用5.0.8版本分析源码,其体系结构如下

redis-standalone

  • 网络层使用NIO模型
  • 主业务流程是单线程模式
  • 主线程定期通过fork一个bsSave task来生成rdb文件

redis cmd

redis cmd

针对IO事件,下图展示了redis的主要处理流程

redis-cmd

针对IO读事件,对流程理解上比较重要的是lookupCommand()方法,其根据请求中的redis指令查找对应的指令处理方法,单机或主备模式下redis所有的命令对应的处理方法是通过代码配置方式,在源码文件server.c中

redis-cmd1

从源码中可以看出,所有的指令配置是一个redisCommand结构体的数组

redisCommand结构如下

redis-cmd2

第二个属性proc就是一个指向实际处理方法的指针,流程中最终通过cmd.proc()执行对应的指令处理方法

redis process event

aeProcessEvents()

从前面流程图中可以看出,redis的主线程在死循环一直执行aeProcessEvents()方法,在该方法中,既处理IO事件也处理定时任务事件,其中IO事件是通过调用epoll_wait()获得的

epoll_wait()

epoll_wait

在epoll_wait()函数中有一个参数 - int _timeout,当_timeout=0时表示,如果没有IO时间,那线程将阻塞在epoll_wait()函数中,直到IO事件到达,这种情况下,redis不能处理任何事件,类似于下图

redis-epoll1

redis使用了一种很巧妙的方式来避免这个问题

redis-epoll2

  • 首先获取到离当前时间最近的事件
  • 使用最近的时间间隔设置epoll_wait()函数的_timeout参数
  • 最终,在系统没有IO事件的场景下,redis主线程最多阻塞最短定时事件时间间隔,然后开始处理定时任务 - processTimeEvents()

redis network

redis network

redis网络使用的NIO模型,在不同的操作系统版本下提供的函数不一样,redis对此做了一层封装,分2部分

  • NIO相关操作部分
  • socket相关操作部分

redis-network

redis epoll

以redis对epoll的封装为例,下图展示了redis具体通过哪些文件封装了哪些方法

redis-epoll

redis server

redis server

redis所有模式下都会有一个redisServer来保存服务需要的一些数据,redisServer结构是一个很大的struct,内部属性被划分为多个模块,比如通用模块、网络模块、RDB模块、AOF模块、Replication模块、Cluster模块等等,在server.h源码中也有相应的注释,整个struct定义从941行到1301行,非常庞大,下图展示一小部分

redis-server

  • 在主线程main()方法及其内部initServer()方法中,其中比较大的一部分就是在构建redisServer结构体
  • 上面短短的源码截图,已经出现了前面介绍过的模块的属性
  • dict *commands就执行了所有的redisCommand,其是一个dict,key是指令名称,value是redisCommand结构,例如 get -> {"get",getCommand,2,"rF",0,NULL,1,1,1,0,0}
  • aeEventLoop *el 内部是对epoll fd的封装
  • 还有一个很重要的属性redisDb *db,这就是redis内存实际存储数据的地方

redisDb

redis-db

redis-db1

  • redisDb内部有个属性dict *dic,这是redis内建的字典结构
  • dict struct内部有一个dictht结构类型数组 dictht ht[2],该数组有2个元素,dictht就是dict hashtable缩写,使用2个hashtable的目的是为了做rehash

redis replica

redis replica

redis PSYNC的实现

redis-psync

  • struct redisServer中有个字节数组 char *repl_backlog,称为积压缓冲区,还有属性long repl_backlog_off,称为复制偏移量
  • master每次执行写命令后,都将命令写入repl_backlog,然后将命令传播给所有slave
  • master每次传播N个字节,就将复制偏移量加上N
  • slave每次收到N个字节时,将自己的复制偏移量加上N
  • 如果主从服务器偏移量一致,那么主从服务器处于一致状态
  • 如果主从偏移量不一致,如果slave offset仍然处于repl_backlog中,主从将执行PSYNC(部分重同步)
  • 如果主从偏移量不一致,如果slave offset已经不处于repl_backlog中,主从将执行SYNC(完整重同步)

redis master-slave

redis master-slave

redis主从连接过程时序图

redis-master-slaver

  • 主从建立连接过程可以理解为使用状态机驱动
  • redisServer struct中有个属性repl_state
  • 客户端发送replicaof命令,redis处理该命令,设置repl_state = REPL_STATE_CONNECT,开启状态转换
  • redis使用定时器事件,根据repl_state不同状态做不同操作,最终完成主备连接,发送PSYNC命令

redis startup

redis startup

redis的启动流程图

redis-flow

  • redis的4种模式(单机模式、主备模式、哨兵模式、集群模式)都是同样的入口函数,针对不同的模式,代码内部有一些if条件判断做不同的动作
  • 单机模式、主备模式 主要关注图中标颜色的2中方法
  • initServer是做redisServer结构的初始化
  • aeMain方法内部是一个死循环,不断的处理io事件和timer事件

redisObject

redisObject

redisDb基本结构如下

redisObject1

其中,key和value都是一个redisObject,结构如下

redis-ds

关于list的实现quicklist结构如下

redis-ds2

intset的实现,看下其结构体的定义,内部其实是一个整形数组,数字按升序排列,使用二分法查找

redis-ds3

redis sentinel startup

sentinel startup

  • redis单机模式和哨兵模式的启动入口是同一个,在启动过程中,有一个if判断,当当前模式是sentinel_mode时执行sentinel的初始化:initSentinel()

sentinel0

  • sentinel模式下,redis使用一个单独的 struct sentinelState 来保存一些信息,字典属性 dict *masters 保存着所有监控的集群的master节点

sentinelState

  • 在initSentinel()中主要是对redis命令集的初始化,首先清空当前命令字典,然后用哨兵模式下的命令初始化redis服务命令集,并初始化 sentinelState 一些属性

sentinel1

  • sentinel模式有其特有的命令集,sentinel模式下的redis服务器只能执行特有的命令集

sentinelCmd

redis 6.*

redis multi thread

redis从6.0开始线程模型从单线程改为了多线程,但是并不影响原有功能,大致结构如下

redis-multithread

  • redis增加的多线程只是IO线程,将IO处理和业务逻辑处理分为2块逻辑
  • 当epoll一批IO事件到达时,redis将启动多个IO线程分组同时并行处理IO事件,main线程将阻塞等待所有IO完成
  • 当所有IO事件完成后,main线程将继续工作,依次处理各种事件
  • 所以,多线程下的redis核心线程对db的处理依然是单线程,并不会有多线程安全问题

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.