本套技术专栏是作者(秦凯新)平时工作的总结和升华,并深度整理大量网上资源和专业书籍。通过从真实商业环境抽取案例进行总结和分享,并给出商业应用的调优建议和集群环境容量规划等内容,请持续关注本套博客。QQ邮箱地址:1120746959@qq.com,如有任何学术交流,可随时联系。

1 Redis 工作模型

redis实际上是个单线程工作模型,其拥有较多的数据结构,并支持丰富的数据操作,redis目前是原生支持cluster模式。如果需要缓存能够支持更复杂的结构和操作,基于以上原因,选择线上使用Redis会是不错的选择。

1.1 Redis 高效的原因:

  • Redis高效的原因:

    1)纯内存操作

    2)核心是基于非阻塞的IO多路复用机制

    3)单线程反而避免了多线程的频繁上下文切换问题

  • mysql单机支撑到2000qps就会出现性能问题了,所以要是你有个系统,高峰期一秒钟过来的请求有1万,那一个mysql单机绝对会死掉。因为 redis单机支撑的并发量轻松一秒几万十几万,支撑高并发so easy。单机承载并发量是mysql单机的几十倍。

  • 使用Redis可能会遇到的问题:

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

1.2 文件事件处理流程

  • (1) redis基于reactor模式开发了网络事件处理器,这个处理器叫做文件事件处理器,file event handler。这个文件事件处理器,是单线程的,redis才叫做单线程的模型,采用IO多路复用机制同时监听多个socket,根据socket上的事件来选择对应的事件处理器来处理这个事件。

  • (2) 文件事件处理器的结构包含4个部分:多个socket,IO多路复用程序,文件事件分派器,事件处理器(命令请求处理器、命令回复处理器、连接应答处理器,等等)。

  • (3) 多个socket可能并发的产生不同的操作,每个操作对应不同的文件事件,但是IO多路复用程序会监听多个socket,但是会将socket放入一个队列中排队,每次从队列中取出一个socket给事件分派器,事件分派器把socket给对应的事件处理器。

  • (4) 一个socket的事件处理完之后,IO多路复用程序才会将队列中的下一个socket给事件分派器。文件事件分派器会根据每个socket当前产生的事件,来选择对应的事件处理器来处理。

1.3 文件事件

  • 如果一个客户端跟redis发起连接,此时会产生一个AE_READABLE事件,然后由连接应答处理器来处理跟客户端建立连接,创建客户端对应的socket,同时将这个socket的AE_READABLE事件跟命令请求处理器关联起来。

  • 如果是客户端要连接redis,那么会为socket关联连接应答处理器。

  • 如果是客户端要写数据到redis,那么会为socket关联命令请求处理器。

  • 如果是客户端要从redis读数据,那么会为socket关联命令回复处理器。

1.4 客户端与redis通信流程

  • 创建客户端对应的socket

    在redis启动初始化的时候,redis会将连接应答处理器跟AE_READABLE事件关联起来,接着如果一个客户端跟redis发起连接,此时会产生一个AE_READABLE事件,然后由连接应答处理器来处理跟客户端建立连接,创建客户端对应的socket,同时将这个socket的AE_READABLE事件跟命令请求处理器关联起来。

  • 请求处理,socket产生一个AE_READABLE事件

    当客户端向redis发起请求的时候(不管是读请求还是写请求,都一样),首先就会在socket产生一个AE_READABLE事件,然后由对应的命令请求处理器来处理。这个命令请求处理器就会从socket中读取请求相关数据,然后进行执行和处理。

  • 客户端这读取响应数据

    接着redis这边准备好了给客户端的响应数据之后,就会将socket的AE_WRITABLE事件跟命令回复处理器关联起来,当客户端这边准备好读取响应数据时,就会在socket上产生一个AE_WRITABLE事件,会由对应的命令回复处理器来处理,就是将准备好的响应数据写入socket,供客户端来读取。

  • 命令回复处理器写完之后,就会删除这个socket的AE_WRITABLE事件和命令回复处理器的关联关系。

