原理

1.一致性哈希 2.多路复用I/O 3.单线程

配置

  • maxmemory:限定最多使用的内存,如果内存到达了指定的上限,还要往redis里面添加更多的缓存内容,需要设置清理内容的策略;
  • maxmemory-policy:数据清理策略;

调优

  • 管理命令:info,cluster info, cluster nodes, –bigkey,slowlog,bgsave,commandstats等等;
  • info输出的信息里面有这几项和缓存的状态比较有关系:
keyspace_hits:14414110keyspace_misses:3228654used_memory:433264648expired_keys:1333536evicted_keys:1547380

通过计算hits和miss,我们可以得到缓存的命中率:14414110 / (14414110 + 3228654) = 81% ,一个缓存失效机制,和过期时间设计良好的系统,命中率可以做到95%以上,对于整体性能提升是很大的。 used_memory,expired_keys,evicted_keys这3个信息的具体含义,redis的官方也有一篇很详细的说明: http://redis.io/commands/info 有个ruby gem叫redis-stat,它利用INFO命令展现出更直观的信息报表,推荐: https://github.com/junegunn/redis-stat

  • 统计数据查看:ops(实际从节点统计包含了主从复制的回放请求),clients等信息;
  • 慢查询slowlog查看,针对部分查询进行优化,如set的随意使用:频繁删除后全量插入;一个set包含了几百万的数据;
  • 规范化业务对用户属性的存储方式:不再提供set集合的操作,统一打平为标签存储;严格控制不同应用场景下,具体标签信息的超时时间;
  • 检查bigkey的占用情况,对部分大key的存储方式进行调整。如将hashmap结构打平,存储为普通的k-v;优化key的长度;
  • 优化日志输出,超时时抛出异常的同时,记录对应操作的KEY!
  • 根据业务实际场景,对数据可靠性进行降级,关闭了RDB,AOF的逻辑。
  • 使用读写分离,引入lettuce,并根据官方文档及经验,调整相关参数,比如长连接,超时时间,线程池大小,集群刷新策略,testOnborrow等等。
  • 对分散的Redis操作进行收口,避免大流量的冲击写入,此处封装了统一的client,业务直接调用client接口即可,不再需要关心具体的redis访问。
  • 针对离线分析数据的导入,将原来的全量导入,优化为通过布隆过滤器之后的增量导入!
  • 容量预估时,要充分考虑管理结构的占用,根据实际经验,key+value的大小再乘以3,是最终实际的占用!严格控制单个实例的存储占比(<75%);
  • 期间也遇到连接池耗尽问题,简单上调pool大小即可。
  • 对于某一类别(如用户维度)的标签,通过hashmap存储,同时对于标签的过期时间,使用zset维护。
  • 中间定位过程中,基本只检查一个实例节点的状态信息,实际上集群中各个redis节点会有好坏差异,需要全量排查!

淘汰策略

Redis的内存淘汰策略是指在Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据

  • noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
  • allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。
  • allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。
  • volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
  • volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
  • volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。

过期清除策略

  • 惰性过期(类比懒加载,这是懒过期):只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存
  • 定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
    (expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。)

Redis中同时使用了惰性过期和定期过期两种过期策略,即使过期时间到了,但是有部分并没有真正删除,等待惰性删除。

持久化

将内存中的数据异步写入硬盘中,两种方式:RDB(默认)和AOF RDB持久化原理:通过bgsave命令触发,然后父进程执行fork操作创建子进程,子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换(定时一次性将所有数据进行快照生成一份副本存储在硬盘中) 优点:是一个紧凑压缩的二进制文件,Redis加载RDB恢复数据远远快于AOF的方式。 缺点:由于每次生成RDB开销较大,非实时持久化, AOF持久化原理:开启后,Redis每执行一个修改数据的命令,都会把这个命令添加到AOF文件中。 优点:实时持久化。 缺点:所以AOF文件体积逐渐变大,需要定期执行重写操作来降低文件体积,加载慢

主从同步

主从复制策略:部分同步(主:异步传输积压缓冲区数据,从:主进程同步数据),全同步(主:单独进程RDB,主进程异步传输RDB数据,从:主进程加载RDB–阻塞,单独进程同步AOF); 主节点:本地AOF,写积压空间,发送数据到从节点(异步,单线程) 从节点:通过定时任务连接主节点,接受数据并更新(非阻塞,单线程,相当于从节点仅执行写的操作) 分为起始的同步阶段,以及运行期间的传播阶段。 由从节点psync(2.8开始)控制是否执行部分同步还是全同步。 由主节点主动传播命令,数据发生修改(写)就会触发,此时仅仅是写到本地缓存,不会直接发起网络请求,因此是异步操作。 从节点收到传播命令后,执行相关操作,此时还是同时存在读写操作。 主节点写入数据,还是会影响从节点!!!读写分离的意义不大,只是提升了写性能,无法提升读!