Redis 缓存中间件
Redis 缓存中间件
- 为什么需要缓存中间件?
- Redis 简介
- 特性
- 单线程
- Redis存储机制
- Snapshot 工作原理
- AOF 工作原理
- 存储模式性能和安全
- 数据结构及使用场景
- 技术总结
- REFERENCES
手机用户请
横屏
获取最佳阅读体验,REFERENCES
中是本文参考的链接,如需要链接和更多资源,可以关注公众号后回复『知识星球』加入并获取长期知识分享服务。
为什么需要缓存中间件?
一个网站演变的过程中,用户量的增加引起了并发量提高,如果不做处理,则频繁的查询数据库,结果是页面显示的慢,服务器、数据库不堪重负。如果网站页面所展示的数据的更新不是特别频繁,想提高页面显示的速度,减轻服务器的负担,此时应该考虑使用缓存。
所以,缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。
使用缓存有一个原则:越高层次的缓存效果越好。推荐使用页面缓存。
Redis 简介
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)和zset(有序集合)、Hash(哈希类型的映射表)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。
在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis 是一个高性能的key-value数据库。redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,Python,Ruby,Perl,PHP客户端,使用很方便。
特性
速度快
- 数据存在内存中
- C语言编写,5W 行代码
- 单线程数据模型
持久化
- 多种数据结构
- 支持多种编辑语言
- 功能丰富
- 主从复制(数据一致性)
高可用
- 哨兵模式
单线程
为什么这么快?
- 纯内存操作
- 非阻塞IO
- 避免线程切换和竞态消耗
如何使用?
- 拒绝长(慢)命令,如 keys、flushall。
- 一次只运行一个命令
Redis存储机制
Redis存储机制分成两种 Snapshot和 AOF。无论是哪种机制,Redis都是将数据存储在内存中。
Snapshot 工作原理
是将数据先存储在内存,然后当数据累计达到某些设定的伐值的时候,就会触发一次DUMP操作,将变化的数据一次性写入数据文件(RDB文件)。
AOF 工作原理
是将数据也是先存在内存,但是在存储的时候会使用调用 fsync 来完成对本次写操作的日志记录,这个日志揭露文件其实是一个基于 Redis 网络交互协议的文本文件。AOF 调用 fsync 也不是说全部都是无阻塞的,在某些系统上可能出现 fsync 阻塞进程的情况,对于这种情况可以通过配置修改,但默认情况不要修改。
- AOF 最关键的配置就是关于调用 fsync 追加日志文件的频率,有两种预设频率,always 每次记录进来都添加,everysecond 每秒添加一次。两个配置各有所长。
- 由于是采用日志追加的方式来持久化数据,所以引出了第二个日志的概念:rewrite。
存储模式性能和安全
性能
Snapshot 方式的性能是要明显高于 AOF 方式的,原因有两点:
- 采用2进制方式存储数据,数据文件比较小,加载快速。
- 存储的时候是按照配置中的 save 策略来存储,每次都是聚合很多数据批量存储,写入的效率很好。
而 AOF 则一般都是工作在实时存储或者准实时模式下。相对来说存储的频率高,效率却偏低。
数据安全
AOF 数据安全性高于 Snapshot 存储,原因:
Snapshot 存储是基于累计批量的思想,也就是说在允许的情况下,累计的数据越多那么写入效率也就越高,但数据的累计是靠时间的积累完成的,那么如果在长时间数据不写入 RDB,但 Redis 又遇到了崩溃,那么没有写入的数据就无法恢复了,但是 AOF 方式偏偏相反,根据 AOF 配置的存储频率的策略可以做到最少的数据丢失和较高的数据恢复能力。说完了性能和安全,这里不得不提的就是在 Redis 中的 Rewrite 的功能,AOF 的存储是按照记录日志的方式去工作的,那么成千上万的数据插入必然导致日志文件的扩大,Redis这个时候会根据配置合理触发Rewrite操作,所谓 Rewrite 就是将日志文件中的所有数据都重新写到另外一个新的日志文件中,但是不同的是,对于老日志文件中对于Key的多次操作,只保留最终的值的那次操作记录到日志文件中,从而缩小日志文件的大小。这里有两个配置需要注意:
auto-aof-rewrite-percentage 100
(当前写入日志文件的大小占到初始日志文件大小的某个百分比时触发Rewrite)auto-aof-rewrite-min-size 64mb
(本次Rewrite最小的写入数据)
两个条件需要同时满足。
数据结构及使用场景
数据结构
存储
存储
String 字符串
缓存、计数器、分布式锁、分布式ID
计数
Hash 哈希
Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。 Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)。
- 存储用户信息
- 存储用户主页访问量
用户信息存储
K-V 存储
命令及描述 |
---|
HDEL key field1 field2 删除一个或多个哈希表字段 |
HEXISTS key field 查看哈希表 key 中,指定的字段是否存在。 |
HGET key field 获取存储在哈希表中指定字段的值。 |
HGETALL key 获取在哈希表中指定 key 的所有字段和值 |
HINCRBY key field increment 为哈希表 key 中的指定字段的整数值加上增量 increment 。 |
HINCRBYFLOAT key field increment 为哈希表 key 中的指定字段的浮点数值加上增量 increment 。 |
HKEYS key 获取所有哈希表中的字段 |
HLEN key 获取哈希表中字段的数量 |
HMGET key field1 field2 获取所有给定字段的值 |
HMSET key field1 value1 field2 value2 同时将多个 field-value (域-值)对设置到哈希表 key 中。 |
HSET key field value 将哈希表 key 中的字段 field 的值设为 value 。 |
HSETNX key field value 只有在字段 field 不存在时,设置哈希表字段的值。 |
HVALS key 获取哈希表中所有值。 |
[HSCAN key cursor MATCH pattern] [COUNT count] 迭代哈希表中的键值对。 |
List 列表
List 类型是用来存储多个有序的字符串的,列表当中的每一个字符看做一个元素,一个列表当中可以存储有一个或者多个元素,redis 的 List 支持存储
2^32 -1
个元素。
- redis 可以从列表的两端进行插入(push)和弹出(pop)元素
- 支持读取指定范围的元素集,或者读取指定下标的元素等操作。
redis 列表是一种比较灵活的链表数据结构,它可以充当队列或者栈的角色。
- 消息队列:reids 的链表结构,可以轻松实现阻塞队列,可以使用左进右出的命令组成来完成队列的设计。比如:数据的生产者可以通过 lpush 命令从左边插入数据,多个数据消费者,可以使用 brpop 命令阻塞的“抢”列表尾部的数据。
- 文章列表或者数据分页展示的应用:比如,我们常用的博客网站的文章列表,当用户量越来越多时,而且每一个用户都有自己的文章列表,而且当文章多时,都需要分页展示,这时可以考虑使用redis的列表,列表不但有序同时还支持按照范围内获取元素,可以完美解决分页查询功能。大大提高查询效率。
命令及描述 |
---|
BLPOP key1 key2 timeout 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
BRPOP key1 key2 timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
BRPOPLPUSH source destination timeout 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它;如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
LINDEX key index 通过索引获取列表中的元素 |
LINSERT key BEFORE|AFTER pivot value 在列表的元素前或者后插入元素 |
LLEN key 获取列表长度 |
LPOP key 移出并获取列表的第一个元素 |
LPUSH key value1 value2 将一个或多个值插入到列表头部 |
LPUSHX key value 将一个值插入到已存在的列表头部 |
LRANGE key start stop 获取列表指定范围内的元素 |
LREM key count value 移除列表元素 |
LSET key index value 通过索引设置列表元素的值 |
LTRIM key start stop 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。 |
RPOP key 移除列表的最后一个元素,返回值为移除的元素。 |
RPOPLPUSH source destination 移除列表的最后一个元素,并将该元素添加到另一个列表并返回 |
RPUSH key value1 value2 在列表中添加一个或多个值 |
RPUSHX key value 为已存在的列表添加值 |
Set 集合
集合类型的数据结构,那么集合类型就比较适合用于聚合分类。 redis 集合(Set)类型和 List 列表类型类似,都可以用来存储多个字符串元素的集合。但是和 List 不同的是 Set 集合当中不允许重复的元素。而且 Set 集合当中元素是
没有顺序的,不存在元素下标
。 redis 的 Set 类型是使用哈希表构造的,因此复杂度是O(1),它支持集合内的增删改查,并且支持多个集合间的交集、并集、差集操作。可以利用这些集合操作,解决程序开发过程当中很多数据集合间的问题。
- 标签:比如我们博客网站常常使用到的兴趣标签,把一个个有着相同爱好,关注类似内容的用户利用一个标签把他们进行归并。
- 共同好友功能,共同喜好,或者可以引申到二度好友之类的扩展应用。
- 统计网站的独立IP。利用set集合当中元素不唯一性,可以快速实时统计访问网站的独立IP。
命令及描述 |
---|
SADD key member1 member2 向集合添加一个或多个成员 |
SCARD key 获取集合的成员数 |
SDIFF key1 key2 返回第一个集合与其他集合之间的差异。 |
SDIFFSTORE destination key1 key2 返回给定所有集合的差集并存储在 destination 中 |
SINTER key1 key2 返回给定所有集合的交集 |
SINTERSTORE destination key1 key2 返回给定所有集合的交集并存储在 destination 中 |
SISMEMBER key member 判断 member 元素是否是集合 key 的成员 |
SMEMBERS key 返回集合中的所有成员 |
SMOVE source destination member 将 member 元素从 source 集合移动到 destination 集合 |
SPOP key 移除并返回集合中的一个随机元素 |
SRANDMEMBER key count 返回集合中一个或多个随机数 |
SREM key member1 member2 移除集合中一个或多个成员 |
SUNION key1 key2 返回所有给定集合的并集 |
SUNIONSTORE destination key1 key2 所有给定集合的并集存储在 destination 集合中 |
[SSCAN key cursor MATCH pattern] [COUNT count] 迭代集合中的元素 |
ZSET 有序集合
redis 有序集合也是集合类型的一部分,所以它保留了集合中元素不能重复的特性,但是不同的是,有序集合给每个元素多设置了一个分数,利用该分数作为排序的依据。 有序集合可以利用分数进行从小到大的排序。虽然有序集合的成员是唯一的,但是分数(score)却可以重复。就比如在一个班中,学生的学号是唯一的,但是每科成绩却是可以一样的,redis 可以利用有序集合存储学生成绩快速做成绩排名功能。
有序集合的使用场景与集合类似,但是 set 集合不是自动有序的,而sorted set可以利用分数进行成员间的排序,而且是插入时就排序好。所以当你需要一个有序且不重复的集合列表时,就可以选择 sorted set 数据结构作为选择方案。
- 排行榜:有序集合经典使用场景。例如视频网站需要对用户上传的视频做排行榜,榜单维护可能是多方面:按照时间、按照播放量、按照获得的赞数等。
- 用 sorted set 来做带权重的队列,比如普通消息的 score 为 1,重要消息的 score为 2,然后工作线程可以选择按 score 的倒序来获取工作任务。让重要的任务优先执行。
命令及描述 |
---|
ZADD key score1 member1 score2 member2 向有序集合添加一个或多个成员,或者更新已存在成员的分数 |
ZCARD key 获取有序集合的成员数 |
ZCOUNT key min max 计算在有序集合中指定区间分数的成员数 |
ZINCRBY key increment member 有序集合中对指定成员的分数加上增量 increment |
ZINTERSTORE destination numkeys key key ... 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 destination 中 |
ZLEXCOUNT key min max 在有序集合中计算指定字典区间内成员数量 |
ZRANGE key start stop WITHSCORES 通过索引区间返回有序集合指定区间内的成员 |
ZRANGEBYLEX key min max LIMIT offset count 通过字典区间返回有序集合的成员 |
ZRANGEBYSCORE key min max WITHSCORES LIMIT 通过分数返回有序集合指定区间内的成员 |
ZRANK key member 返回有序集合中指定成员的索引 |
ZREM key member member ... 移除有序集合中的一个或多个成员 |
ZREMRANGEBYLEX key min max 移除有序集合中给定的字典区间的所有成员 |
ZREMRANGEBYRANK key start stop 移除有序集合中给定的排名区间的所有成员 |
ZREMRANGEBYSCORE key min max 移除有序集合中给定的分数区间的所有成员 |
ZREVRANGE key start stop WITHSCORES 返回有序集中指定区间内的成员,通过索引,分数从高到低 |
ZREVRANGEBYSCORE key max min WITHSCORES 返回有序集中指定分数区间内的成员,分数从高到低排序 |
ZREVRANK key member 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序 |
ZSCORE key member 返回有序集中,成员的分数值 |
ZUNIONSTORE destination numkeys key key ... 计算给定的一个或多个有序集的并集,并存储在新的 key 中 |
ZSCAN key cursor MATCH pattern COUNT count 迭代有序集合中的元素(包括元素成员和元素分值) |
技术总结
文本介绍了 Redis 的两种存储模式,AOF 和 Snapshot。简要分析他们的区别和应用场景后,介绍了常用的数据结构和对应支撑的场景。
REFERENCES
- redis 集合(set)类型的使用和应用场景
- redis有序集合(sorted set)详解和应用场景
相关文章
- 保护使用Redis数据库实现强大的密码保护(redis数据库密码)
- Redis版本发展历史及全部版本清单(redis版本列表)
- 分析处理Redis慢日志的技巧(redis慢日志)
- 缓存数据库:Redis优势深度剖析(redis如何缓存数据库)
- Redis 缓存系统:提高应用性能的必备工具(redis缓存系统)
- Redis:内存中的数据刷新不可或缺(redis 刷盘)
- 缓存如何清理Redis缓存(怎么清redis)
- 空虚无助Redis中的缓存空对象(缓存空对象 redis)
- 快速入门Redis缓存小白的视频教程(缓存redis视频教程)
- 探寻Redis运行状况一探究竟(查看redis 运行情况)
- Redis开启数据处理新时代(用redis可以做什么)
- 基于Redis计数器的接口限流技术(接口限流redis计数器)
- 速度极快为什么Redis性能优秀(为什么redis访问快)
- 的安装挑战无网环境,安装Redis的实践之旅(不联网情况下redis)
- Syslog日志分析与Redis缓存管理技术(syslog redis)
- 简单易用的分布式Redis缓存实现高性能(分布式redis缓存)
- 掌握Redis缓存查询及应用简易指南(怎么查redis缓存)
- 大数据技术与Redis的结合有何作用(大数据redis有用吗)
- 缓存利用多大型服务器实现高效Redis缓存(多大服务器做redis)
- 灵活的Redis饱和策略解决方案(redis 饱和策略)
- 深入浅出Redis 队列原理(redis队列原理简书)
- Redis 构建优化数据库缓存(redis配置数据库缓存)
- 调整Redis连接池大小,有效节省资源(redis 连接池大小)
- Redis实现自动切换优雅解决缓存瓶颈(redis设置自动切换)
- 解锁Redis破解条件竞争之谜(redis解决条件竞争)
- Redis实现多键值一次性获取(redis获取多键值)
- Redis缓存雪崩有多大威胁(redis缓存雪崩是什么)
- Redis如何有效能处理过期缓存(redis 过期效率)
- 实时更新Redis缓存,实现数据最佳化(redis缓存的更新)