2 redis 过期策略及内存淘汰机制

  • 用内存当缓存。内存是无限的吗?内存是很宝贵而且是有限的,磁盘是廉价而且是大量的。可能一台机器就几十个G的内存,但是可以有几个T的硬盘空间。redis主要是基于内存来进行高性能、高并发的读写操作的。

      set key value 过期时间(1小时)set进去的key,1小时之后就没了,就失效了,但是数据明明都过期了,怎么还占用着内存呢?
    复制代码
  • 定期删除+惰性删除

    所谓定期删除,指的是redis默认是每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。假设redis里放了10万个key,都设置了过期时间,你每隔几百毫秒,就检查10万个key,那redis基本上就死了,cpu负载会很高的,消耗在你的检查过期key上了。注意,这里可不是每隔100ms就遍历所有的设置过期时间的key,那样就是一场性能上的灾难。实际上redis是每隔100ms随机抽取一些key来检查和删除的。

    所谓惰性删除了,指的是在你获取某个key的时候,redis会检查一下 ,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。

    如果定期删除漏掉了很多过期key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?如果大量过期key堆积在内存里,导致redis内存块耗尽了,也会出现严重的线上事故。

  • 内存淘汰

    如果redis的内存占用过多的时候,此时会进行内存淘汰,有如下一些策略:

      redis 10个key,现在已经满了,redis需要删除掉5个key1个key,最近1分钟被查询了100次1个key,最近10分钟被查询了50次1个key,最近1个小时倍查询了1次
    复制代码

    1)noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。

    2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)

    3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的key给干掉啊。

    4)volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key(这个一般不太合适)

    5)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key

    6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除

3 redis 高并发和高可用企业级实践

  • redis高并发:主从架构,一主多从,一般来说,很多项目其实就足够了,单主用来写入数据,单机几万QPS,多从用来查询数据,多个从实例可以提供每秒10万的QPS。

    redis高并发的同时,还需要容纳大量的数据:一主多从,每个实例都容纳了完整的数据,比如redis主就10G的内存量,其实你就最对只能容纳10g的数据量。如果你的缓存要容纳的数据量很大,达到了几十g,甚至几百g,或者是几t,那你就需要redis集群,而且用redis集群之后,可以提供可能每秒几十万的读写并发。

  • redis高可用:如果你做主从架构部署,其实就是加上哨兵就可以了,就可以实现,任何一个实例宕机,自动会进行主备切换。

4 redis replication基本原理

  • redis采用异步方式复制数据到slave节点,不过redis 2.8开始, slave node会周期性地确认自己每次复制的数据量

  • 一个master node是可以配置多个slave node的

  • slave node也可以连接其他的slave node

  • slave node做复制的时候,是不会阻塞master node正常工作的

  • slave node在做复制的时候,也不会block对自己的查询操作,它会用旧的数据集来提供服务; 但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了

  • slave node主要用来进行横向扩容,做读写分离,扩容的slave node可以提高读的吞吐量。

5 Redis数据持久性重要性

5.1 数据丢失风险

  • 如果采用了主从架构,那么建议必须开启master node的持久化,不建议用slave node作为master node的数据热备,因为那样的话,如果你关掉master的持久化,可能在master宕机重启的时候数据是空的,然后可能一经过复制,salve node数据也丢了。

    master -> RDB和AOF都关闭了 -> 全部在内存中

    master宕机,重启,是没有本地数据可以恢复的,然后就会直接认为自己IDE数据是空的

    master就会将空的数据集同步到slave上去,所有slave的数据全部清空。

    100%的数据丢失,因此master节点,必须要使用持久化机制。

  • 采用高可用机制也是有风险的,slave node可以自动接管master node,但是也可能sentinal还没有检测到master failure,master node就自动重启了,还是可能导致上面的所有slave node数据清空故障。

5.2 主从架构和断点续传原理

  • 当启动一个slave node的时候,它会发送一个PSYNC命令给master node。如果这是slave node重新连接master node,那么master node仅仅会复制给slave部分缺少的数据; 否则如果是slave node第一次连接master node,那么会触发一次full resynchronization

    开始full resynchronization的时候,master会启动一个后台线程,开始生成一份RDB快照文件,同时还会将从客户端收到的所有写命令缓存在内存中。RDB文件生成完毕之后,master会将这个RDB 发送给slave,slave会先写入本地磁盘,然后再从本地磁盘加载到内存中。然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据。

    slave node如果跟master node有网络故障,断开了连接,会自动重连。master如果发现有多个slave node都来重新连接,仅仅会启动一个rdb save操作,用一份数据服务所有slave node。

  • 从redis 2.8开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份

    master node会在内存中常见一个backlog,master和slave都会保存一个replica offset还有一个master id,offset就是保存在backlog中的。如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制

    但是如果没有找到对应的offset,那么就会执行一次resynchronization

  • 无磁盘化复制,master在内存中直接创建rdb,然后发送给slave,不会在自己本地落地磁盘了,

    repl-diskless-sync
    repl-diskless-sync-delay,等待一定时长再开始复制,因为要等更多slave重新连接过来
    复制代码
  • 过期key处理

    slave不会过期key,只会等待master过期key。如果master过期了一个key,或者通过LRU淘汰了一个key,那么会模拟一条del命令发送给slave。

