redis深度历险--读书笔记
2020-03-04 本文已影响0人
江江的大猪
- list的底层数据结构是ziplist+quicklist,是将ziplist串起来的quicklist,双向链表。避免头尾指针比值还大的问题
- hash和java的hashmap类似,只不过是渐进式rehash过程,rehash过程中会在新老hashmap中都查询,rehash完成后删除老hashmap
- set底层是一个特殊的字典,value都是null
- zset类似java的sortedSet和hashMap的合体,底层结构是跳跃链表
- list/set/hash/zset 这四种数据结构是容器型数据结构,如果容器不存在,那就创建一个,再进行操作。如果容器里元素没有了,那么立即删除元素
- Redis 的作者认为数据库系统的瓶颈一般不在于网络流量,而是数据库自身内部逻辑处理上。所以即使 Redis 使用了浪费流量的文本协议,依然可以取得极高的访问性能。Redis 将所有数据都放在内存,用一个单线程对外提供服务,单个节点在跑满一个 CPU 核心的情况下可以达到了 10w/s 的超高 QPS。
- redis通信协议resp:不同类型的信息用不同的符号开头(+$:-*)
- redis持久化rdb是全量快照,aof是增量备份。做快照的时候,redis会fork一个子进程,被修改的内存页会copy on write复制一份,极限情况是真个redis内存扩大一倍(实际情况大都是冷数据,只有少量会复制一份),然后对冷数据的内存页和热数据复制出来的内存页做快照
- aof是先执行指令再存储指令
- 重写aof时,开启子进程遍历内存转换成指令,遍历结束再将期间产生的aos日志补充进来,最后替换老aof日志
- 写aof时,是写到了内核为文件描述符分配的一个内存缓存中,然后内核会异步将脏数据刷回到磁盘。所以有丢数据的情况,所以通常是每隔 1s 左右执行一次 fsync 操作强制从内核缓存刷到磁盘
- 让从节点开启持久化,主节点追求最好性能。rdb快照文件写文件和aof写文件都比较费资源
- redis4出了混合持久化,rdb和aof放在一起,aof只记录rdb之后的增量指令
- redis的事务利用了redis的单线程天然顺序执行,保证了一个事务里的所有操作不被其他操作打断,但是不保证原子性,其中有一个操作失败了,整个事务队列里产生的影响不会回滚
- watch multi exec 可以做到乐观锁操作,不用自己使用分布式上锁,exec返回null就是失败(jedis)
- 管道是客户端的能力,将多条命令合并发送,在一起读取server的返回结果
- redis中删掉key之后不会立即释放空间,因为操作系统的内存页上只要有使用的key就不会被释放。
- redis主从增量同步:master存储已经执行的指令的buffer可以看做一个环,满了的话会覆盖头上的。所以此时需要用快照进行全量同步,在快照同步的过程中,指令buffer还会不断增长,如果快照同步过慢或者buffer太小,则会触发又一次快照同步,陷入死循环快照同步
- 从节点刚加入时,先进行一次快照同步在进行增量同步
- redis sentinel一般用3个实例,和zk一样的作用,负责监控实际提供服务的redis,客户端通过sentinel获得当前的master
- redis5之后有了借鉴kafka的stream,作为一个队列允许有多个group进行消费,但是不像kafka天生支持partition,但是kafka的分区也是在客户端里进行hash分区的,所以都差不多
- redis会把设置了过期时间的key额外存储到一个字典中,每秒扫描十次,每次随机找出20个key检查是否过期,如果过期就删除,过期的超过四分之一就继续循环,每次扫描虽多25ms。为了避免每次都循环到25s,最好让过期时间随机取。从库没有扫描,主库在扫描到过期key时,会在aof里增加一条del命令同步给从库
- redis本身不支持ssl,官方推荐使用spiped做ssl代理,避免被窃听
- SCRIPT LOAD将lua脚本加载到redis中但是不执行,返回一个id,客户端通过EVALSHA id执行该lua脚本。对一些很大的lua脚本可以节省直接使用eval的网络流量
- 为了避免lua的执行时间过长,redis的lua 引擎执行10w条指令并且lua执行超时后会去执行hook函数,这个超时时间默认是 5 秒
- redis的动态字符串sds的len和capacity默认一直,因为一般不会有append过程。有两种具体数据结构,raw和embeded,长度超过44字节时,用emb结构。
- RedisObject结构,类似java的对象头,占16字节,redis对超过64字节的字符串认为是大字符串,所以64-RedisObject的16字节-sds的最少3字节就是44字节。
- Redis 数据库的所有 key 和 value 也组成了一个全局字典,还有带过期时间的 key 集合也是一个字典。zset 集合中存储 value 和 score 值的映射关系也是通过 dict 结构实现的。Redis 里面 set 的结构底层实现也是字典,只不过所有的 value 都是 NULL,其它的特性和字典一模一样。
- dict 结构内部包含两个 hashtable,通常情况下只有一个 hashtable 是有值的。但是在 dict 扩容缩容时,需要分配新的 hashtable,然后进行渐进式搬迁,这时候两个 hashtable 存储的分别是旧的 hashtable 和新的 hashtable。待搬迁结束后,旧的 hashtable 被删除,新的 hashtable 取而代之
- lru和lfu