深入理解redis
redis
常见非关系型数据库分类
NoSQL具有扩展简单、高并发、高稳定性、成本低廉等优势,也存在一些问题
- Column-Oriented(烈士存储)
面向检索的列式存储,其存储结构为列式结构,同于关系型数据库的行式结构,这种结构会让很多统计聚合操作更简单方便,使系统具有较高的可扩展性。
代表作:HBase(适用于云计算)
2. Key-Value(键值)
面向高性能并发读/写的缓存存储,其结构类似于数据结构中的Hash表,每个Key分别对应一个Value,能够提供非常快的查询速度、大数据存放量和高并发操作,非常适合通过主键对数据进行查询和修改等操作
代表作:Redis(适用于分布式缓存)
3. Document-Oriented(文档型)
面向海量数据访问的文档存储,这类存储的结构与Key-Value非常相似,也是每个Key分别对应一个Value,但是这个Value主要以JSON(JavaScriptObjectNotations)或者XML等格式的文档来进行存储
代表作:MongoDB
4. Graph(图形)
图形结构的数据库通其他行列以及刚性结构的SQL数据库不同.它是使用灵活的图形模型.并且能拓展到多个服务器上
代表作:Neo4j
redis优缺点
redis通常做分布式缓存,直接操作内存,读写速率很快,差不多10w/s读取速率
优点:
对数据高并发读写(直接是内存中进行读写的)
redis是操作内存的,对海量数据的高效率存储和访问
对数据的可拓展性和高可用性.
redis是单线程的,不存在资源切换与系统抢夺
使用IO多路复用
缺点:
redis(ACID处理非常简单)
无法做太复杂的关系数据库模型
redis集群三大特征
-
拓展性
水平拓展:在平行的基础上我们增加主的服务器,或者从的服务器.
垂直拓展:直接在主的服务器中加内存或者加硬盘. -
高可用
高可用就是我们会有多台主服务器,如果一台主服务器挂了,它下面的从服务器会自动挂载到新的主服务器中.
三种形式:
1. 主从形式:只有一台机器是主节点,有多台机器是从节点.如果主节点挂了,应用就挂.
2. 哨兵形式(Redis2.x版本):在主从模式下(单主多从),会有一台机器充当哨兵的角色.它去监控其他机器的状态.当.会在从节点之间进行选举,看那台机器性能比较好,比较高.然后把指定的一台从节点升级为主节点.实现高可用.下次主节点修复好了,会自动加入进来变成从节点.
3. 集群模式(Redis3.0之后):可以拥有多主多从,如果其中一台主节点挂了,会选举下面的从节点为主节点,可以做哨兵的这个事情
- 数据可靠性
redis操作数据其实是操作内存中的数据,但是它还是会基于一定的策略把数据持久化到数据库。做持久化目的:在服务器断电之后重新启动,数据还能恢复
Redis做持久化主要两种方式:
-
RDB:
- 可以周期性的同步内存中的数据到所在的机器的硬盘上.
- RDB核心配置(redis.conf中配置)
save <seconds> <changes> # save "" save 900 1 save 300 10 save 60 10000
- 可以大致理解为:如果每60秒超过10000的key写入或者每900s超过1的key写入…,此时就会向数据库发起快照进行数据持久化
- 特点:适合大规模的数据恢复,性能高,数据的完整性和一致性不高
-
AOF:
-
会把里面的DML操作写到一个日志里,实时记录.断电之后可以从日志里面知道你之前做了什么操作了.
-
Redis 默认不开启AOF,需要在redis.conf中配置。它的出现是为了弥补RDB的不足(数据的不一致性),所以它采用日志的形式来记录每个写操作,并追加到文件中。Redis 重启的会根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
-
更新日志的三个条件:
设置redis.conf文件appendonly yes,这样就可以使用aof了
appendfsync always:同步持久化,每次发生数据变化会立刻写入到磁盘中。性能较差当数据完整性比较好(慢,安全)
appendfsync everysec:出厂默认推荐,每秒异步记录一次(默认值)
appendfsync no:不同步 -
特点:数据的完整性和一致性更高,同时AOF记录的内容多,文件会越来越大,数据恢复也会越来越慢。
-
-
两种方式对比
- Redis 默认开启RDB持久化方式,在指定的时间间隔内,执行指定次数的写操作,则将内存中的数据写入到磁盘中。
- RDB 持久化适合大规模的数据恢复但它的数据一致性和完整性较差。
- Redis 需要手动开启AOF持久化方式,默认是每秒将写操作日志追加到AOF文件中。
- AOF 的数据完整性比RDB高,但记录内容多了,会影响数据恢复的效率。
- Redis 针对 AOF文件大的问题,提供重写的瘦身机制。
- 若只打算用Redis 做缓存,可以关闭持久化。
- 若打算使用Redis 的持久化。建议RDB和AOF都开启。其实RDB更适合做数据的备份,留一后手。AOF出问题了,还有RDB。
redis应用场景
-
缓存功能:字符串最经典的使用场景,redis最为缓存层,Mysql作为储存层,绝大部分请求数据都是
redis中获取,由于redis具有支撑高并发特性,所以缓存通常能起到加速读写和降低 后端压力的作用。 -
计数器:许多运用都会使用redis作为计数的基础工具,他可以实现快速计数、查询缓存的功能,
同时数据可以异步落地到其他的数据源。
如:视频播放数系统就是使用redis作为视频播放数计数的基础组件。 -
共享session:出于负载均衡的考虑,分布式服务会将用户信息的访问均衡到不同服务器上,
用户刷新一次访问可能会需要重新登录,为避免这个问题可以用redis将用户session集中管理,
在这种模式下只要保证redis的高可用和扩展性的,每次获取用户更新或查询登录信息
都直接从redis中集中获取。 -
限速:处于安全考虑,每次进行登录时让用户输入手机验证码,为了短信接口不被频繁访问,
会限制用户每分钟获取验证码的频率。
redis五种数据类型
Redis中存储方式为键值对存储,其中键只能为字符串/二进制数据;value的类型就是以下五种数据类型(如果想存储对象,则对象需要实现序列化,本质上是存对象对应的二进制数据)
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)
-
String
-
解释
String类型包含多种类型的特殊类型,并且是二进制安全的.比如序列化的对象进行存储,比如一张图片进行二进制存储.,比如一个简单的字符串,数值等等. -
应用场景
a. 缓存功能:字符串最经典的使用场景,redis最为缓存层,Mysql作为储存层,绝大部分请求数据都是
redis中获取,由于redis具有支撑高并发特性,所以缓存通常能起到加速读写和降低 后端压力的作用。
b. 计数器:许多运用都会使用redis作为计数的基础工具,他可以实现快速计数、查询缓存的功能,
同时数据可以异步落地到其他的数据源。
如:视频播放数系统就是使用redis作为视频播放数计数的基础组件。
c. 共享session:出于负载均衡的考虑,分布式服务会将用户信息的访问均衡到不同服务器上,
用户刷新一次访问可能会需要重新登录,为避免这个问题可以用redis将用户session集中管理,
在这种模式下只要保证redis的高可用和扩展性的,每次获取用户更新或查询登录信息
都直接从redis中集中获取。具体实现:redis+token,redis+cookie,redis+shiro 此时session已不复存在,服务器生成uuid做token,redis中存储比如 username:$uuid,然后将该token相应给客户端,客户端每次登陆携带自己对应的token,登陆信息存在redis中,这样不同服务器访问到的登录对象信息是一致的
d. 限速:处于安全考虑,每次进行登录时让用户输入手机验证码,为了短信接口不被频繁访问,
会限制用户每分钟获取验证码的频率。
-
-
Hash
- 解释
Hash类型是String类型的field和value的映射表.或者说是一个String集合.它特别适合存储对象,相比较而言,讲一个对象存储在Hash类型里要比存储在String类型里占用更少的内存空间,并方便存储整个对象 - 应用场景
哈希结构相对于字符串序列化缓存信息更加直观,并且在更新操作上更加便捷。所以常常用于用户信息等管理,但是哈希类型和关系型数据库有所不同,哈希类型是稀疏的,而关系型数据库是完全结构化的,关系型数据库可以做复杂的关系查询,而redis去模拟关系型复杂查询开发困难,维护成本高
- 解释
-
List
- 解释
Redis中的List类似Java中的queue,也可以当做List来用。List类型是一个链表结构的集合,其主要功能有push,pop,获取元素等.更详细的说,List类型是一个双端链表的结构,我们可以通过相关操作进行集合的头部或者尾部添加删除元素,list的设计非常简单精巧,即可以作为栈,又可以作为队列.满足绝大多数需求。 - 应用场景
a. 消息队列: redis的lpush+brpop命令组合即可实现阻塞队列,生产者客户端是用lupsh从列表左侧插入元素,多个消费者客户端使用brpop命令阻塞时的“抢”列表尾部的元素,多个客户端保证了消费的负载均衡和高可用性.
b. 文章列表:每个用户都有属于自己的文章列表,现在需要分页展示文章列表,此时可以考虑使用列表,列表不但有序,同时支持按照索引范围获取元素。
c. 朋友圈点赞;
规定:朋友圈内容的格式:
1,内容: user❌post:x content来存储;
2,点赞: post❌good list来存储;
1,创建一条朋友圈内容:set user:1:post:91 ‘hello redis’;
2,点赞:
lpush post:91:good ‘{id:1,name:stef,img:xxx.jpg}’
lpush post:91:good ‘{id:2,name:lanxw,img:xxx.jpg}’
lpush post:91:good ‘{id:3,name:fly,img:xxx.jpg}’
3,查看有多少人点赞: llen post:91:good
4,查看哪些人点赞:lrange post:91:good 0 -1
思考,如果用数据库实现这个功能,SQL会多复杂??
d. 回帖
1,创建一个帖子:set user:1:post:90 ‘wohenshuai’
2,创建一个回帖:set postreply:1 ‘nonono’
3,把回帖和帖子关联:lpush post:90:replies 1
4,再来一条回帖:set postreply:2 ‘hehe’
lpush post:90:replies 2
5,查询帖子的回帖:lrange post:90:replies 0 -1
get postreply:2
- 解释
-
Set
-
解释
Set集合是string类型的无序集合,set是通过hashtable实现的,对集合我们可以取交集,并集,差集. -
应用场景
a,去重,因为set是不可重复的;
b,抽奖;
1,准备一个抽奖池:sadd luckydraw 1 2 3 4 5 6 7 8 9 10 11 12 13
2,抽3个三等奖:spop luckydraw 3
3,抽2个二等奖:spop luckydraw 2
4,抽1个二等奖:spop luckydraw 1c,做set运算(好友推荐)
1,初始化好友圈 sadd user:1:friends ‘user:2’ ‘user:3’ ‘user:5’
sadd user:2:friends ‘user:1’ ‘user:3’ ‘user:6’
sadd user:3:friends ‘user:1’ ‘user:7’ ‘user:8’
2,把user:1的好友的好友集合做并集;
user:1 user:3 user:6 user:7 user:8
3,让这个并集和user:1的好友集合做差集;
user:1 user:6 user:7 user:8
4,从差集中去掉自己
user:6 user:7 user:8
5,随机选取推荐好友
-
-
ZSet(有序集合)
- 解释
zadd 向有序集合中添加一个元素,该元素如果存在,则更新顺序.在重复插入的时候,会根据顺序属性更新. - 应用场景
排行榜:有序集合经典使用场景。例如视频网站需要对用户上传的视频做排行榜,榜单维护可能是多方面。可能会按照时间、按照播放量、按照获得的赞数等。
- 解释
redis事务(弱事务,只能一起成功,不能一起失败)
Redis的事务非常简单,使用方法如下:
首先是使用multi方法打开事务,然后进行设置,这时设置的数据会放到队列里进行保存.最后使用exec执行.把数据依次存储到redis中.使用discard方法取消事务.
redis订阅与发布
-
Redis提供了发布订阅功能,可以用于消息的传输,Redis的发布订阅机制包括三个部分,发布者,订阅者和Channel
-
发布者和订阅者都是Redis客户端,Channel则为Redis服务器端,发布者将消息发送到某个的频道,订阅了这个频道的订阅者就能接收到这条消息
-
使用subscribe [频道] 进行订阅监听,使用publish [频道] [发布内容进行发布消息广播]
redis主从复制
-
主从复制是redis2.0支持的功能,redis3.0出了集群模式,二者有区别。
-
主从复制是为了实现读写分离,特点是只用一个主节点,可以拥有多个从节点。写操作必须都得通过主节点写入,读取可以从主节点或者从节点读取数据(相当于减轻了主节点读的压力,写的压力还是集中在主节点上)。同时主从复制不会阻塞master,同步数据时master可以继续处理client请求。短时间内写入大量数据仍旧会造成主节点压力大
-
主从复制过程
- slave与master建立连接,发送sync同步命令
- Master会开启一个后台进程,将数据库快照保存到文件中.同时master主进程会收集新的写命令并缓存
- 后台完成保存后,就将文件发给slave
- Slave清空内存数据,根据接收的快照文件,重建内存表数据结构
slave server如果因为网络或其他原因断与master server的连接,当slave server重新连接时,需要重新获取master server的内存快照文件,slave server的数据会自动全部清空,然后再重新建立内存表,这样会让slave server 启动恢复服务比较慢,同时也给master server带来较大压力。不过2.8后就支持增量复制
redis集群
一个集群其实就是多个主从共同构成
在使用集群时,数据会随即根据算法设置到某个主节点,不同主节点之间信息是不同步的,但是在它对应的那个主从中,他们的信息是同步的。那也就得出一个推论,获取数据时它会从有那条数据的主从中去获取数据。在某个主从中,如果主节点挂掉,集群会把这个主从
-
3.0之后的功能,至少需要3(Master)+3(Slave)才能建立集群,是无中心的分布式存储架构,可以在多个节点之间进行数据共享,解决了Redis高可用、可扩展等问题。
-
特点
- 将数据自动切分(split)到多个节点
- 当集群中的某一个节点故障时,redis还可以继续处理客户端的请求。
- 集群中的每个节点都有1个至N个复制品,其中一个为主节点,其余的为从节点,如果主节点下线了,集群就会把这个主节点的一个从节点设置为新的主节点,继续工作。这样集群就不会因为一个主节点的下线而无法正常工作
- 如果某一个主节点和他所有的从节点都下线的话,redis集群就会停止工作了。redis集群不保证数据的强一致性,在特定的情况下,redis集群会丢失已经被执行过的写命令
- 使用异步复制(asynchronous replication)是redis 集群可能会丢失写命令的其中一个原因,有时候由于网络原因,如果网络断开时间太长,redis集群就会启用新的主节点,之前发给主节点的数据就会丢失。