1主从模式介绍在笔者的另外两篇文章《Redis系列:RDB内存快照提供持久化能力》、《Redis稳定性之战:AOF日志支撑数据持久化》中,我们介绍了Redis中的数据持久化技术,包括RDB快照和AOF日志。有了这两个利器,我们再也不用担心机器宕机,数据丢失了。但是持久化技术只是解决了Redis服务故障之后,快速数据恢复的问题。宕机和数据恢复的过程中整个业务系统来说,还是有损失的,并没有根本上提升可用性问题,而且持久化技术对于Redis服务性能来说是有损的。我们需要的是保障Redis的高可用,减少甚至避免Redis服务发生宕机的可能。目前实现Redis高可用的模式主要有三种:主从模式、哨兵模式、
1介绍作者是互联网一线研发负责人,所在业务也是业内核心流量来源,经常参与业务预定、积分竞拍、商品秒杀等工作。近期参与多场新员工的面试工作,经常就『超高并发场景下热点数据』可用性保障与候选人进行讨论。本文聚焦一些关键点技术进行讨论,并总结一些热点场景的处理经验。2业务基础架构简图(假设)3超高并发下热点数据的稳定性保障3.1命题背景1000w+请求同时投向后端,如果缓存未建立、失效,甚至缓存服务故障,就会透过缓存层直接投向数据库。可能会造成整体击穿/雪崩,怎么破?3.2各种业务场景及应对方案3.2.1规律性热点数据预热无论是聚集式热key,还是散列式热key,只要是有一定规律性的,均可以做预热。
1介绍AOF(AppendOnlyFile)持久化:以独立日志的方式存储了Redis服务器的顺序指令序列,并只记录对内存进行修改的指令。当Redis服务发生雪崩等故障时,可以重启服务并重新执行AOF文件中的指令达到恢复数据的目的。也就是说,通过重放(replay),来重新建立Redis当前实例的内存数据结构。这种模式有没有很熟悉,可以联想到MySQL主从同步时的relaylog。相对于咱们上一篇介绍的《RDB内存快照提供持久化能力》定点快照的做法,AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式。2AOF实现日志记录2.1开启AOF日志记录1、开启AOF日志记录
1介绍从上一篇的《深刻理解高性能Redis的本质》中可以知道,我们经常在数据库层上加一层缓存(如Redis),来保证数据的访问效率。这样性能确实也有了大幅度的提升,因为从内存中取数远比从磁盘中快的多,但是本身Redis也是一层服务,也存在宕机、故障的可能性。一旦服务挂起,可能生产的后果包括如下几方面:1.Redis的数据是存在内存中的,所以一旦挂起,内存中的数据会全部丢失。2.I/O从内存层级迁移到磁盘层级,性能极速下降。3.原本访问缓存的请求会透过缓存层直接投向数据库,给数据库带来极大的压力,甚至导致雪崩。所以,缓存层崩溃产生的后果是灾难的。为了避免宕机和宕机后的数据丢失,为了保证数据的快速
1背景互联网产品为了保证高性能和高可用性,经常会使用缓存来进行架构设计。最常用的就是使用Redis了,也有部分企业会选择使用Memcache。所以了解Redis和Memcache的区别、共性以及各自应用场景,有助于我们在做技术选型的时候,有合理的判断依据。2Redis和Memcache的区别和共同点Redis和Memcache都是非常流行的内存数据存储系统,但它们在设计和使用上有一些关键的区别。2.1区别2.1.1数据结构Redis支持更丰富的数据类型(即更复杂的应用场景),包括字符串、哈希表、列表、集合、有序集合等,使得它不仅仅是一个简单的键值对存储系统。而Memcache只支持简单的键值对
1啥是RedisModuleRedisModule是Redis的一种扩展模块,从4.0版本开始,允许用户自定义扩展模块,在Redis内部实现新的数据类型和功能,使用统一的调用方式和传输协议格式扩展Redis的能力。它本身的设计目的就是在不同版本的Redis中运行,因此无需重新编译模块即可与特定版本(Redis>4.0)一起运行。通过使用RedisModule,可以在Redis中添加新的命令和数据类型,以实现更高级的功能。例如,一些第三方模块支持全文搜索、JSON数据的存储和查询、自定义分布式锁、时间序列数据的存储和查询等。我们也可以基于Redis去定制开发属于自己的Module,来支撑自
1Redis操作规范1.1缓存的使用时机判断【建议】系统为单体系统,整体QPS小于200的,不建议草率引入缓存,应该有更多的办法进行效率提升缓存的引入根据系统的业务流量、应用规模而定,对于系统规模小低并发低流量的应用而言,引入缓存并不会带来性能的显著提升,反而会带来应用的复杂度以及较高的运维成本。【建议】响应能力,数据响应的正常容忍度为0.5s,临界容忍度为2s,当我们发现响应时间超建议值,并没有太大优化空间的时候,可以考虑加入缓存。说明:建立在对数据具有高效响应的需求的时候,缓存是基于内存映射的,相对于磁盘存取来说会快很多。【建议】热点数据,这边指的是同一个系统中的相对热点数据,20%的数据
1介绍Redis是我们在业务开发中很重要的一个辅助,能够极大提高我们系统的运行效率,为后端的存储服务减少压力,提升用户使用体验。但是作为一个辅助提升速度的组件,如果自己存在请求延迟的情况,那将是一个巨大的灾难,可能引起整条业务链路的雪崩。在我以往的博客里面,也有过相应的案例,比如《架构与思维:一次缓存雪崩的灾难复盘》。但在实际业务场景中,可能有更加复杂的原因导致Redis访问效率变慢,下面我们详细来分析下。2发现和监测Redis的慢执行2.1如何判断Redis变慢了在之前的章节中,我们根据官网的资料有过这样的结论:在较高的配置基准下(比如8C16G+),在连接数为0~10000的时候,最高QP
1介绍1.1数据一致性的概念缓存与数据库的数据一致性指的是,缓存中存储的数据与数据库中存储的数据需保持一致。即缓存中存有数据,缓存的数据值=数据库中的值;缓存中没有该数据,数据库中的值=最新值。数据一致性主要包含以下两种情况:缓存中有数据,那么缓存中的值需要和数据库中值相同。缓存中本身没有数据,那么,数据库中的值必须是最新值。如果存在以下情况,则说明存在不一致性情况:缓存中有数据,但是缓存中的数据与数据库中的数据不一致。缓存或者数据库中存在旧的数据,导致单个线程读到的数据是旧的。1.2数据不一致的原因缓存(Redis)和数据库(MySQL)是两套系统,所以任何一方的数据改写,都需要另一方的协同
1介绍上一期我们介绍了Redis系列19:LRU淘汰内存淘汰算法分析,大致了解了LRU(LeastRencentlyUsed)的算法原理,即将最近最久未使用的算法进行数据淘汰。但是这样的算法也有一些比较明显缺陷:稳定性和性能问题:LRU算法认为最近最少使用的数据是最该被淘汰的,但是这可能导致某些数据被频繁地淘汰和加载,因为它们可能只在某个时间段内被使用一次,而在其他时间段内则不会被使用。这会使得缓存的效率降低,增加了CPU和内存之间的通信开销。空间问题:LRU算法需要维护一个链表来记录数据的访问顺序,这需要额外的空间。链表可能会占用较大的空间,导致缓存的效率降低。访问顺序问题:我们的访问顺序并
1介绍上一期我们介绍了Redis系列18:过期数据的删除策略,但是无论是惰性删除还是定期删除,都可能存在删除不尽的情况,无法删除完全,比如每次删除完过期的key还是超过25%,且这些key再也不会被客户端访问。这样的话,定期删除和堕性删除可能都彻底的清理掉。如果这种情况长时间持续下去,可能会导致内存耗尽,所以Redis必须有一个完善的内存淘汰机制来保障。这就是我们这一篇的重点,Redis内存自动淘汰机制。2Redis内存淘汰策略在redis中总共由8种淘汰策略,默认的淘汰策略是noeviction。noeviction不淘汰策略(默认)noeviction不淘汰策略(默认)淘汰数据策略设置过期
1介绍通过前面的章节,我们知道,Redis是一个kv型数据库,我们所有的数据都是存放在内存中的,但是内存是有大小限制的,不可能无限制的增量。想要把不需要的数据清理掉,一种办法是直接删除,这个咱们前面章节有详细说过;另外一种就是设置过期时间,缓存过期后,由Redis系统自行删除。这边需要注意的是,缓存过期之后,并不是马上删除的,那Redis是怎么删除过期数据的呢?主要通过两个方式惰性删除通过定时任务,定期选取部分数据删除2Redis缓存过期命令我们通过以下指令给指定key的缓存设置过期时间,如果都没设置过期时间,key将一直存在,直到我们使用Del的命令明确删除掉。#缓存时间过期命令,参考如下E
1BloomFilter介绍布隆过滤器(BloomFilter)是Redis4.0版本提供的新功能,我们一般将它当做插件加载到Redis服务器中,给Redis提供强大的去重功能。它是一种概率性数据结构,可用于判断一个元素是否存在于一个集合中。相比较之Set集合的去重功能,布隆过滤器空间上能节省90%+,不足之处是去重率大约在99%左右,那就是有1%左右的误判率,这种误差是由布隆过滤器的自身结构决定的。优点:空间效率和查询时间都比一般的算法要好的多缺点:有一定的误识别率和删除困难2原理分析布隆过滤器(BloomFilter)是一个高空间利用率的概率性数据结构,由二进制向量(即位数组)和一系列随机
1介绍在分布式系统中,很重要的一个能力就是消息中间件。我们通过消息队列实现功能解耦、消息有序性、消息路由、异步处理、流量削峰等能力。目前主流的Mq主要有RabbitMQ、RocketMQ、kafka,可以参考这篇《MQ系列2:消息中间件技术选型》。那除了这些主流MQ之外,咱们的这一节要说的Redis也具备实现消息队列的能力。我们来看看消息队列主要要实现哪些能力,原理是什么,以及如何在Redission中应用。2关于消息队列2.1什么是消息队列消息中间件是指在分布式系统中完成消息的发送和接收的基础软件。消息中间件也可以称消息队列(MessageQueue/MQ),用高效可靠的消息传递机制进行与平
1先来了解下分布式锁1.1什么是分布式锁分布式锁,即分布式系统中的锁,我们通过锁解决控制共享资源访问的问题,来保证只有一个线程可以访问被保护的资源。1.2分布式锁的实现方案基于数据库实现分布式锁基于Zookeeper实现分布式锁基于Redis实现分布式锁等等,本篇基于Redis角度进行讨论1.3分布式锁满足哪些特性互斥性:在分布式系统下,一个事件在同一个时间内只能被一个线程执行,即只能有一个线程持有锁。安全性:可以方便的获取锁和释放锁,不产生死锁情况过期性:具备锁失效机制,即可以在时效预期外自动解锁,防止死锁可重入:具备可重入特性(可理解为重新进入,由多于一个任务并高性能:高性能的获取锁与释放
1介绍在之前的一篇文章《一次缓存雪崩的灾难复盘》中,我们比较清晰的描述了缓存雪崩、穿透、击穿的各自特征和解决方案,想详细了解的可以移步。最近在配合HR筛选候选人,作为大厂的业务方向负责人,招人主要也是我们自己团队在用,而缓存是必不可少的面试选项之一。下面我们就来聊一聊在特定业务场景下缓存击穿和雪崩的应对场景!2问题背景一个核心的应用或者服务(比如微信、钉钉、百度APP),高峰QPS是百万甚至是千万★分析:上述类型的应用具有很明显的峰值高斯分布的特征,就是9~10点是用户早高峰。微信是,百度APP是,钉钉也是,钉钉一般给政企、教学等使用,通用是10点左右峰值期,每天的峰值如下:应用缓存了用户的基
1前言通过前面的一些文章我们知道,Redis的各项能力是基于内存实现的,相对其他的持久化存储(如MySQL、File等,数据持久化在磁盘上),性能会高很多,这也是高速缓存的一个优势。但是问题来了,每一台机器内存终归是有限的,即使是集群模式,总的内存空间也是有限的,不能无限制的消耗。而在Redis的使用过程中,很有可能出现使用消耗超过内存实际大小的情况。比如以下几种情况:未设置过期时间,Redis的Key将一直存在,直至我们明确将它删除。过度跟不合理的持久化(无论是RDB快照或是AOF日志),都会在内存和磁盘中反复操作,需要一定的内存空间进行处理。不及时清理过期缓存:清理过期缓存的方式主要有以下
1前言我们来回顾下在这个系列的第一篇深刻理解高性能Redis的本质中介绍过Redis的几种基本数据结构,它服务于各种不同的业务场景而设计的,比如:动态字符串(REDIS_STRING):整数(REDIS_ENCODING_INT)、字符串(REDIS_ENCODING_RAW)双端列表(REDIS_ENCODING_LINKEDLIST)压缩列表(REDIS_ENCODING_ZIPLIST)跳跃表(REDIS_ENCODING_SKIPLIST)哈希表(REDIS_HASH)整数集合(REDIS_ENCODING_INTSET)除了这些常见数据类型,还有一些不常用的数据类型,如BitMap、
1前言我们在第一篇深刻理解高性能Redis的本质的时候就介绍过Redis的几种基本数据结构,它是基于不同业务场景而设计的:动态字符串(REDIS_STRING):整数(REDIS_ENCODING_INT)、字符串(REDIS_ENCODING_RAW)双端列表(REDIS_ENCODING_LINKEDLIST)压缩列表(REDIS_ENCODING_ZIPLIST)跳跃表(REDIS_ENCODING_SKIPLIST)哈希表(REDIS_HASH)整数集合(REDIS_ENCODING_INTSET)除了这些常见数据类型,还有一些不常用的数据类型,如BitMap、Geo、HyperLog
1前言我们在第一篇深刻理解高性能Redis的本质的时候就介绍过Redis的几种基本数据结构,它是基于不同业务场景而设计的:动态字符串(REDIS_STRING):整数(REDIS_ENCODING_INT)、字符串(REDIS_ENCODING_RAW)双端列表(REDIS_ENCODING_LINKEDLIST)压缩列表(REDIS_ENCODING_ZIPLIST)跳跃表(REDIS_ENCODING_SKIPLIST)哈希表(REDIS_HASH)整数集合(REDIS_ENCODING_INTSET)除了这常见数据类型,还有一些不常用的数据类型,如BitMap、Geo、HyperLogL
背景前面一篇我们说到,2020年5月份,Redis官方推出了令人瞩目的Redis6.0,提出很多新特性,包括了客户端缓存(Clientsidecaching)、ACL、ThreadedI/O和RedisClusterProxy等诸多新特性。如下:我们也专门对Redis6.0的ThreadedI/O(多线程网络I/O模式)做了很详细的说明,有兴趣的翻到前面一篇。这一篇咱们就来聊下这个Clientsidecaching(客户端缓存),看看Redis为什么需要客户端缓存、是基于什么原理实现的,以及具体应该怎么使用。1为什么需要客户端缓存1.1缓存服务的目的回顾一下我们在第一篇《深刻理解高性能Redi
背景我们在第一篇《Redis系列1:深刻理解高性能Redis的本质》中就已经提到了,Redis的网络IO以及键值对指令读写是由单个线程来执行的,避免了不必要的contextswitch和资源竞争,对于性能提升有很大的帮助。而到了2020年的5月份,Redis官方推出了令人瞩目的Redis6.0,提出很多新特性,包含多线程网络IO的概念,如下:新特性内核优化应用优化其他ACL细粒度权限管控(包括ACLLOG)过期Key回收优化,增加配置参数新版本ModuleAPI全面支持SSL协议、并新增TSL协议客户端缓存(Clientsidecaching)Resp3协议,兼容Resp2,更加简单、高效di
1背景前面我们学习了Redis高可用的两种架构模式:主从模式、哨兵模式。解决了我们在Redis实例发生故障时,具备主从自动切换、故障转移的能力,最终保证服务的高可用。但是这些其实远远不够,随着我们业务规模的不断扩展,用户量膨胀,并发量持续提升。原有的主从架构,已经远远达不到我们的需求了,这时候会有一些问题出现,比如:单机的CPU、内存、连接数、计算力都是有极限的,不能无限制的承载流量的扩增。超额的请求、大规模的数据计算,导致必然的慢响应。这时候就需要适当的推进架构的演进,来满足发展的需要。2Cluster模式介绍2.1什么是Cluster模式Cluster即集群模式,类似MySQL,Redis
1背景分布式系统绕不开的核心之一的就是数据缓存,有了缓存的支撑,系统的整体吞吐量会有很大的提升。通过使用缓存,我们把频繁查询的数据由磁盘调度到缓存中,保证数据的高效率读写。当然,除了在内存内运行还远远不够,我们今天就以具有代表性的缓存中间件Redis为例子,分析下,它是如何达到飞起的效率。2Redis高效性能分析Redis之所以能够提供超高的执行效率,主要从以下几个维度来实现的:存储模式:基于内存实现,而非磁盘数据结构:基于不同业务场景的高效数据结构动态字符串(REDIS_STRING):整数(REDIS_ENCODING_INT)、字符串(REDIS_ENCODING_RAW)双端列表(RE
在前面几篇文章中,小编陆陆续续介绍了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