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全套面试题

    在这里插入图片描述

  • 相关阅读:
    poj 2187 Beauty Contest(旋转卡壳)
    poj 2540 Hotter Colder(极角计算半平面交)
    poj 1279 Art Gallery(利用极角计算半平面交)
    poj 3384 Feng Shui(半平面交的联机算法)
    poj 1151 Atlantis(矩形面积并)
    zoj 1659 Mobile Phone Coverage(矩形面积并)
    uva 10213 How Many Pieces of Land (欧拉公式计算多面体)
    uva 190 Circle Through Three Points(三点求外心)
    zoj 1280 Intersecting Lines(两直线交点)
    poj 1041 John's trip(欧拉回路)
  • 原文地址:https://www.cnblogs.com/robotsh/p/14130994.html
Copyright © 2011-2022 走看看