搞懂Redis,这一篇就够了

1、缓存带来的好处:

  • 高性能
    大量相同的请求过来,每次查询mysql耗时600ms,如果用缓存耗时20ms,性能提高30倍.
  • 高并发
    单机mysql一般的最大QPS 2000,超过2000mysql直接死掉;单机redis QPS轻松10万,并发提高50倍.

2、缓存带来的坏处:

  • 缓存与数据库的双写不一致
  • 缓存雪崩、缓存穿透、缓存击穿
  • 缓存并发竞争问题

3、redis高性能的三大核心(为什么单线程还能这么快):

  • 纯内存操作:

这时Redis达到每秒万级别访问的重要基础

  • 单线程:

保证高并发下数据的一致性,避免了多线程下的并发问题:资源共享、线程切换、死锁、竞态产生的消耗;

  • 多路I/O复用,非阻塞I/O:

linux平台下,Redis使用epoll作为I/O多路复用技术的实现,在加上Redis自身的事件处理模型将epoll中的链接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间;

3.1 源码层面

C语言编写,源代码精简(2万行),C语言实现的程序”距离“操作系统更近,执行速度快;
Redis源码里,包含了多种数据结构的实现:
简单动态字符串(SDS)、双端链表、字典、压缩列表、整数集合、跳跃表等等;
Redis并没有直接使用这些数据结构来实现键值对数据库,而是基于这些数据结构创建了一个对象系统,这个系统包含了字符串、列表、哈希、集合、有序集合这五种类型的对象,每种对象都用到了至少一种前面所说的数据结构;
针对不同的使用场景,为对象设置多种不同的数据结构实现,从而优化对象在不同场景下的使用效率;

image.png

4、除了缓存,Redis能做些什么特别的事 ?

  • 利用redis生成唯一key
  • 分布式锁
  • 消息队列

5、利用redis实现分布式锁

redis是单线程的,利用setnx命令的原子性(判断指定key是否存在,不存在才能添加成功),实现多线程状态下的分布式锁
SET my_key my_value NX PX milliseconds

引用:如何优雅地用Redis实现分布式锁?

6、redis过期策略

Reference:引用
当redis存了非常多数据数据时,过期的数据不是实时删除的,如果每次删除都是扫描全部获取过期数据,代价太大,所以很可能当内存满了时,会先删除没有过期的

定期删除

每个一段时间,从设置了过期的key里面随机挑选,判断是否过期,过期则删除

惰性删除

通过定期删除肯定会遗留很多没删掉的,所以,当在获取某个key时,会判断是否已经过期,过期则删除不返回

8、内存淘汰机制(LRU算法)

当内存不足以容纳新写入数据时,redis会启用内存淘汰机制:

  • allkey_LRU:移除最近最少使用的key(最常用
  • allkey_Random:随机移除一个key
  • volatile_LRU:在设置了过期时间的键空间中,移除最近最少使用的key
  • volatile_Random:在设置了过期时间的键空间中,随机移除key
  • volatile_TTL:在设置了过期时间的键空间中,优先移除更早过期的key

9、Redis的I/O多路复用

Reference:引用
下面举一个例子,模拟一个tcp服务器处理30个客户socket。假设你是一个老师,让30个学生解答一道题目,然后检查学生做的是否正确,你有下面几个选择:

  1. 第一种选择:按顺序逐个检查,先检查A,然后是B,之后是C、D。。。这中间如果有一个学生卡主,全班都会被耽误。这种模式就好比,你用循环挨个处理socket,根本不具有并发能力。
  2. 第二种选择:你创建30个分身,每个分身检查一个学生的答案是否正确。 这种类似于为每一个用户创建一个进程或者线程处理连接。
  3. 第三种选择,你站在讲台上等,谁解答完谁举手。这时C、D举手,表示他们解答问题完毕,你下去依次检查C、D的答案,然后继续回到讲台上等。此时E、A又举手,然后去处理E和A。。。

这种就是IO复用模型,Linux下的select、poll和epoll就是干这个的。将用户socket对应的fd注册进epoll,然后epoll帮你监听哪些socket上有消息到达,这样就避免了大量的无用操作。此时的socket应该采用非阻塞模式。这样,整个过程只在调用select、poll、epoll这些调用的时候才会阻塞,收发客户消息是不会阻塞的,整个进程或者线程就被充分利用起来,这就是事件驱动,所谓的reactor模式。

java的NIO 是IO的多路复用; IO多路复用听上去好像是多个数据可以共享一个IO(socket连接),实际上并非如此。IO多路复用不是指多个服务共享一个连接,而仅仅是指多个连接的管理可以在同一进程。

IO多路复用:各个平台的底层IO复用实现各不相同,linux采用select、poll、epoll实现,macOS采用kqueue,windows采用IOCP,netty在此基础上进行了封装,使其更好用,而底层实际上是调用的当前平台的IO复用接口(native方法),而Redis底层也是依赖平台的IO复用

10、redis 集群的三种模式

10.1 主从复制(无法保证高可用)

image.png

10.2 哨兵模式(无法保证高性能)

Redis主从模式虽然能做到很好的数据备份,但是他并不是高可用的。一旦主服务器点宕机后,只能通过人工去切换主服务器。因此Redis的哨兵模式也就是为了解决主从模式的高可用方案。


image.png

10.3 集群模式

Redis哨兵模式实现了高可用,读写分离,但是其主节点仍然只有一个,即写入操作都是在主节点中,这也成为了性能的瓶颈。
因此Redis在 3.0 后加入了Cluster模式,它采用去无心节点方式实现,集群将会通过分片方式保存数据库中的键值对;
每个分片节点又通过主从方式保证高可用:与哨兵类似,分片中的每个节点会定期向其他节点发送消息,已检测各个节点的状态,如果主节点被半数以上节点检测到下线,会重新选择主节点;


image.png
  • 集群模式下的扩缩容:
    每个分片节点的分片范围维护在配置文件中,当增删节点时,需要将重新将16383个slots分配到集群中的节点上(数据迁移)

11、一致性Hash算法

先说一个误区:Redis的集群模式本身没有使用一致性hash算法,而是使用slots插槽实现了数据分片
一致性Hash算法主要用于解决分布式缓存集群节点新增,和节点失效的问题;
我们说的一致性hash都不是缓存机器自身的功能,而是集群前置的代理或客户端实现的。比如在redis的jedis客户端jar包就是实现了一致性hash算法(客户端模式)。

12、缓存穿透、缓存雪崩、缓存击穿

缓存穿透(不存在key)
  • 概念:访问一个数据库不存在的key,一般情况不会缓存这种数据,所以的请求都命中DB;
  • 解决方案
  1. 采用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的key,不存在的key直接被过滤;引用

  2. 访问key未在DB查询到值,也将空值写进缓存,但可以设置较短过期时间。

缓存雪崩(同时过期)
  • 概念:大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。
  • 解决方案
    可以给缓存设置过期时间时加上一个随机值时间,使得每个key的过期时间分布开来,不会集中在同一时刻失效。
缓存击穿(热点key过期)
  • 概念
    一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。
  • 解决方案
    设置热点缓冲永不过期
    缓存预热:每次查出来看看是不是要过期了,快过期了则更新缓存
    在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key。

13、数据库与缓存双写一致性问题

引用
一般采用:先更新数据库,再删除缓存

14、redis的持久化

14.1 redis持久化的意义

redis服务器宕机的兜底措施,避免宕机时直接访问数据库、降低请求响应速度;

14.2 AOF(Append Only File)日志

写后日志,类似redo log,每执行一次命令,如果成功则保存命令到aof日志文件,在主线程中执行,有阻塞风险;

  • 三种写回策略


    AOF三种写回策略

AOF重写机制

如果一直往AOF文件里写日志,日志文件会爆炸;
当AOF文件的大小超过了配置所设置的阙值时,Redis就会启动AOF文件压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof;

  • 触发机制:Redis会记录上次重写时的AOF文件大小,默认配置时当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发
      auto-aof-rewrite-percentage 100 (一倍)
       auto-aof-rewrite-min-size 64mb
    AOF重写可避免主线程阻塞:主线程fork一个子线程,同时把主线程的内存通过写时复制的方式拷贝给子线程,然后子线程在不影响主线程的情况下逐一把拷贝的数据写成操作,记入重写日志;
    如果在子线程写日志的过程中主线程产生的数据,会放到一个缓存区中,后续写入AOF文件;
    AOF非阻塞的重写过程

14.3 RDB(Redis DataBase)内存快照

默认持久化方式

与AOF对比

AOF记录的是操作命令,不是实际数据,故障恢复的时候缓慢;
RDB能够快速恢复,但是相比于AOF的增量式操作,RDB的全量试操作更耗时耗力;

两个命令来生成RDB

Redis 提供了两个命令来生成 RDB 文件,分别是 save 和 bgsave。

  • save:在主线程中执行,会导致阻塞;
  • bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是 Redis RDB 文件生成的默认配置。

AOF和RDB结合使用

Redis 4.0提出一个混合使用AOF日志和内存快照的方法;内存快照以一定频率执行,两次快照间,使用AOF日志记录这期间的所有命令操作;
这个方法既能享受到 RDB 文件快速恢复的好处,又能享受到 AOF 只记录操作命令的简单优势

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容