redis学习笔记(一)
一、非关系数据库
not only Sql
是非关系型数据库
1.NoSQL的特点
方便扩展(数据之间没有关系,很好扩展)
大数据高性能(8w写,11w读)
数据类型多样性(无需事先设计数据库,随取随用)
2.传统RDBMS和NoSQL
传统的RDBMS
是结构化组织、建立在SQL
语句之上,数据和数据间的关系存储在表中,严格的一致性,事务等。
非关系型数据库NoSQL
是没有固定的查询语言,有列存储、键值对存储、图像数据库、文件存储,强调最终一致性,建立在CAP
定理和BASE
理论,具有高性能、高可用、高可扩。
大数据时代的3V(海量Volume,多样Variety,实时Velocity)+3高(高并发、高可用、高性能)
3.四大分类
KV键值对
代表性的有
redis
、memecache
文档型数据库
MongoDB
一个基于分布式文件存储的数据库,C++
编写,主要用来处理大量的文档,是一个介于关系型数据库和非关系型数据库的中间产品,MongoDB
是非关系型数据库中功能最丰富,最像关系型数据库的。列存储数据库
Hbase
- 分布式文件系统
图关系数据库
- 存储拓扑图关系,比如朋友圈社交网络、广告推荐!(
Neo4j、infoGrid
)
- 存储拓扑图关系,比如朋友圈社交网络、广告推荐!(
二、redis简介
Redis
是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如字符串String
, 散列hashes
, 列表lists
, 集合sets
, 有序集合sorted sets
与范围查询, bitmaps
, hyperloglogs
和地理空间geospatial
索引半径查询。Redis
内置了复制,LUA
脚本,LRU
驱动事件,事务transactions
和不同级别的磁盘持久化persistence
, 并通过Redis
哨兵Sentinel
和自动分区Cluster
提供高可用性high availability
。
Redis
官方发布效率8w写,11万读 (mysql在300w数据之后需要加索引)
1. 作用
- 内存存储、持久化,内存是断电即失,所以持久化很重要(
AOP
、RDB
) - 效率高可用用于高速缓存。
- 发布订阅系统。
- 地图信息分析。
- 计时器、计数器(浏览量、点赞数、发布数)
2. 单线程
redis
是单线程,官方表示redis
是基于内存操作,CPU
不是redis
性能瓶颈,redis
的性能瓶颈是根据机器的内存和网络带宽。
redis是单线程为什么还这么快?
两个误区:高性能服务器一定是多线程?多线程一定比单线程效率高?
核心是:redis
是将所有数据全部存放在内存中,所以使用单线程去操作效率就是最高的,减少了CPU
上下文切换的时间,多线程会引发上下文切换,对于内存系统来说,如果没有上下文切换效率就是最高的。而且redis
是基于reactor
模型,使用的是I/O
多路复用的IO
模型。
I/O
多路复用:在I/O
多路复用模型中,最重要的函数调用就是select
,该方法能同时监控多个文件描述符的可读可写情况,当其中某个文件描述符可读或可写时,select
方法就会返回可读以及可写的文件描述符个数,netty
的底层采用的也是I/O
多路复用的模型。
三、持久化
redis
是内存数据库,如果不将内存中的数据保存在硬盘中,若出现断电或者宕机等情况,内存中保存的数据也会丢失。
1. RDB
RDB
全称是Redis DataBase
,在指定的时间间隔内将内存中的数据集快照Shapshot
写入磁盘,恢复时只需要将快照加载入内存即可,默认保存的文件名为dump.rdb
。
redis
会通过创建子线程的方式单独创建一个线程来进行持久化,这个线程会将所有内存数据写入到一个临时文件中,待持久化结束后,会替换掉上一次持久化好的文件。整个过程,主进程不进行任何I/O
操作,确保了极高的性能。并且.rdb
是二进制文件,比较轻量,灾难之后的恢复会快一些。
两种方式
save
:阻塞主线程,使得主线程不能继续对外提供请求,若数据量小,将数据写入备份文件快,则没有多大影响,若数据量大,写入备份文件时间长,则写多长时间就会停机多长时间。bgsave
:主线程fork
子进程,子进程进行数据的备份,主进程在fork
子进程时阻塞,之后不会阻塞,相比于save
方式,阻塞时间可以忽略不计。
bgsave
的原理
主进程在fork()
子进程之后,内核把主进程所有的内存页的权限都设置为read-only
,然后将子进程的地址空间指向主进程。所以这里两个进程共享了同一块内存空间,最极端的情况当子进程在备份数据时,主进程接收到写请求,这时由于内存页的权限是read-only
,会触发页异常中断后,会将这个数据的内存页复制一份,并且主进程指向该内存页。所以可以得出,在某一个时间节点触发了bgsave
,则它只会备份那个时间节点的数据,那个时间节点只有的写操作,它都无法处理到。从一般设计来说,缓存中都是使用频繁且读多写少的数据,所以这一机制并不会使得在备份时频繁带来内存页数据异常导致的性能问题。
2.AOF
AOF
全称是Append only file
,以日志的形式来记录每个写操作(默认情况是关闭),将redis
执行过的所有写操作命令备份下来,会把写操作命令一直追加到文件中。恢复时,默认会读取appendonly.aof
文件中的命令,逐个执行命令,使得数据恢复。
redis
通过创建子线程的方式单独创建一个线程来进行持久化,这个线程会将所有AOF
缓冲区的命令同步到appendonly.aof
文件中。
AOF
的配置项
appendonly on
:默认是关闭状态appendfilename "appendonly.aof"
:默认的持久化文件名称appendfsync always
:同步策略,有三种always
(每次修改都会同步),everysec
(每秒同步一次),no
由操作系统控制同步,默认是everysec
AOF
重写
AOF
重写会在保持最终数据一致的前提下,将一些多条命令,整合成一条命令来代替多条命令。AOF
重写是通过子进程的方式进行,使用子进程不会阻塞父进程,使得父进程还是可以处理客户端请求,并且子进程可以继承父进程资源,并且这种继承采取copy-on-write
的策略,所以AOF
重写无需关心由于客户端写请求导致数据不一致问题。
AOF
重写的写命令不仅要写入到AOF
缓冲区,还会写入AOF
重写缓冲区,写入原AOF
缓冲区是为了避免若重写失败导致数据丢失;写入AOF
重写缓冲区是为了子进程在进行AOF
重写期间还是在继续处理命令请求。
子进程在重写完毕后会发送一个信号给父进程,父进程收到信号后,会将AOF
重写缓冲区的所有内容写入到新的AOF
文件中,并且采用原子操作覆盖现有AOF
文件,完成新旧文件的替换。
小结
如果需要大规模恢复数据,且对数据恢复的完整性不是非常敏感,那么RDB
比AOF
方式更加有效,RDB
的缺点是最后一次持久化可能会丢失一部分数据。若从安全性来说,AOF
会比较高一点,AOF
最多丢失1秒的数据(采用默认配置的话),而RDB
丢失上一次备份与宕机时间差之间的数据。在redis
服务器开启AOF
持久化功能时,会采用AOF
文件来恢复数据,若没有开启AOF
功能时,才会使用RDB
来恢复数据。