java基础-redis缓存篇

Redis的数据类型

Redis总共支持5种数据类型,分别是:

类型 说明,命令
String set ,get
Hash HMSET myhash field1 "Hello" field2 "World"
HGET myhash field1
List lpush lrange
Set sadd smembers
(ZSet)Sorted Set zadd
ZRANGEBYSCORE runoob 0 1000

AOF和RDB区别

RDB: redis database,在某一个时间点将Redis存储的数据快照一份存储在磁盘上,生成的文件可以随时备份.RDB恢复比AOF的方式更高效.对于数据完整性不是很敏感的可以用该方式.

AOF:append only file ,将Redis所有的写指令存储下来,这样Redis重启的时候按照指令执行一遍就可以了.RDB和AOF方式可以同时使用,以AOF的优先,因为一般AOF的数据恢复更全.但是更慢.
appendonly yes 即可打开AOF功能
默认每隔一秒会fsync一次到文件中
提供了redis-check-aof工具用来日志文件恢复
提供了AOF文件重写的方式来减小文件大小.
AOF文件和RDB文件一样可以随时备份,不影响完整性.


AOF rewrite过程

  1. Redis(fork)一个“重写子进程”,读取现有的AOF文件,并将其包含的指令进行分析压缩并写入到一个临时文件中
  2. 与此同时,主工作进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样就保证了原有的AOF文件是完整的.防止重写子进程出意外.
  3. 当" 重写子进程"完成重写任务后就会向主进程发信号,主进程就会将内存缓存区中的数据追加到新的文件中.
  4. 当追加结束后,Redis就会用新的AOF文件替换掉原有的文件,之后新的指令就写到新的AOF文件中.

缓存雪崩

  • 什么是缓存雪崩
    由于各种原因导致缓存服务宕机了.此时大量请求发到后端,后端因负载有限很快也宕机了,导致整个服务不可用或很慢.
  • 解决方案
  1. 保证缓存层高可用,用Redis Sentinel 和Redis Cluster
  2. 限流,当缓存服务失效时用hystrix限流
  3. 充分测试,了解后端的抗压能力以及会出现的问题并做出一些预案

缓存击穿

  • 什么是缓存击穿
    当用户请求了缓存中没有缓存的数据,该请求会一直到数据库上,数据库上也没有,如果有大量的这种请求,相当于缓存失效了,没有起到保护数据库的作用,数据库会很快挂掉.
  • 解决方案
  1. 缓存空值,但是这个会浪费大量的存储空间,最好对这种值设置一个相对短的过期时间
  2. 用布隆过滤器,把数据库有的值缓存起来,没有的值直接返回错误信息.适合更新不频繁的数据.

一致性Hash

  • 第一种 传统的 对key值的hashcode和 节点 求模 ;这种会数据不均衡,当有一台死了会导致大部分数据都命中不了.而不只是1/n (n = 节点数)

  • 第二种


    image.png
  • 第三种


    image.png
  • Redis 独创的Hash slot
    一个 Redis 集群包含 16384 个哈希槽(hash slot),
    数据库中的每个键都属于这 16384 个哈希槽的其中一个,
    集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽,
    其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和
    这样的方式使得用户可以很容易地向集群中添加或者删除节点

总结:环形Hash空间可以解决一致性问题,有效防止一个节点宕机导致rehash使得大部分数据都失效的问题;添加虚拟节点方法可以解决数据不平衡问题.参考


缓存一致性

写:先写数据库再淘汰缓存,如果计算缓存值要很长时间,为了避免缓存失效后第一次访问很卡可以主动更新缓存,做到缓存永不过期的效果,对于热点缓存失效问题也可以用这个方法解决.
读:先读缓存再读数据库

缓存命中率

命中率 = 命中数 / 总请求数
缓存一般都是用在读多写少的场景,如果读少写多,用缓存意义不大.命中率会很低.
通常情况下,缓存的粒度越小,命中率会越高;
可以通过缓存预加载(预热)、增加存储容量、调整缓存粒度、更新缓存等手段来提高命中率

缓存无底洞

随着节点数的增加,读取缓存的时间因为要加上节点间通讯时间而更慢.表现为新增了很多服务器性能不但没有提升反而下降了.

  • 方案:
  1. 尽量让需要访问的数据在一个节点上.用hash_tag实现
  2. 对于批量操作,客户端计算出每个节点的key子列表,之后对每个节点执行mget或者pipeline操作(这一步可以弄成多线程并行)

