1
日常使用Redis大概就是需要的时候就查一下文档,于是决定开始完整地看一遍,并做一些笔记.需要说明的是,部分笔记个人理解可能有不对的地方,欢迎指正交流.

1. Pipelining

  1. Redis是一个TCPServer,使用CS模型

  2. 1次请求将命令集合发送,Redis执行命令后将结果队列化后,再写入返回

  3. 队列化执行结果需要使用内存,如果多次大批量操作需要注意内存的使用

  4. 使用Redis脚本能够处理更快处理批量命令.管道无法在脚本中使用,因为使用管道时在写入之前需要返回响应给客户端(需要注意:这里个人理解可能存在偏差).反之,管道可以使用脚本

2. Redis Pub/Sub

  1. 发布订阅模式: 发布者发布消息到Channel,订阅者订阅Channel接收消息

  2. Redis客户端一旦为订阅模式,不能接收其他命令

  3. redis-cli命令行客户端时进入订阅模式之后只能通过ctrl-c取消订阅,因为此时客户端阻塞等待接收订阅消息

  4. 发布订阅无关于key所在空间,db10发布的,db1订阅仍能接收

  5. 可用模式匹配发布多个channel 和订阅多个channel

3. Redis Lua scripting

  1. EVAL,EVALSHA命令执行Lua脚本

  2. Lua 脚本可以使用redis.call 或redis.pcall执行redis命令

  3. redis.call执行遇到错误时直接抛出Lua异常结果,redis.pcall则会把异常处理成Lua table返回

  4. Lua调用redis命令时把数据转成redis对应数据类型,脚本执行结果返回给客户端时Lua的数据类型转成redis对应数据类型

  5. 使用Lua脚本时对于浮点数最好使用字符串替代

  6. 如果Lua返回数组中包含nil,则数据转换终止,最终只能返回nil之前的结果

  7. redis.error_reply,redis.status_reply 在Lua脚本中是比较有用的按redis数据类型返回结果的方法

  8. 执行Lua脚本时,其他客户端的命令和脚本将无法执行

  9. redis内部缓存机制会缓存脚本,使用EVALSHA,如果redis通过匹配SHA1文摘匹配到脚本,则执行脚本,否则返回错误信息通知使用EVAL代替

  10. 使用SCRIPT FLUSH或重启redis实例会刷新脚本缓存

  11. 脚本自身会被从库复制或写入AOF文件,而不是脚本的结果命令.不过从3.2版本开始,已经可选设置复制结果命令

  12. 脚本不允许设置全局变量

4. Debugging Lua scripts

  1. Redis Lua debugger默认,每一个新的Debug session是一个forked session,这意味着当脚本在debug中时,不会阻塞redis server执行其他命令,同时也意味着debug结束后会回滚脚本执行的结果

  2. 官网有视频详解https://redis.io/topics/ldb

5. Memory optimization

  1. 通过修改redis.conf调整每一种数据类型的最大数量和最大空间

  2. RDB和AOF文件兼容32位和64位,之间可以互转

  3. 合理利用bit和byte操作

  4. 尽可能使用hash结构存储数据

  5. 每个hash最多存储100个field是cpu和内存之间的最佳妥协

  6. redis根据配置文件maxmemory分配内存

  7. 被删除的key实际上并不会立刻释放内存,例如在同一页中存在其他的key未被删除,需要根据峰值内存使用量限定内存使用

  8. redis底层内存分配器会尽可能重复利用被删除key的内存,所以也不用太担心被删除key没有及时释放的问题

  9. 如果不设置maxmemory,所有的内存将可能被吃光

  10. 当超过最大内存限制时,导致写入时out of memory error,但不会因此导致整个机器挂掉

6. Expires

  1. 过期时间只针对key不针对值

  2. 过期时间可以通过persist命令清除

  3. 通过rename重命名key,原key的过期时间仍然有效,如果由别的key rename覆盖,则该key具有别的key的特性

  4. 如果设置的过期时间为过去时间,则key相当于del 而不是expired

  5. 消极检查: 当客户端获取该key时才检查该key是否过期

  6. 积极检查: redis 1秒内执行10个检查过期,每次随机选取20个key,发现过期的则清除,如果发现超过25%过期,则继续下一个检查

  7. 过期执行删除的命令会传递给从库和AOF文件同步执行.从库不会检查key过期,当切换为主库时才会去检查

7. Redis as an LRU (Less Recently Used) cache

7.1 Redis达到最大内存限制时策略

  1. noeviction: 直接抛出异常

  2. allkeys-lru: 将最近不常用的key清除腾出空间

  3. volatile-lru: 将带有过期时间的最近不常用的key清除腾出空间

  4. allkeys-random: 随机将key清除腾出空间

  5. volatile-random: 随机将带有过期时间的key清除腾出空间

  6. volatile-ttl: 将较小剩余存活时间的key清除腾出空间

  7. 如果不确定使用哪种策略,allkeys-lru是一个较好选择

  8. volatile-lru和volatile-random比较适用于只用单个实例,混用缓存和持久key

7.2 近似LRU算法

  1. redis使用的并不是实际的LRU算法,而是大致评估一定样本量中选取最符合的key

  2. 可以通过设置配置样本量参数maxmemory-samples调节精度

7.3 LFU (Least Frequently Used)

  1. 4.0版本以后新增了新策略,根据命中的频率决定清除哪些key

  2. lfu-log-factor和lfu-decay-time是两项主要调节参数

8. Redis transactions

  1. 事务中的所有命令会序列化并串行化执行,在事务过程中,其他客户端发起的请求不会被处理

  2. 所有命令要么全部被处理或不处理(这里的处理并不表示一定执行成功),保证了原子性

  3. 如果使用append-only file,在发生崩溃或强制关闭redis时有可能导致执行事务中部分命令.redis重启后会检测到直接退出.使用redis-check-aof tool修复

  4. MULTI开启事务,命令存储到队列,命令EXEC执行事务所有命令

  5. 执行EXEC检测到命令错误时,会在EXEC直接返回错误信息,并丢弃所有命令

  6. 执行EXEC后,部分命令执行失败,对应的命令返回错误信息,其他命令执行成功

  7. redis不支持回滚:因为官方认为不需要,语法上的错误,在命令队列化时就能检测到,而编码错误导致命令执行失败redis表示不背这个锅,redis追求更简单,更快

  8. 使用WATCH命令实现乐观锁,如果多个客户端对同一个key进行操作并存储时,被观察的key被改变后,其他客户端对该key的修改的事务则会失败,实现了对该key的原子操作

  9. 需要注意的一点,当WATCH某个key之后,key过期了,那EXEC就会正常执行

  10. 使用WATCH可以实现对有序集合操作的原子性

  11. 对事务的操作在脚本中也能实现,而且脚本可以更简单更快


whales
147 声望24 粉丝