文章原创于公众号:程序猿周先森。本平台不定时更新,喜欢个人文章,欢迎关注个人微信公众号。redis
redis是一个key-value存储系统。它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操做,并且这些操做都是原子性的。在此基础上,redis支持各类不一样方式的排序。为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操做写入追加的记录文件,而且在此基础上实现了主从同步。简单来讲 Redis 就是一个数据库,不过与传统数据库不一样的是 Redis 的数据是存在内存中的,因此存写速度很是快,所以 Redis 被普遍应用于缓存方向。Redis 也常常用来作分布式锁。Redis 提供了多种数据类型来支持不一样的业务场景。除此以外,Redis 支持事务 、持久化、LUA 脚本、LRU 驱动事件、多种集群方案。数据库
本篇文章将从下列几个方向讲解 Redis:segmentfault
第一个问题先抛出来,既然选择使用Redis做缓存,其实主要从“高性能”和“高并发”来进行理解。后端
高性能缓存
由于从数据库读取数据,是从硬盘中读取数据,因此效率较低。若是将数据存入缓存中,二次读取从缓存读取,从缓存读取数据是直接操做内存,因此效率很是之高。安全
高并发服务器
直接操做缓存可以承受的请求是远远大于直接访问数据库的,因此咱们能够考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求能够不用操做数据库,提升高并发能力。微信
为何要用 Redis 而不用 map/guava 作缓存网络
缓存分为本地缓存和分布式缓存。以 Java 为例,使用自带的 map /guava 实现的是本地缓存,最主要的特色是轻量以及快速,生命周期随着 JVM 的销毁而结束。并且在多实例状态下缓存不具备惟一性。使用 Redis 做缓存称为分布式缓存,在多实例状态下共用一份缓存数据,缓存具备一致性。数据结构
Redis 和 Memcached 的区别
贴一张对比图可能看起来更加明显:
Redis 常见数据结构以及使用场景分析
String
String 数据结构是简单的 Key-Value 类型,Value 能够是string或者数字。常规 Key-Value 缓存应用;常规计数:博客数,阅读数等。
Hash
Hash 特别适合用于存储对象。
List
链表是 Redis 最重要的数据结构之一,Redis List 为一个双向链表,支持反向查找和遍历,更方便操做,不过带来了额外的内存开销。
Set
Set 其实和List都是列表的选项,Set 是能够自动去重的。当须要存储一个不出现重复数据的列表数据,Set 是一个最好的选择。你能够基于 Set 轻易实现交集、并集、差集的操做。
Sorted Set
Sorted Set 相比Set增长了一个权重参数 Score,使得集合中的元素可以按 Score 进行有序排列。
Redis 设置过时时间
Redis能够对存储在缓存中的数据设置过时时间。做为一个缓存数据库,这是很是实用的功能。以前写过一篇先后端交互的文章讲过,Token 或者一些登陆信息,尤为是短信验证码都是有时间限制的,按照传统的数据库处理方式,通常都是本身判断过时,这样无疑会严重影响项目性能。而有一个好的方案其实就是将这些验证信息存入Redis设置过时时间,若是设置了存活时间30分钟,那么半小时以后这些数据就会从Redis中进行删除。那说到删除,Redis是若是作到对这些数据进行删除的呢:
可是只是使用按期删除 + 惰性删除的删除机制仍是存在一个致命问题:若是按期删除漏掉了不少过时 Key,并且用户长时间也没有使用到这些过时key,就会致使这些过时key堆积在内存里,致使Redis内存块被消耗殆尽。因此有了Redis内存淘汰机制的诞生。
Redis 内存淘汰机制
Redis 提供 6 种数据淘汰策略:
Redis 持久化机制
怎么保证 Redis 宕机以后再重启Redis后数据能够进行恢复?不少时候咱们须要持久化数据也就是将内存中的数据写入到硬盘里面。Redis持久化支持两种不一样的持久化操做。接下来,咱们来简单聊聊Redis的两种持久化机制RDB和AOF。
快照持久化(RDB)
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操做过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换以前的文件,用二进制压缩存储。RDB是Redis默认的持久化方式,会在对应的目录下生产一个dump.rdb文件,重启会经过加载dump.rdb文件恢复数据。
优势:
缺点:
快照持久化是 Redis 默认采用的持久化方式,在 redis.conf 配置文件中已经进行配置:
AOF持久化
AOF持久化是以日志的形式记录服务器所处理的每个写、删除操做,查询操做不会记录,以文本的方式记录,文件中能够看到详细的操做记录。她的出现是为了弥补RDB的不足(数据的不一致性),因此它采用日志的形式来记录每一个写操做,并追加到文件中。Redis 重启的会根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工做。与快照持久化相比,AOF 持久化的实时性更好,所以已成为主流的持久化方案。 默认状况下 Redis 没有开启 AOF持久化,能够经过设置 appendonly 参数开启:
开启 AOF 持久化后每执行一条会更改 Redis 中的数据的命令,Redis 就会将该命令写入硬盘中的 AOF 文件。AOF 文件的保存位置和 RDB 文件的位置相同,都是经过 dir 参数设置的,默认的文件名是 appendonly.aof。
在 Redis 的配置文件中存在三种不一样的 AOF 持久化方式,它们分别是:
用户可使用appendfsync everysec选项 ,让 Redis 每秒同步一次 AOF 文件,这样Redis性能几乎不会受到影响,并且这样即便出现宕机,用户最多只会丢失一秒以内产生的数据。当硬盘忙于执行写入操做的时候,Redis 还会优雅的放慢本身的速度以便适应硬盘的最大写入速度。
优势:
缺点:
Redis 4.0 对于持久化机制的优化
Redis 事务
事务提供了一种按顺序地执行多个命令的机制。而且在事务执行期间,服务器会将事务中的全部命令都执行完毕,而后才去处理其余客户端的命令请求。事务老是具备原子性、一致性和隔离性,而且当 Redis 运行在某种特定的持久化模式下时,事务也具备持久性。
缓存雪崩
缓存处理过程:接收到请求请求,先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。
缓存雪崩:缓存雪崩是指缓存中数据大批量到过时时间,而查询数据量巨大,引发数据库压力过大甚至down机。
解决办法:
缓存穿透
简介:缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户极可能是攻击者,攻击会致使数据库压力过大。
解决办法:
缓存击穿
简介: 缓存击穿是指缓存中没有但数据库中有的数据,这时因为并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引发数据库压力瞬间增大
解决方法:
解决 Redis 并发竞争 Key 问题
问题描述:多客户端同时并发写一个key,可能原本应该先到的数据后到了,致使数据版本错了。或者是多客户端同时获取一个key,修改值以后再写回去,只要顺序错了,数据就错了。一个key的值是1,原本按顺序修改成2,3,4,最后是4,可是顺序变成了4,3,2,最后变成了2.
我我的认为比较好的方案是分布式锁+时间戳:
1.总体技术方案
这种状况,主要是准备一个分布式锁,你们去抢锁,加锁的目的实际上就是把并行读写改为串行读写的方式,从而来避免资源竞争。利用SETNX很是简单地实现分布式锁。
2.时间戳
因为key的操做须要顺序执行,因此须要保存一个时间戳判断顺序。假设系统B先抢到锁,将key1设置为{ValueB 7:05}。接下来系统A抢到锁,发现本身的key1的时间戳早于缓存中的时间戳(7:00<=7:05),那就不作set操做了。
3.什么是分布式锁
分布式锁能够基于不少种方式实现,好比zookeeper、redis等,无论哪一种方式实现,基本原理是不变的:用一个状态值表示锁,对锁的占用和释放经过状态值来标识。
保证缓存与数据库双写时的数据一致性
可能对大部分来讲最早想到的方案就是读请求和写请求串行化,串到一个内存队列里去。可是这个方案有着特别大的缺点:它也会致使系统的吞吐量大幅度下降,用比正常状况下多几倍的机器去支撑线上的一个请求。
最经典的缓存+数据库读写的模式。
读的时候,先读缓存,缓存没有的话,就读数据库,而后取出数据后放入缓存,同时返回响应。
更新的时候,先更新数据库,而后再删除缓存。
若是喜欢个人文章,欢迎关注个人我的公众号:程序猿周先森。**