zoukankan      html  css  js  c++  java
  • redis 八股文

    1.redis 是什么?

    redis 是 nosql(也是个巨大的 map) 单线程,但是可处理 1 秒 10w 的并发(数
    据都在内存中)
    使用 java 对 redis 进行操作类似 jdbc 接口标准对 mysql,有各类实现他的实现
    类,我们常用的是 druid
    其中对 redis,我们通常用 Jedis(也为我们提供了连接池 JedisPool)
    在 redis 中,key 就是 byte
    redis 的数据结构(value):
    String,list,set,orderset,hash
    每种数据结构对应不同的命令语句

    2.redis 怎么使用?

    先安装好 redis,然后运行,在 pom 文件中引入依赖,在要使用 redis 缓存的类
    的 mapper.xml 文件配置 redis 的全限定名。引入 redis 的 redis.properties 文
    件(如果要更改配置就可以使用)

    3.应用场景

    list(双向链表)

    1 可以使用 redis 的 list 模拟队列,堆,栈

    2 朋友圈点赞(一条朋友圈内容语句,若干点赞语句)
    规定:朋友圈内容的格式:

    1,内容: user❌post:x content 来存储;点赞: post❌good list 来存储;(把相应头像取出来显示)

    4.为什么 redis 是单线程的都那么快

    • 1.数据存于内存
    • 2.用了多路复用 I/O
    • 3.单线程

    5.redis 也可以进行发布订阅消息吗?

    可以,(然后可以引出哨兵模式(后面会讲)怎么互相监督的,就是因为每隔 2
    秒哨兵节点会发布对某节点的判断和自身的信息到某频道,每个哨兵订阅该频道
    获取其他哨兵节点和主从节点的信息,以达到哨兵间互相监控和对主从节点的监
    控)和很多专业的消息队列系统(例如 Kafka、RocketMQ)相比,Redis 的发
    布订阅略显粗糙,例如无法实现消息堆积和回溯。但胜在足够简单

    6.redis 能否将数据持久化,如何实现

    能,将内存中的数据异步写入硬盘中,两种方式:RDB(默认)和 AOF

    RDB 持久化原理:通过 bgsave 命令触发,然后父进程执行 fork 操作创建
    子进程,子进程创建 RDB 文件,根据父进程内存生成临时快照文件,完成后对
    原有文件进行原子替换(定时一次性将所有数据进行快照生成一份副本存储在硬
    盘中)

    优点:是一个紧凑压缩的二进制文件,Redis 加载 RDB 恢复数据远远快于 AOF
    的方式。

    缺点:由于每次生成 RDB 开销较大,非实时持久化,

    AOF 持久化原理:开启后,Redis 每执行一个修改数据的命令,都会把这
    个命令添加到 AOF 文件中。

    优点:实时持久化。

    缺点:所以 AOF 文件体积逐渐变大,需要定期执行重写操作来降低文件体积,
    加载慢

    7.主从复制模式下,主挂了怎么办?

    redis 提供了
    哨兵模式(高可用)
    何谓哨兵模式?就是通过哨兵节点进行自主监控主从节点以及其他哨兵节点,发
    现主节点故障时自主进行故障转移

    8.哨兵模式实现原理?(2.8 版本或更高才有)

    1.三个定时监控任务:

    • 1.1 每隔 10s,每个 S 节点(哨兵节点)会向主节点和从节点发送 info 命令获
      取最新的拓扑结构
    • 1.2 每隔 2s,每个 S 节点会向某频道上发送该 S 节点对于主节点的判断以及当
      前 Sl 节点的信息,
      同时每个 Sentinel 节点也会订阅该频道,来了解其他 S 节点以及它们对主节点
      的判断(做客观下线依据)
    • 1.3 每隔 1s,每个 S 节点会向主节点、从节点、其余 S 节点发送一条 ping 命令
      做一次心跳检测(心跳检测机制),来确认这些节点当前是否可达

    2.主客观下线

    • 2.1 主观下线:根据第三个定时任务对没有有效回复的节点做主观下线处理
    • 2.2 客观下线:若主观下线的是主节点,会咨询其他 S 节点对该主节点的判断,
      超过半数,对该主节点做客观下线

    3.选举出某一哨兵节点作为领导者

    • 来进行故障转移。选举方式:raft
      算法。每个 S 节点有一票同意权,哪个 S 节点做出主观下线的时候,就会询问其
      他 S 节点是否同意其为领导者。获得半数选票的则成为领导者。基本谁先做出客
      观下线,谁成为领导者

    9.redis 集群(采用虚拟槽方式,高可用)原理(和哨兵模式原理类似,3.0 版本或以上才有)

    1.Redis 集群内节点通过 ping/pong 消息实现节点通信,消息不但可以传播节
    点槽信息,还可以传播其他状态如:主从状态、节点故障等。因此故障发现也是
    通过消息传播机制实现的,主要环节包括:主观下线(pfail)和客观下线(fail)

    2.主客观下线:

    • 2.1 主观下线:集群中每个节点都会定期向其他节点发送 ping 消息,接收节点
      回复 pong 消息作为响应。如果通信一直失败,则发送节点会把接收节点标记为
      主观下线(pfail)状态。
    • 2.2 客观下线:超过半数,对该主节点做客观下线
    • 3.主节点选举出某一主节点作为领导者,来进行故障转移。
    • 4.故障转移(选举从节点作为新主节点)

    10.缓存更新策略(即如何让缓存和 mysql 保持一致性)?

    10.1 key 过期清除(超时剔除)策略

    惰性过期(类比懒加载,这是懒过期):只有当访问一个 key 时,才会判断该 key
    是否已过期,过期则清除。该策略可以最大化地节省 CPU 资源,却对内存非常
    不友好。极端情况可能出现大量的过期 key 没有再次被访问,从而不会被清除,
    占用大量内存。
    定期过期:每隔一定的时间,会扫描一定数量的数据库的 expires 字典中一定数
    量的 key,并清除其中已过期的 key。该策略是前两者的一个折中方案。通过调
    整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得 CPU 和
    内存资源达到最优的平衡效果。
    (expires 字典会保存所有设置了过期时间的 key 的过期时间数据,其中,key 是
    指向键空间中的某个键的指针,value 是该键的毫秒精度的 UNIX 时间戳表示的
    过期时间。键空间是指该 Redis 集群中保存的所有键。)
    问:比如这么个场景,我设计了很多 key,过期时间是 5 分钟,当前内存占用率
    是 50%。但是 5 分钟到了,内存占用率还是很高,请问为什么?
    Redis 中同时使用了惰性过期和定期过期两种过期策略,即使过期时间到了,但
    是有部分并没有真正删除,等待惰性删除。
    为什么有定期还要有惰性呢?其实很简单,比如 10 万个 key 就要过期了,Redis
    默认是 100ms 检查一波。如果他检查出 10 万个即将要清除,那他接下来的时
    间基本都是在干这些清空内存的事了,那肯定影响性能,所以他只会部分删除,
    剩下的等惰性

    10.2 Redis 的内存淘汰策略

    Redis 的内存淘汰策略是指在 Redis 的用于缓存的内存不足时,怎么处理需要新
    写入且需要申请额外空间的数据。

    • noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
    • allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用
      的 key。
    • allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个
      key。
    • volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,
      移除最近最少使用的 key。
    • volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空
      间中,随机移除某个 key。
    • volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,
      有更早过期时间的 key 优先移除

    11.如何防止缓存穿透?

    (缓存穿透指的是查询一个根本不存在的数据,缓存层不命中,又去查存储层,
    又不命中。但如果有大量这种查询不存在的数据的请求过来,会对存储层有较大
    压力,若是恶意攻击,后果就)

    • 采用布隆过滤器,将所有可能存在的数据存到一个bitMap中,不存在的数据就会进行拦截。
    • 对查询结果为空的情况也进行缓存,缓存时间设置短一点,不超过5分钟。

    12.无底洞优化?

    造成原因:redis 分布式越来越多,导致性能反而下降,因为键值分布到更多的
    节点上,所以无论是 Memcache 还是 Redis 的分布式,批量操作通常需要从不
    同节点上获取,相比于单机批量操作只涉及一次网络操作,分布式批量操作 会
    涉及多次网络时间。 即分布式过犹不及。

    用一句通俗的话总结就是,更多的节点不代表更高的性能,所谓“无底 洞”就是说投入越多不一定产出越多。但是分布式又是不可以避免的,因为 访问量和数据量越来越大,一个节点根本抗不住,所以如何高效地在分布式缓存中批量操作是一个难点
    优化思路

    命令本身的优化,例如优化SQL语句等

    • 减少网络通信次数
    • 降低接入成本,例如客户端使用长连/连接池、NIO等

    这里我们假设命令、客户端连接已经为最优,重点讨论减少网络操作次数
    以Redis批量获取n个字符串为例,有三种实现方法,如下图所示:

    • 客户端n次get:n次网络+n次get命令本身
    • 客户端1次pipeline get:1次网络+n次get命令本身
    • 客户端1次mget:1次网络+1次mget命令本身

    13.雪崩优化

    如果缓存层由于某些原因不能提供服务,于是所有的请求都会达到存储层,存储
    层的调用量会暴增,造成存储层也会级联宕机的情况

    • 1、保持缓存层服务器的高可用。
      –监控、集群、哨兵。当一个集群里面有一台服务器有问题,让哨兵踢出去。
    • 2、依赖隔离组件为后端限流并降级。
      比如推荐服务中,如果个性化推荐服务不可用,可以降级为热点数据。
    • 3、提前演练。
      演练 缓存层crash后,应用以及后端的负载情况以及可能出现的问题。
      对此做一些预案设定。

    14.热点 key 优化

    当前 key 是一个热点 key(例如一个热门的娱乐新闻),并发量非常大

    • 1、互斥锁:
      只允许一个请求重建缓存。
      其他请求等待缓存重建执行完,重新从缓存获取数据即可。

    • 2、用户过期
      “物理”不过期,
      逻辑设置过期时间(根据上一次更新时间,构建一个队列,主动去更新)

    15.Redis 持久化机制

    Redis 是一个支持持久化的内存数据库,通过持久化机制把内存中的数据同步到
    硬盘文件来保证数据持久化。当 Redis 重启后通过把硬盘文件重新加载到内存,
    就能达到恢复数据的目的。
    实现:单独创建 fork()一个子进程,将当前父进程的数据库数据复制到子进程的
    内存中,然后由子进程写入到临时文件中,持久化的过程结束了,再用这个临时
    文件替换上次的快照文件,然后子进程退出,内存释放。

    RDB 是 Redis 默认的持久化方式。按照一定的时间周期策略把内存的数据以快
    照的形式保存到硬盘的二进制文件。即 Snapshot 快照存储,对应产生的数据文
    件为 dump.rdb,通过配置文件中的 save 参数来定义快照的周期。( 快照可以
    是其所表示的数据的一个副本,也可以是数据的一个复制品。

    AOF:Redis 会将每一个收到的写命令都通过 Write 函数追加到文件最后,类似
    于 MySQL 的 binlog。当 Redis 重启是会通过重新执行文件中保存的写命令来
    在内存中重建整个数据库的内容。
    当两种方式同时开启时,数据恢复 Redis 会优先选择 AOF 恢复

    16 缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题

    一、缓存雪崩

    我们可以简单的理解为:由于原有缓存失效,新缓存未到期间
    (例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存
    过期),所有原本应该访问缓存的请求都去查询数据库了,而对数据库 CPU 和内
    存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整
    个系统崩溃。

    解决办法:
    大多数系统设计者考虑用加锁( 最多的解决方案)或者队列的方式保证来保证
    不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落
    到底层存储系统上。还有一个简单方案就时讲缓存失效时间分散开。

    二、缓存穿透

    缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导
    致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回
    空(相当于进行了两次无用的查询)。这样请求就绕过缓存直接查数据库,这也
    是经常提的缓存命中率问题。
    解决办法;

    • 最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的
      bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底
      层存储系统的查询压力。

    • 另外也有一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数据
      不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会
      很短,最长不超过五分钟。通过这个直接设置的默认值存放到缓存,这样第二次
      到缓冲中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴。
      5TB 的硬盘上放满了数据,请写一个算法将这些数据进行排重。如果这些数据是
      一些 32bit 大小的数据该如何解决?如果是 64bit 的呢?
      对于空间的利用到达了一种极致,那就是 Bitmap 和布隆过滤器(Bloom Filter)。

    Bitmap: 典型的就是哈希表

    缺点是,Bitmap 对于每个元素只能记录 1bit 信息,如果还想完成额外的功能,
    恐怕只能靠牺牲更多的空间、时间来完成了。

    布隆过滤器(推荐)

    就是引入了 k(k>1)k(k>1)个相互独立的哈希函数,保证在给定的空间、误判率
    下,完成元素判重的过程。

    它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别
    率和删除困难。

    Bloom-Filter 算法的核心思想就是利用多个不同的 Hash 函数来解决“冲突”。
    Hash 存在一个冲突(碰撞)的问题,用同一个 Hash 得到的两个 URL 的值有可
    能相同。为了减少冲突,我们可以多引入几个 Hash,如果通过其中的一个 Hash
    值我们得出某元素不在集合中,那么该元素肯定不在集合中。只有在所有的 Hash
    函数告诉我们该元素在集合中时,才能确定该元素存在于集合中。这便是
    Bloom-Filter 的基本思想。
    Bloom-Filter 一般用于在大数据量的集合中判定某元素是否存在。

    三、缓存预热

    缓存预热这个应该是一个比较常见的概念,相信很多小伙伴都应该可以很容易的
    理解,缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样
    就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户
    直接查询事先被预热的缓存数据!

    解决思路:

    • 1、直接写个缓存刷新页面,上线时手工操作下;
    • 2、数据量不大,可以在项目启动的时候自动进行加载;
    • 3、定时刷新缓存;

    四、缓存更新

    除了缓存服务器自带的缓存失效策略之外(Redis默认的有6中策略可供选择),
    我们还可以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种:

    • (1)定时去清理过期的缓存;
    • (2)当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话
      就去底层系统得到新数据并更新缓存。

    两者各有优劣,第一种的缺点是维护大量缓存的 key 是比较麻烦的,第二种的缺
    点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂!具体用哪种方
    案,大家可以根据自己的应用场景来权衡。

    五、缓存降级

    当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核
    心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根
    据一些关键数据进行自动降级,也可以配置开关实现人工降级。
    降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级
    的(如加入购物车、结算)。
    以参考日志级别设置预案:

    • (1)一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自
      动降级;
    • (2)警告:有些服务在一段时间内成功率有波动(如在 95~100%之间),可以
      自动降级或人工降级,并发送告警;
    • (3)错误:比如可用率低于 90%,或者数据库连接池被打爆了,或者访问量突
      然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级;
    • (4)严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级。
      服务降级的目的,是为了防止 Redis 服务故障,导致数据库跟着一起发生雪崩问
      题。因此,对于不重要的缓存数据,可以采取服务降级策略,例如一个比较常见
      的做法就是,Redis 出现问题,不去数据库查询,而是直接返回默认值给用户

    17.热点数据和冷数据是什么

    热点数据,缓存才有价值
    对于冷数据而言,大部分数据可能还没有再次访问到就已经被挤出内存,不仅占
    用内存,而且价值不大。频繁修改的数据,看情况考虑使用缓存

    对于上面两个例子,寿星列表、导航信息都存在一个特点,就是信息修改频率不
    高,读取通常非常高的场景。
    对于热点数据,比如我们的某 IM 产品,生日祝福模块,当天的寿星列表,缓存
    以后可能读取数十万次。再举个例子,某导航产品,我们将导航信息,缓存以后
    可能读取数百万次。

    数据更新前至少读取两次缓存才有意义。这个是最基本的策略,如果缓存
    还没有起作用就失效了,那就没有太大价值了。
    那存不存在,修改频率很高,但是又不得不考虑缓存的场景呢?有!比如,这个
    读取接口对数据库的压力很大,但是又是热点数据,这个时候就需要考虑通过缓
    存手段,减少数据库的压力,

    比如我们的某助手产品的,点赞数,收藏数,分享
    数等是非常典型的热点数据,但是又不断变化,此时就需要将数据同步保存到
    Redis 缓存,减少数据库压力。

    18.Memcache 与 Redis 的区别都有哪些

    • 存储方式 Memecache 把数据全部存在内存之中,断电后会挂掉,数据不
      能超过内存大小。 Redis 有部份存在硬盘上,redis 可以持久化其数据
    • 数据支持类型 memcached 所有的值均是简单的字符串,redis 作为其替代
      者,支持更为丰富的数据类型 ,提供 list,set,zset,hash 等数据结构的存储
    • 使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协
      议不一样。 Redis 直接自己构建了 VM 机制 ,因为一般的系统调用系统函数
      的话,会浪费一定的时间去移动和请求。
    • value 值大小不同:Redis 最大可以达到 1gb;memcache 只有 1mb。 5)redis 的速度比 memcached 快很多
    • Redis 支持数据的备份,即 master-slave 模式的数据备份

    19.单线程的 redis 为什么这么快

    • 纯内存操作
    • 单线程操作,避免了频繁的上下文切换
    • 采用了非阻塞 I/O 多路复用机制

    20.Redis 为什么是单线程的

    官方 FAQ 表示,因为 Redis 是基于内存的操作,CPU 不是 Redis 的瓶颈,Redis
    的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且
    CPU 不会成为瓶颈,那就顺理成章地采用单线程的方案了(毕竟采用多线程会
    有很多麻烦!)Redis 利用队列技术将并发访问变为串行访问

    • 绝大部分请求是纯粹的内存操作(非常快速)
    • 采用单线程,避免了不必要
      的上下文切换和竞争条件

    非阻塞 IO 优点:

    • 速度快,因为数据存在内存中,类似于 HashMap,HashMap 的优势就是查
      找和操作的时间复杂度都是 O(1)
    • 支持丰富数据类型,支持 string,list,set,sorted set,hash
    • 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,
      要么全部不执行
    • 丰富的特性:可用于缓存,消息,按 key 设置过期时间,过期后将会自动删
      除如何解决 redis 的并发竞争 key 问题
      同时有多个子系统去 set 一个 key。这个时候要注意什么呢? 不推荐使用 redis
      的事务机制。因为我们的生产环境,基本都是 redis 集群环境,做了数据分片操
      作。你一个事务中有涉及到多个 key 操作的时候,这多个 key 不一定都存储在
      同一个 redis-server 上。因此,redis 的事务机制,十分鸡肋。(1)如果对这个 key 操作,不要求顺序: 准备一个分布式锁,大家去抢锁,抢到
      锁就做 set 操作即可 ;(2) 如果对这个 key 操作,要求顺序: 分布式锁+时间戳。 假设这会系统 B 先
      抢到锁,将 key1 设置为{valueB 3:05}。接下来系统 A 抢到锁,发现自己的 valueA
      的时间戳早于缓存中的时间戳,那就不做 set 操作了。以此类推。(3) 利用队列,将 set 方法变成串行访问也可以 redis 遇到高并发,如果保证读
      写 key 的一致性
      对redis的操作都是具有原子性的,是线程安全的操作,你不用考虑并发问题,redis
      内部已经帮你处理好并发的问题了。

    21.Redis 集群方案应该怎么做?都有哪些方案?

    1.twemproxy,大概概念是,它类似于一个代理方式, 使用时在本需要连接
    redis 的地方改为连接 twemproxy, 它会以一个代理的身份接收请求并使用
    一致性 hash 算法,将请求转接到具体 redis,将结果再返回 twemproxy。
    缺点: twemproxy 自身单端口实例的压力,使用一致性 hash 后,对 redis
    节点数量改变时候的计算值的改变,数据无法自动移动到新的节点。

    2.codis,目前用的最多的集群方案,基本和 twemproxy 一致的效果,但它支
    持在 节点数量改变情况下,旧节点数据可恢复到新 hash 节点

    3.redis cluster3.0 自带的集群,特点在于他的分布式算法不是一致性 hash,而
    是 hash 槽的概念,以及自身支持节点设置从节点。具体看官方文档介绍。

    22.有没有尝试进行多机 redis 的部署?如何保证数据一致的?

    主从复制,读写分离
    一类是主数据库(master)一类是从数据库(slave),主数据库可以进行读写操
    作,当发生写操作的时候自动将数据同步到从数据库,而从数据库一般是只读的,
    并接收主数据库同步过来的数据,一个主数据库可以有多个从数据库,而一个从
    数据库只能有一个主数据库。

    33.对于大量的请求怎么样处理

    redis 是一个单线程程序,也就说同一时刻它只能处理一个客户端请求;
    redis 是通过 IO 多路复用(select,epoll, kqueue,依据不同的平台,采取不
    同的实现)来处理多个客户端请求的

    34.Redis 常见性能问题和解决方案?

    (1) Master 最好不要做任何持久化工作,如 RDB 内存快照和 AOF 日志文件

    (2) 如果数据比较重要,某个 Slave 开启 AOF 备份数据,策略设置为每秒同步
    一次

    (3) 为了主从复制的速度和连接的稳定性, Master 和 Slave 最好在同一个局
    域网内

    (4) 尽量避免在压力很大的主库上增加从库

    (5) 主从复制不要用图状结构,用单向链表结构更为稳定,即: Master <-
    Slave1 <- Slave2 <-
    Slave3

    35.为什么 Redis 的操作是原子性的,怎么保证原子性的?

    对于 Redis 而言,命令的原子性指的是:一个操作的不可以再分,操作要么执行,
    要么不执行。
    Redis 的操作之所以是原子性的,是因为 Redis 是单线程的。
    Redis 本身提供的所有 API 都是原子操作,Redis 中的事务其实是要保证批量操
    作的原子性。
    多个命令在并发中也是原子性的吗?
    不一定, 将 get 和 set 改成单命令操作,incr 。使用 Redis 的事务,或者使用
    Redis+Lua==的方式实现

    36.Redis 事务

    Redis 事务功能是通过 MULTI、EXEC、DISCARD 和 WATCH 四个原语实现的
    Redis 会将一个事务中的所有命令序列化,然后按顺序执行。

    1.redis 不支持回滚“Redis 在事务失败时不进行回滚,而是继续执行余下的命
    令”, 所以 Redis 的内部可以保持简单且快速。

    2.如果在一个事务中的命令出现错误,那么所有的命令都不会执行;

    3.如果在一个事务中出现运行错误,那么正确的命令会被执行。

    • MULTI 命令用于开启一个事务,它总是返回 OK。 MULTI 执行之后,客户
      端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到
      一个队列中,当 EXEC 命令被调用时,所有队列中的命令才会被执行。
    • EXEC:执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令
      执行的先后顺序排列。 当操作被打断时,返回空值 nil。
    • 通过调用 DISCARD,客户端可以清空事务队列,并放弃执行事务, 并且客
      户端会从事务状态中退出。
    • WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为。 可以
      监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执
      行,监控一直持续到 EXEC 命令。

    37.Redis 实现分布式锁

    Redis 为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户
    端对 Redis 的连接并不存在竞争关系 Redis 中可以使用 SETNX 命令实现分布式
    锁。
    将 key 的值设为 value ,当且仅当 key 不存在。 若给定的 key 已经存在,
    则 SETNX 不做任何动作

    解锁:使用 del key 命令就能释放锁

    解决死锁:

    • 通过 Redis 中 expire()给锁设定最大持有时间,如果超过,则 Redis 来帮我
      们释放锁。
    • 使用 setnx key “当前系统时间+锁持有的时间”和 getset key “当前系
      统时间+锁持有的时间”组合的命令就可以实现。

    福利

    关注公众号:程序员小R,回复“666” 获取2G全套面试题

    在这里插入图片描述

  • 相关阅读:
    终端解析 规格严格
    用HQ时,出现了一个Bug 规格严格
    GC这篇文章介绍得很基本 规格严格
    DB2协议研究 规格严格
    JVM monitoring 规格严格
    很有趣的GC内容 规格严格
    在linux内核中修改TCP MSS值 规格严格
    最近为项目写了一个调试模块,由此想到的一些内容 规格严格
    Java中国象棋博弈程序探秘[3]——着法合法性判断
    NetBeans 时事通讯(刊号 # 10 Jun 03, 2008)
  • 原文地址:https://www.cnblogs.com/robotsh/p/14130994.html
Copyright © 2011-2022 走看看