Redis篇


1. NoSQL数据库简介

NoSQL(Not Only SQL),即“不仅仅是SQL”,泛指非关系型数据库。
特点:
(1)NoSQL不依赖于业务逻辑方式存储,而以简单的key-value模式存储,因此大大的增加了数据库的扩展能力。
(2)不遵循SQL标准
(3)不支持ACID
(4)远超于SQL的性能

NoSQL适用场景:
(1)对数据高并发的读写
(2)海量数据的读写
(3)对数据高可扩展的

NoSQL不适用的场景:
(1)需要事务支持
(2)基于sql的结构化查询存储,处理复杂的关系

常见的NoSQL数据库有如下几种:
Memcached数据库
(1)很早出现的NoSQL数据库
(2)数据在内存中,一般不持久化
(3)支持简单的key-value模式
(4)一般是作为缓存数据库辅助持久化的数据库

Redis数据库(Remote Dictionary Server, 远程字典服务器)
(1)几乎覆盖了Memcached的绝大部分功能
(2)数据在内存中,支持持久化,主要用作备份恢复
(3)除了支持简单的key-value模式,还支持多种数据结构的存储,比如list、set、hash、zset等。
(4)一般是作为缓存数据库辅助持久化的数据库
(5)是一款高性能的分布式数据库

mongoDB数据库
(1)高性能、开源、模式自由的文档型数据库
(2)数据都在内存中,如果内存不足,把不常用的数据保存到硬盘
(3)虽然是key-value模式,但是对value(尤其是json)提供了丰富的查询功能
(4)支持二进制数据及大型对象
(5)可以根据数据的特点代替RDBMS,称为独立的数据库。或者配合RDBMS,存储特定的数据。

2. Redis的介绍

(1)默认端口号:6379
(2)默认16个数据库,类似数组下标从0开始,初始默认使用0号库
(3)统一密码管理,所有库都是相同的密码
(4)Redis是单线程 + 多路 IO 复用技术
(5)Redis 是一个高性能的分布式数据库

为什么说 Redis 是高性能的?
(1)基于内存实现,完全内存计算;
(2)单线程操作,避免了线程上下文切换操作;
(3)多路 I/O 复用的线程模型,实现了一个线程监控多个IO流,及时响应请求;
(4)Redis 对外部的依赖比较少,属于轻量级内存数据库。

I/O多路复用技术是什么,为什么很快?
常见的IO模型有阻塞模型、非阻塞模型、IO多路复用,信号驱动IO,异步IO。

(1) 阻塞式IO: 使用系统调用,并一直阻塞直到内核将数据准备好,之后再由内核缓冲区复制到用户态,在等待内核准备的这段时间什么也干不了。
(2) 非阻塞式IO:内核在没有准备好数据的时候会返回错误码,而调用程序不会休眠,而是不断轮询询问内核数据是否准备好
(3) IO多路复用:类似非阻塞,只不过轮询不是由用户线程去执行,而是由内核去轮询,内核监听程序监听到数据准备好后,调用内核函数复制数据到用户空间
(4) 信号驱动IO: 应用进程使用 sigaction 系统调用,内核立即返回,应用进程可以继续执行,也就是说等待数据阶段应用进程是非阻塞的。
(5) 异步IO:应用进程执行 aio_read 系统调用会立即返回,应用进程可以继续执行,不会被阻塞,内核会在所有操作完成之后向应用进程发送信号。

3. Redis的五大数据类型

Redis中是以key-value的形式存储数据的,对于value,有五种数据类型:String、List、Set、Hash、ZSet。

3.1 String

(1)String 是Redis最基本的类型,可以理解成与Memcached一模一样的类型,一个key对应一个value
(2)String类型是二进制安全的,意味着Redis的String可以包含任何数据,比如 jpg 图片或者序列化的对象
(3)String类型是Redis 最基本的数据类型,一个Redis 中字符串 value 最多可以是 512M。
(4)可以用来做一些计数器(也是实际工作中最常见的)

