Redis

2020-04-25  本文已影响0人  技术灭霸

1、为什么lua脚本结合redis命令可以实现原子性

Redis 提供了非常丰富的指令集,但是用户依然不满足,希望可以自定义扩充若干指令来完成一些特定领域的问题。Redis 为这样的用户场景提供了 lua 脚本支持,用户可以向服务器发送 lua 脚本来执行自定义动作,获取脚本的响应数据。Redis 服务器会单线程原子性执行 lua 脚本,保证 lua 脚本在处理的过程中不会被任意其它请求打断。

redis会为lua脚本执行创建伪客户端模拟客户端调用redis执行命令,伪客户端执行lua脚本是排他的,再加上redis是原子性的。

2、redis分布式锁会导致什么问题。

业务逻辑执行太慢,比锁失效时间还长怎么办,redisson的WatchDog 会每10秒轮询,延长锁。

如果你很在乎高可用性,希望挂了一台 redis 完全不受影响,可以考虑 redlock。

3、redis六种淘汰key策略(默认时no-eviction)

4、redis三种删除过期键策略

定时删除(并没有用到)

在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作;

定时删除操作对于内存来说是友好的,内存不需要操作,而是通过使用定时器,可以保证尽快的将过期键删除,但是对于CPU来说不是友好的,如果过期键比较多的话,起的定时器也会比较多,删除的这个操作会占用到CPU的资源;

惰性删除

放任键过期不管,但是每次从键空间中获取键是,都检查取得的键的过期时间,如果过期的话,删除即可;

惰性操作对于CPU来说是友好的,过期键只有在程序读取时判断是否过期才删除掉,而且也只会删除这一个过期键,但是对于内存来说是不友好的,如果多个键都已经过期了,而这些键又恰好没有被访问,那么这部分的内存就都不会被释放出来;

定期删除

每隔一段时间,程序就对数据库进行一次检查,删除掉过期键;

定期删除是上面两种方案的折中方案,每隔一段时间来删除过期键,并通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响,除此之外,还有效的减少内存的浪费;但是该策略的难点在于间隔时长,这个需要根据自身业务情况来进行设置;

目前,Redis采用的是惰性删除+定期删除的方案,通过配合使用,服务器可以很好的平衡 CPU 和内存。

5、Redis4.0新特性

包含几个重大改进:更好的复制(PSYNC2),线程DEL / FLUSH,混合RDB + AOF格式,活动内存碎片整理,内存使用和性能改进。

一、主从数据同步机制

PSYNC2: 新的一种主从复制同步机制。
PSYNC1:2.8~4.0之前版本的同步为PSYNC1

psync1因为网络中断或者阻塞导致主从中断,恢复后必须重新到主节点dump一份全量数据同步到从节点。psync2再中断恢复后只需要同步复制延迟的那部分数据。

二、命令优化

线程DEL / FLUSH 优化
Redis现在可以在不同的线程中删除后台的key而不会阻塞服务器。

三、慢日志记录客户端来源IP地址,这个小功能对于故障排查很有用处。

四、混合RDB + AOF格式

混合RDB + AOF格式: 混合的RDB-AOF格式。 如果启用,则在重写AOF文件时使用新格式:重写使用更紧凑和更快的方式来生成RDB格式,并将AOF流附加到文件。 这允许在使用AOF持久性时更快地重写和重新加载。

五、内存使用和性能改进:

1、Redis现在使用更少的内存来存储相同数量的数据。
2、Redis现在可以对使用的内存进行碎片整理,并逐渐回收空间(这个功能依然是试用阶段,可以通过参数不开启即可)

6、redis有1000万个key,找出前缀为aaa的key的命令是什么?

7、本地redis客户端连接远程服务器命令

redis-cli -h host -p port -a password

8、为什么Redis选择使用跳表而不是红黑树来实现有序集合?

Redis 中的有序集合(zset) 支持的操作:

  1. 插入一个元素
  2. 删除一个元素
  3. 查找一个元素
  4. 有序输出所有元素
  5. 按照范围区间查找元素(比如查找值在 [100, 356] 之间的数据)

其中,前四个操作红黑树也可以完成,且时间复杂度跟跳表是一样的。但是,按照区间来查找数据这个操作,红黑树的效率没有跳表高。按照区间查找数据时,跳表可以做到 O(logn) 的时间复杂度定位区间的起点,然后在原始链表中顺序往后遍历就可以了,非常高效。

