《Redis开发与运维》笔记

一、redis特性
1、(1)速度快:C/内存/单线程架构;(2)丰富功能:建过期/订阅发布/Lua脚本创建新命令/简单事务/流水线(pipeline)功能;(3)持久化:RDB/AOF;(4)高可用:主从复制/哨兵/集群。
2、对外数据结构由内部多种编码实现,改进内部编码对外无感知,不同编码在不同场景发挥各自优势。
3、选择单线程是因为纯内存访问、非阻塞I/O、避免线程切换和竞态消耗,所以redis是面向快速执行场景。

 

二、API理解和使用
1、数据类型
(1)字符串
    内部编码:int(8字节长整型)、embstr(小于等于39字节字符串)、raw(大于39字节字符串)
    场景:缓存功能、计数、共享session、利用过期时间限速
(2)哈希
    内部编码:ziplist(field个数小于配置数且所有值小于配置的字节数,省内存读写相对慢)、hashtable哈希表(读写快耗内存)
    场景-存储对象比较:每个字段存一个key,优点是简单直观,每个字段可以直接更新,缺点是占用过多键,消耗内存多,对象信息内聚性差;序列化,优点编程简单,提高内存使用率,缺点序列化有开销,不能直接更新单个字段;哈希类型,优点使用合理可以减少内存使用,缺点要控制好内部编码的转换,否则会消耗更多内存。
(3)列表
    内部编码:ziplist、linkedlist
    场景:消息队列、列表数据
(4)集合
    内部编码:intset(元素都是整数且个数小于配置数量)、hashtable
    场景:集合操作、随机数
(5)有序集合
    内部编码:ziplist、skiplist
    场景:排行榜

2、键管理
(1)遍历键
    keys,在redis包含了大量键时,keys很可能造成redis阻塞,所以一般在键少下使用或可以在从节点使用。
    scan,渐进式遍历,返回一个游标值即下次遍历起点和当前遍历出来的键,虽然解决了阻塞问题但是无法保证键有变化时遍历的正确性。
3、其它功能
(1)慢查询,只是命令执行时间,不包含网络传输和命令排队时间,慢查询日志存在内存中,如果慢查询多则有必要定期存放。
(2)简单事务,不支持回滚特性。
(3)pipeline批量执行命令,有效节约RTT(往返时间),但它是非原子性的。
(4)Lua脚本创建原子、高效、自定义命令组合。
(5)简单的发布/订阅功能。

 

三、持久化
1、RDB
    描述:RDB是把当前进程数据生成快照保存到硬盘,是一个紧凑压缩的二进制文件。
    手动触发:save会阻塞,已废弃;bgsave创建子进程生成RDB文件。
    自动触发:save相关配置、从节点全量复制时、执行debug reload命令、未开启AOF执行shutdown命令。
    主线程阻塞:fork阻塞时间跟redis进程内存量和系统有关。
    优缺点:优点是全量复制、恢复速度快,缺点是无法实时执行、RDB文件版本兼容可能存在问题。

2、AOF
    描述:AOF是以独立日志的方式把每次写命令追加到aof_buf,然后根据策略同步到硬盘,并定期重写命令来压缩。
    重写触发:执行bgrewriteaof命令、根据配置的触发时机。重写时原aof流程不变,并添加aof_rewrite_buf保存新数据,创建子进程根据内存快照写入新aof文件,最后把aof_rewrite_buf的数据写入新aof文件并替换老文件。
    主线程阻塞:aof追加阻塞说明硬盘资源紧张。
    优缺点:优点是实时记录,缺点是恢复相对慢,aof文件可能出错,可以备份后redis-check-aof --fix修复,然后diff -u对比丢失数据,人工补全。

3、其它
    单机下部署多个实例时,为了防止多个子进程执行重写操作,建议做隔离控制,避免CPU和IO资源竞争。

 

