• 《Redis深度历险》原理篇


    原理1:鞭辟入里--线程IO模型

    • Redis是个单线程程序。Redis的所有数据都在内存中,所有的运算都是内存级别的运算。对于一些时间复杂度为O(n)级别的指令,需谨慎使用,一不小心就会造成redis卡顿
    • Redis单线程处理并发客户端连接的技术被称为多路复用,使用select系列的事件轮询
    • select函数是操作系统提供给用户程序的。
    • Redis会将每个客户端套接字都关联一个指令队列,客户端的指令通过队列来排队顺序执行
    • Redis同样为每个客户端套接字关联一个响应队列
    • Redis的定时任务会记录在最小堆的数据结构中

    原理2:交头接耳--通信协议

    • RESP是redis序列化协议的简写,优势:实现简单、解析性能好
    127.0.0.1:6379> set author codehole
    *3
    $3
    set
    $6
    author
    $8
    codehole
    
    127.0.0.1:6379> scan 0
    1) "0"
    2) 1) "info"
       2) "books"
       3) "author"
    *2
    $1
    0
    *3
    $4
    info
    $5
    books
    $6
    author
    

    原理3:未雨绸缪--持久化

    • Redis的持久化有两种,快照和AOF日志。快照是一次全量备份,AOF日志是连续的增量备份
    • 快照是内存数据的二进制序列化形式,在存储上非常紧凑,而AOF日志记录的是内存数据修改的指令记录文本。Redis重启时需要加载AOF日志进行指令重放,过程漫长,所以需要定期进行AOF重写
    • Redis为了边持久化边响应客户端请求,Redis使用操作系统的多进程COW(copy on write)。
    • Redis在持久化时会调用glibc的函数fork产生一个子进程来处理快照持久化,与父进程共享内存里的代码段和数据段
    • 子进程只是对数据进行遍历然后序列化写道磁盘,父进程需要根据客户端请求对内存数据进行修改。这时候就会使用操作系统的COW机制来进行数据段页面的分离。当父进程对其中一个系统页面数据进行修改时,会将被共享的页面复制一份并进行修改。
    • AOF日志存储的是Redis服务器的顺序指令序列,只记录对内存进行修改的指令记录。
    • Redis收到客户端修改指令后,先进行参数校验,没有问题就立即将改指令文本存储到AOF日志中,然后再执行指令。
    • Redis提供了bgrewriteaof指令对AOF日志进行重写瘦身。其原理就是开辟一个子进程对内存进行遍历转换成一系列Redis的操作指令,序列化到一个新的AOF日志文件中,序列化完成后再将操作期间发生的增量AOF日志追加到新的AOF日志中。追加完成后立即替代旧的AOF日志文件
    • 当程序对文件进行写操作时,实际上是将内容写到了内核为文件描述符分配的一个内存缓冲中,然后内核会异步将数据刷回磁盘。这时候机器宕机,AOF日志内容可能还没有来得及刷到磁盘就会出现日志丢失。
    • Linux的glibc提供fsync(int fd)函数可以将指定文件的内容强制从内核缓冲刷到磁盘。因为fsync时磁盘IO操作,所以一般生产环境中通常每个1s执行一次fsync操作,周期1s是可配置的。在数据安全性和性能中做一个折中。
    • 因为持久化是耗时的IO操作,会加重系统负载,降低redis性能,增加系统IO负担。所以一般主节点不做持久化,由从节点进行持久化操作。
    • Redis4.0为了解决rdb丢失大量数据和aof性能慢的两个问题,采用了新的持久化方案--混合持久化。将rdb文件的内容和增量aof日志文件存在一起。redis重启时,先加载rdb内容再重放增量aof日志,重启效率因此大幅得到提升。

    原理4:雷厉风行--管道

    • Redis管道Pipeline本质上是由客户端提供的,跟服务器没什么直接关系。
    • 管道的本质就是Redis客户端改变了消息的读写顺序。redis的write只负责将数据写到本地操作系统内核的发送缓冲旧返回。read只负责将数据从本地操作系统内核的缓冲中取出来。对于管道来说,连续的write操作根本没有耗时,之后第一个read操作会等待一个网络的来回开销,然后所有的响应消息就都会送到内核的读缓冲了。后续的read操作可以从缓冲拿到结果。

    原理5:同舟共济--事务

    • Redis事务具有简单性,能够确保多个操作的原子性,但事务模型不严格。
    • Redis事务的关键字:multi/exec/discard
    • Redis事务中的所有指令再exec之前不执行,而是缓冲再服务器的一个事务队列中,一旦收到exec指令,才开始执行整个事务队列,执行完毕后一次性返回所有指令的运行结果。
    • Redis事务根本不能算"原子性",仅仅满足事务的隔离性。事务在遇到指令执行失败后,后面的指令还继续执行。
    • 事务一般会结合pipeline一起使用,将多次IO操作压缩为单次IO操作。
    • watch机制相当于乐观锁。在事务开始之前watch一个或多个关键变量,当事务执行时,Redis会检查关键变量自watch之后是否被修改,如果被修改,则exec指令返回null,告知客户端事务执行失败。

    原理6:小道消息--PubSub

    • 为了支持消息多播,Redis单独使用了PubSub来支持消息多播,也就是发布订阅者模型。
    • 客户端发起订阅命令后,Redis会立即给予一个反馈消息通知订阅成功。
    • PubSub在生产者传递消息的时候会直接找到相应的消费者传递过去。如果没有消费者,消息直接丢弃。如果消费者中间挂掉,则断连期间的消息就彻底丢失。

    原理7:开源节流--小对象压缩

    • 如果Redis内部管理的集合数据结构很小,它会使用紧凑存储形式压缩存储。
    • Redis的ziplist是一个紧凑的字节数组结构。每个元素之间都是紧挨着的。
    • Redis的intset是一个紧凑的整数数组结构,用于存放元素都是整数且元素个数较少的set集合。如果整元素可以用用uint16表示,那么intset的元素就是16位的数组,如果新加入元素超过uint16的范围,那么就是用uint32,如果超时uint32就是用uint64。如果添加元素为字符串,则立即升级为hashtable结构。
    • 当集合对象的元素不断增加,或者某个value值过大,小对象存储也会被升级为标准结构。
    • Redis并不总是可以将空闲内存立即归还给操作系统。操作系统回收内存是以页为单位的,如果这个页上有一个key还在使用,就不能被回收。内存虽然不会被回收,但会被重用。
    • Redis的内存分配细节由第三方内存分配库实现。jemalloc或者tcmalloc,jemalloc性能稍好一点,也是Redis的默认内存分配器

    原理8:有备无患--主从同步

    • CAP 一致性、可用性、分区容错性。网络分区发生时,一致性和可用性两难全。
    • Redis的主从数据是异步同步的,所以分布式的Redis系统并不满足"一致性"要求。在主从网络断开情况下,主节点依旧可以提供服务,所以是满足"可用性"的。
    • Redis保证"最终一致性",从节点会努力追赶主节点,最终从节点状态与主节点状态将保持一致。
    • Redis的主从同步细分为主从和从从同步。Redis同步的是指令流,将产生修改的指令记录在本地的内存buffer中,然后异步将buffer中的指令同步到从节点。内存buffer是一个定长的环形数组。数组内容满了会从头开始覆盖
    • 如果从节点网络不好没有同步的指令被覆盖,这时候需要用到更加复杂的同步机制--快照同步
    • 快照同步:在主库上执行一次bgsave将内存数据快照到磁盘文件,然后将快照文件内容全部传送到从节点,从节点执行一次全量加载,加载完毕通知主节点继续进行增量同步
    • 如果快照同步时间过长,指令同步的buffer又被覆盖,则同步失败,再次发起快照同步。所以需要配置合适的复制buffer大小,避免快照复制的死循环
    • 增加从节点会首先进行一次快照同步,然后进行增量同步
    • 无盘复制:主节点直接通过套接字将快照内容发送到从节点,从节点将接受的内容存储到磁盘文件再进行一次性加载
  • 相关阅读:
    Vue.js——60分钟快速入门
    SpringMVC--拦截器的使用
    wex5中集成的mysql数据库 打开时一闪而过 报错
    技术资源集合
    解析xml的4种方法详解
    回调方法介绍之中国好室友篇(Java示例)
    org/springframework/cache/jcache/config/AbstractJCacheConfiguration.class
    maven创建父项目和子项目
    SpringBoot学习之一 Unable to find a single main class from the following candidates
    Spring事务管理5-----声明式事务管理(3)
  • 原文地址:https://www.cnblogs.com/prelude1214/p/14207177.html
Copyright © 2020-2023  润新知