NIUCLOUD是一款SaaS管理后台框架多应用插件+云编译。上千名开发者、服务商正在积极拥抱开发者生态。欢迎开发者们免费入驻。一起助力发展! 广告
## 1.redis是什么? ~~~ redis是基于内存高速缓存的key-value存储数据库。性能极高,读写速度能达到10万次/s左右,满足日常的高并发需求。 但它不能用作海量数据的高性能读写,因此redis适合的场景主要局限在较小数据量的高性能操作和运算上。 它具有以下几个特点: 1.支数据持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。 2.不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。 3.支持数据备份,即主从master-slave模式的数据备份。 4.支持 publish/subscribe, 通知, key 过期等等特性。 5.支持集群部署。 ~~~ ## 2.数据类型 ~~~ Redis一共支持五种数据类型 String(字符串):Redis最基本的数据类型,一个键对应一个值,一个键值最大存储512MB Hash(字典):hash是一个键值对的集合,是一个String类型的field和value的映射表,适合用于存储对象 List(列表):是redis的简单的字符串列表,按插入顺序排序 Set(集合):是String字符串类型的无序集合,也不可重复 ZSet(sorted  set  有序集合)是String类型的有序集合,也不可重复。有序集合中的每个元素都需要指定一个分数,根据分数对元素进行升序排序。 ~~~ ## 3.应用场景 ~~~ 将一些热点数据存储到redis中,直接从内存取,极大的提高了速度和节约了服务器的开销,同时也减轻了数据库压力。 1、会话缓存(最常用)  2、消息队列(支付) 3、活动排行榜或计数 4、发布,订阅消息(消息通知) 5、商品列表,评论列表 6、热门推荐,热门商品 ~~~ ## 4.常见问题 **a.缓存穿透** ~~~ 缓存穿透指的是 高并发请求一个redis和数据库里都不存在的key。 缓存穿透极大多数是人为故意发起的攻击。那如何避免呢? 解决方法: 当缓存和数据库里都不存在的,需要再缓存里为这个key设置null值, 并且设置失效时间,从而减轻数据库的压力。 ~~~ **b.缓存击穿** ~~~ 缓存击穿指的是 高并发请求一个指定key的数据,缓存里的key值刚好过期了, 那么这些请求都会去访问数据库,促使数据库压力变大。 解决方法: 使用互斥锁,简单地说,当这个key失效了以后,使用线程锁锁定当前第一个请求, 等从数据库拿到这个key的数据,再缓存起来后,释放这个锁,后面的请求才开始处理。 这样就确保了过期的缓存,又重新被缓存起来,后续的请求也不会涌向数据库。 ~~~ **c.缓存雪崩** ~~~ 缓存雪崩指的是 redis缓存里大量的key都在同一时间过期,导致redis服务卡顿。 另一方面,当部分key过期了,刚好又有大量请求访问这些过期的key, 那么请求都会涌向数据库,造成两边难的局面。 解决方法: 同一时间为大量key设置缓存失效时间时,都要加上一个随机时间,分散过期时间。 ~~~ **d.缓存持久化** ~~~ 1.RDB持久化方式是一种全量快照,能够在指定的时间间隔里对你的数据进行全量存储。 RDB的优点: 1. RDB是一个非常紧凑的文件,它保存了某个时间点得数据集,非常适用于数据集的备份, 比如你可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据, 这样即使出了问题你也可以根据需求恢复到不同版本的数据集。 2. RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心或者亚马逊的S3(可能加密), 非常适用于灾难恢复。 3. RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部 由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能。 4. 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些。 RDB的缺点: 1. 耗时、耗性能。RDB 需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候, fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求。如果 数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork, 但是你可以调节重写日志文件的频率来提高数据集的耐久度。 2. 不可控、丢失数据。如果你希望在redis意外停止工作(例如电源中断)的情况下丢失的数据最少的话, 那么RDB不适合你。虽然你可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作), 是Redis要完整的保存整个数据集是一个比较繁重的工作,你通常会每隔5分钟或者更久做一次完整的保存, 万一在Redis意外宕机,你可能会丢失几分钟的数据。 2.AOF持久化方式是一种增量快照,能够在指定时间间隔里或者每次写入时记录你的写入命令。 再redis重启时,通过回放命令进行数据的重写。 AOF的优点 : 1. 使用AOF 会让你的Redis更加耐久: 你可以使用不同的fsync策略:无fsync, 每秒fsync,每次写的时候fsync。使用默认的每秒fsync策略,Redis的性能依然很好 (fsync是由后台线程进行处理的,主线程会尽力处理客户端请求),一旦出现故障,你最多丢失1秒的数据。 2. AOF文件是一个只进行追加的日志文件,所以不需要写入seek,即使由于某些原因(磁盘空间已满,写的过程中宕机等等) 未执行完整的写入命令,你也也可使用redis-check-aof工具修复这些问题。 3. Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的, 因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机, 现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。 4. AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。 AOF的缺点 : 1. 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。 2. 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。 3.RDB-AOF混合持久化是综合两者的优缺点而来的新方式,如果把混合持久化打开, aof rewrite 的时候就直接把 rdb 的内容写到 aof 文件开头。 这样做的好处是可以结合 rdb 和 aof 的优点, 快速加载同时避免丢失过多的数据。 当然缺点也是有的, aof 里面的 rdb 部分就是压缩格式不再是 aof 格式,可读性差。 ~~~ **e.高可用(主从、哨兵、集群)** ~~~ 1. 主从模式是为了避免Redis单点故障,以及构建读写分离的架构模式(一主多从)。 一般来说,是以主写从读的模式运行,当主redis写入了数据时,会异步同步到从redis里。 2. 哨兵模式则是在主从模式的基础上添加了监控等功能。当发现主redis挂掉了,从redis则升为主redis (当有多个从redis时,以id最小的为准),挂掉的主redis重启后则变成新晋升的redis的从。 3. 集群是为了解决单机Redis容量有限的问题,将数据按一定的量分配到多台机器。 ~~~ **f.一致性** ~~~ 不管是先写MySQL数据库,再删除Redis缓存;还是先删除缓存,再写库,都有可能出现数据不一致的情况。 因为写和读是并发的,没法保证顺序,就会出现缓存和数据库的数据不一致的问题。常见的做法是先更新数据, 再删除缓存。在查询的时候,给缓存设置短效过期时间来实现最终的一致性,同时也能避免更新缓存失败了还是旧数据的问题。 ~~~ ## 5.内存淘汰机制 ~~~ Redis清除过期Key的方式 定期删除+惰性删除 定期删除 Redis设定每隔100ms随机抽取设置了过期时间的key,并对其进行检查,如果已经过期则删除。 为什么是随机抽取? 因为如果存储了大量数据,全部遍历一遍是非常影响性能的! 惰性删除 每次获取key时会对key进行判断是否还存活,如果已经过期了则删除。 ~~~ ![](https://img.kancloud.cn/3e/c7/3ec7aa53f58e4c37cb63ac3c183274c0_970x572.png) ## 6.发布订阅/消息队列 ~~~ 1. 发布订阅拆解开来就是发布和订阅两个操作,很好理解,针对的是一个消息有多个消费者的场景。 拿一个场景来说,比如直播里有喜欢的播主,点关注了这时候就相当于订阅了他的频道, 当他哪一天开播的时候就会发布开播通知。关注的人都能收到通知,但没关注他的人,后面才点的关注, 那今天的开播通知就不会收到,说明发布的消息具有时效性。 2. 消息队列针对的是一个消息只有一个消费者的场景。 ~~~