Redis知识点
前言-关系型数据库与非关系型数据库的特点及区别
关系型数据库代表:MySQL,Oracle,DB2,Microsoft SQL Server,Microsoft Access
关系型数据库:关系数据库,是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据。
关系型数据库的优点:
- 容易理解:二维表结构是非常贴近逻辑世界的一个概念,关系模型相对网状、层次等其他模型来说更容易理解
- 使用方便:通用的SQL语言使得操作关系型数据库非常方便
- 易于维护:丰富的完整性(实体完整性、参照完整性和用户定义的完整性)大大减低了数据冗余和数据不一致的概率
关系型数据库瓶颈:
- 高并发读写需求:网站的用户并发性非常高,往往达到每秒上万次读写请求,对于传统关系型数据库来说,硬盘I/O是一个很大的瓶颈
- 海量数据的高效率读写:网站每天产生的数据量是巨大的,对于关系型数据库来说,在一张包含海量数据的表中查询,效率是非常低的
- 高扩展性和可用性:在基于web的结构当中,数据库是最难进行横向扩展的,当一个应用系统的用户量和访问量与日俱增的时候,数据库却没有办法像web server和app server那样简单的通过添加更多的硬件和服务节点来扩展性能和负载能力。对于很多需要提供24小时不间断服务的网站来说,对数据库系统进行升级和扩展是非常痛苦的事情,往往需要停机维护和数据迁移。对网站来说,关系型数据库的很多特性不再需要了
- 事务一致性:关系型数据库在对事物一致性的维护中有很大的开销,而现在很多web2.0系统对事物的读写一致性都不高
- 读写实时性:对关系数据库来说,插入一条数据之后立刻查询,是肯定可以读出这条数据的,但是对于很多web应用来说,并不要求这么高的实时性,比如发一条消息之后,过几秒乃至十几秒之后才看到这条动态是完全可以接受的
- 复杂SQL,特别是多表关联查询:任何大数据量的web系统,都非常忌讳多个大表的关联查询,以及复杂的数据分析类型的复杂SQL报表查询,特别是SNS类型的网站,从需求以及产品阶级角度,就避免了这种情况的产生。往往更多的只是单表的主键查询,以及单表的简单条件分页查询,SQL的功能极大的弱化了
非关系型数据库代表:HBase(列存储数据),Redis(键值数据库),MongodDB(分布式文件存储数据库),Neo4J(图形存储数据库)
对于NoSQL并没有一个明确的范围和定义,但是他们都普遍存在下面一些共同特征:
- 不需要预定义模式:不需要事先定义数据模式,预定义表结构。数据中的每条记录都可能有不同的属性和格式。当插入数据时,并不需要预先定义它们的模式。
- 无共享架构:相对于将所有数据存储的存储区域网络中的全共享架构。NoSQL往往将数据划分后存储在各个本地服务器上。因为从本地磁盘读取数据的性能往往好于通过网络传输读取数据的性能,从而提高了系统的性能。
- 弹性可扩展:可以在系统运行的时候,动态增加或者删除结点。不需要停机维护,数据可以自动迁移。
- 分区:相对于将数据存放于同一个节点,NoSQL数据库需要将数据进行分区,将记录分散在多个节点上面。并且通常分区的同时还要做复制。这样既提高了并行性能,又能保证没有单点失效的问题。
- 异步复制:和RAID存储系统不同的是,NoSQL中的复制,往往是基于日志的异步复制。这样,数据就可以尽快地写入一个节点,而不会被网络传输引起迟延。缺点是并不总是能保证一致性,这样的方式在出现故障的时候,可能会丢失少量的数据。
- BASE:相对于事务严格的ACID特性,NoSQL数据库保证的是BASE特性。BASE是最终一致性和软事务。
1.什么是Redis
什么是Redis?
Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库。
2.Redis的特点
Redis优点:
- 可以高速读
- 多种多样的数据结构。string,hash,list,set,sorted set
Redis缺点:
- 持久化,Redis直接将数据存储在内存,定时进行持久化,redis的两种持久化方式一种是RDB,这种方式每隔一段时间就要将全部数据写到磁盘上,耗时耗空间;另一种是AOF,将更改数据的命令存储在日志中,但是执行日志文件中的命令仍然需要大量的时间.
- 耗费内存,虽然Redis数据结构采用了压缩算法,但是还是会占用大量内存的.
那么redis为什么快呢?
- 完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);
- 数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;
- 采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出 现死锁而导致的性能消耗;
- 使用多路I/O复用模型,非阻塞IO;
- 使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间 去移动和请求;
3.Redis的持久化有哪些方式
RDB 持久化
1.RDB文件:
RDB持久化功能所生成的RDB文件是一个保存在磁盘中、经过压缩的二进制文件,通过该文件可以还原生成RDB文件时的数据库状态。
2.生成RDB文件的命令:
SAVE:SAVE命令会阻塞服务器进程,直到RDB文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何命令请求。
BGSAVE:BGSAVE命令会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程可以继续处理命令请求。
以下是rdb.c/rdbSave函数,用于创建RDB文件
def SAVE(): # 创建RDB文件 rdbSave() def BGSAVE(): # 创建子进程 pid = fork() if pid == 0: # 子进程负责创建RDB文件 rdbSave() # 完成之后向父进程发送信号 signal_parent() elif pid > 0: # 父进程继续处理命令请求,并通过轮询等待子进程的信号 handle_request_and_wait_signal() else: # 处理出错情况 handle_fork_error()
注意:
- 在BGSAVE命令执行期间,客户端发送的SAVE命令会被服务器拒绝,服务器进制SAVE命令和BGSAVE命令同时执行是为了避免父进程和子进程同时执行两个rdbSave调用,防止出现竞争条件。
- 在BGSAVE命令执行期间,客户端发送的BGSAVE命令会被服务器拒绝,因为同时执行两个BGSAVE命令也会出现竞争条件。
- 同样,BGREWRITRAOF和BGSAVE命令也不能同时执行。如果BGSAVE命令正在执行,那么客户端发送的BGREWRITEAOF命令会被延迟到BGSAVE命令执行完毕之后执行。如果BGREWRITRAOF命令正在执行,那么户端发送的BGSAVE命令会被服务器拒绝。
自动间隔性保存:
save 900 1
save 300 10
save 60 10000
以上三个条件满足任意的一个,BGSAVE命令就会被执行。
服务器在900秒之内,对数据库进行了至少1次修改。
服务器在300秒之内,对数据库进行了至少10次修改。
服务器在60秒之内,对数据库进行了至少10000次修改。
服务器会根据save选项所设置的保存条件,设置服务器状态redisServer结构的saveparams属性:
struct redisServer{ // ... // 记录了保存条件的数组 struct saveparam *saveparams; // ... }; struct saveparam{ // 秒数 time_t seconds; // 修改数 int changes; };
RDB文件结构:
REDIS:长度为5个字节,保存着“REDIS”五个字符,通过这5个字符,程序可以在载入文件时,快速检查所载入的文件是否是RDB文件。
db_version:长度为4字节,它的值是一个字符串表示的整数,这个整数记录了redis的版本号,如“0002”代表RDB文件的版本为第2版
databases:包含着零个或任意多个数据库,以及各个数据库中的键值对数据。
EOF:长度为1字节,这个常量标志着RDB文件正文内容的结束,当读入程序遇到这个值时,它知道所有数据库的所有键值对都已经载入完毕了。
check_sum:一个8字节长的无符号整数,保存着一个校验和,这个校验和是程序通过对REDIS,db_version,databases,EOF四个部分内容进行计算得出。服务器通过检验和检查RDB文件是否损坏是否完整。
例子:如果服务器的5号和7号数据库非空,那么RDB文件是怎样保存的呢?
AOF持久化
AOF:AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的。
AOF持久化功能的实现可以分为命令追加,文件写入,文件同步
命令追加:当AOF持久化功能处于打开状态时,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾
例如: 执行命令 SET KEY VALUE
会在aof_buf缓冲区追加以下协议内容: *3\r\n$3\r\nSET\r\n$3\r\nKEY\r\n$5\r\nVALUE\r\n
*3表示以下会有三个单词,$3表示下面这个单词会有三个字母
文件写入及同步:因为服务器在处理文件时间时可能会执行写命令,使得一些内容被追加到aof_buf缓冲区里面,所以在服务器每次结束一个事件循环之前,它都会调用flushAppendOnlyFile函数,考虑是否需要将aof_buf缓冲区中的内容写入和保存到AOF文件里面。flushAppendOnlyFile函数的行为有服务器配置的appendfsync选项的值来决定
appendfsync选项的值 | flushAppendOnlyFile函数的行为 |
always | 将aof_buf缓冲区中所有的内容写入并同步到AOF文件 |
everysec | 将aof_buf缓冲区中的所有内容写入到AOF文件,如果上次同步AOF文件的时间距离现在超过一秒钟,那么再次对AOF文件进行同步,并且这个同步操作是由一个线程专门负责执行的 |
no | 将aof_buf缓冲区中所有的内容写入到AOF文件,但不对AOF文件进行同步,何时同步由操作系统来决定 |
服务器如何选择持久化方式?
如果服务器开启了AOF持久化功能,那么服务器会优先使用AOF文件来还原数据库状态。- 只有在AOF持久化功能处于关闭状态时,服务器才会使用RDB文件来还原数据库状态。
参考:
《Redis设计与实现》
https://www.cnblogs.com/suncan0/p/4735129.html