浅谈Redis(超详细讲解)
🙈作者简介:练习时长两年半的Java up主
🙉个人主页:老茶icon
🙊 ps:点赞👍是免费的,却可以让写博客的作者开兴好久好久😎
📚系列专栏:Java全栈,计算机系列(火速更新中)
💭 格言:种一棵树最好的时间是十年前,其次是现在
🏡动动小手,点个关注不迷路,感谢宝子们一键三连
目录
- 课程名:Redis
-
- 内容/作用:知识点/设计/实验/作业/练习
- 学习:redis基础知识
- Redis
课程名:Redis
内容/作用:知识点/设计/实验/作业/练习
学习:redis基础知识
Redis
常见面试题
15、 Redis 是什么?都有哪些使用场景?
16、 Redis 有哪些功能?
17、Redis 支持的数据类型有哪些?
18、 怎么保证缓存和数据库数据的一致性?
19、 Redis 如何做内存优化?
20、Redis 常见的性能问题有哪些?该如何解决?
Redis视频教程:
参考连接:黑马程序员Redis入门到实战教程,深度透析redis底层原理+redis分布式锁+企业解决方案+黑马点评实战项目_哔哩哔哩_bilibili
Redis资料:
链接:https://pan.baidu.com/s/1KWArCcseJv7xq47RC6a9lg
提取码:xHk9
复制这段内容打开「百度网盘APP 即可获取」
Redis是什么
参考文章:https://www.cnblogs.com/powertoolsteam/p/redis.html
Redis是现在最受欢迎的NoSQL数据库之一,Redis是一个使用ANSI C编写的开源、包含多种数据结构、支持网络、基于内存、可选持久性的键值对存储数据库,其具备如下特性:
- 基于内存运行,性能高效– Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 支持分布式,理论上可以无限扩展
- key-value存储系统
- 开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API
相比于其他数据库类型,Redis具备的特点是:
- C/S通讯模型
- 单进程单线程模型
- 丰富的数据类型
- 操作具有原子性
- 持久化
- 高并发读写
- 支持lua脚本
哪些大厂在使用Redis?
-
github
-
twitter
-
微博
-
Stack Overflow
-
阿里巴巴
-
百度
-
美团
-
搜狐
参考文章:https://github.com/Zeb-D/my-review
背景
在面试的时候,常被问比较下Redis与Memcache的优缺点,个人觉得这二者并不适合一起比较,一个是非关系型数据库不仅可以做缓存还能干其它事情,一个是仅用做缓存。常常让我们对这二者进行比较,主要也是由于Redis最广泛的应用场景就是Cache。那么Redis到底能干什么?又不能干什么呢?
Redis能做什么
-
缓存,毫无疑问这是Redis当今最为人熟知的使用场景。再提升服务器性能方面非常有效;
-
排行榜,如果使用传统的关系型数据库来做这个事儿,非常的麻烦,而利用Redis的SortSet数据结构能够非常方便搞定;
-
计算器/限速器,利用Redis中原子性的自增操作,我们可以统计类似用户点赞数、用户访问数等,这类操作如果用MySQL,频繁的读写会带来相当大的压力;限速器比较典型的使用场景是限制某个用户访问某个API的频率,常用的有抢购时,防止用户疯狂点击带来不必要的压力;
注:限速器也是对请求限流的一种实现方式。
-
好友关系,利用集合的一些命令,比如求交集、并集、差集等。可以方便搞定一些共同好友、共同爱好之类的功能;
-
简单消息队列,除了Redis自身的发布/订阅模式,我们也可以利用List来实现一个队列机制,比如:到货通知、邮件发送之类的需求,不需要高可靠,但是会带来非常大的DB压力,完全可以用List来完成异步解耦;
-
Session共享,默认Session是保存在服务器的文件中,即当前服务器,如果是集群服务,同一个用户过来可能落在不同机器上,这就会导致用户频繁登陆;采用Redis保存Session后,无论用户落在那台机器上都能够获取到对应的Session信息。
注:对于基于Redis实现分布式session 笔者会在以后文章接入说明
Redis不能做什么
Redis感觉能干的事情特别多,但它不是万能的,合适的地方用它事半功倍。如果滥用可能导致系统的不稳定、成本增高等问题。
比如,用Redis去保存用户的基本信息,虽然它能够支持持久化,但是它的持久化方案并不能保证数据绝对的落地,并且还可能带来Redis性能下降,因为持久化太过频繁会增大Redis服务的压力。
简单总结就是数据量太大、数据访问频率非常低的业务都不适合使用Redis。
数据太大会增加成本,访问频率太低,保存在内存中纯属浪费资源。如果不担心浪费资源,那请忽略。
Redis为什么能做这些
上面说了Redis的一些使用场景,那么这些场景的解决方案也有很多其它选择,比如缓存可以用Memcache,Session共享还能用MySql来实现,消息队列可以用RabbitMQ,我们为什么一定要用Redis呢?
那是因为Redis执行速度快:
-
速度快,完全基于内存;
-
使用C语言实现,网络层使用epoll解决高并发问题;
-
单线程模型避免了不必要的上下文切换及竞争条件;
注意:单线程仅仅是说在网络请求这一模块上用一个请求处理客户端的请求,像持久化它就会重开一个线程/进程去进行处理
丰富的数据类型:
Redis有8种数据类型,当然常用的主要是 String、Hash、List、Set、 SortSet 这5种类型(还有Bitmaps-位图、HyperLogLog、GEO-地理信息定位),他们都是基于键值的方式组织数据。每一种数据类型提供了非常丰富的操作命令,可以满足绝大部分需求,如果有特殊需求还能自己通过 lua 脚本自己创建新的命令(具备原子性);
除了提供的丰富的数据类型,Redis还提供了像慢查询分析、性能测试、Pipeline、事务、Lua自定义命令、Bitmaps、HyperLogLog、发布/订阅、Geo等个性化功能。
Redis的代码开源在GitHub,代码非常简单优雅,任何人都能够吃透它的源码;它的编译安装也是非常的简单,没有任何的系统依赖;有非常活跃的社区,各种客户端的语言支持也是非常完善。另外它还支持事务(没用过)、持久化、主从复制让高可用、分布式成为可能。
做为一个开发者,对于我们使用的东西不能让它成为一个黑盒子,我们应该深入进去,对它更了解、更熟悉。
总结Redis特性
-
速度快
数据存放在内存中;单线程模式,避免了线程上下文切换及多线程竞争访问;c语言实现,更容易接近系统api;采用epoll非阻塞IO,不在网络上浪费时间; -
支持多种数据类型
支持8种数据类型:String、Hash、List、Set、 SortSet、Bitmaps、HyperLogLog、GEO; -
功能丰富
丰富的API,如可设置键过期,存在即设置(这可以用来解决分布式锁问题),基于发布订阅可实现简单的消息队列,通过Lua创建新命令,具有原子性,管道(pipeline)功能,解决网络开销; -
服务器简单
开源代码优雅,容易阅读源码,采用单线程模型,避免并发问题,redis自己实现了多路复用; -
客户端语言版本多
如Java、Php、Go -
支持多种持久化方式
RDB和AOP,这两种持久化深入分析请看:https://blog.csdn.net/u014229282/article/details/81121214 -
支持集群部署
支持主从复制,高可用集群,内部集群方式与Memcache做集群实现不一样的机制。
Redis的应用场景有哪些?
Redis 的应用场景包括:缓存系统(“热点”数据:高频读、低频写)、计数器、消息队列系统、排行榜、社交网络和实时系统。
Redis的数据类型及主要特性
Redis提供的数据类型主要分为5种自有类型和一种自定义类型,这5种自有类型包括:String类型、哈希类型、列表类型、集合类型和顺序集合类型。
String类型:
它是一个二进制安全的字符串,意味着它不仅能够存储字符串、还能存储图片、视频等多种类型, 最大长度支持512M。
对每种数据类型,Redis都提供了丰富的操作命令,如:
- GET/MGET
- SET/SETEX/MSET/MSETNX
- INCR/DECR
- GETSET
- DEL
哈希类型:
该类型是由field和关联的value组成的map。其中,field和value都是字符串类型的。
Hash的操作命令如下:
- HGET/HMGET/HGETALL
- HSET/HMSET/HSETNX
- HEXISTS/HLEN
- HKEYS/HDEL
- HVALS
列表类型:
该类型是一个插入顺序排序的字符串元素集合, 基于双链表实现。
List的操作命令如下:
- LPUSH/LPUSHX/LPOP/RPUSH/RPUSHX/RPOP/LINSERT/LSET
- LINDEX/LRANGE
- LLEN/LTRIM
集合类型:
Set类型是一种无顺序集合, 它和List类型最大的区别是:集合中的元素没有顺序, 且元素是唯一的。
Set类型的底层是通过哈希表实现的,其操作命令为:
- SADD/SPOP/SMOVE/SCARD
- SINTER/SDIFF/SDIFFSTORE/SUNION
Set类型主要应用于:在某些场景,如社交场景中,通过交集、并集和差集运算,通过Set类型可以非常方便地查找共同好友、共同关注和共同偏好等社交关系。
顺序集合类型:
ZSet是一种有序集合类型,每个元素都会关联一个double类型的分数权值,通过这个权值来为集合中的成员进行从小到大的排序。与Set类型一样,其底层也是通过哈希表实现的。
ZSet命令:
- ZADD/ZPOP/ZMOVE/ZCARD/ZCOUNT
- ZINTER/ZDIFF/ZDIFFSTORE/ZUNION
怎么保证缓存和数据库数据的一致性?
参考文章:https://blog.csdn.net/zhizhengguan/article/details/122972503
为什么要保证缓存和数据库的数据一致
如果数据不一致,那么业务应用从缓存中读取的数据就不是最新的数据,这会导致严重的错误
这里的“数据一致性”是什么意思?
首先,我们必须知道这里的“数据一致性”是什么意思。这里“一致性”包括两种情况:
- 缓存中有数据,那么,缓存的数据需要和数据库中的值相同
- 缓存中本身没有数据,那么,数据库中的值就必须是最新值。
不符合这两种情况的,就是缓存和数据库的数据不一致了。
为什么会发生缓存和数据库的数据不一致
当缓存的读写模式不同时,缓存数据不一致发生的情况不一样。
当redis作为读写缓存时
对于读写缓存来说,如果要对数据进行增删改,就需要在缓存中进行,同时还要根据采取的写回策略,决定是否同步写回到数据库中。
- 同步直写策略:写缓存时,也同步写数据库,缓存和数据库中的数据一致
- 异步写回策略:写缓存时不同步写数据库,等到数据从缓存中淘汰时,再写回数据库。使用这种策略时,如果数据还没有写回数据库,缓存就发生了故障。那么,此时,数据库就没有最新数据了
所以,对于读写缓存来说,要想保证缓存和数据库中的数据一致,就要采用同步直写策略。不过,需要注意的是:如果采用这种策略,就需要保证同时更新缓存和数据库。所以,我们要在业务应用中使用事务机制,来保证缓存和数据库的更新具有原子性,也就是说,两者要不一起更新,要不都不更新,返回错误信息,进行重试。否则,我们就无法实现同步直接。
当然,在有些场景下,我们对数据一致性的要求可能不是那么高,那么,我们可以使用异步写回策略。
Redis 如何做内存优化
- 缩减键值对象:满足业务要求下 key 越短越好;value 值进行适当压缩
- 共享对象池:即 Redis 内部维护[0-9999]的整数对象池,开发中在满足需求的前提下,尽量使用整数对象以节省内存
- 尽可能使用散列表(hashes)
- 编码优化,控制编码类型
- 控制 key 的数量
参考文章:https://blog.csdn.net/smartbetter/article/details/97971151
Redis 常见的性能问题有哪些?该如何解决
1.master写内存快照,seve命令调度rdbsave函数,会阻塞主线程的工程,当快照比较大的时候对性能的影响是非常大的,会间断性暂停服务 。所以master最好不要写内存快照。
2.master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响master重启时的恢复速度。master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个slave开启AOF备份数据,策略每秒为同步一次。
3.master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂的服务暂停现象。
4.redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,slave和master最好在同一个局域网内。
Redis常见问题解析:击穿
概念:在Redis获取某一key时, 由于key不存在, 而必须向DB发起一次请求的行为, 称为“Redis击穿”。
引发击穿的原因:
- 第一次访问
- 恶意访问不存在的key
- Key过期
合理的规避方案:
- 服务器启动时, 提前写入
- 规范key的命名, 通过中间件拦截
- 对某些高频访问的Key,设置合理的TTL或永不过期
Redis常见问题解析:雪崩
概念:Redis缓存层由于某种原因宕机后,所有的请求会涌向存储层,短时间内的高并发请求可能会导致存储层挂机,称之为“Redis雪崩”。
合理的规避方案:
- 使用Redis集群
- 限流
往期专栏 |
---|
Java全栈开发 |
数据结构与算法 |
计算机组成原理 |
操作系统 |
数据库系统 |
物联网控制原理与技术 |