一、关系型数据库与非关系型数据库
1.关系型数据库
关系型数据库是一个结构化的数据库,创建在关系模型(二维表格模型)基础上,一般面向于记录。
SQL语句(标准数据查询语言)就是一种基于关系型数据库的语言,用于执行对关系型数据库中数据的检索和操作。
主流的关系型数据库包括Oracle、MySQL、SQLServer、DB2、PostgreSQL等。以上数据库在使用的时候必须先建库建表设计表结构,然后存储数据的时候按表结构去存,如果数据与表结构不匹配就会存储失败。
2.非关系型数据库
NoSQL(NoSQL=NotonlysQL),意思是“不仅仅是SQL",是非关系型数据库的总称。
除了主流的关系型数据库外的数据库,都认为是非关系型。
不需要预先建库建表定义数据存储表结构,每条记录可以有不同的数据类型和字段个数(比如微信群聊里的文字、图片、视频、音乐等)。
主流的NOSQL 数据库有Redis、MongoBD、 Hbase(分布式非关系型数据库,大数据使用)、Memcached、ElasticSearch(简称ES,索引型数据库)、TSDB(时续型数据库) 等
两者区别
1.数据存储方式不同
-
关系型:依赖于关系模型E-R图,同时以表格式的方式存储数据
-
非关系型:除了以表格形式存储之外,通常会以大块的形式组合在一起进行存储数据
关系型和非关系型数据库的主要差异是数据存储的方式。关系型数据天然就是表格式的,因此存储在数据表的行和列中。数据表可以彼此关联协作存储,也很容易提取数据。
与其相反,非关系型数据不适合存储在数据表的行和列中,而是大块组合在一起。非关系型数据通常存储在数据集中,就像文档、键值对或者图结构。你的数据及其特性是选择数据存储和提取方式的首要影响因素。
2.扩展方式不同
- 关系:纵向(天然表格式)
- 非关系型:横向(天然分布式)
SQL和NoSQL数据库最大的差别可能是在扩展方式上,要支持日益增长的需求当然要扩展。
要支持更多并发量,SQL数据库是纵向扩展,也就是说提高处理能力,使用速度更快速的计算机,这样处理相同的数据集就更快了。因为数据存储在关系表中,操作的性能瓶颈可能涉及很多个表,这都需要通过提高计算机性能来克服。虽然SQL数据库有很大扩展空间,但最终肯定会达到纵向扩展的上限。
而NoSQL数据库是横向扩展的。因为非关系型数据存储天然就是分布式的,NoSQL数据库的扩展可以通过给资源池添加更多普通的数据库服务器 (节点) 来分担负载。
3.对事务性的支持不同
- 关系型:特别适合高事务性要求和需要控制执行计划的任务
- 非关系型:此处会稍显弱势,其价值点在于高扩展性和大数据量处理方面
如果数据操作需要高事务性或者复杂数据查询需要控制执行计划,那么传统的SQL数据库从性能和稳定性方面考虑是最佳选择。SQL数据库支持对事务原子性细粒度控制,并且易于回滚事务。
虽然NoSQL数据库也可以使用事务操作,但稳定性方面没法和关系型数据库比较,所以它们真正闪亮的价值是在操作的扩展性和大数据量处理方面。
4.非关系型数据库产生背景
可用于应对 Web2.0 纯动态网站类型的三高问题(高并发、高性能、高可用)。
- High performance——对数据库高并发读写需求
- Huge Storage——对海量数据高效存储与访问需求
- High Scalability && High Availability——对数据库高可扩展性与高可用性需求
关系型数据库和非关系型数据库都有各自的特点与应用场景,两者的紧密结合将会给Web2.0的数据库发展带来新的思路。让关系型数据库关注在关系上和对数据的一致性保障,非关系型数据库关注在存储和高效率上。例如,在读写分离的MySQL数据库环境中,可以把经常访问的数据存储在非关系型数据库中,提升访问速度。
二、Redis介绍
1.Redis概念
Redis(远程字典服务器) 是一个开源的、使用 C 语言编写的 NoSQL 数据库。
Redis 基于内存运行并支持持久化,采用key-value(键值对)的存储形式,是目前分布式架构中不可或缺的一环。
Redis服务器程序是单进程模型,也就是在一台服务器上可以同时启动多个Redis进程,Redis的实际处理速度则是完全依靠于主进程的执行效率。
-
若在服务器上只运行一个Redis进程,当多个客户端同时访问时,服务器的处理能力是会有一定程度的下降;
-
若在同一台服务器上开启多个Redis进程,Redis在提高并发处理能力的同时会给服务器的CPU造成很大压力。
即:在实际生产环境中,需要根据实际的需求来决定开启多少个Redis进程。若对高并发要求更高一些,可能会考虑在同一台服务器上开启多个进程。若CPU资源比较紧张,采用单进程即可。
2.Redis优缺点
1.优点
-
具有极高的数据读写速度:数据读取的速度最高可达到 110000 次/s,数据写入速度最高可达到 81000 次/s。(因为Redis是基于内存运行的)
-
支持丰富的数据类型:支持 key-value、Strings、Lists、Hashes、Sets 及 Sorted Sets 等数据类型操作。
-
支持数据的持久化:当服务意外宕机,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
-
原子性:Redis 所有操作都是原子性的。(支持事务,所有操作都作为事务)
-
支持数据备份:即 master-salve 模式的数据备份。(支持主从复制)
2.缺点
-
缓存和数据库双写一致性问题
-
缓存雪崩问题
-
缓存击穿问题
-
缓存的并发竞争问题
3.Redis适用场景
Redis作为基于内存运行的数据库,是一个高性能的缓存,一般应用在Session缓存、队列、排行榜、计数器、最近最热文章、最近最热评论、发布订阅等。
Redis 适用于数据实时性要求高、数据存储有过期和淘汰特征的、不需要持久化或者只需要保证弱一致性、逻辑简单的场景。
我们通常会将部分数据放入缓存中,来提高访问速度,然后数据库承担存储的工作。
4.Redis为什么这么快?
-
redis是基于内存运行的,数据读写都是在内存中完成的
-
数据读写采用单线程模式,避免了多线程切换带来的CPU性能消耗,同时也不要考虑各种锁的问题
-
采用IO多路复用模型,可以使线程处理更多的网络连接请求,提高并发能力
注意:在 Redis 6.0 中新增加的多线程也只是针对处理网络请求过程采用了多线性,而数据的读写命令,仍然是单线程处理的。
三、Redis安装部署
1.编译安装Redis
源码包:download.redis.io/releases/
1.安装依赖包
点击查看代码
[root@node6 ~]# yum -y install gcc jemalloc-devel systemd-devel
2.下载redis安装包并解压
点击查看代码
[root@node6 ~]# cd /data
[root@node6 data]# wget http://download.redis.io/releases/redis-5.0.7.tar.gz
[root@node6 data]# tar xf redis-5.0.7.tar.gz
3.编译安装
点击查看代码
[root@node6 data]# cd redis-5.0.7/
[root@node6 redis-5.0.7]# make USE_SYSTEMD=yes PREFIX=/apps/redis install
4.配置变量
点击查看代码
[root@node6 redis-5.0.7]# echo 'PATH=/apps/redis/bin:$PATH' > /etc/profile.d/redis.sh
[root@node6 redis-5.0.7]# . /etc/profile.d/redis.sh
5.准备配置文件及目录
点击查看代码
[root@node6 redis-5.0.7]# mkdir /apps/redis/{etc,log,data,run} //创建配置文件、日志、数据等目录
[root@node6 redis-5.0.7]# cp redis.conf /apps/redis/etc/ //源码包中自带的配置文件[root@node6 redis-5.0.7]# cd /apps/redis/
[root@node6 redis]# ls
bin data etc log run
[root@node6 redis]# tree
.
├── bin
│ ├── redis-benchmark
│ ├── redis-check-aof
│ ├── redis-check-rdb
│ ├── redis-cli
│ ├── redis-sentinel -> redis-server
│ └── redis-server
├── data
├── etc
│ └── redis.conf
├── log
└── run
6.启动redis
- 前台启动
redis-sever是redis服务器程序
点击查看代码
[root@node6 redis]# redis-server /apps/redis/etc/redis.conf //指定配置文件启动[root@node6 redis]# redis-server --port 端口号 //指定端口号开启,默认端口为6379
- systemd启动
点击查看代码
//准备用户 修改权限
[root@node6 apps]# useradd redis -M -s /sbin/nologin
[root@node6 apps]# chown -R redis.redis /apps/redis///准备service文件
[root@node6 redis]# vim /usr/lib/systemd/system/redis.service[Unit]
Description=Redis persistent key-value database
After=network.target[Service]
ExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
#Type=notify 如果支持systemd可以启用此行
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755[Install]
WantedBy=multi-user.target[root@node6 redis]# systemctl daemon-reload
[root@node6 redis]# systemctl start redis
[root@node6 redis]# systemctl status redis
2.处理redis的warning信息
TCP backlog
backlog参数控制的是三次握手的时候server端收到client ack确认号之后的队列值,即全连接队列
点击查看代码
#vim /etc/sysctl.conf
net.core.somaxconn = 1024
#sysctl -p
vm.overcommit_memory
内核参数说明:
-
0 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
-
1 表示内核允许分配所有的物理内存,而不管当前的内存状态如何
-
2 表示内核允许分配超过所有物理内存和交换空间总和的内存
点击查看代码
#vim /etc/sysctl.conf
vm.overcommit_memory = 1
#sysctl -p
transparent hugepage
警告:您在内核中启用了透明大页面(THP,不同于一般内存页的4k为2M)支持。 这将在Redis中造成延迟和内存使用问题。 要解决此问题,请以root 用户身份运行命令“echo never>/sys/kernel/mm/transparent_hugepage/enabled”,并将其添加到您的/etc/rc.local中,以便在重启后保留设置。禁用THP后,必须重新启动Redis。
点击查看代码
//临时修改
echo never > /sys/kernel/mm/transparent_hugepage/enabled//永久修改
echo 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >> /etc/rc.d/rc.local
chmod +x /etc/rc.d/rc.local
四、Redis多实例
测试环境中经常使用多实例,需指定不同实例的相应的端口,配置文件,日志文件等相关配置。
示例:
- 准备配置文件
点击查看代码
[root@node6 etc]# cp -a /apps/redis/etc/redis.conf /apps/redis/etc/redis6380.conf
[root@node6 etc]# vim redis6380.conf
70 bind 0.0.0.0 //允许远程连接
93 port 6380 //修改端口号
159 pidfile /apps/redis/run/redis_6380.pid //修改pid文件
172 logfile /apps/redis/log/redis6380.log //修改日志文件
254 dbfilename dump6380.rdb //修改备份文件的名字
264 dir /apps/redis/data/ //快照文件保存路径[root@node6 etc]# cp -a redis6380.conf redis6381.conf
[root@node6 etc]# cp -a redis6380.conf redis6382.conf
[root@node6 etc]# vim redis6381.conf
:% s/6380/6381/g //全文替换
[root@node6 etc]# vim redis6382.conf
:% s/6380/6382/g //全文替换
- 准备service文件
点击查看代码
[root@node6 etc]# cp /lib/systemd/system/redis.service /lib/systemd/system/redis6380.service
[root@node6 etc]# cp /lib/systemd/system/redis.service /lib/systemd/system/redis6381.service
[root@node6 etc]# cp /lib/systemd/system/redis.service /lib/systemd/system/redis6382.service[root@node6 etc]# vim /lib/systemd/system/redis6380.serviceExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis6380.conf --supervised systemd
[root@node6 etc]# vim /lib/systemd/system/redis6381.serviceExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis6381.conf --supervised systemd
[root@node6 etc]# vim /lib/systemd/system/redis6382.serviceExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis6382.conf --supervised systemd[root@node6 etc]# systemctl daemon-reload
[root@node6 etc]# systemctl start redis6380
[root@node6 etc]# systemctl start redis6381
[root@node6 etc]# systemctl start redis6382[root@node6 etc]# ss -natp |grep '63'
LISTEN 0 511 *:6379 *:* users:(("redis-server",pid=59386,fd=6))
LISTEN 0 511 *:6380 *:* users:(("redis-server",pid=59976,fd=6))
LISTEN 0 511 *:6381 *:* users:(("redis-server",pid=59986,fd=6))
LISTEN 0 511 *:6382 *:* users:(("redis-server",pid=59996,fd=6))
- 测试info指令
点击查看代码
[root@node6 etc]# redis-cli -p 6380
127.0.0.1:6380> info[root@node6 etc]# redis-cli -p 6381
127.0.0.1:6381> info[root@node6 etc]# redis-cli -p 6382
127.0.0.1:6382> info
五、Redis的配置优化
1.redis主要配置项
点击查看代码
bind 0.0.0.0
//监听地址,可以用空格隔开后多个监听IPprotected-mode yes
//redis3.2之后加入的新特性,在没有设置bind IP和密码的时候,redis只允许访问127.0.0.1:6379,可以远程连接,但当访问将提示警告信息并拒绝远程访问port 6379
//监听端口,默认6379/tcptcp-backlog 511
//三次握手的时候server端收到client ack确认号之后的队列值,即全连接队列长度timeout 0 #客户端和Redis服务端的连接超时时间,默认是0,表示永不超时tcp-keepalive 300
//tcp 会话保持时间300sdaemonize no
//默认no,即直接运行redis-server程序时,不作为守护进程运行,而是以前台方式运行,如果想在后台运行需改成yes,当redis作为守护进程运行的时候,它会写一个 pid 到/var/run/redis.pid 文件supervised no
//和OS相关参数,可设置通过upstart和systemd管理Redis守护进程,centos7后都使用systemdpidfile /var/run/redis_6379.pid
//pid文件路径,可以修改为/apps/redis/run/redis_6379.pidloglevel notice
//日志级别logfile "/path/redis.log"
//日志路径,示例:logfile "/apps/redis/log/redis_6379.log"databases 16 #设置数据库数量,默认:0-15,共16个库always-show-logo yes
//在启动redis 时是否显示或在日志中记录记录redis的logo//自动保存策略,三者满足其一就会保存
save 900 1 //在900秒内有1个key内容发生更改,就执行快照机制
save 300 10 //在300秒内有10个key内容发生更改,就执行快照机制
save 60 10000 //60秒内如果有10000个key以上的变化,就自动快照备份stop-writes-on-bgsave-error yes
//默认为yes时,可能会因空间满等原因快照无法保存出错时,会禁止redis写入操作,生产建议为no。此项只针对配置文件中的自动save有效rdbcompression yes
//持久化到RDB文件时,是否压缩,"yes"为压缩,"no"则反之rdbchecksum yes
//是否对备份文件开启RC64校验,默认是开启dbfilename dump.rdb
//快照文件名dir ./
//快照文件保存路径,示例:dir "/apps/redis/data"//主从复制相关
replicaof <masterip> <masterport> //指定复制的master主机地址和端口,5.0版之前的指令为slaveof
masterauth <master-password> //指定复制的master主机的密码replica-serve-stale-data yes
//当从库同主库失去连接或者复制正在进行,从机库有两种运行方式:
//设置为yes(默认设置),从库会继续响应客户端的读请求,此为建议值
//设置为no,除去特定命令外的任何请求都会返回一个错误"SYNC with master in progress"。replica-read-only yes
//是否设置从库只读,建议值为yes,否则主库同步从库时可能会覆盖数据,造成数据丢失repl-diskless-sync no
//是否使用socket方式复制数据(无盘同步),新slave第一次连接master时需要做数据的全量同步,redis server就要从内存dump出新的RDB文件,然后从master传到slave,有两种方式把RDB文件传输给客户端:
//基于硬盘(disk-backed):为no时,master创建一个新进程dump生成RDB磁盘文件,RDB完成之后由父进程(即主进程)将RDB文件发送给slaves,此为默认值
//基于socket(diskless):master创建一个新进程直接dump RDB至slave的网络socket,不经过主进程和硬盘
//推荐使用基于硬盘(为no),是因为RDB文件创建后,可以同时传输给更多的slave,但是基于socket(为yes), 新slave连接到master之后得逐个同步数据。只有当磁盘I/O较慢且网络较快时,可用diskless(yes),否则一般建议使用磁盘(no)repl-diskless-sync-delay 5
//diskless时复制的服务器等待的延迟时间,设置0为关闭,在延迟时间内到达的客户端,会一起通过diskless方式同步数据,但是一旦复制开始,master节点不会再接收新slave的复制请求,直到下一次同步开始才再接收新请求。即无法为延迟时间后到达的新副本提供服务,新副本将排队等待下一次RDB传输,因此服务器会等待一段时间才能让更多副本到达。推荐值:30-60repl-ping-replica-period 10
//slave根据master指定的时间进行周期性的PING master,用于监测master状态,默认10srepl-timeout 60
//复制连接的超时时间,需要大于repl-ping-slave-period,否则会经常报超时repl-disable-tcp-nodelay no
//是否在slave套接字发送SYNC之后禁用 TCP_NODELAY,如果选择"yes",Redis将合并多个报文为一个大的报文,从而使用更少数量的包向slaves发送数据,但是将使数据传输到slave上有延迟,Linux内核的默认配置会达到40毫秒,如果 "no" ,数据传输到slave的延迟将会减少,但要使用更多的带宽repl-backlog-size 512mb
//复制缓冲区内存大小,当slave断开连接一段时间后,该缓冲区会累积复制副本数据,因此当slave 重新连接时,通常不需要完全重新同步,只需传递在副本中的断开连接后没有同步的部分数据即可。只有在至少有一个slave连接之后才分配此内存空间,建议建立主从时此值要调大一些或在低峰期配置,否则会导致同步到slave失败repl-backlog-ttl 3600
//多长时间内master没有slave连接,就清空backlog缓冲区replica-priority 100
//当master不可用,哨兵Sentinel会根据slave的优先级选举一个master,此值最低的slave会优先当选master,而配置成0,永远不会被选举,一般多个slave都设为一样的值,让其自动选择
//min-replicas-to-write 3 #至少有3个可连接的slave,mater才接受写操作
//min-replicas-max-lag 10 #和上面至少3个slave的ping延迟不能超过10秒,否则master也将停止写操作requirepass foobared
//设置redis连接密码,之后需要AUTH pass,如果有特殊符号,用" "引起来,生产建议设置rename-command
//重命名一些高危命令,示例:rename-command FLUSHALL "" 禁用命令
//示例: rename-command del 123456
maxclients 10000
//Redis最大连接客户端maxmemory <bytes>
//redis使用的最大内存,单位为bytes字节,0为不限制,建议设为物理内存一半,8G内存的计算方式8(G)*1024(MB)1024(KB)*1024(Kbyte),需要注意的是缓冲区是不计算在maxmemory内,生产中如果不设置此项,可能会导致OOMappendonly no
//是否开启AOF日志记录,默认redis使用的是rdb方式持久化,这种方式在许多应用中已经足够用了,但是redis如果中途宕机,会导致可能有几分钟的数据丢失(取决于dump数据的间隔时间),根据save来策略进行持久化,Append Only File是另一种持久化方式,可以提供更好的持久化特性,Redis会把每次写入的数据在接收后都写入 appendonly.aof 文件,每次启动时Redis都会先把这个文件的数据读入内存里,先忽略RDB文件。默认不启用此功能appendfilename "appendonly.aof"
//文本文件AOF的文件名,存放在dir指令指定的目录中appendfsync everysec
//aof持久化策略的配置
//no表示由操作系统保证数据同步到磁盘,Linux的默认fsync策略是30秒,最多会丢失30s的数据
//always表示每次写入都执行fsync,以保证数据同步到磁盘,安全性高,性能较差
//everysec表示每秒执行一次fsync,可能会导致丢失这1s数据,此为默认值,也生产建议值
2.config动态修改配置
config命令用于查看当前redis配置、以及不重启redis服务实现动态更改redis配置等。
注意:不是所有配置都可以动态修改,且此方式无法持久保持。
点击查看代码
CONFIG SET parameter value
config set 参数值
时间复杂度:O(1)
CONFIG SET 命令可以动态地调整 Redis 服务器的配置(configuration)而无须重启。
示例:设置连接密码
点击查看代码
127.0.0.1:6379> CONFIG SET requirepass 123456
OK
示例:设置最大内存
点击查看代码
127.0.0.1:6379> CONFIG SET maxmemory 8589934592
OK
127.0.0.1:6379> CONFIG GET maxmemory
1) "maxmemory"
2) "8589934592"
3.慢查询
点击查看代码
slowlog-log-slower-than 1 //指定为超过1us即为慢的指令
slowlog-max-len 1024 //指定保存1024条慢记录127.0.0.1:6379> CONFIG GET slow-log-slower-then //慢查询列表
(empty list or set)127.0.0.1:6379> SLOWLOG LEN //查看慢日志的记录条数127.0.0.1:6379> SLOWLOG RESET //清空慢日志127.0.0.1:6379> slowlog get //查看全部
127.0.0.1:6379> slowlog get 2 //查看慢查询具体情况,看前2条
4.持久化
Redis 虽然是一个内存级别的缓存程序,也就是redis是使用内存进行数据的缓存的,但是其可以将内存的数据按照一定的策略保存到硬盘上,从而实现数据持久保存的目的目前redis支持两种不同方式的数据持久化保存机制,分别是RDB和AOF。
持久化功能:Redis是内存数据库,所有数据都是保存在内存中,为了避免服务器断电等原因导致Redis进程异常退出后数据永久丢失,需要定期将Redis中的数据以某种形式(数据或者命令)从内存保存到硬盘;当下次Redis重启时,利用持久化文件实现数据恢复。除此之外为了进行灾难备份,可以持久将文件拷贝到一个远程位置(比如备份服务器)。
Redis 提供两种方式进行持久化:
-
RDB 持久化 (Redis DataBase):原理是将Redis在内存中的数据库记录定时保存到磁盘上,类似于快照。
-
AOF 持久化(append only file):原理是将Redis的操作日志以追加的方式写入文件,类似于mysql的binlog。优先级高
由于AOF的持久性实时性更好,即发生特殊情况导致数据丢失时,丢失的数据更少,因此是目前主流的持久化方式,不过RDB持久化仍然有其用武之地。
RDB模式
RDB(Redis DataBase):基于时间的快照,其默认只保留当前最新的一次快照,特点是执行速度比较快,缺点是可能会丢失从上次快照到当前时间点之间未做快照的数据。
RDB持久化是指在指定的时间间隔内将内存中当前进程中的数据生成快照保存到硬盘(因此也称作快照持久化),用二进制压缩存储,保存的文件后缀是rdb;当Redis重新启动时,可以读取快照文件恢复数据。
实现RDB方式
-
save:同步,会阻塞其它命令,不推荐使用
-
bgsave:异步后台执行,不影响其它命令的执行
-
自动:制定规则,自动执行
触发条件
RDB持久化的触发分为手动触发和自动触发两种。
- 手动触发
save命令和bgsave命令都可以生成RDB文件。
- 自动触发
在自动触发RDB持久化时,Redis 也会选择bgsave而不是save来进行持久化。
自动触发最常见的情况是在配置文件中通过 save m n 指定当m秒内发生n次变化时,会触发bgsave
点击查看代码
//自动触发,两个条件 m 和 n 都要满足
save 900 1 //900s内修改了1个key即触发保存RDB
save 300 10 //300s内修改了10个key即触发保存RDB
save 60 10000 //60s内修改了10000个key即触发保存RDBdir /apps/redis/run //指定RDB文件和AOF文件所在目录
dbfilename dump.rdb //指定RDB文件名
stop-writes-on-bgsave-error yes //默认为yes时,可能会因空间满等原因快照无法保存出错时,会禁止redis写入操作,生产建议为no
rdbcompression yes //是否开启RDB文件压缩
rdbchecksum yes //是否对备份文件开启RC64校验,默认是开启
bgsave实现快照的具体过程
1.Redis父进程首先判断:当前是否在执行save,或bgsave/bgrewriteaof的子进程,如果在执行则bgsave命令直接返回。bgsave/bgrewriteaof 的子进程不能同时执行,主要是基于性能方面的考虑:两个并发的子进程同时执行大量的磁盘写操作,可能引起严重的性能问题。
2.父进程执行fork操作创建子进程,这个过程中父进程是阻塞的,Redis不能执行来自客户端的任何命令
3.父进程fork后,bgsave 命令返回 "Background saving started" 信息并不再阻塞父进程,并可以响应其他命令
4.子进程创建RDB文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行替换
5.子进程发送信号给父进程表示完成,父进程更新统计信息
AOF 模式
AOF:AppendOnylFile,按照操作顺序依次将操作追加到指定的日志文件末尾。
同时启用RDB和AOF,进行恢复时,默认AOF文件优先级高于RDB文件,即会使用AOF文件进行恢复。
注意: AOF 模式默认是关闭的,第一次开启AOF后,并重启服务生效后,会因为AOF的优先级高于RDB,而先恢复AOF文件,AOF默认没有数据文件存在,从而导致所有数据丢失
AOF相关配置
点击查看代码
appendonly yes //开启AOF
appendfilename "appendonly.aof" //指定AOF文件名称
aof-load-truncated yes //是否忽略最后一条可能存在问题的指令//保存规则
appendfsync everysec //aof持久化策略的配置
//no表示由操作系统保证数据同步到磁盘,Linux的默认fsync策略是30秒,最多会丢失30s的数据
//always表示每次写入都执行fsync,以保证数据同步到磁盘,安全性高,性能较差
//everysec表示每秒执行一次fsync,可能会导致丢失这1s数据,此为默认值,也生产建议值//重写规则 rewrite相关
no-appendfsync-on-rewrite yes //在aof rewrite期间,是否对aof新记录的append暂缓使用文件同步策略,主要考虑磁盘IO开支和请求阻塞时间
auto-aof-rewrite-percentage 100 //当Aof log增长超过指定百分比例时,重写AOF文件,设置为0表示不自动重写Aof日志,重写是为了使aof体积保持最小,但是还可以确保保存最完整的数据
auto-aof-rewrite-min-size 64mb //触发aof rewrite的最小文件大小
aof-load-truncated yes //是否加载由于某些原因导致的末尾异常的AOF文件(主进程被kill/断电等),建议yes
AOF重写机制
随着时间流逝,Redis服务器执行的写命令越来越多,AOF文件也会越来越大;过大的AOF文件不仅会影响服务器的正常运行,也会导致数据恢复需要的时间过长。
文件重写是指定期重写AOF文件,减小AOF文件的体积。需要注意的是,AOF重写是把Redis进程内的数据转化为写命令,同步到新的AOF文件;不会对旧的AOF文件进行任何读取、写入操作!
关于文件重写需要注意的另一点是:对于AOF持久化来说,文件重写虽然是强烈推荐的,但并不是必须的;即使没有文件重写,数据也可以被持久化并在Redis启动的时候导入;因此在一些现实中,会关闭自动的文件重写,然后通过定时任务在每天的某一时刻定时执行。
文件重写的流程:
-
执行重写操作的时候,父进程会开启一个子进程
-
这个子进程会分析AOF文件,删除一些重复过期的数据,将这些写入 重写的缓存区,然后形成一个新的aof临时文件
-
同时也有新的数据写入,会将新写入的数据放入aof缓存区
-
最后将临时文件和新写入的数据合并到旧的aof文件中
关于文件重写的流程,有两点需要特别注意:(1)重写由父进程fork子进程进行;(2)重写期间Redis执行的写命令,需要追加到新的AOF文件中,为此Redis引入了aof_rewrite_buf缓存。
RDB和AOF对比
RDB和AOF的选择
-
如果主要充当缓存功能,或者可以承受数分钟数据的丢失,通常生产环境一般只需启用RDB即可,此也是默认值
-
如果数据需要持久保存,一点不能丢失,可以选择同时开启RDB和AOF
-
一般不建议只开启AOF
RDB和AOF的优缺点
-
RDB持久化
-
优点:RDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快很多。当然,与AOF相比,RDB最重要的优点之一是对性能的影响相对较小。
-
缺点:RDB文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此AOF持久化成为主流。此外,RDB文件需要满足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)。
-
对于RDB持久化,一方面是bgsave在进行fork操作时Redis主进程会阻塞,另一方面,子进程向硬盘写数据也会带来IO压力。
-
AOF持久化
-
与RDB持久化相对应,AOF的优点在于支持秒级持久化、兼容性好,缺点是文件大、恢复速度慢、对性能影响大。
-
对于AOF持久化,向硬盘写数据的频率大大提高(everysec策略下为秒级),IO压力更大,甚至可能造成AOF追加阻塞问题。
-
AOF文件的重写与RDB的bgsave类似,会有fork时的阻塞和子进程的IO压力问题。相对来说,由于AOF向硬盘中写数据的频率更高,因此对 Redis主进程性能的影响会更大。
六、Redis相关命令
命令 | 作用 |
---|---|
info | 显示当前节点redis运行状态信息 |
select | 切换数据库,相当于在MySQL的 USE DBNAME 指令(0-15 共16个库) |
keys | 查看当前库下的所有key,慎用!!! |
mset | 一次性设置多个key**** |
bgsave | 手动在后台执行RDB持久化操作**** |
dbsize | 返回当前库下的所有key 数量**** |
flushdb | 强制清空当前库中的所有key,此命令慎用 |
flushall | 强制清空当前redis服务器所有数据库中的所有key,即删除所有数据,此命令慎用! |
shutdown | 停止所有客户端 |
七、Redis数据类型
-
字符型(string): 普通字符串
-
哈希(hash): 键值对的 键值对
-
列表 (linked lists): 类似于 数组
-
集合(set): 无序
-
有序集合(sorted set): 排行榜
字符串string
字符串是所有编程语言中最常见的和最常用的数据类型,而且也是redis最基本的数据类型之一,而且redis 中所有的 key 的类型都是字符串。常用于保存 Session 信息场景,此数据类型比较常用。
点击查看代码
TYPE key名称 //判断数据类型
2.列表list
列表是一个双向可读写的管道,其头部是左侧,尾部是右侧,一个列表最多可以包含2^32-1(4294967295)个元素,下标 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,元素值可以重复,常用于存入日志等场景,此数据类型比较常用。
特点:
- 有序
- 可重复
- 左右都可以操作
命令 | 解释 | 例子 |
---|---|---|
lpush | 从左边添加数据 | 例子:lpush name zhou wu zheng wang |
rpush | 从右边添加数据 | 例子: rpush car benz bmw |
llen | 获取列表长度 | 例子: llen 列表名称 |
lindex | 获取单个元数 | 例子: lindex name 0 ; lindex name -1 |
lrange | 获取多个元素 | 例子: lrange name 0 3 第1个到第三个元素 |
lset | 修改列表元素 | 例子: lset name 2 feng 将name的第二个元素改为feng |
lpop | 删除列表元素 | 例子: lpop name 删除左边第一个 |
rpop | 删除列表元素 | 例子: rpop name 删除右边第一个 |
ltrim | 对列表修剪 | 例子: ltrim name 1 2 只留下编号为 1 2 的文件 |
del删除列表 | 例子:del name |
3.集合set
Set 是 String 类型的无序集合,集合中的成员是唯一的,这就意味着集合中不能出现重复的数据,可以在两个不同的集合中对数据进行对比并取值,常用于取值判断,统计,交集等场景,例如: 实现共同的朋友,微信好友,qq好友
集合特点:
- 无序
- 无重复
- 集合间操作
4.有序集合sorted set
Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员,不同的是每个元素都会关联一个double(双精度浮点型)类型的分数,redis正是通过该分数来为集合中的成员进行从小到大的排序,有序集合的成员是唯一的,但分数(score)却可以重复,集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1), 集合中最大的成员数为 2^32 - 1 (4294967295, 每个集合可存储40多亿个成员),经常用于排行榜的场景。
有序集合特点:
- 有序
- 无重复元素
- 每个元素是由score和value组成
- score 可以重复
- value 不可以重复
5.哈希hash
hash 即字典, 是一个string类型的字段(field)和值(value)的映射表,Redis 中每个 hash 可以存储 2^32 -1 键值对,类似于字典,存放了多个k/v 对,hash特别适合用于存储对象场景。
八、消息队列
消息队列的两种模式:
- 生产者/消费者模式
- 发布者/订阅者模式