5 Redis主从复制原理深入剖析

5.1 完整流程

  • slave node启动,仅仅保存master node的信息,包括master node的host和ip,但是复制流程没开始时, master host和ip是从哪儿来的,是在redis.conf里面的slaveof配置的。
  • slave node内部有个定时任务,每秒检查是否有新的master node要连接和复制,如果发现,就跟master node建立socket网络连接
  • slave node发送ping命令给master node
  • 口令认证,如果master设置了requirepass,那么salve node必须发送masterauth的口令过去进行认证
  • master node第一次执行全量复制,将所有数据发给slave node
  • master node后续持续将写命令,异步复制给slave node

5.2 数据同步

  • master和slave都会维护一个offset

    master会在自身不断累加offset,slave也会在自身不断累加offset slave每秒都会上报自己的offset给master,同时master也会保存每个slave的offset

    这个倒不是说特定就用在全量复制的,主要是master和slave都要知道各自的数据的offset,才能知道互相之间的数据不一致的情况。

  • backlog

    master node有一个backlog,默认是1MB大小

    master node给slave node复制数据时,也会将数据在backlog中同步写一份

    backlog主要是用来做全量复制中断后增量复制的

  • master run id

    info server,可以看到master run id,如果根据host+ip定位master node,是不靠谱的,如果master node重启或者数据出现了变化,那么slave node应该根据不同的run id区分,run id不同就做全量复制 如果需要不更改run id重启redis,可以使用redis-cli debug reload命令

  • psync

    从节点使用psync从master node进行复制,psync runid offset

    master node会根据自身的情况返回响应信息,也可能是FULLRESYNC runid offset触发全量复制,可能是CONTINUE触发增量复制。

5.3 全量复制

  • master执行bgsave,在本地生成一份rdb快照文件
  • master node将rdb快照文件发送给salve node,如果rdb复制时间超过60秒(repl-timeout),那么slave node就会认为复制失败,可以适当调节大这个参数
  • 对于千兆网卡的机器,一般每秒传输100MB,6G文件,很可能超过60s
  • master node在生成rdb时,会将所有新的写命令缓存在内存中,在salve node保存了rdb之后,再将新的写命令复制给salve node
  • client-output-buffer-limit slave 256MB 64MB 60,如果在复制期间,内存缓冲区持续消耗超过64MB,或者一次性超过256MB,那么停止复制,复制失败
  • slave node接收到rdb之后,清空自己的旧数据,然后重新加载rdb到自己的内存中,同时基于旧的数据版本对外提供服务
  • 如果slave node开启了AOF,那么会立即执行BGREWRITEAOF,重写AOF
  • rdb生成、rdb通过网络拷贝、slave旧数据的清理、slave of rewrite,很耗费时间,如果复制的数据量在4G~6G之间,那么很可能全量复制时间消耗到1分半到2分钟。

5.4 增量复制

  • 如果全量复制过程中,master-slave网络连接断掉,那么salve重新连接master时,会触发增量复制
  • master直接从自己的backlog中获取部分丢失的数据,发送给slave node,默认backlog就是1MB
  • msater就是根据slave发送的psync中的offset来从backlog中获取数据的。

5.5 heartbeat

  • 主从节点互相都会发送heartbeat信息,master默认每隔10秒发送一次heartbeat,salve node每隔1秒发送一个heartbeat。

5.6 异步复制

master每次接收到写命令之后,先在内部写入数据,然后异步发送给slave node

6 总结

在此感谢石杉的讲义,结合大数据在我们工业大数据平台的实践,总结成一篇实践指南,方便以后查阅反思,后续我会根据本篇博客进行代码技术实践实现。

凯新云技术社区

转载于:https://juejin.im/post/5c8cd67bf265da2dc006a168

