Redis服务器是典型的一对多服务器程序,通过使用由IO多路复用技术实现的文件事件处理器,Redis服务器使用单线程单进程的方式来处理命令请求,并与多个客户端进行网络通信. Redis客户端与服务器之间通过TCP协议进行通信.TCP协议是一种流式协议,数据以字节流的形式进行传递,没有固有的"报文"或"报文边界"的概念,如果需要设置边界,需要应用层自行处理. 因此,Redis客户端与服务器之间的交互数据,都按照Redis自定义的统一请求协议的格式进行编码.使用这种协议…
主从复制过程中,主节点根据从节点发来的命令执行相应的操作.结合上一章中讲解的从节点在主从复制中的流程,本章以及下一篇文章讲解一下主节点在主从复制过程中的流程. 本章主要介绍完全重同步流程. 一:从节点建链和握手 从节点在向主节点发起TCP建链,以及复制握手过程中,主节点一直把从节点当成一个普通的客户端处理.也就是说,不为从节点保存状态,只是收到从节点发来的命令进而处理并回复罢了. 从节点在握手过程中第一个发来的命令是"PING",主节点调用redis.c中的pingCommand函数处…
Redis的主从复制功能,可以实现Redis实例的高可用,避免单个Redis 服务器的单点故障,并且可以实现负载均衡. 一:主从复制过程 Redis的复制功能分为同步(sync)和命令传播(commandpropagate)两个操作: 同步操作用于将从节点的数据库状态更新至主节点当前所处的数据库状态: 命令传播操作则用于在主节点的数据库状态被修改,导致主从节点的数据库状态不一致时,让主从节点的数据库重新回到一致状态: 1:同步 当客户端向从节点发送SLAYEOF命令,或者从节点的配置文件中配置了…
Redis中,处理网络IO时,采用的是事件驱动机制.但它没有使用libevent或者libev这样的库,而是自己实现了一个非常简单明了的事件驱动库ae_event,主要代码仅仅400行左右. 没有选择libevent或libev的原因大概在于,这些库为了迎合通用性造成代码庞大,而且其中的很多功能,比如监控子进程,复杂的定时器等,这些都不是Redis所需要的. Redis中的事件驱动库只关注网络IO,以及定时器.该事件库处理下面两类事件: a:文件事件(file  event):用于处理Redis…
我们再来学习如何从跳跃表中查询数据,跳跃表本质上是一个链表,但它允许我们像数组一样定位某个索引区间内的节点,并且与数组不同的是,跳跃表允许我们将头节点L0层的前驱节点(即跳跃表分值最小的节点)zsl->header.level[0].forward当成索引0的节点,尾节点zsl->tail(跳跃表分值最大的节点)当成索引zsl->length-1的节点,索引按分值从小到大递增查询:也允许我们将尾节点当成索引0的节点,头节点L0层的前驱节点当做索引zsl->length-1的节点,索…
上一篇文章已经介绍了MemoryCache,MemoryCache存储的数据类型是Object,也说了Redis支持五中数据类型的存储,但是微软的Redis缓存组件只实现了Hash类型的存储.在分析源码之前,先学几个关于Redis操作的命令. 一.Redis命令 Redis所有的命令在http://doc.redisfans.com/上有详细介绍.下面介绍几个常用的关于Hash类型的命令. HSET:用于添加缓存 用法:HSET key field value . 返回值:如果 field 是哈…
Redis集群通过分片的方式来保存数据库中的键值对:一个集群中,每个键都通过哈希函数映射到一个槽位,整个集群共分16384个槽位,集群中每个主节点负责其中的一部分槽位. 当数据库中的16384个槽位都有节点在处理时,集群处于上线状态:相反,如果数据库中有任何一个槽没有得到处理,那么集群处于下线状态. 所谓键的分配,实际上就是指槽位在集群节点中的分配:所谓键的迁移,实际上指槽位在集群节点间的迁移. 一:数据结构    在集群最主要的数据结构,记录集群状态的clusterState结构体中,与槽位相…
首先编写thrift文件(rpcserver.thrift),运行thrift --gen go rpcserver.thrift,生成代码 namespace go rpc service RpcService { : string name); : string name); } 搭建一个以二进制为传输协议的服务器如下: type rpcService struct{ } func (this *rpcService)SayHi(name string)(r string, err erro…
首先使用redis客户端来进行publish与subscribe的功能是否能够正常运行. 打开redis服务器 [root@localhost ~]# redis-server /opt/redis-2.4.10/redis.conf [7719] 16 Apr 11:37:22 # Warning: 32 bit instance detected but no memory limit set. Setting 3.5 GB maxmemory limit with 'noeviction'…
Redis集群是Redis提供的分布式数据库方案,通过分片来进行数据共享,并提供复制和故障转移功能. 一:初始化 1:数据结构 在源码中,通过server.cluster记录整个集群当前的状态,比如集群中的所有节点:集群目前的状态,比如是上线还是下线:集群当前的纪元等等.该属性是一个clusterState类型的结构体.该结构体的定义如下: typedef struct clusterState { clusterNode *myself; /* This node */ ... int sta…
链表提供了高效的节点重排能力,以及顺序性的节点访问方式,因为Redis使用的C语言并没有内置这种数据结构,所以Redis自己实现了链表. 链表在Redis中的应用非常广泛,比如列表的底层实现之一就是链表.当一个列表中包含的元素比较多时,又或者列表中包含的元素都是比较长的字符串时,Redis就会使用链表作为列表的底层实现. 除了列表之外,Redis中的发布与订阅.慢查询.监视器等功能也用到了链表,Redis服务器本身还使用链表来保存多个客户端的状态信息,以及使用链表来构建客户端输出缓冲区. 在ad…
Ziplist是用字符串来实现的双向链表,对于容量较小的键值对,为其创建一个结构复杂的哈希表太浪费内存,所以redis 创建了ziplist来存放这些键值对,这可以减少存放节点指针的空间,因此它被用来作为哈希表初始化时的底层实现.下图即ziplist 的内部结构. Zlbytes是整个ziplist 所占用的空间,必要时需要重新分配. Zltail便于快速的访问到表尾节点,不需要遍历整个ziplist. Zllen表示包含的节点数. Entries表示用户增加上去的节点. Zlend是一个255…
服务容器的绑定 bind 绑定 bind 绑定是服务容器最常用的绑定方式,在 上一篇文章中我们讨论过,bind 的绑定有三种: 绑定自身 绑定闭包 绑定接口 今天,我们这篇文章主要从源码上讲解 Ioc 服务容器是如何进行绑定的. /** * Register a binding with the container. * * @param string|array $abstract * @param \Closure|string|null $concrete * @param bool $s…
一.src/server.c 中的redisCommandTable列出的所有redis支持的命令,其中字符串命令包括从get到mget:列表命令从rpush到rpoplpush:集合命令包括从sadd到sscan:有序集合命令从zadd到zscan:哈希表命令包括从hse到hscan:地理命令包括从geoadd到geodist:位操作从bitop到bitpos:HyperLogLog命令包含padd到pfmerge等. 二.每种存储类型对应的底层数据结构 字符串-->sds.c  简单动态字符…
Redis的sentinel模式使用了Hiredis代码,Hiredis是redis数据库一个轻量级的C语言客户端库.它实现的向Redis发送命令的API函数redisCommand,使用方法类似于printf.因此只要熟悉redis命令,就可以很容易的使用该函数将redis命令字符串,转换成统一请求协议格式之后,发送给Redis服务器. Hiredis库包含三类API:同步操作API.异步操作API和回复解析API.本文主要介绍同步操作API和回复解析API,下一篇介绍异步操作API. 一:同…
zmalloc.h的内容如下: void *zmalloc(size_t size); void *zcalloc(size_t size); void *zrealloc(void *ptr, size_t size); void zfree(void *ptr); char *zstrdup(const char *s); size_t zmalloc_used_memory(void); void zmalloc_enable_thread_safeness(void); float zm…
make解析 服务容器对对象的自动解析是服务容器的核心功能,make 函数.build 函数是实例化对象重要的核心,先大致看一下代码: public function make($abstract) { $abstract = $this->getAlias($abstract); if (isset($this->deferredServices[$abstract])) { $this->loadDeferredProvider($abstract); } return parent…
除了RDB持久化功能之外,Redis还提供了AOF(AppendOnly File)持久化功能.与RDB持久化通过保存数据库中的键值对来记录数据库状态不同,AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的.与RDB持久化相比,AOF持久化可能丢失的数据更少,但是AOF持久化可能会降低Redis的性能. 写人AOF文件的所有命令都是以Redis的统一请求协议格式保存的. 在表示Redis服务器的结构体redisServer中,有关AOF的成员如下: struct redisS…
跳跃表(skiplist) 有序集合(sorted set)是Redis中较为重要的一种数据结构,从名字上来看,我们可以知道它相比一般的集合多了一个有序.Redis的有序集合会要求我们给定一个分值(score)和元素(element),有序集合将根据我们给定的分值对元素进行排序.Redis共有两种编码来实现有序集合,一种是压缩列表(ziplist),另一种是跳跃表(skiplist),也是本章的主角.下面,让笔者带领大家稍微了解下有序集合的使用. 假设某软件公司统计了公司内的程序员所掌握的编程语…
Hiredis中的异步API函数需要与事件库(libevent,libev, ev)一起工作.因为事件循环的机制,异步环境中的命令是自动管道化的.因为命令是异步发送的,因此发送命令时,必要情况下,需要提供一个回调函数,以便在收到命令回复时调用该函数. 异步API涉及到的函数分别是: redisAsyncContext *redisAsyncConnect(const char *ip, int port); int redisAsyncCommand(redisAsyncContext *ac,…
Redis的RDB持久化的相关功能主要是在src/rdb.c中实现的.RDB文件是具有一定编码格式的数据文件,因此src/rdb.c中大部分代码都是处理数据格式的问题. 一:RDB文件格式 上图就是一个完整RDB文件的格式. RDB文件的最开头是REDIS部分,这个部分的长度为5字节,保存着"REDIS"五个字符.通过这个字符串,程序可以在载人文件时,快速检查所载人的文件是否RDB文件. db_version长度为4字节,它是一个字符串表示的整数,这个整数记录了RDB文件的版本号.比如…
像keys或者smembers命令,需要遍历数据集合中的所有元素.在一个大的数据库中使用,可能会阻塞服务器较长的一段时间,造成性能问题,因此不适用与生产环境. 在Redis2.8.0中引入了scan类命令,可用于迭代整个数据库或者是哈希键.集合键和有序集合键这样的数据集合. scan类命令支持增量式迭代,它们每次执行都只会返回少量元素,所以这些命令可以用于生产环境. scan类命令使用游标迭代数据集合,命令每次被调用之后,都会向用户返回一个新的游标,用户在下次迭代时,使用这个新游标作为scan类…
在文章的开头我们把所有服务端文件列出来,并且标示出其作用: adlist.c //双向链表 ae.c //事件驱动 ae_epoll.c //epoll接口, linux用 ae_kqueue.c //kqueue接口, freebsd用 ae_select.c //select接口, windows用 anet.c //网络处理 aof.c //处理AOF文件 config.c //配置文件解析 db.c //DB处理 dict.c //hash表 intset.c //转换为数字类型数据 m…
Redis 内部有个小型的事件驱动,它主要处理两项任务: 文件事件:使用I/O多路复用技术处理多个客户端请求,并返回执行结果. 时间事件:维护服务器的资源管理,状态检查. 主要的数据结构包括文件事件结构体,时间事件结构体,触发事件结构体,事件循环结构体 /* File event structure */ typedef struct aeFileEvent { int mask; /* one of AE_(READABLE|WRITABLE) */ aeFileProc *rfileProc…
Redis的发布与订阅功能,由SUBSCRIBE,PSUBSCRIBE,UNSUBSCRIBE,PUNSUBSCRIBE,以及PUBLISH等命令实现. 通过执行SUBSCRIBE命令,客户端可以订阅一个或多个频道.当有客户端通过PUBLISH命令向某个频道发布消息时,频道的所有订阅者都会收到这条消息. 除了订阅具体的频道之外,客户端还可以通过执行PSUBSCRIBE命令订阅一个或多个频道模式.当有客户端通过PUBLISH命令向某个频道发布消息时,消息不仅会被发送给这个频道的所有订阅者,它还会发…
Redis通过MULTl,EXEC,WATCH,DISCARD等命令来实现事务(transaction)功能. 事务从MULTI命令开始,之后,该客户端发来的其他命令会被排队,客户端发来EXEC命令之后,Redis会依次执行队列中的命令.并且在执行期间,服务器不会中断事务而改去执行其他客户端的命令请求,它会将事务中的所有命令都执行完毕后,然后才去处理其他客户端的命令请求. WATCH命令,使得客户端可以在EXEC命令执行之前,监视任意数量的数据库键,并在EXEC命令执行时,检查被监视的键是否被其…
十一:TILT模式 根据之前的介绍可知,哨兵的运行,非常依赖于系统时间,但是当系统时间被调整,或者哨兵中的流程因为某种原因(比如负载较高.IO发生阻塞.进程被信号停止等)而被阻塞时,哨兵的行为就会变得不可预知了. 所谓TILT模式,就是一种特殊的保护模式.进入TILT模式后,哨兵只定期发送命令用于收集信息,而不采取实质性的动作,比如不会进行故障转移流程. 当恢复正常30秒后,哨兵就是退出TILT模式. 在哨兵的定时器函数sentinelTimer中,首先就是调用函数sentinelCheckTi…
sentinel(哨兵)是redis的高可用解决方案.由一个或多个sentinel实例组成的分布式系统,可以监控任意多个主节点,以及它们属下的所有从节点.当某个主节点下线时,sentinel可以将下线主节点属下的某个从节点升级为新的主节点. 一:哨兵进程 哨兵,本质上是redis服务器的一种运行模式.也就是说它们共用大部分的代码,只是哨兵模式中有部分代码是自己特有的. 在Makefile中,哨兵的编译和安装,实际上跟redis服务器是一模一样的: REDIS_SERVER_NAME=redis-…
本章对Redis服务器的数据库实现进行介绍,说明Redis数据库相关操作的实现,包括数据库中键值对的添加.删除.查看.更新等操作的实现:客户端切换数据库的实现:键超时相关功能的实现.键空间事件通知等. 以上这些功能,键空间事件通知是在src/notify.c中实现的,其他功能都是在src/db.c中实现的. 在redis.h中定义的redisServer数据结构,定义了redis服务器相关的所有属性,其中就包含了数据库的结构: struct redisServer { ... redisDb *…
Redis在实现键值对数据库时,并没有直接使用数据结构,而是基于已有的数据结构创建了一个对象系统,每种对象至少包含一种数据结构. redis3.0 中对象结构: typedef struct redisObject { unsigned type:4; unsigned encoding:4; unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */ int refcount; void *ptr; } r…