9、Redis Sentinel 与 Redis Cluster区别和各自适用场景

Redis Sentinel

Redis-Sentinel(哨兵模式)是Redis官方推荐的高可用性(HA)解决方案,当用Redis做Master-slave的高可用方案时,假如master宕机了,Redis本身(包括它的很多客户端)都没有实现自动进行主备切换,而Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自懂切换。它的主要功能有以下几点:

Redis Cluster

10、redis的内存优化

1、redisObject对象
2、缩减键值对象
3、共享对象池
4、字符串优化
5、编码优化
6、控制key的数量
https://www.cnblogs.com/williamjie/p/11288062.html

11、热key问题,如何发现,业内方案

热Key问题

怎么发现热key
方法一:凭借业务经验,进行预估哪些是热key
其实这个方法还是挺有可行性的。比如某商品在做秒杀,那这个商品的key就可以判断出是热key。缺点很明显,并非所有业务都能预估出哪些key是热key。
方法二:在客户端进行收集
这个方式就是在操作redis之前,加入一行代码进行数据统计。那么这个数据统计的方式有很多种,也可以是给外部的通讯系统发送一个通知信息。缺点就是对客户端代码造成入侵。
方法三:在Proxy层做收集
有些集群架构是下面这样的,Proxy可以是Twemproxy,是统一的入口。可以在Proxy层做收集上报,但是缺点很明显,并非所有的redis集群架构都有proxy。
方法四:用redis自带命令
(1)monitor命令,该命令可以实时抓取出redis服务器接收到的命令,然后写代码统计出热key是啥。当然,也有现成的分析工具可以给你使用,比如redis-faina。但是该命令在高并发的条件下,有内存增暴增的隐患,还会降低redis的性能。
(2)hotkeys参数,redis 4.0.3提供了redis-cli的热点key发现功能,执行redis-cli时加上–hotkeys选项即可。但是该参数在执行的时候,如果key比较多,执行起来比较慢。
方法五:自己抓包评估
Redis客户端使用TCP协议与服务端进行交互,通信协议采用的是RESP。自己写程序监听端口,按照RESP协议规则解析数据,进行分析。缺点就是开发成本高,维护困难,有丢包可能性。

(1)利用二级缓存
比如利用ehcache,或者一个HashMap都可以。在你发现热key以后,把热key加载到系统的JVM中。
针对这种热key请求,会直接从jvm中取,而不会走到redis层。
假设此时有十万个针对同一个key的请求过来,如果没有本地缓存,这十万个请求就直接怼到同一台redis上了。
现在假设,你的应用层有50台机器,OK,你也有jvm缓存了。这十万个请求平均分散开来,每个机器有2000个请求,会从JVM中取到value值,然后返回数据。避免了十万个请求怼到同一台redis上的情形。
(2)备份热key
这个方案也很简单。不要让key走到同一台redis上不就行了。我们把这个key,在多个redis上都存一份不就好了。接下来,有热key请求进来的时候,我们就在有备份的redis上随机选取一台,进行访问取值,返回数据。
(1)监控热key
在监控热key方面,有赞用的是方式二:在客户端进行收集。
在《有赞透明多级缓存解决方案(TMC)》中有一句话提到

TMC 对原生jedis包的JedisPool和Jedis类做了改造,在JedisPool初始化过程中集成TMC“热点发现”+“本地缓存”功能Hermes-SDK包的初始化逻辑。

也就说人家改写了jedis原生的jar包,加入了Hermes-SDK包。
那Hermes-SDK包用来干嘛?
OK,就是做热点发现和本地缓存。
从监控的角度看,该包对于Jedis-Client的每次key值访问请求,Hermes-SDK 都会通过其通信模块将key访问事件异步上报给Hermes服务端集群,以便其根据上报数据进行“热点探测”。

当然,这只是其中一种方式,有的公司在监控方面用的是方式五:自己抓包评估。
具体是这么做的,先利用flink搭建一套流式计算系统。然后自己写一个抓包程序抓redis监听端口的数据,抓到数据后往kafka里丢。
接下来,流式计算系统消费kafka里的数据,进行数据统计即可,也能达到监控热key的目的。

(2)通知系统做处理
在这个角度,有赞用的是上面的解决方案一:利用二级缓存进行处理。
有赞在监控到热key后,Hermes服务端集群会通过各种手段通知各业务系统里的Hermes-SDK,告诉他们:"老弟,这个key是热key,记得做本地缓存。"
于是Hermes-SDK就会将该key缓存在本地,对于后面的请求。Hermes-SDK发现这个是一个热key,直接从本地中拿,而不会去访问集群。