Redis内核原理及读写一致企业级架构深入剖析1-综合组件环境实战相关推荐

  1. Redis 读写分离技术架构解析

    以下文章来源方志朋的博客,回复"666"获面试宝典 Redis 不管主从版还是集群规格,replica作为备库不对外提供服务,只有在发生HA的时候,replica提升为master ...

  2. Redis读写分离技术架构解析

    作者:小热爱 来源:juejin.cn/post/6955355686108659726 背景 Redis 不管主从版还是集群规格,replica作为备库不对外提供服务,只有在发生HA的时候,repl ...

  3. Redis基础与高可用集群架构进阶详解

    一.NoSQL简介 1.问题引入 每年到了过年期间,大家都会自觉自发的组织一场活动,叫做春运!以前我们买票都是到火车站排队,后来呢,有了 12306,有了它以后就更方便了,我们可以在网上买票,但是带来 ...

  4. B-树(B-Tree)与二叉搜索树(BST):讲讲数据库和文件系统背后的原理(读写比较大块数据的存储系统数据结构与算法原理)...

    人类总喜欢发明创造一些新名词(比如说,简写/缩写/简称什么的),并通过这些名词把人群分成了三六九等.弄到最后,把自己都绕晕了. 你看,首先就是,B树,不要与Binary tree或B+tree混淆. ...

  5. 全面剖析Redis Cluster原理和应用 (good)

    redis redis cluster注意的问题 : 1.'cluster-require-full-coverage'参数的设置.该参数是redis配置文件中cluster模式的一个参数,从字面上基 ...

  6. Redis系列教程(二):详解Redis的存储类型、集群架构、以及应用场景

    高并发架构系列 高并发架构系列:数据库主从同步的3种一致性方案实现,及优劣比较 高并发架构系列:Spring Cloud的核心成员.以及架构实现详细介绍 高并发架构系列:服务注册与发现的实现原理.及实 ...

  7. redis单线程原理___Redis为何那么快-----底层原理浅析

    redis单线程原理 redis单线程问题 单线程指的是网络请求模块使用了一个线程(所以不需考虑并发安全性),即一个线程处理所有网络请求,其他模块仍用了多个线程. 1. 为什么说redis能够快速执行 ...

  8. 高性能分布式缓存redis(持久化原理 安全策略 过期删除内存淘汰策略 性能压测 高可用 Redis Cluster)

    redis redis(持久化原理 安全策略 过期删除&内存淘汰策略 性能压测 高可用 Redis Cluster) 1. 持久化原理 1.1 持久化流程(落盘) 1.2 RDB详解 1.2. ...

  9. 全面剖析Redis Cluster原理和应用

    全面剖析Redis Cluster原理和应用 1.Redis Cluster总览 1.1 设计原则和初衷 在官方文档Cluster Spec中,作者详细介绍了Redis集群为什么要设计成现在的样子.最 ...

最新文章

  1. python编写安装脚本_Python-将脚本安装到系统
  2. Solaris的syslog机制
  3. vSphere利用NTP为主机同步时间
  4. html 制作条形图,Highcharts 基本条形图
  5. Caffe+Kubuntu16.04_X64+CUDA 8.0配置
  6. 从 vue3 和 vite 源码中,我学到了一行代码统一规范团队包管理器的神器
  7. java 根据类路径获取类_Java类加载器
  8. 谈一下我对如何设计微服务接口的理解和思考
  9. 一个文件版的名片管理系统(Python3)
  10. qtouch跨平台组态软件
  11. 架构之美第九章-架构与设计
  12. 计算机质量监督检验报告,质量监督检验(检测)报告自动生成管理系统软件
  13. 动态生成的html click事件,如何动态生成HTML时将jquery附加到click()事件?
  14. 【黑灰产犯罪研究】恶意点击
  15. java 制作甘特图,看我如何用简单的步骤打造出复杂的web甘特图
  16. 26个字母大小写转换
  17. 红米AC2100路由器刷机教程(附避坑秘籍)
  18. uniapp APPH5端获取地理位置信息(百度地图高德地图)
  19. Caffe中的损失函数
  20. CMOS反相器基础(数字电路学习笔记)

热门文章

  1. mysql path密码忘记_mysql密码忘记
  2. BZOJ3196 二逼平衡树 ZKW线段树套vector(滑稽)
  3. C# 大数组赋值给小数组,小数组赋值给大数组
  4. HTML5八大特性助力移动WebApp开发
  5. linq distinct 不够用了!
  6. 如何去掉有背景图的a标签的边框
  7. @@ERROR 变量
  8. Hyperledger fabric学习笔记(一)
  9. AttributeError: module ‘urllib’ has no attribute ‘quote’的解决办法
  10. Storm对DRPC权限控制Version1.0.1