Redis的使用,怎么保证高可用。

用主从,Redis Sentinel和Redis Cluster,Redis Cluster引入了master和slave节点,每个master节点会对应两个对应的slave节点,这样在整个集群中,任意两个节点宕机都不会导致数据不可用.当master节点退出后,集群会自动选择一个slave节点为新的master节点.

redis和Memcached的区别

Redis Memcached
支持的数据结构 哈希、列表、集合、有序集合 纯kev-value
持久化支持
高可用支持 redis天然支持集群功能,可以实现主动复制,读写分离。官方也提供了sentinel集群管理工具,能够实现主从服务监控,故障自动转移,这一切,对于客户端都是透明的,无需程序改动,也无需人工介入 需要二次开发
存储value容量 最大512M 最大1M
内存分配 临时申请空间,可能导致碎片 预分配内存池的方式管理内存,能够省去内存分配时间
虚拟内存使用 有自己的VM机制,理论上能够存储比物理内存更多的数据,当数据超量时,会引发swap,把冷数据刷到磁盘上 所有的数据存储在物理内存里
网络模型 非阻塞IO复用模型,提供一些非KV存储之外的排序,聚合功能,在执行这些功能时,复杂的CPU计算,会阻塞整个IO调度 非阻塞IO复用模型
水平扩展的支持 暂无 暂无
多线程 Redis是单线程 Memcached支持多线程,CPU利用方面Memcache优于Redis
过期策略 有专门线程,清除缓存数据 懒淘汰机制:每次往缓存放入数据的时候,都会存一个时间,在读取的时候要和设置的时间做TTL比较来判断是否过期
单机QPS 约10W 约60W
源代码可读性 代码清爽简洁 考虑了太多的扩展性,多系统的兼容性,代码不清爽
适用场景 复杂数据结构、有持久化、高可用需求、value存储内容较大 纯KV,数据量非常大,并发量非常大的业务

Redis的内存模型

  1. 查看内存使用情况 info memory

Redis Sentinel选举

主观下线(subjectively down):Sentinel 会定时心跳检查,如果超时未回复,Sentinel会标记该节点为 S_DOWN
客观下线(objectively down):多个Sentinel认为master挂了,就会标记为 O_DOWN,开启-
failover过程
先有一台标记为 主观下线,然后这台Sentinel会发消息和其他Sentinel确认master是否失效了,如果回复超过法定人数(quorum)就会开启选举.过程如下图:


image.png

is-master-down-by-addr命令,格式如下IS-MASTER-DOWN-BY-ADDR

  • 开始选举Leader
    首先发现master节点的节点会在等待failover_start_time 后开始向其他节点发送is-master-down-by-addr命令,主要关注 ,并给自己投一票;其他节点根据 current-epoch 和自己的 current-epoch 比较,比自己大就选对方,最后会选出一个Leader

  • 开始选举新的master

  1. 过滤掉一些节点.选出备选节点
  2. 选出master
    过程如图:


    Redis选举.png

缓存设计原则

原则
只应将热数据放到缓存中
缓存过期时间应尽量分散,以避免集中过期
缓存key应具备可读性
避免不同业务出现同名key
可对key进行适当的缩写以节省内存空间
选择合适的数据结构
避免使用耗时长的命令,如keys*
一个key对应的数据不应过大
避免缓存穿透
进行适当的缓存预热

数据淘汰策略

淘汰策略 说明
volatile-lru remove the key with an expire set using an LRU algorithm
从已设置过期时间的key中挑选最少使用的数据淘汰
allkeys-lru remove any key accordingly to the LRU algorithm
从所有的数据集中挑选最近最少使用的数据淘汰
volatile-random remove a random key with an expire set
从已设置过期时间的数据集中任意挑选数据淘汰
allkeys->random remove a random key, any key
在整个数据集中随机挑选key淘汰
volatile-ttl remove the key with the nearest expire time (minor TTL)
从已设置过期时间的数据集中挑选将要过期的数据淘汰
noeviction don't expire at all, just return an error on write operations
禁止淘汰数据,如果写满了直接报错

你可能感兴趣的:(java基础-redis缓存篇)