Redis的知识可以分为两大类,一类是上层生产使用和问题发现和解决,第二类是底层源码知识学习
上层生产使用和问题发现和解决
Redis快的原因: 内存,单线程, 数据结构,IO多路复用,Jemalloc ,
数据结构: Redis数据结构(基本数据结构5种及其底层实现,应对大数据的数据结构,最新Redis5.0 stream,listpack等结构)
Redis速度变慢排查: 大key(what,why),复杂度过高的命令,key集中过期,内存不足淘汰压力变大,大量短连接请求,AOF和RDB,Swap,NUMA架构下cpu绑定不合理
Redis作为缓存: 缓存穿透,缓存击穿,缓存雪崩;缓存和数据库一致性
Redis分布式锁: 分布式锁具备的特点(互斥,可重入,超时释放,)
Redis消息队列: 1. 列表(BLPOP, BRPOP, Brpoplpush )2.stream 消息队列
Redis集群方案: 1.主从复制 2.哨兵 3.切片集群 4.codis集群
主从切换,脑裂,数据倾斜,Gossip协议
Redis内存淘汰: LRU,LFU
**Redis持久化: ** AOF和RDB
Redis事务:
Redis新特性: 从Redis2.8 —>7.0
Redis客户端: Jedis,Redisson,Lettuce
Redis的各个设置参数:了解这些参数可用帮助我们在生产中发现问题以及性能调优
底层源码知识学习
从Redis源码中我们可以学到哪些东西?
-
源码目录组织
C语言项目的目录与Java项目不同,但与Go相同,较为简单明了,其功能模块与源码一一对应
-
其数据结构实现(避免内存碎片+避免使用统一大小的数据对象+使用共享对象避免重复创建冗余的数据)
- 字符串:重写c语言字符串,字符串几种:sdshdr16、sdshdr32、sdshdr64+多种编码方式:整数,raw,embeding;
- Hash:渐进式rehash实现,MurmurHash2 和SipHash 哈希函数,为什么没有使用红黑树解决冲突?
- zset=哈希表+跳表,同时支持范围查询和单查询
- ziplist虽然内存占用少但存在连锁更新,查询复杂度过高的问题–> quickList(采用链表+ziplist)—>listpack
- stream=listpack+radix tree 用于消息队列场景 ,radix tree保存key,适用于保存前缀相同的数据,节省内存同时加快查找,listpack保存value,进一步节省内存
- 内存分配器(jemalloc)来提高内存使用效率,避免内存碎片;
-
基于事件驱动框架的网络通信机制+ Redis 线程执行模型
- 参数解析:initServerConfig(参数赋默认值) –>loadServerConfig (根据配置文件和命令行携带参数),
- 基于socket的编程模型–>采用多线程的Reactor模型–>基于不同操作系统对IO多路复用进行封装(如何封装的select和epoll?并且根据不同操作系统调用其对应的封装函数)
- reactor线程模型(三类处理事件,即连接事件、写事件、读事件;三个关键角色,即 reactor、acceptor、handler),学习如何实现一个简单高效的事件驱动框架,并根据不同的事件组织调用不同的函数。(回调函数很关键)
- 总体流程:从initServer初始化为每一个监听的端口创建一个socket+回调函数,然后main–>aemain循环监听事件–>处理不同的IO事件和时间事件–>调用相应注册的回调函数
- Redis单线程?多线程?执行Redis增删改查是单线程(main函数–>aemain的流程),在main–>InitServerLast –>bioInit 创建三类后台线程(BIO_CLOSE_FILE,BIO_AOF_FSYNC,BIO_LAZY_FREE)还有后台任务如何生成的?如何分配处理的
- Redis6.0 多线程IO又是怎么回事?是因为多核处理器的发展,开启多线程IO就能够利用多核处理器的优势,具体bioInit–>initThreadedIO进行初始化,具体如何使用客户端多线程读写:读postponeClientRead ,写prepareClientToWrite ,分配handleClientsWithPendingReadsUsingThreads
- Redis处理一条命令流程:命令读取readQueryFromClient –>解析processInputBufferAndReplicate –>执行processCommand –>返回addReply
-
缓存模块(LRU+LFU)
- Redis对LRU算法的改进优化
- LFU是如何实现的?
- Lazy free 对Redis有什么影响