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. 对事务的操作在脚本中也能实现,而且脚本可以更简单更快