除了这种通知方式以外。我们也可以这么做,比如你的流式计算系统监控到热key了,往zookeeper里头的某个节点里写。然后你的业务系统监听该节点,发现节点数据变化了,就代表发现热key。最后往本地缓存里写,也是可以的。

12、思维导图

大纲

数据结构与对象

image image image image image

单机数据库

image image image image image

多机数据库

image image image

独立功能

image image

13、Gossip是什么

Gossip协议是一个通信协议,一种传播消息的方式,灵感来自于:瘟疫、社交网络等。使用Gossip协议的有:Redis Cluster、Consul、Apache Cassandra等。

Gossip协议基本思想就是:一个节点想要分享一些信息给网络中的其他的一些节点。于是,它周期性的随机选择一些节点,并把信息传递给这些节点。这些收到信息的节点接下来会做同样的事情,即把这些信息传递给其他一些随机选择的节点。一般而言,信息会周期性的传递给N个目标节点,而不只是一个。这个N被称为fanout(这个单词的本意是扇出)

Gossip协议的主要用途就是信息传播和扩散:即把一些发生的事件传播到全世界。它们也被用于数据库复制,信息扩散,集群成员身份确认,故障探测等

特点:
1、可扩展性:即使某条消息传播过程中丢失,它也不需要做任何补偿措施
2、失败容错:因为一个节点会多次分享某个需要传播的信息,即使不能连通某个节点,其他被感染的节点也会尝试向这个节点传播信息。
3、健壮性:没有任何扮演特殊角色的节点(比如leader等)。任何一个节点无论什么时候下线或者加入,并不会破坏整个系统的服务质量。

14、Redis中的11大优秀设计

Redis中的11大优秀设计

15、Redis RDB和AOF的优缺点对比以及如何选择

RDB的优点

RDB的缺点

AOF的优点

AOF的缺点

RDB和AOF到底该如何选择

重启Redis时,我们很少使用rdb来恢复内存状态,因为会丢失大量数据。我们通常使用AOF日志重写,

但是AOF重写性能相对rdb来说要慢很多,这样在Redis实例很大的情况下,启动需要花费很长的时间。

Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。

AOF在进行文件重写时将重写这一刻之前的内存rdb快照文件的内容和增量的AOF修改内存数据的命令日志文件存在一起,都写入新的aof文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,原子的覆盖原有的AOF文件,完成新旧两个AOF文件的替换。

混合持久化文件结构:

image

16、为什么恢复的时候RDB比AOF快?

17、怎么设置redis失效时间、怎么设置永久有效?

设置redis失效时间

**redis设置了数据永不过期 **

18、分布式锁的使用场景

使用分布式锁的目的,无外乎就是保证同一时间只有一个客户端可以对共享资源进行操作

订单系统和库存系统部署两台机器
1、检查redis库存
2、更新redis库存数量
3、锁定库存MySQL数据库
保证1、2、3是原子性。防止库存超卖

19、redis的主从复制怎么做的?

主从复制主要通过旧版同步和命令传播来实现。

20、缓存穿透、缓存击穿和缓存雪崩

image.png

1、缓存穿透

访问一个不存在的key,缓存不起作用,请求会穿透到DB,流量大时DB会挂掉。

解决方案

  1. 采用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的key,不存在的key直接被过滤;
  2. 拦截器,id<=0的直接拦截。
  3. 从cache和db都取不到,可以将key-value写为key-null,设置较短过期时间,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击。

2、缓存击穿

一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。

解决方案

  1. 设置热点数据永远不过期。
  2. 加互斥锁。

3、缓存雪崩

大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。

解决方案

  1. 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
  2. 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
  3. 设置热点数据永远不过期。

21、Redis事务和MySQL事务有什么区别?

Redis之Redis事务

image.png

22、如何使用redis来保证幂等性

可以利用redis的setnx函数对请求入参的某个唯一的字段(如orderId)做幂等拦截,防止重复处理请求。

//幂等校验
if(!jedisTemplate.setnx(RedisConstants.RED_PACKET_RECV + getRedPacketDto.getOrderId() + getRedPacketDto.getRedPacketId(), "0.00")){
//业务代码
}
业务代码执行成功删除key。

上一篇下一篇

猜你喜欢

热点阅读