注:Redis 单命令的原子性主要得益于 Redis 的单线程。

3.2 List

(1)单键多值
(2)Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边),添加数据的时候可以将其想象成一个“管道”。
(3)它的底层是双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。
(3)可以实现一个简单消息队列功能,做基于Redis的分页功能等

3.3 Set

(1)Redis Set 对外提供的功能与 List 类似是一个列表的功能,特殊之处在于 Set 是可以自动排重的。
(2)Redis 的 Set 是 String 类型的无序集合,它底层其实是一个 value 为 null 的 hash 表,所以添加、删除、查找的复杂度都是 O(1)。
(3)可以做用户标签

3.4 Hash

(1)Redis Hash 是一个键值对集合
(2)Redis Hash 是一个String 类型的 field 和 value 的映射表,Hash 特别适合于存储对象
(3)类似于Java 里面的 Map<String, Object>
(4)可以用来存放一些具有特定结构的信息。用于用户信息管理。

在这里插入图片描述

3.5 ZSet (sorted set)

(1)Redis 有序集合 ZSet 与普通集合 Set 非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的所有成员都关联了一个评分(score),这个 score 被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以重复。
(2)因为元素是有序的,所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的圆度。使用有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复元素的只能列表。
(3)可以用来做排行榜应用或者进行范围查找等。

4. Redis的Java客户端

Redis 的客户端是 Jedis。

5. Redis的事务

5.1 定义

Redis 事务是一个单独的隔离操作;事务中的所有命令都会序列化、按顺序执行。事务在执行的过程中,不会被其他客户端发送来的命令请求打断。
Redis 事务的主要作用就是串联多个命令防止别的命令插队。

5.2 MULTI、EXEC、DIACARD

从输入 MULTI 命令开始,输入的命令会依次进入到命令队列中,但不会执行,直到输入 EXEC 后,Redis 会将之前的命令队列中的命令依次执行。
组队的过程中可以通过 DISCARD 来放弃组队。

在这里插入图片描述

5.3 事务的错误处理

(1)组队中某个命令出现了报告错误,执行时整个的所有队列都会被取消。
(2)如果执行阶段某个命令报出了错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。

5.4 悲观锁和乐观锁

悲观锁(Pessimistic Lock):顾名思义,就是很悲观,每次去拿数据的时候都认为被人会修改,所以每次拿数据的时候都会上锁,这样被人想拿这个数据就会处于阻塞状态直到它拿到锁。传统的关系型数据库里面很多用到了悲观锁。 比如行锁、表锁、读锁、写锁等,都是在操作之前先上锁。

乐观锁(Optimistic Lock):顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会先判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis 就是利用这种 check-and-set 机制实现事务的。

5.5 Redis 事务的三大特性

(1)单独的隔离机制
事务中的所有命令都会序列化、按顺序执行。事务在执行的过程中,不会被其他客户端发来的请求所打断。
(2)没有隔离级别的概念
队列中的命令没有提交之前都不实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在 “事务内的查询要看到事务里的更新,在事务外查询不能看到” 这个问题。
(3)不保证原子性
Redis 同一事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。

6. Redis的持久化

持久化 是将程序数据在持久状态和瞬时状态间转换的机制。通俗的讲,就是瞬时数据(比如内存中的数据,是不能永久保存的)持久化为持久数据(比如持久化至数据库中,能够长久保存)。

Redis 提供了两个不同形式的持久化方式:
(1)RDB(Redis DataBase)
(2)AOF(Append Of File)

6.1 RDB

指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的 Snapshot 快照,它恢复时是将快照文件直接读到内存里。
在这里插入图片描述

备份是如何执行的?
Redis 会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主程序是不进行任何 IO 操作的,这就确保了极高的性能。如果需要进行大规模数量的恢复,且对于数据恢复的完整性不是非常敏感,那 RDB 方式要比 AOF 方式更加的高效。RDB 的缺点是最后一次持久化后的数据可能丢失。

