缓存-Redis

311 阅读5分钟

这是我参与更文挑战的第5天,活动详情查看:更文挑战

一、概念及优势

  • 概念
  • 高可用
    • 访问内存比访问磁盘的速度要快
  • 高并发
    • QPS:服务器每秒可以查询的次数
    • 数据库 1W (4核8G) <<---->> redis 10W或30W
  • redis与map
    • Redis 可以用几十 G 内存来做缓存,Map 不行,一般 JVM 也就分几个 G 数据就够大了
    • Redis 的缓存可以持久化,Map 是内存对象,程序一重启数据就没了
    • Redis 可以实现分布式的缓存,Map 只能存在创建它的程序里
    • Redis 可以处理每秒百万级的并发,是专业的缓存服务,Map 只是一个普通的对象
    • Redis 缓存有过期机制,Map 本身无此功能
    • Redis 有丰富的 API,Map 就简单太多了

二、缓存分类及常用缓存

1.Redis(6379)

docker run -p 6378:6379 --name redis01 -v /root/redis/redis01/conf/redis.conf:/etc/redis/redis.conf -v /root/redis/redis01/data:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes

2.Memcache(11211)

  • 一款高性能的 分布式 内存缓存服务器
  • 目的:通过缓存 数据库的查询结果,减少对数据库访问次数,以提高动态web应用的速度,提高可扩展性。

clipboard1.png

三、Redis

1. redis的单线程模式

2. 数据结构

2.1 字符串 String

set key1 value1
get key1

2.2 列表 list

rpush/lpush myList value1 value2 
lpop myList

2.3 哈希 hash

hset userInfo name 'ss' age 30
hget userInfo name 

2.4 集合 set

sadd mySet value1 value2
smembers mySet

2.5 有序集合 sortset

   zadd   myzSet 3.0 value1 2.0 value2 1.0 value3
   zrange myzSet 0 -1  -- > value3 value2 value3
   zrange myzSet 0  1  -- > value3 value2
zrevrange myzSet 0  1  -- > value1 value2

3. RDB与AOF

3.1.数据持久化

3.2.RDB

  • RDB:(snapshotting,RDB) dump.rdb 快照 (redis默认的方式)
save 900 1        #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 300 10       #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 60 10000     #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
触发时机:
    自动触发:
            (1) 服务关闭时
            (2) 满足以上条件时
    手动触发:
            save命令    通过 redis 主进程  写 dump.rdb
            bgsave命令  通过 fork  子进程  写 dump.rdb

3.3.AOF

  • AOF:(append-only file, AOF) appendonly.aof 参数 文件追加 (越来越主流 - 优点:实时性更好)
    • TIPS:
      • AOF重写 不是基于上一次AOF文件进行重写、而是基于当前Redis内存中的数据 进行重写
      • AOF 产生一个新的aof文件, 该文件和原有的aof文件保存的数据状态一致,但体积更小;
        • 该功能是读取数据库的键值对来实现,不会对现有的aof文件做操作:
          • (1)Redis 服务器会维护一个 AOF 重写 缓冲区
          • (2)子线程完成AOF文件的创建
appendfsync always    	#每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync everysec  	#每秒钟同步一次,显示地将多个写命令同步到硬盘
appendfsync no        	#让操作系统决定何时进行同步

参数设置:appendonly yes 

3.4其他

  • Redis 4.0开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通过配置项 aof-use-rdb-preamble 开启)
    • 优点:AOF 重写的时候就直接把 RDB 的内容写到 AOF 文件开头,这样结合了RDB和AOF的优点,快速加载
    • 缺点: AOF 里面的 RDB 部分是压缩格式不再是 AOF 格式,可读性较差

四、缓存常见问题

1.缓存穿透

  • 【大量请求的key 在缓存中根本不存在,导致全部都要在数据库查一遍,失去了Redis缓存的意义】
  • 解决办法
    • (1) 缓存无效key (无效key缓存至redis并设置过期时间)
      • 一般情况下我们是这样设计 key 的: 表名:列名:主键名:主键值
    • (2) 布隆过滤器
      • 所有可能的数据放在布隆过滤器中,用户请求过来,先在布隆过滤器中做判断;
      • 布隆过滤器说某个元素存在,小概率会误判;
      • 布隆过滤器说某个元素不在,那么这个元素一定不在。

2.缓存雪崩

  • 【缓存在同一时间大面积失效,导致大量请求直接请求数据库】
  • 解决办法
    • 针对redis不可用情况:
      • (1) 采用redis集群,避免单机
      • (2) 限流,避免同时处理大量请求
    • 针对热点失效问题:
      • (1) 设置不同的缓存失效时间 比如:随机
      • (2) 设置缓存永久不失效

3.数据库与缓存数据一致性问题

  • 一般采用删除缓存策略 而不是更新缓存
  • 3.1先更新数据库,再删除缓存
高并发情况下:(读取时候缓存失效、同时并发有一个写操作)
    [缓存刚好失效]
    线程A查询数据库,得一个旧值
    线程B将新值写入数据库
    线程B删除缓存
    线程A将查到的旧值写入缓存
  • 3.2先删除缓存,再更新数据库
    线程A删除了缓存
    线程B查询,发现缓存已不存在
    线程B去数据库查询得到旧值
    线程B将旧值写入缓存
    线程A将新值写入数据库
  • 我们可以发现,两种策略各自有优缺点:
    • 先删除缓存,再更新数据库
      • 【在高并发下表现不如意,在原子性被破坏时表现优异】
    • 先更新数据库,再删除缓存(Cache Aside Pattern设计模式)
      • 【在高并发下表现优异,在原子性被破坏时表现不如意】

参考地址: