🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
2021-03-28 周天 ## 知识点 ***2个数据结构(sds,dict),单机数据库*** ### c语言字符串 ``` redisLog(warning,'xxx') ``` 其中xxx就是用普通字符串类型。 ### sds simple dynamic string - 简单动态字符串。 ![](https://img.kancloud.cn/52/f1/52f1c8cde962ba80eebee9ec8bdfe8cf_1428x546.png) 1. 存的字符串能被修改时,默认使用sds。(比如strings,hash里的key) ***buf指向一个数组,最后存的是一个'\0'空字符,不计算在len长度内*** 2. 缓存区 aof 里的buff也是用sds实现。 ### dict 保存键值对,也叫做映射,或者关联。 因为C语言没有实现这种高级的数据结构,所以redis实现了自己的字典数据结构。 并且基于字典实现了redis数据库。 应用在hash键和数据库内。 1. dict数据结构 ![](https://img.kancloud.cn/5c/7a/5c7a81e54e514676c05f1bcc5ad35997_2120x1250.png) 2. hash算法 > Redis不同版本使用的哈希算法并不一样. > 5.0,4.0 版本使用的siphash. > 3.2, 3.0, 2.8 使用的是murmurhash2. 3. hash冲突解决 因为就算使用了hash算法,数据量大起来后,会用不同的key落在同一个hash桶的同一个下标,于是数组后面挂的是链表,这样就能解决hash冲突。 4. dict rehash redis的dict rehash采用渐进式的方式,具体请参考[redis中的hash扩容、渐进式rehash过程](https://zhuanlan.zhihu.com/p/258340429)。 注意点: * `rehash`时`ht[1].size=ht[0].size * 2`。 * hash表的负载因子计算方式(`load_factor = ht[0].used / ht[0].size`) * 服务端在存在持久化子进程时,load_factor>=5才会扩容;不存在时,load_factor>=1时会扩容;load_factor<=0.1,会缩容。 * rehash过程是渐进式完成的,比如有1万个key需要转移,会将整个操作分散到客户端对该dict的新增,查询,修改,删除里,分而治之。 * 在rehash过程中,rehashidx=0开始,直到ht[0].used=0,表示rehash完成,rehashidx重置为-1。 * 在rehash过程中,查询操作会先查找ht[0],再查询ht[1];新增操作则直接插入到ht[1]里,保证ht[0].used一直减少。 ### redisDb数据库 1. redisServer 和 redisDb的数据结构 ``` c struct redisServer { ... redisDb *db; /* 一个数组,保存服务端所有数据库 */ int dbnum; /* 配置初始化的db数量,默认16 */ ... } ``` ``` c struct redisDb { dict *dict; /* 数据库键空间 */ dict *expires; /* 键的超时时间空间 */ ... int id; /* 数据库下标 */ ... } ``` 2. redisDb里的键空间,过期时间空间 redis是一个key-value型数据库服务器,服务器上的每个数据库都是由redisDb里的dict字典来保存所有键值对,将这个字典称之为"键空间"。 * 键空间里的键就是数据库里的key,是字符串对象,用的sds。 * 键空间里的值就是数据库里的value,是redis支持的对象类型,比如字符串,列表,哈希表,集合,有序集合对象中的一种。 ![](https://img.kancloud.cn/75/a3/75a305fa8d5011bae7a6e2572e7c1c79_1272x706.png) 其中超时时间也是用dict字典空间来存储的,而且存的是计算后的时刻。 TTL - 剩余生存时间。 ![](https://img.kancloud.cn/e2/ab/e2abf3d87ed3db7a6248ea0f1a135463_1300x890.png) ***请参考[info命令统计信息](https://zhuanlan.zhihu.com/p/78297083)*** 3. 过期键删除 有如下3种,定时删除策略,惰性删除策略,定期删除策略。 ***而redis采用的是惰性删除和定期删除策略*** * 惰性删除实现 ![](https://img.kancloud.cn/3d/e7/3de736495a65da0426e00cc96b74e3df_1214x580.png) * 定期删除实现 每当服务端执行serverCron周期性执行函数时,就会执行`activeExpiressCycle`函数 ![](https://img.kancloud.cn/50/3d/503dc12d7c9a633562cda75168d6aca4_1054x1492.png) 分多次检查16个数据库,每个库20个键,如果失效就删除。没有执行完就下次接着执行,unsigned long expires\_cursor; /* Cursor of the active expire cycle. */。 ## 会后讨论 * sds vs C字符串 1. sds 长度O(1),C字符串 长度O(n)。 2. sds不需要指定分配长度大小,从而杜绝缓冲区溢出。 3. sds的free实现了空间预分配和惰性释放2种优化方式减少空间重分配次数。 ![](https://img.kancloud.cn/a3/37/a337af007a4b1ba815b2f50eae371147_1310x350.png) * 二进制安全 sds里存的是字节数组,就是二进制数据。存入什么,读取什么,不会被篡改。不会因为客户端编码异常。 * 序列化 1. 概念 > 序列化:把对象转化为可传输的字节序列过程称为序列化。 > 反序列化:把字节序列还原为对象的过程称为反序列化。 2. 目的 序列化最终的目的是为了对象可以跨平台存储,和进行网络传输。 3. 场景 凡是需要进行“跨平台存储”和”网络传输”的数据,都需要进行序列化。 4. 方式 JDK(不支持跨语言)、JSON、XML、Hessian、Kryo(不支持跨语言)、Thrift、Protostuff、FST(不支持跨语言) 5. Java序列化pk ![](https://img.kancloud.cn/e2/d4/e2d4abb39418ab7182a08be047e13598_1326x406.png)