在前面几篇文章中,小编陆陆续续介绍了Redis用到的所有主要数据结构,如比如简单动态字符串(SDS)、字典(dict)、压缩列表(ziplist)、整数集合(intset)、跳跃表(skiplist)。然而Redis并没有直接使用这些数据结构来实现键值对的数据库,而是在这些数据结构之上又包装了一层RedisObject(对象),RedisObject有五种对象:字符串对象、列表对象、哈希对象、集合对象和有序集合对象。redisObject定义在redis.h文件中:typedefstructredisObject{unsignedtype:4;unsignedencoding:4;unsign
intset是Redis实现Set的底层实现之一,当集合元素不大于设定值并且元素都是整数时,就会用intset作为Set的底层数据结构。它有如下几个特点:元素类型只能为数字元素有三种类型:int16_t、int32_t、int64_t元素有序且不可重复和SDS一样,intset也是内存连续的,就像数组一样下面是数据结构的定义:typedefstructintset{//编码类型int16_t、int32_t、int64_tuint32_tencoding;//长度最大长度:2^32uint32_tlength;//数组,元素int8_tcontents[];}intset;encoding:为
关于跳跃表其实在JUC里面有一个并发容器就是利用跳跃表来实现的:ConcurrentSkipListMap(【死磕Java并发】—–J.U.C之Java并发容器:ConcurrentSkipListMap)。这篇博客我们来分析Redis里面的跳跃表。skiplist什么是跳跃表?百度百科是这么定义的:跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表。跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能。从这里我们我们了解到,跳跃表是一种有序的数据结构,通过在节点上面增加索引(指针)从而达到快速检索的目的。跳
这篇文章我们来分析Redis数据结构的第三个:ziplist。什么是ziplist什么是ziplist?Redis官方是这样定义的:Theziplistisaspeciallyencodedduallylinkedlistthatisdesignedtobeverymemoryefficient.Itstoresbothstringsandintegervalues,whereintegersareencodedasactualintegersinsteadofaseriesofcharacters.Itallowspushandpopoperationsoneithersideoftheli
字符串使我们在编程过程中使用最为广泛的对象了,在Redis中同样如此。我们知道Redis是C语言实现的,但是Redis放弃了C语言传统的字符串而是自己创建了一种名为简单动态字符串SDS(SimpleDynamicString)的抽象类型,并将SDS用作Redis的默认字符串表示,其主要原因就是传统的字符串表示方式并不能满足Redis对字符串在安全性、效率、以及功能方面的要求。所以这篇文章就来说说SDS。在Redis里面,只会将C语言字符串当做字符串字面量,用于一些无须对字符串进行修改的地方,比如打印日志。在大多数场景下,Redis都是使用SDS来作为字符串的表示。对比C语言字符串,SDS具有如
字典,又称映射,是一种用于保存键值对的抽象数据结构。在Redis中,字典得到了广泛的使用,比如Redis的数据库就是使用字典来作为底层实现的Redis中的字典有dict.h/dict结构表示,如下:typedefstructdict{//类型特定函数//type里面主要记录了一系列的函数,可以说是规定了一系列的接口dictType*type;//私有数据//privdata保存了需要传递给那些类型特定函数的可选参数void*privdata;//两张哈希表dicththt[2];//rehash索引,并没有rehash时,值为-1longrehashidx;//目前正在运行的安全迭代器的数量u
Redis是一个可基于内存亦可持久化的日志型(aof,rdb)、高性能Key-Value数据库,并提供多种语言的API,Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。本文将详细介绍Rediscluster搭建过程,集群为三主三从。准备工作本次集群准备三台服务器(虚拟机也可以),每台服务器上面安装两个Redis实例,端口分别是6379和6380,如下:IPRedis实例192.168.2.170Redis1(6379/主)、Redis2(6380/从)192.168.2.142Redis1(6379/主)、Redis2(6380/
我们知道Redis的所有数据都存储在内存中,内存是我们系统中的一个非常珍贵的资源,不能随意浪费,所以如何合理高效地利用Redis内存就变得非常重要了。本文从两个方面来阐述Redis的内存机制:知道Redis的内存主要消耗在什么地方如何管理内存查看内存在文章【死磕Redis】-----info命令详解介绍了infomemory命令可以查看Redis内存消耗情况,是我们分析Redis内存使用情况的好工具。执行命令后如下:我们重点关注几个指标:属性名属性说明used_memoryRedis分配器分配的内存总量,指Redis存储的所有数据所占的内存used_memory_human以可读的形式返回us
Redis提供了一个非常有用的查看状态信息的命令:info。它以一种易于理解和阅读的格式,返回关于Redis服务器的各种信息和统计数值。使用方法有如下三种:info:部分Redis系统状态统计信息。infoall:全部Redis系统状态统计信息。infosection:某一块的系统状态统计信息,其中section可以忽略大小写。详细内容如下表格:参数名说明server获取server信息clients获取clients信息,如客户端连接数等memory获取server的内存信息,包括当前内存消耗、内存使用峰值persistence获取server的持久化配置信息stats获取server的一些
上篇博文【死磕Redis】---哨兵(一):部署哨兵架构介绍了RedisSentinel是一个能够自动完成故障发现和故障转移并通知应用方,从而实现真正的高可用的分布式架构,他具备监控、通知、自动故障转移等功能,同时详细演示了哨兵的架构部署和自动故障转移,相信各位小伙伴对Redis哨兵机制有了一个简单的认识,这篇博文将详细介绍哨兵的基本原理,包括:心跳机制主观下线、客观下线Sentinel选举故障转移心跳检查Sentinel通过三个定时任务来完成对各个节点的发现和监控,这是保证Redis高可用的重要机制。1、每隔10秒,每个Sentinel节点会向已知的主从节点发送info命令获取最新的主从架构
在介绍Redis主从复制的时候,提到了相比于单机的Redis架构,主从复制架构具有如下优势:保证数据安全性。从节点作为主节点备份,一旦主节点不可用,从节点可以顶上去,保证了数据尽量不被丢失提高读能力。主从读写分离,横向扩展的系统的读负载Redis高可用的基础但是主从复制架构有一个非常致命的问题,那就是一旦主节点由于故障不可用时,需要手动将一个从节点晋升为主节点,需要将其他节点的主节点替换为新的主节点,同时还需要修改应用的主节点地址,如果应用方没使用配置中心则还需要重启服务,整个过程都需要人工干预,而且工程量也不小,这是一个无法接受的问题。幸好,在Redis2.8提供比较完善的解决方案:Redi
前面两篇博客已经详细介绍了主从复制的原理,相信各位对Redis的主从复制有了一个比较深入的了解,这篇博客主要介绍主从复制的应用以及它的一些问题。读写分离我们都知道对于读多写少的场景,我们可以使用读写分离的方式来提供整体的并发量,对于Redis也一样,由于从节点是主节点的副本,我们可以利用主节点提供写服务,一个或者多个从节点提供读服务,这样就最大化Redis的读负载能力。当然,这样并不是说主从架构下的读写分离没有问题,恰恰是有大问题,在这种情况下,业务需要面对如下几个问题:数据延迟读到过期数据从节点故障数据延迟在命令传送阶段,Redis主从节点同步命令的过程是异步的,所以势必会导致主从节点的数据
在上篇博客【死磕Redis】---主从复制(一)提到,主从节点在数据同步阶段,主节点会根据当前状态的不同执行不同复制操作,包括:全量复制和部分复制,这篇博文将详细介绍这两种情况。全量复制:用于首次复制或者其他不能进行部分复制的情况。全量复制是一个非常重的操作,一般我们都要规避它部分复制:用于从节点短暂中断的情况(网络中断、短暂的服务宕机)。部分复制是一个非常轻量级的操作,因为它只需要将中断期间的命令同步给从节点即可,相比于全量复制,它显得更加高效。在Redis2.8以前,从节点向主节点发送sync命令请求同步数据,此种方式是全量复制。在Redis2.8以后,Redis支持部分复制,发送的命令是
在前面持久化文章中(【死磕Redis】---持久化)阐述了,单台服务器是如何保证数据安全性的,它保证了即使Redis服务器因为宕机而重启也不会丢失数据,因为他将内存中的数据持久化到硬盘中了,在重启的时候只需要重新加载即可,但是如果硬盘坏了呢?是不是就没救了,就算硬盘没坏,你去重启Redis应用,服务不可用得产生多发的负面影响?所以我们应该尽量避免这种因为单点故障而导致Redis服务不可用的情况。Redis单机部署一般存在如下几个问题:机器故障,导致Redis不可用,数据丢失容量瓶颈:容量不能水平扩展QPS瓶颈:一台机器的处理能力、网络宽带总是有限的,如果能够划分一些流量到其他机器,可以有效解决
我们知道Redis的数据全部都存储在内存中,如果Redis服务器突然宕机,则会导致数据全部丢失,所以必须要有一种机制来保证Redis的数据不丢失或者丢失很少一部分,这种机制就是Redis的持久化机制。Redis的持久化则是将内存中的数据持久备份到硬盘中,在服务重启时可以恢复。Redis目前提供了两种持久化方式:RDB,即RedisDataBase:把Redis服务器中内存的数据保存到一个dump文件中,数据的集合AOF,即Append-onlyfile:把所有对Redis服务器进行修改的命令保存到一个aof文件中,命令的集合下面就这两种方式来做详细说明。RDBRDB,即Redis的内存快照,它
我们知道MySQL提供了慢查询日志帮助我们定位系统存在的慢操作,同样在Redis里面也提供了类似的功能。所谓慢查询日志就是系统记录那些执行时间超过预设阀值的命令,包括发生时间、耗时、命令的详细信息等相关信息都记录下来。慢查询的作用:通过慢查询分析,找到有问题的命令进行优化。Redis执行命令分为四个步骤:发送命令、命令排队、执行命令、返回结果。需要注意的是,慢查询只统计步骤3的时间,所以没有慢查询并不代表客户端没有超时问题。Redis慢查询有两个参数需要配置:slowlog-log-slower-than:设置慢查询预设的超时阈值,单位是微秒slowlog-max-len:表示慢查询日志存储的
Redis提供了基于“发布/订阅”模式的消息机制,发送者(publish)发布消息,订阅者(subscribe)接收消息,两者之间不需要进行直接通信,他们之间通过频道进行消息传递。发布者向指定的频道(channel)发布消息,订阅了该频道的订阅者都可以接收到该消息。Redis中相关的命令如下:PSUBSCRIBEpattern[pattern...]:订阅一个或多个符合给定模式的频道。PUBSUBsubcommand[argument[argument...]]:查看订阅与发布系统状态。PUBLISHchannelmessage:将信息发送到指定的频道。PUNSUBSCRIBE[pattern
布隆过滤器在讲述布隆过滤器的原理之前,我们先思考一个问题,如果想要判断一个元素是否存在,你通常会怎么做?一般的做法都是将其保存起来然后通过比较确认,一共会有如下几种情况:如果使用线性表或者数组存储,则查找的时间复杂度为O(n)。如果使用树存储,则查找的时间复杂度为O(logn)。如果使用哈希表存储,则查找的时间复杂度为O(log(n/m)),m为哈希分桶数。对于上述三种情况我相信大部分读者都倾向于哈希表,因为其时间复杂度最低(在极端情况下时间复杂度可以为O(1)),但是哈希表也有缺陷,例如存储容量占比高,考虑到负载因子的存在,通常存储空间都不会被用完。当然无论是哈希表、树、线性表,一旦元素的数
在前面博客中小编提到过Redis性能瓶颈主要是网络,主要原因就在于Redis执行命令的时间通常在微妙级别。正常情况下,我们执行一条Redis命令流程要经过如下几个步骤:客户端发送Redis命令,阻塞等待Redis应答Redis接收到命令,执行命令应答,客户端收到响应信息其中1、3称之为一次RTT(RoundTripTime)。在这种情况下,如果同时执行大量命令,那当前命令需要等待上一条命令应答完成后才会执行,这个过程不仅仅只有多次RTT,还有频繁的调用系统IO,发送网络请求,如下图:把大量的时间消耗在来回路上,真正办事的时间就只有一点点,这种做法是非常不明智且低效的,为了解决这种低效的做法,p
Redis通过MULTI、EXEC、DISCARD、WATCH、UNWATCH来实现事务功能,Redis事务具备如下几个特性Redis会将事务中的多个命令一次性、按顺序一次执行,在执行期间可以保证不会中断事务去执行其他命令Redis的事务机制是不能保证原子性的,它只保证隔离性和一致性。Redis事务详解Redis的事务形式如下:multicommand1()command2()...commandn()exec/discardmulti标志着事务的开始,在multi之后的命令都不会执行,全部进入事务队列中,直到服务器接收exec或者discard才会开始执行或者放弃整个事务,当执行完整个事务后
Redis在单线程下还可以支持高并发的一个重要原因就是Redis的线程模型:基于非阻塞的IO多路复用机制。这篇文章就Redis的线程模型做详细说明。Redis是基于reactor模式开发了网络事件处理器,这个处理器叫做文件事件处理器(fileeventhandler)。由于这个文件事件处理器是单线程的,所以Redis才叫做单线程的模型。采用IO多路复用机制同时监听多个Socket,根据socket上的事件来选择对应的事件处理器来处理这个事件。模型如下图:从上图可知,文件事件处理器的结构包含了四个部分:多个SocketIO多路复用程序文件事件分派器事件处理器多个socket会产生不同的事件,不同
我们在第一次成功安装完Redis,启动Redis服务后,都会通过ping命令来测试Redis服务是否启动成功,如果服务启动成功则会响应PONG,否则启动失败。这么一个简单的过程就完成了Redis客户端-服务端的一次交互。我们知道,Redis客户端与服务端是通过命令的方式来完成交互过程的,主要分为两个部分:网络模型和序列化协议。前者讨论的是数据交互的组织方式,后者讨论的是数据如何序列化。本篇文章将分析后者即,Redis的序列化协议。简介Redis的通信协议是RedisSerializationProtocol,翻译为Redis序列化协议,简称RESP。它具有如下特征:在TCP层是二进制安全的基于
Redis的重要性不需要小编再次强调,无论是你工作中,还是面试中,你几乎不可能离开他,尤其是面试中,几乎每次面试都会被问到,他也是区分你实力的一个重要标志,小编有一次面试就是夭折在Redis,那时对Redis的了解仅限于客户端的使用和对Redis分布式锁有点儿了解,连集群都没有部署过。在写这篇文章的半年前,小编对Redis同样仅限于jedis/Redisson客户端的使用,顶多再加点分布式锁的知识,其余的都是懵懵懂懂,一知半解。于是,小编花了几个月时间死磕了一番Redis,一边学习一边做笔记,完成后,遇到面试者,每次必问Redis,而他们大部分也是每逢Redis必死(当然不会仅限于Redis而