要透过现象看本质~
redis的数据类型和对应的底层数据结构
大key问题
当value为字符串时一般指单个字符串超过1M,如果是其他的集合类型那么指的是集合元素过多
根据如下的时间复杂度,我们知道查询的一个数的O(n)的时间复杂度是很可怕的
redis的string类型底层
Entry -> RedisObject -> SDS
Entry 指向RedisObject,RedisObject 指向SDS
Redis 扩容
采用渐进式hash。
1、在原先的基础上增加一倍
2、拷贝原先的数据
3、释放哈希表1
比较耗时的是2,因此Redis采用渐进式哈希,先访问哈希表1,不存在则访问哈希表2,如果存在则将其复制到2上,并且删除;
除此之外,redis还有一个后台线程,定时迁移
为什么进行全量复制时不用AOF而是用RDB
- RDB文件小,RDB文件内容是经过压缩的二进制数据(不同数据类型数据做了针对性优化),文件很小。而AOF文件记录的是每一次写操作的命令,写操作越多文件会变得很大,其中还包括很多对同一个key的多次冗余操作。在主从全量数据同步时,传输RDB文件可以尽量降低对主库机器网络带宽的消耗,从库在加载RDB文件时,一是文件小,读取整个文件的速度会很快,二是因为RDB文件存储的都是二进制数据,从库直接按照RDB协议解析还原数据即可,速度会非常快,而AOF需要依次重放每个写命令,这个过程会经历冗长的处理逻辑,恢复速度相比RDB会慢得多,所以使用RDB进行主从全量同步的成本最低。
- 使用AOF需要打开AOF设置。假设要使用AOF做全量同步,意味着必须打开AOF功能,打开AOF就要选择文件刷盘的策略,选择不当会严重影响Redis性能。而RDB只有在需要定时备份和主从全量同步数据时才会触发生成一次快照。而在很多丢失数据不敏感的业务场景,其实是不需要开启AOF的。
repl_backlog_buffer 和 replication buffer
repl_backlog_buffer 是为了避免从库网络中断后造成全量复制,只要有从库存在,这个repl_backlog_buffer就会存在。主库的所有写命令除了传播给从库之外,都会在这个repl_backlog_buffer中记录一份,缓存起来,只有预先缓存了这些命令,当从库断连后,从库重新发送psync $master_runid o f f s e t , 主 库 才 能 通 过 offset,主库才能通过 offset,主库才能通过offset在repl_backlog_buffer中找到从库断开的位置,只发送$offset之后的增量数据给从库即可。如果被覆盖了那么需要全量复制。
replication buffer:一个客户端一个
repl_backlog_buffer:所有客户端共用一个
replication buffer:Redis和客户端通信也好,和从库通信也好,Redis都需要给分配一个 内存buffer进行数据交互,客户端是一个client,从库也是一个client,我们每个client连上Redis后,Redis都会分配一个client buffer,所有数据交互都是通过这个buffer进行的:Redis先把数据写到这个buffer中,然后再把buffer中的数据发到client socket中再通过网络发送出去,这样就完成了数据交互。所以主从在增量同步时,从库作为一个client,也会分配一个buffer,只不过这个buffer专门用来传播用户的写命令到从库,保证主从数据一致,我们通常把它叫做replication buffer。