blog

博客

View on GitHub

1.0 SDS

C字符串和SDS的区别

C字符串 SDS
获取字符串长度发复杂度为O(N) 获取字符串长度发复杂度为O(1)
API不安全,可能会缓冲区溢出 API是安全的不会缓冲区溢出
修改字符串长度必然需要执行N次内存分配 修改字符串长度最多需要执行N次内存分配
只能存文本数据 可以存文本或者二进制数据
可以使用所有的的函数 可以使用部分的的函数
  惰性内存释放,也有相应的API不用担心内存浪费
缓冲区溢出

当C字符串容纳大于自己长度的内容时,就会发生缓冲区溢出, 影响内存块的数据


1.1 链表

链表的特点


1.2 字典

hashtable数据结构 基本结构Redis的字典是使用哈希表做底层实现的, hashtable + 单链表 链表解决hash冲突

rehash 扩容、收缩
原来的数据在 ht[0]->table 中,新建一个扩容或者收缩的 ht[1]; ht[1]的大小是以前的两倍,然后讲 原ht[0]的数据, 渐进式rehash 放到ht[1]中。当数据全部转移完之后,释放ht[0], ht[1]变成ht[0]。

什么时候会执行rehash
// 负载因子 load_factor = ht[0].size/ht[0].used
1 执行BGSAVE的时候,负载因子 > 5 才会执行,是因为执行BGSAVE的时候, Reids会创建子进程,并且大部分操作系统会采取写时复制(copy-on-write)来提高子进程的使用效率,所以为了避免在有子进程的时候rehash,避免写内存的操作,提高了负载因子的值。
2 未执行BGSAVE的时候,负载因子 > 1 的时候会执行, 或者负载因子 < 0.1执行收缩。

渐进式rehash

数据从ht[0]到ht[1]的过程不是一次性写入的,是分多次,渐进式完成的。字典dict有个字段 rehashidx 设置为0表示是在rehash状态,每次对字典读写删除更新等操作时,会把对应的数据转移到ht[1],最终在某个时间,rehash结束。rehash过程中, 新增的部分会直接写到ht[1],

其他知识点


1.3 跳跃表

跳表是一种有序的数据结构,大部分情况下查找效率可以和平衡树媲美,并且实现起来比平衡树简单。redis 只在zset 和集群节点中用作内部数据结构。


1.4整数集合

intset整数集合是 set的底层实现之一(set本身是无序的, 但是intset有序),当set集合中只包含数值元素,并且集合的元素数量不多(读配置set-max-intset-entries,默认是512)的时候。 内部结构的C语言的数组。

升级

压缩列表(ziplist)是列表键(list)和哈希键(hash)的底层实现之一。

特点

1.7 快速列表quicklist

快速列表quicklist是3.2版本新增的list编码,是由ziplist组成的双向链表。

编码常量| 编码所对应的底层数据结构 –| – REDIS_ENCODING_INT |long 类型的整数 REDIS_ENCODING_EMBSTR |embstr 编码的简单动态字符串 REDIS_ENCODING_RAW| 简单动态字符串 REDIS_ENCODING_HT |字典 REDIS_ENCODING_LINKEDLIST| 双端链表 REDIS_ENCODING_QUICKLIST| 快速链表 REDIS_ENCODING_ZIPLIST |压缩列表 REDIS_ENCODING_INTSET| 整数集合 REDIS_ENCODING_SKIPLIST| 跳跃表和字典


1.9 内存回收+对象共享

C语言不具备自动内存回收的功能, Redis自己使用引用计数技术实现了内存回收,引用计数带有对象共享的作用, 可以多个相同值共享一个数据对象,但是只会共享值(0~9999)的字符串对象。因为共享的对象越大,验证两个对象相同就越麻烦, 所以只会共享毕竟小的数据。


2.0 RDB持久化

RDB功能可以把某个时间点redis内存中的数据状态保存到硬盘上RDB文件里。
redis提供了两个命令来生成RDB文件一个是阻塞SAVE, 一个是非阻塞BGSAVE。
redis启动的时候会自动载入RDB文件,所以没有导入RDB文件的命令,如果开启了AOF,会优先使用AOF文件做数据导入的工作。

执行过程
当执行SAVE的时候, 会在主进程进行,Redis服务器会被阻塞, 此时客户端的所有命令都被拒绝,只有当SAVE执行完之后,才会接受客户端的命令
当执行BGSAVE的时候,会启动一个子进程来执行,redis服务器依然可以执行命令,假如此时有新的值插入到redis中,这部分数据不会写入到RDB中。 此时也不能执行 SAVE BGSAVE , BGREWRITEAOF 会延时到BGSAVE执行完之后再执行.

执行方式

其他知识点


2.0 AOF持久化

AOF持久化是通过保存redis执行的写操作的命令来记录数据库状态的,具体分为三个步骤 命令追加 文件写入 文件同步

AOF重写
随着服务器运行的时间变长,aof文件会越来越大,会有一些冗余的命令,可以重写创建一个新的aof文件替代原来的文件,新的aof文件不包含浪费空间的命令,体积要小, AOF重写是通过读取服务器的当前数据库状态来执行的。
执行BGREWRITEAOF,会有一个子进程来从数据库中读取现在的键的值,然后用一条命令去记录键值对,去代替直接记录这个键值对的多条命令

#1 redis> sadd set cat
#2 redis> sadd set dog
#3 redis> sadd set lion

此时原本aof文件会记录三条命令
重写的话

只需要记录一条命令就好
redis> sadd set cat dog lion 

子进程处理aof重写的期间,服务器主进程还可以继续请求处理命令,会把写操作同时放入 aof缓冲区aof重写缓冲区,当子进程创建完新的aof文件之后, 还会把aof重写缓冲区的命令写入到aof文件中, 然后原子性的替换旧aof文件, 此时aof重写完成。

重点终结


3.0 事件

4.0 主从复制

主从复制的基本过程是 同步命令传播

断线重连之后,从服务器会根据服务器的运行ID判断是否是以前连接的主服务器,假如不是之前的主服务器,执行同步的操作,如果是原本的主库,主库会判断复制积压缓冲区(固定大小的队列,大小可以配置)里是否有从库记录的复制偏移量,假如没有,说明这部分命令已经丢失,需要执行同步的操作。假如主库再复制积压缓冲区找到了从库复制偏移量对应的数据,则会从这个命令开始发送给从库,从库执行命令完成数据同步。


4.1 Sentinel哨兵

Sentinel哨兵是reids基于主从模式扩展的高可用方案。 实现原理是有个 Sentinel系统(特殊的redis服务器运行模式)监控主库、从库,当发现主库故障不可用的时候,会选举一个从库当作主库,保障了服务的运行。
一般为了保障服务的可用,会有三台哨兵机器组成Sentinel系统 Sentinel内部也会互相通信,当发现主库服务器被判断为下线的时候,会先选出一个领头Sentinel,领头Sentinel来操作选择一个从库作为主库,然后其他从库变为新主库的从库。然后设置旧主库变为新主库的从库, 这样旧主库重新上线的时候,可以作为新的从库使用。


4.2 集群cluster

名词解释

重新分片

重点知识

事务

慢查询日志

redis版本区别

面试题