缓存系列-Redis入门教程
Redis是什么?
Redis (REmote DIctionary Server)是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列,是一个高性能的key-value数据库。
Redis与其他key-value缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
为什么要用Redis
- 性能极高 – Redis读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 – Redis支持Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 原子 – Redis的所有操作都是原子性的,即要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
- 丰富的特性 – Redis还支持publish/subscribe, key过期等特性。
Redis的数据类型及使用场景
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。每种数据类型有其适合的使用场景,下面具体介绍.
String(字符串)
string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。
使用方法
SET key value 设置指定 key 的值
GET key 获取指定 key 的值。
SETEX key seconds value 将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)。
使用场景
1.会话缓存
用户登录系统后,使用Redis保存用户的Session信息,每次用户查询登录信息都直接从Redis中获取。
2.计数器
- 比如登录系统会限制密码错误次数,当一个用户在一定时间内连续输入密码错误,就不能登录,需要一段时间后才能登录,我们可以使用redis,把username作为key,错误的次数作为value,同时设置过期时间即可.
- 手机验证码限收到短信的次数
- 统计其他计数
3.定时器
redis的key可以设置过期时间,我们基于此特性设置一个定时器.
4.对象
我们把对象序列化后,可以使用redis保存该对象,然后在获取对象信息的时候,反序列化value
5.分布式锁
redis提供了setnx()方法,即SET IF NOT EXIST,只有在key不存在的时候才能set成功,这就意味着同一时间多个请求只有一个请求能保存成功,这块的可以自行搜索redis的分布式锁
Hash(哈希)
Redis hash 是一个键值(key=>value)对集合,即编程语言中的Map类型.
Redis hash 是一个 string 类型的 field 和 value 的映射表.
使用方法
HSET key field value
将哈希表 key 中的字段 field 的值设为 value 。
HGET key field
获取存储在哈希表中指定字段的值。
HKEYS key
获取所有哈希表中的字段
HMSET key field1 value1 [field2 value2 ]
同时将多个 field-value (域-值)对设置到哈希表 key 中。
使用场景
hash 特别适合用于存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值(Memcached中需要取出整个字符串反序列化成对象修改完再序列化存回去)
List(列表)
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
使用方法
LPUSHX key value
将一个值插入到已存在的列表头部
LPUSH key value1 [value2]
将一个或多个值插入到列表头部
LPOP key
移出并获取列表的第一个元素
BLPOP key1 [key2 ] timeout
移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
使用场景
1.消息队列
Redis的lpush+brpop命令组合即可实现阻塞队列,生产者客户端使用lrpush从列表左侧插入元素,多个消费者客户端使用brpop命令阻塞式的"抢"列表尾部的元素,多个客户端保证了消费的负载均衡和高可用性。
2.类目/文章/活动等列表
最常见的就是各个系统的首页数据,包括电商系统的商品类目,拼团活动列表,博客园的首页文章列表等
3.其他
根据push和pop的方式不同,有以下组合方式
lpush + lpop = Stack(栈)
lpush + rpop = Queue(队列)
lpush + ltrim = Capped Collection(有限集合)
lpush + brpop = Message Queue(消息队列)
Set(集合)
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
使用方法
SADD key member1 [member2]
向集合添加一个或多个成员
SDIFF key1 [key2]
返回给定所有集合的差集
SINTER key1 [key2]
返回给定所有集合的交集
SMEMBERS key
返回集合中的所有成员
使用场景
1.标签(tag)
比如在点餐评价系统中,用户给某商家评价,商家会有多个评价标签,但是不会重复的,如果100万人给某商家评价打了标签,如果使用MySQL数据库获取大数据量去重后的评价标签,会影响数据库的性能和系统的并发量.
2.相同点/异同点
利用交集、并集、差集等操作,可以计算两个人的共同喜好,全部的喜好,自己独有的喜好等功能。
zset(sorted set:有序集合)
Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
使用方法
ZADD key score1 member1 [score2 member2]
向有序集合添加一个或多个成员,或者更新已存在成员的分数
ZCARD key
获取有序集合的成员数
ZREM key member [member ...]
移除有序集合中的一个或多个成员
使用场景
1.排行榜
例如博客园需要对用户发表的文章做排行榜,榜单的维度可能是多个方面的:按照时间、按照点赞数、按照热度,浏览数等
Redis持久化
Redis 提供了不同级别的持久化方式:
- RDB持久化,该方式能够在指定的时间间隔能对数据进行快照存储.
- AOF持久化,该方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大.
- 不持久化,如果你只希望数据在服务器运行的时候存在,你也可以不使用任何持久化方式.
- RDB+AOF模式, 在这种情况下, 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.
RDB的优点
- RDB是一个非常紧凑的文件,它保存了某个时间点得数据集,非常适用于数据集的备份,比如你可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出了问题你也可以根据需求恢复到不同版本的数据集.
- 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些.
RDB的缺点
- 如果你希望在redis意外停止工作(例如电源中断)的情况下丢失的数据最少的话,那么RDB不适合你.虽然你可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Redis要完整的保存整个数据集是一个比较繁重的工作,你通常会每隔5分钟或者更久做一次完整的保存,万一在Redis意外宕机,你可能会丢失几分钟的数据.
- RDB 需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求.
AOF优点
- 使用AOF 会让你的Redis更加耐久: 你可以使用不同的fsync策略:无fsync,每秒fsync,每次写的时候fsync.使用默认的每秒fsync策略,Redis的性能依然很好(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求),一旦出现故障,你最多丢失1秒的数据.
AOF缺点
- 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
- 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。
如何选择持久化方式
如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。
有很多用户都只使用 AOF 持久化,但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快
一般来说,如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能.
使用Redis出现的问题
在一个高频访问的应用系统中,每次用户的请求需要去DB中获取数据,会对数据库造成很大的压力、容易导致数据库的奔溃。所以才会出现缓存来分担一部分的数据库的压力。
但是使用缓存也带来了一系列问题:
1.缓存一致性问题
当数据时效性要求很高时,需要保证缓存中的数据与数据库中的保持一致,而且需要保证缓存节点和副本中的数据也保持一致,不能出现差异现象。这就比较依赖缓存的过期和更新策略。一般会在数据发生更改的时,主动移除对应的缓存。
所以需要通过事物机制来保证缓存的一致性。
2.缓存雪崩问题
在高并发场景下,有多个请求去共同请求一份相同的业务数据。有可能多个请求先去从缓存中获取数据、获取不到的并发的去从数据库获取数据,对后端数据库造成极大的冲击,甚至导致 “雪崩”现象。
- 方案一: 可以做一个随机的等待、错峰去访问缓存的信息。这样就能保证同一时刻高并发的访问、经过时间离散之后只有小部分的请求访问数据库、大部分的请求去命中缓存。
- 方案二: 可以按照比例限制有部分数据直接访问数据库然后更新缓存、大部分的数据直接请求缓存。
按照实际的场景去做判断例如 1%的场景直接访问数据库,99%的可以通过缓存获取到数据。
3.缓存击穿的问题
在系统设计的的时候预期是通过缓存来减轻数据库的压力、防止数据奔溃的情况。在某个实际发生的场景中、大量的请求并没有命中缓存而导致了大量请求达到数据库、从而导致数据库有巨大冲击和压力。
3.1缓存中没有数据
在某个大促活动中有大量的热点数据,互动一开始需要访问这些数据。由于活动开始的时候洪峰流量到来,所有的请求缓存、缓存直接击穿,访问数据库导致数据库直接cpu 100%,业务系统直接奔溃。
对于这种场景可以提前对数据进行预热,开活动开始前先将数据推送到缓存中。
3.2缓存集中失效
由于我们在缓存使用的过程中会设置缓存的失效时间、如果设置的不合理可能会导致数据集中失效的情况。由于缓存集中失效会导致系统缓存穿透、在同一时刻高并发的访问数据,造成数据雪崩。
解决这种场景的可以将失效的时间由固定值+随机值来构成。EXPIRETIME=FIXTIME+RUND_TIME 例如你想保证整个EXPIRETIME是5S 左右,可以 通过EXPIRETIME=4000+Random(1000)
Redis的过期策略
通常Redis keys创建时没有设置相关过期时间,他们会一直存在,除非使用显示的命令移除,例如,使用DEL命令。
EXPIRE一类命令能关联到一个有额外内存开销的key。当key执行过期操作时,Redis会确保按照规定时间删除他们。
key的过期时间和永久有效性可以通过EXPIRE和PERSIST命令(或者其他相关命令)来进行更新或者删除过期时间。
Redis keys过期有两种方式:定期删除和惰性删除。
1.定期删除
定时删除,用一个定时器来负责监视key,当key过期则自动删除key。
虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,会影响redis的性能.
2.惰性删除
客户端尝试访问key时,key会被发现并主动的过期.
但是这样是不够的,因为有些过期的keys,永远不会访问他们,那么他们就永远不会被删除,而占用内存,导致redis内存被过期的key占用.
3.定期删除+惰性删除
redis默认每100ms检查一次,是否有过期的key,有过期key则删除。需要说明的是,redis不是每100ms将所有的key检查一次,而是随机抽取20个keys进行过期检查,同时删除已经过期的keys,如果有多于25%的keys过期,重复抽取。直到过期的keys的百分比低于25%,这意味着,在任何给定的时刻,最多会清除1/4的过期keys
那么问题来了,采用定期删除+惰性删除就能保证过期的key会全部删除掉么?
内存淘汰机制
如果定期删除没删除key。然后也没去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制。
在redis.conf中有配置
maxmemory-policy volatile-lru
内存淘汰策略如下:
- noeviction:当内存不足以容纳新写入数据时,新写入操作会报错,不建议使用
- allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。推荐使用
- allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key
- volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key
- volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key
- volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除
缓存系列-Redis入门教程的更多相关文章
- 【原】Redis入门教程
最近在学习Redis,写几篇文章记录一下学习过程:Redis入门教程. 1.Redis基本概念 Redis Redis Keys Redis 基本数据类型 Redis基本操作 遍历操作 Pub-Sub ...
- 超强、超详细Redis入门教程【转】
这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下 [本教程目录] 1.redis是什么2.redis的作者何许人也3.谁在使用red ...
- 超详细Redis入门教程【转】
这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下 [本教程目录] 1.redis是什么 2.redis的作者何许人也 3.谁在使 ...
- Redis入门教程:特性及数据类型的操作
虽然Redis已经很火了,相信还是有很多同学对Redis只是有所听闻或者了解并不全面,下面是一个比较系统的Redis介绍,对Redis的特性及各种数据类型及操作进行了介绍.是一个很不错的Redis入门 ...
- Redis入门教程(二)
推荐阅读: Redis入门教程(一)https://www.cnblogs.com/jichi/p/10285346.html 5. Redis 的数据结构 5.1 Redis 数据结构介绍 redi ...
- Redis入门教程(三)— Java中操作Redis
在Redis的官网上,我们可以看到Redis的Java客户端众多 其中,Jedis是Redis官方推荐,也是使用用户最多的Java客户端. 开始前的准备 使用jedis使用到的jedis-2.1.0. ...
- pyqt系列原创入门教程
pyqt4入门教程 python pyqt4 PyQt是一个创建GUI应用程序的工具包.它是Python编程语言和Qt库的成功融合.Qt库是目前最强大的库之一. 通过pyqt可以实现很多我们想要的功能 ...
- 超强、超详细Redis入门教程
(1)什么是redis? Redis 是一个基于内存的高性能key-value数据库. (有空再补充,有理解错误或不足欢迎指正) (2)Reids的特点 Redis本质上是一个Key-Value类型的 ...
- Spring Boot 缓存应用 Memcached 入门教程
本章学习 Mmecached 在 Spring Boot 中的使用教程.Memcached 与 Redis 各有好处.本文主要学习 Spring Boot 中如何应用集成 Mmecached spri ...
随机推荐
- 解决tensorflow模型保存时Saver报错:TypeError: TF_SessionRun_wrapper: expected all values in input dict to be ndarray
TypeError: TF_SessionRun_wrapper: expected all values in input dict to be ndarray 对于下面的实际代码: import ...
- Docker部署web环境之Lanmp
1. 案例一 整套项目多容器分离通过docker-compose部署lanmp环境 中方文档参考网址: docker/kubernets网址 http://www.dockerinfo.net/doc ...
- 一位 iOS 大牛的 BAT面试心得与经验总结,送给正在迷茫 的你!
前言: 目前形势,参加到 iOS 队伍的人是越来越多,可以说是已经达到了供过于求的地步了. 今年,找过工作人可能会更深刻地体会到今年的就业形势不容乐观,之前实习的时候就想着写一篇面经,后来忙就给忘了, ...
- C#中unit
整理的百度百科的一些关于UNIT的资料 中文名UINT 外文名typedef unsigned short UIN 性 质 32位无符号整数 应 用 是unsigned int派生出来的 ...
- Ubuntu通过修改配置文件进行网络配置
Ubuntu系统进行网络配置有的时候用图形界面不起作用,这种情况下可以直接修改某些启动脚本或配置文件 Ubuntu系统进行网络配置涉及到几个配置文件1./etc/network/interfaces ...
- PHP使用array_unique对二维数组去重处理
去重,点这里,东西是好东西,就是有点懒.莫见怪
- 深挖Openstack Nova - Scheduler调度策略
深挖Openstack Nova - Scheduler调度策略 一. Scheduler的作用就是在创建实例(instance)时,为实例选择出合适的主机(host).这个过程分两步:过滤(F ...
- spring+mybatis最简多数据源配置
作者:纯洁的微笑出处:http://www.ityouknow.com/ 版权所有,欢迎保留原文链接进行转载:) 说起多数据源,一般都来解决那些问题呢,主从模式或者业务比较复杂需要连接不同的分库来支持 ...
- python 读取文件1
1.脚本 from sys import argv script,filename = argv txt = open(filename) print ("the filename is % ...
- 贪心算法---The best time to buy and sell store-ii
Say you have an array for which the i th element is the price of a given stock on day i. Design an a ...