四、阻塞
1、内在原因
(1)API或数据结构使用不合理,如keys *、查询大对象。
(2)CPU饱和问题,指redis把单核cpu使用率近100%,首先判断并发量是否达到极限,否则不正常,可能使用了高算法复杂度的命令或过度的内存优化导致操作变慢且更消耗CPU,如过度放开ziplist使用条件,而ziplist操作算法复杂度在O(n)到O(n*n)之间。
(3)持久化相关的阻塞,包括fork阻塞、AOF刷盘阻塞、HugePage写操作阻塞。

2、外在原因
(1)CPU竞争,redis是典型的CPU密集型应用,建议redis不与其它CPU密集型服务部署在一起,把redis进程绑定到CPU上。
(2)内存交换,指系统把redis使用的部分内存换到硬盘,这会导致性能急剧下降,建议保证充足内存、设置redis最大可用内存、降低系统使用swap优先级。
(3)网络问题。

 

五、理解内存
1、内存消耗
(1)对象内存,redis内存占用最大的一块,存储着用户所有数据。
(2)缓冲内存,包括客服端缓冲(tcp连接)、复制积压缓冲区(主节点)、AOF缓冲区。
(3)内存碎片,频繁更新操作、大量过期键删除容易造成碎片率上升,尽量使用数字类型或固定长度字符串减少碎片,安全重启节点重新整理碎片。
(4)子进程内存消耗。

2、管理内存
(1)设置redis内存使用上限。
(2)内存回收策略,删除过期键(惰性删除过期键和定时删除过期键)、内存溢出控制策略(默认拒绝写、LRU算法删除设置了过期时间的键、随机删除所有键、随机删除过期键、根据键值对ttl属性删除即将过期数据)。

3、内存优化
(1)缩减键值对象。
(2)共享对象池,指redis内部维护[0-9999]的整数对象池,所以数据优先考虑使用整数。
(3)字符串优化,redis自身实现字符串,存在预分配机制,所以尽量减少字符串频繁修改操作(append、setrange),直接使用set,降低预分配带来的内存浪费和内存碎片化。
(4)编码优化,控制对应的内部编码类型。
(5)控制键的数量。

 

六、缓存设计
1、考虑缓存的收益与成本
(1)收益:加速读写、降低后端负载。
(2)成本:数据不一致性、代码维护成本、redis运维成本。

2、缓存更新策略
(1)策略:LRU/LFU/FIFO算法剔除、超时剔除、主动更新。
(2)建议:低一致性业务可配置最大内存和淘汰策略的方式使用,高一致性业务可以结合超时剔除和主动更新。

3、缓存粒度控制

4、穿透优化
(1)缓存空对象,防止在查询一个数据层不存在的数据导致后端负载加大,为防止空对象占据内存可设置过期时间。
(2)布隆过滤器拦截。

5、无底洞优化
(1)无底洞是指更多的节点不代表更高的性能,因为一次批量操作的网络开销会增大,网络连接数变多对节点性能也有一定影响。
(2)优化批量操作方式:串行命令、串行IO、并行IO、hash_tag。

6、雪崩问题
(1)保证缓存层高可用。
(2)客服端降级处理。

7、热点key问题
(1)热点key并发量大,过期后重建缓存不能在短时间完成,可能造成大量线程重建缓存,加大后端负载。
(1)互斥锁(只允许一个线程重建缓存)、“永远不过期”能够一定程度上解决问题,开发人员使用时要了解各自的使用成本。

 

七、linux配置优化
1、内存分配控制,设置vm.overcommit_memory=1,表示内核允许超量使用内存直到用完为止。
2、swap控制,设置vm.swappiness,可实时查看swap使用情况,防止内存不足时系统把redis内存部分转变成swap或redis直接被kill.
3、禁用Transparent HugePage,否则在fork操作后,每个内存页会从4KB变成2MB,会增加重写内存消耗,同时每次写命令引起的复制内存页被放大512倍造成写操作慢查询。
4、设置ulimit -n当前用户同时打开的最大文件数(redis连接属于文件句柄),可提高redis的最大连接数。
5、设置tcp-backlog,使其大于redis的tcp-backlog。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值