redis原理

2,414 阅读5分钟

掘金小册-redis原理讲解

(一)线程IO模型

redis是单线程。memcached 是多线程模型,nginx 是master 和work 多进程模型

如何处理多并发客户端连接?

非异步IO+事件轮询API(多路复用,相当于JAVA里面的NIO)。

指令队列:redis会为每个客户端关联一个指令队列,通过队列的顺序进行排队,先来先服务(响应队列类似)

定时任务:redis的定时任务会被记录在一个叫“最小堆”的数据结构中,最快要执行的任务排在堆的最上方

(二)通信协议

RESP 是 Redis 序列化协议的简写

协议传输的数据结构:Redis 协议将传输的结构数据分为 5 种最小单元类型,单元结束时统一加上回车换行符号\r\n。

无论是客户端-->服务器 还是 服务器-->客户端都是基于下面五种数据结构的组合

1.单行字符串以“+”开头

2.多行字符串以“$”开头,后面跟字符串的长度

3.数值以“:”开头,后跟整数的字符串形式

4.错误消息以“-”开头

5.数组以“*”开头,后跟数组的长度

(三)持久化

持久化的目的:redis的数据全是存在内存的,如果突然宕机,需要保证数据的完整性,就需要将数据持久化

持久化的方式:1.快照 2.AOF日志

快照

类型:全量备份

原理:Redis 使用操作系统的多进程 COW(Copy On Write) 机制来实现快照持久化

COW机制:数据段页面的分离

fork(多进程):Redis 在持久化时会调用 glibc 的函数fork产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求。这样就不会造成阻塞。

子进程只会复制数据,但是父进程会修改数据结构,如何保证持久化的数据不变:利用COW机制

AOF日志

类型:增量备份

原理:AOF 日志存储的是 Redis 服务器的顺序指令序列,AOF 日志只记录对内存进行修改的指令记录,但是注意:Redis在长期运行中会产生大量的日志,如果redis宕机,重放整个AOF日志会非常费时,所以需要定期对AOF日志瘦身。

运维相关

因为对数据持久化是一个非常耗资源的操作,所以一般redis的主节点主节点不会进行持久化操作,而是由从节点来备份

redis4.0采用了混合持久化的方式:rdb+aof重放的方式使重启的效率大大提高

(四)管道

客户端通过对管道中的指令列表改变读写顺序就可以大幅节省 IO 时间。管道中指令越多,效果越好。

例如:客户端发送两次消息:write->read->write->read,利用管道改变读写顺序后变为write->write->read->read,服务器端的操作并没有变,收到的是同样的数据

(五)事务

multi 指示事务的开始,exec 指示事务的执行,discard 指示事务的丢弃。 所有的指令在exec之前都不执行,只是被缓存到服务器的一个队列里,只有在收到exec指令后才开始执行

redis的事务不能满足原子性,仅仅是满足了事务的隔离性(当前执行的事务不被其他事务打断)

discard指令:用于丢弃事务缓存队列中的所有指令,在exec执行之前

watch机制

分布式锁是一种悲观锁,redis提供的watch(命令)机制就是一种乐观锁,也可以用来解决并发修改的问题

注意事项:

redis不能在multi和exec之间使用watch命令,而必须在 multi 之前做好盯住关键变量,否则会出错。

tips:悲观锁和乐观锁:读取频繁使用乐观锁,写入频繁使用悲观锁。

悲观锁:总是假设最坏的情况,认为每次取数据时数据都会被其他线程所修改,所以都会加锁(行锁,表锁等),当其他线程想要读取数据时,都需要阻塞挂起(互斥锁)。可以依靠数据库实现,如行锁、读锁和写锁等。(synchronized的思想也是悲观锁)

乐观锁:总是认为不会有并发问题,认为每次取数据时数据不会被其他线程更改,所以不会加锁,但是在更新之前会判断数据有没有被其他线程修改,一般通过版本号或CAS(自旋锁)操作实现

(六)PubSub

PublisherSubscriber,发布者订阅者模型,用于支持消息多播

详看小册

(七)小对象压缩(ziplist)

ziplist是一个紧凑的字节数组结构

intset是一个整数数组结构,用于存放元素都是整型且元素个数较少的set集合

(八)主从同步

一句话说明分布式CAP理论:当网络分区发生时,一致性和可用性两难全(一般只保证最终一致性)。

redis保证可用性最终一致性:即redis主节点修改数据之后直接返回,即使在从节点挂了的情况下依然保持可用性,而不保证一致性,redis保证最终一致性,即从节点在恢复正常后会采用相应的办法保持与主库的一致性。

主从同步

同步方法:增量同步,快照同步

增量同步:在网络不好时,从节点在短时间内无法与主节点同步,会导致需要同步的指令在buffer中被后续指令覆盖,所以需要快照同步

当增加从节点时,必须要先进行一次快照同步,然后在进行增量同步