注:关于fork
在Linux程序中,fork() 会产生一个和父进程完全相同的子进程,但是子进程在此后多会 exec 系统调用,处于效率的考虑,Linux 中引入了“写时复制技术”,一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。

RDB的优缺点:
优点:
(1)节省磁盘空间
(2)恢复速度快
缺点:
(1)虽然 Redis 在 fork 时使用了写时拷贝技术,但是如果数据庞大时还是会消耗性能。
(2)在一定的间隔时间做一次备份,如果 Redis 意外down掉的话,就会丢失最后一次快照后的所有修改。

6.2 AOF

以日志的形式来记录每个写操作。 将 Redis 执行过的所有写指令记录下来(读操作不记录),只许追加文件但是可以改写文件,Redis 启动之初会读取该文件重新构建数据,换言之,Redis 重启的话就根据日志文件的内容将写指令从前往后执行一次以完成数据的恢复工作。

在这里插入图片描述

注:当 AOF 和 RDB 同时开启的时候,系统默认读取 AOF 的数据。

AOF 文件故障备份:
AOF 的备份机制和性能虽然和 RDB 不同,但是备份和恢复的操作和 RDB 一样,都是拷贝备份文件,需要恢复时再拷贝到 Redis 目录工作下,启动系统即加载。

AOF 文件故障恢复:
(1)AOF 文件的保存路径同RDB的路径一致
(2)如遇到 AOF 文件损坏,可通过 redis-check-aof ==fix appendonly.aof 进行恢复。

ReWrite
AOF 采用文件追加的方式,文件会越来越大。为避免这种情况,新增了重写机制。当 AOF 文件的大小超过所设定的阈值时,Redis 会启动 AOF 文件的内容压缩,只保留可以恢复数据的最小指令集。可以使用bgrewriteaof。

