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个key
    1个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 总结

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

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

  1. ShardingSphere内核原理 原创 鸽子 架构漫谈 2021-01-09

    ShardingSphere内核原理 原创 鸽子 架构漫谈 2021-01-09

  2. 15套java架构师、集群、高可用、高可扩展、高性能、高并发、性能优化、Spring boot、Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm大型分布式项目实战视频教程

    * { font-family: "Microsoft YaHei" !important } h1 { color: #FF0 } 15套java架构师.集群.高可用.高可扩展. ...

  3. 15套java架构师、集群、高可用、高可扩 展、高性能、高并发、性能优化Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm大型分布式项目实战视频教程

    * { font-family: "Microsoft YaHei" !important } h1 { color: #FF0 } 15套java架构师.集群.高可用.高可扩 展 ...

  4. 全面剖析Redis Cluster原理和应用 (转)

    1.Redis Cluster总览 1.1 设计原则和初衷 在官方文档Cluster Spec中,作者详细介绍了Redis集群为什么要设计成现在的样子.最核心的目标有三个: 性能:这是Redis赖以生 ...

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

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

  6. 【Redis】四、Redis设计原理及相关问题

    (六)Redis设计原理及相关问题   通过前面关于Redis五种数据类型.相关高级特性以及一些简单示例的使用,对Redis的使用和主要的用途应该有所掌握,但是还有一些原理性的问题我们在本部分做一个探 ...

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

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

  8. Redis的存储类型、集群架构、以及应用场景

    什么是redis redis是一种支持Key-Value等多种数据结构的存储系统.可用于缓存.事件发布或订阅.高速队列等场景.该数据库使用ANSI C语言编写,支持网络,提供字符串.哈希.列表.队列. ...

  9. Docker Compose 部署 Redis 及原理讲解 | 懒人屋

    原文:Docker Compose 部署 Redis 及原理讲解 | 懒人屋 Docker Compose 部署 Redis 及原理讲解  4.4k  字    16  分钟    2019-10-1 ...

随机推荐

  1. C++函数重载详解

    我们在开瓶瓶罐罐的时候,经常会遭遇因各种瓶口规格不同而找不到合适的工具的尴尬.所以有时候就为了开个瓶,家里要备多种规格的开瓶器.同样是开个瓶子嘛,何必这么麻烦?于是有人发明了多功能开瓶器,不管啤酒瓶汽 ...

  2. [原]NYOJ-小光棍数-458

    大学生程序代写 /http://acm.nyist.net/JudgeOnline/problem.php?pid=458 *题目458题目信息运行结果本题排行讨论区小光棍数 时间限制:1000 ms ...

  3. Cot

    题目大意 两种操作 给坐标上一个直角三角形中每个整点权值$+1$ 求坐标上一个直角三角形中每个整点权值之和 题解 一顿分析思考加推导之后,发现并不存在这样的数据结构(大概是有,只是我不知道),于是考虑 ...

  4. 每天一个linux命令(10):touch命令

    版权声明更新:2017-05-14博主:LuckyAlan联系:liuwenvip163@163.com声明:吃水不忘挖井人,转载请注明出处! 1 文章介绍 本文介绍了Linux下面的mv命令. 2. ...

  5. nvidia-docker 安装

    1.安装docker 官方网址安装说明 https://docs.docker.com/install/linux/docker-ce/ubuntu/ 2.ubuntu 14.04/16.04/18. ...

  6. VBA记录当前系统时间并精确到毫秒

    想做个功能,点一次按钮,就在A1记录一次当前系统时间,要精确到毫秒的.再点一次按钮就在A2显示,以此类推! 例如:这个功能可以用来做歌词记时间! Sub ttt() ActiveCell.Select ...

  7. CSS之EM相对单位

    之前以为em单位只是在font-size中起到继承作用, 后来慢慢觉得,继承,应该是在几乎所有样式中都可以是实现的,比如height,width,border... 今天才简单测试了下,果真是可以实现 ...

  8. CF 1036B Diagonal Walking v.2——思路

    题目:http://codeforces.com/contest/1036/problem/B 比赛时只能想出不合法的情况还有走到终点附近的方式. 设n<m,不合法就是m<k.走到终点方式 ...

  9. java中toString() 、(String)、String.valueOf的区别

    1.采用toString() 在使用时要注意,必须保证object不是null值,否则将抛出NullPointerException异常.采用这种方法时,通常派生类会覆盖Object里的toStrin ...

  10. 宽字符wchar_t和窄字符char区别和相互转换

    转自:http://blog.csdn.net/nodeathphoenix/article/details/7416725 1.    首先,说下窄字符char了,大家都很清楚,就是8bit表示的b ...