admin管理员组

文章数量:1561808

1.Redis热点数据

①热key描述

在上面说的缓存击穿、缓存雪崩都是因为热点key集中突然访问或者过期。突然几十万的请求都去访问这个热点key流量过于集中,达到物理网卡上限,导致这台redis服务器宕机,然后这些请求就会直接访问数据库,导致服务不可用

②怎么发现热点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协议规则解析数据,进行分析。缺点就是开发成本高,维护困难,有丢包可能性。

③怎么解决热key问题

目前存在两种解决方案:1.二级缓存、2.备份热key

1.二级缓存

比如利用ehcache,或者一个HashMap都可以。在你发现热key以后,把热key加载到系统的JVM中。

针对这种热key请求,会直接从jvm中取,而不会走到redis层。

假设此时有十万个针对同一个key的请求过来,如果没有本地缓存,这十万个请求就直接怼到同一台 redis上了。 现在假设,你的应用层有50台机器,OK,你也有jvm缓存了。这十万个请求平均分散开来,每个机器 有2000个请求,会从JVM中取到value值,然后返回数据。避免了十万个请求怼到同一台redis上的情 形。

2.备份热key

不要让key全部走一台redis服务器,在多台服务器上都备份这个热点key的内容。

接下来,有热key请求进来的时候,我们就在有备份的redis上随机选取一台,进行访问取值,返回数据。

④MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中的数据都是热点数据

淘汰策略

Redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。

Redis 提供 6 种数据淘汰策略:

  • volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

  • volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

  • volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

  • allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

  • allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

  • no-enviction(驱逐):禁止驱逐数据

12.Redis过期删除策略

①定时删除

在设置键的过期时间的时候,创建一个定时器,让定时器在快到键的过期时间来执行对键的删除操作

②定期删除

redis默认是每个100ms就随机抽取一些已经设置过期时间的key,检查是否过期,如果过期就删除

随机抽取时,如果数据的过期率超过1/4,就再执行一次抽取,直到比例低于1/4.

问题:可能已经过期的key因为没有被抽到而继续留在内存中

③惰性删除

放任键过期不管,但是每次从键空间中获取key时,都检查取得的键是否过期,如果过期的话,就删 除该键,返回空; 如果没有过期,就返回该键。

如果大量的key没有被扫描到,且已过期,也没有被再次访问,即没有走惰性删除,这些大量过期 key 堆积在内存里,也有可能导致 redis 内存块耗尽了,这种情况下,就会用到内存淘汰策略

13.Redis与MySQL数据不一致问题

为何出现

在高并发场景下,对数据的更新很容易导致redis与MySQL数据不一致的情况。

不管是先写mysql再删除redis缓存,还是先删除redis缓存再写mysql,都可能出现数据不一致的情况

比如:

(1)如果删除了redis,还没来得及去写mysql,有另外一个数据来读数据,发现缓存为空,去mysql中读,就读到不一致的数据了

(2)如果先写mysql,还没来得及删除redis,那另外一个线程就直接读到的就是redis原来的数据。

写和读是并发的,不能保证顺序,就会出现redis和mysql数据不一致的情况

解决方案

①延时双删策略

在写库前后都进行redis.del(key)操作,并且设定合理的超时时间

public void write(String key,Object data){
redis.delKey(key);   // 1.先删除缓存
db.updateData(data);  //2.mysql更新数据
Thread.sleep(500);   // 3.休眠500毫秒
redis.delKey(key);  // 4.再次删除缓存
}
 

休眠时间怎么确定:

这个休眠时间主要是为了确保读请求结束,写请求可以删除读请求造成的缓存脏数据

根据读数据业务逻辑的耗时进行设置

设置过期时间:

从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。所有的写操作以数据库为准, 只要到达缓存过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存。

弊端:

最差的情况就是在超时时间内数据存在不一致,而且又增加了写请求的耗时。

②异步更新缓存(基于订阅binlog的同步机制)

技术整体思路:

MySQL binlog增量订阅消费+消息队列+增量数据更新到redis

1)读Redis:热数据基本都在Redis

2)写MySQL:增删改都是操作MySQL

3)更新Redis数据:MySQ的数据操作binlog,来更新到Redis

Redis更新

1)数据操作主要分为两大块:

一个是全量(将全部数据一次写入到redis)

一个是增量(实时更新)

这里说的是增量,指的是mysql的update、insert、delate变更数据。

2)读取binlog后分析 ,利用消息队列,推送更新各台的redis缓存数据。

这样一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推送至Redis, Redis再根据binlog中的记录,对Redis进行更新。

其实这种机制,很类似MySQL的主从备份机制,因为MySQL的主备也是通过binlog来实现的数据一致性。 这里可以结合使用canal(阿里的一款开源框架),通过该框架可以对MySQL的binlog进行订阅,而canal 正是模仿了mysql的slave数据库的备份请求,使得Redis的数据更新达到了相同的效果。

当然,这里的消息推送工具你也可以采用别的第三方:kafka、rabbitMQ等来实现推送更新Redis。

14.Redis IO多路复用

IO多路复用概念:

在单个线程中通过记录跟踪每一个socket(IO)流的状态来管理多个IO流

在同一个线程里面, 通过拨开关的方式,来同时传输多个I/O流

Redis为什么要IO多路复用

Redis是单线程的,按顺序执行,当执行到IO操作时,读写操作在等待时进程都处于阻塞状态, I/O 操作在一般情况下往往不能直接返回,这会导致某一文件的 I/O 阻塞导致整个进程无法对其它客户提供服务

采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),且Redis在内存中操作数据的速度非常快(内存内的操作不会成为这里的性能瓶颈),主要以上两点造就了Redis具有很高的吞吐量。

实现复用的方式

①select

轮询所有流

底层采用轮询的方式判断每个文件描述符是否被激活。比较慢,但是有良好的跨平台支持;但是单个进程能够监视的文件描述符数量存在最大限制(1024)

②poll

解决了select的个数限制问题,但是依然是轮询

③epoll

基于事件回调(没有采用轮询的方式),当文件描述符被激活时都会调用一个回调函数,epoll根据回调函数直接定位文件描述符

15.Redis的一些问题

为什么 Redis 需要把所有数据放到内存中?

追求读写速度

答 :Redis 为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以 redis 具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘 I/O 速度为严重影响 redis 的性 能。在内存越来越便宜的今天,redis 将会越来越受欢迎。如果设置了最大使用的内存,则数据已有记 录数达到内存限值后不能继续插入新值。

Redis 的同步机制了解么?

答:Redis 可以使用主从同步,从从同步。第一次同步时,主节点做一次 bgsave,并同时将后续修改操 作记录到内存 buffer,待完成后将 rdb 文件全量同步到复制节点,复制节点接受完成后将 rdb 镜像加 载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过 程。

Pipeline 有什么好处,为什么要用 pipeline?

答:可以将多次 IO 往返的时间缩减为一次,前提是 pipeline 执行的指令之间没有因果相关性。使用 redis-benchmark 进行压测的时候可以发现影响 redis 的 QPS峰值的一个重要因素是 pipeline 批次指 令的数目。

Redis 集群最大节点个数是多少?

答:16384 个。

Redis 集群如何选择数据库?

答:Redis 集群目前无法做数据库选择,默认在 0 数据库。

Redis 集群方案什么情况下会导致整个集群不可用?

答:有 A,B,C 三个节点的集群,在没有复制模型的情况下,如果节点 B 失败了,那么整个集群就会以为 缺少 5501-11000 这个范围的槽而不可用。

说说 Redis 哈希槽的概念?

答:Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群有16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。

本文标签: 数据热点多路复用笔记