Reids 如何实现重写?
AOF 文件持续增长而过大时,会 fork 出一条新进程来将文件重写(也是先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条的Set语句。重写 aof 文件的操作,并没有读取旧的 aof 文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的 aof 文件,这点和快照有些类似。

AOF的优缺点:
优点:
(1)备份机制更稳健,丢失数据概率更低
(2)可读的日志文本,通过操作 AOF 文件,可以处理误操作。
缺点:
(1)比起 RDB 占用更多的磁盘空间
(2)恢复备份速度要慢
(3)每次读写都同步的话,有一定的性能压力
(4)存在个别Bug,造成恢复不能。

6.3 RDB 和 AOF 的选取

(1)官方推荐两个都启用
(2)如果对数据不敏感,可以单独用 RDB。
(3)不建议单独使用 AOF,因为可能会出现 Bug
(4)如果只是做纯内存缓存,可以都不用

7. Redis的主从复制

主从复制,就是主机数据更新后根据配置和策略,自动同步到备机的master/slaver 机制,Master 以写为主,Slave 以读为主。

在这里插入图片描述

用处:(1)读写分离,性能扩展; (2)容灾快速恢复

7.1 复制原理

(1)每次从机联通后,都会给主机发送 sync 指令
(2)主机立刻进行存盘操作,发送 RDB 文件给从机
(3)从机收到 RDB 文件后进行全盘加载
(4)之后每次主机的写操作,都会立刻发送给从机,从机执行相同的命令。

在这里插入图片描述

7.2 薪火相传

(1)上一个 salve 可以是下一个 slave 的 Master,slave 同样地可以接收其他 slaves 的连接和同步请求,那么该 slaves 作为了链条中下一个的 master,可以有效的减轻 master 的写压力,去中心化降低风险。
(2)用 slaveof
(3)中途变更转向:会清除之前的数据,重新建立拷贝最新的
(4)风险是一旦某个 slave 宕机,后面的 slave 都没法备份。

在这里插入图片描述

7.3 故障恢复

(1)新主登基
从下线的主服务的所有从服务里面挑选一个从服务,将其转成主服务。选择的条件依次为:
①选择优先级靠前的
②选择偏移量最大的(偏移量是指获得原主数据最多的)
③选择 runid 最小的从服务
(2)群仆俯首
挑选出新的主服务之后,sentinel 向原主服务的从服务发送 slaveof 新主服务的命令,复制新master
(3)旧主俯首
当已下线的服务重新上线时,sentinel 会向其发送 slaveof 命令,让其成为新主的从。

8. Redis的集群

集群的产生:容量不够,Redis 如何进行扩容?并发写操作,Redis 如何分摊?

Redis集群实现了对 Redis 的水平扩容,即启动 N 个 Redis 节点,将整个数据库分布存储在这 N 个节点中,每个节点存储总数据的 1/N。

Redis 集群通过分区(partition)来提供一定程度的可用性(availablity):即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。

9. 使用Redis可能出现的问题

首先我们应该先明确缓存处理的流程:
前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。

1.缓存雪崩: 指缓存由于某些原因(比如 宕机、cache服务挂了或者不响应)整体失效了,导致大量请求到达后端数据库,从而导致数据库崩溃,整个系统崩溃,发生灾难。
解决办法:可以给缓存设置不同的缓存时间,更新数据使用互斥锁或者通过双缓存在避免缓存雪崩。

2.缓存击穿: 缓存击穿是指缓存中没有但数据库中有的数据。如果一些key被高并发访问,恰好在这个时间点某个key缓存过期,从而导致了大量请求达到数据库,这就导致数据库中并发的去执行了很多不必要的查询操作,从而导致巨大冲击和压力。
解决办法:使用互斥锁,只让一个请求去load DB,成功之后重新写缓存,其余请求没有获取到互斥锁,可以尝试重新获取缓存中的数据。

3.缓存穿透: 是指缓存和数据库中都没有的数据,而用户不断发起请求,导致请求都打到了数据库上,导致数据库异常。
解决办法:可以使用互斥锁或者无论是否取到结果都将结果存入缓存,还可以使用有效的机制(比如布隆过滤器)来拦截不合法的key值等。

4.数据库和缓存的双写一致性问题:
在高并发请求下很容易导致数据不一致的问题,如果你的业务需要保证数据的强一致性,那么建议不要使用缓存。在数据库中和缓存数据的删除或者写入过程中,如果有失败的情况,会导致数据的不一致。
解决办法:
双删延时的解决办法。可以先删除缓存数据,然后再更新数据库数据,最后再隔固定的时间再次删除缓存。
更新数据库产生的binlog订阅(使用canal)。将有变化的key记录下来,并且尝试去不断的去删除缓存(如果上次删除缓存失败)


[拓展] 缓存雪崩、缓存穿透、缓存击穿的区别记忆方法
打个比方,数据库是人,缓存是防弹衣,子弹是线程,本来防弹衣是防止子弹打到人身上的,但是当防弹衣里面没有防弹的物质时,子弹就会穿过它打到人身上。

缓存雪崩: "雪崩"对应的是大量请求。缓存某一时间失效了,然后大量请求到达后端数据库,从而导致数据库崩溃。
缓存击穿:"击穿"对应的是Redis某点被(key)击穿。缓存击穿是指缓存中没有但数据库中有的数据。 如果一些key被高并发访问,恰好在这个时间点某个key缓存过期,从而导致了大量请求达到数据库,这就导致数据库中并发的去执行了很多不必要的查询操作,从而导致巨大冲击和压力。
缓存穿透:"穿透"最为严重,指的是缓存和数据库被穿透,都穿的透透的了。是指缓存和数据库中都没有的数据,而用户不断发起请求,导致请求都打到了数据库上,导致数据库异常。这时的用户很可能是攻击者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值