Redis配置、优化以及相命令

672 阅读36分钟

一:redis 概述

1.1 redis 简介

Redis (远程字典服务器) 是一个开源的、使用c语言编写的NoSQL数据库。

Redis基于内存运行并支持持久化,采用key-value (键值对)的存储形式,是目前分布式架构中不可或缺的一环。

Redis服务器程序是单进程模型,也就是在一台服务器上可以同时启动多个Redis进程, Redis的实际处理速度则是完全依靠于主进程的执行效率。若在服务器上只运行一个Redis进程,当多个客户端同时访问时,服务器的处理能力是会有一定程度的下降;若在同一台服务器上开启多个Redis进程, Redis在提高并发处理能力的同时会给服务器的CPU造成很大压力。即:在实际生产环境中,需要根据实际的需求来决定开启多少个Redis进程。若对高并发要求更高一些,可能会考虑在同一台服务器上开启多个进程。若CPU资源比较紧张,采用单进程即可。

redis 在6.0 之前,都是单线程。一个进程中只有一个线程

1.2 redis 的优点

  • 具有极高的数据读写速度: (数据读取的速度最高可达到11000次/s,数据写入速度最高可达到81000次/s.

  • 支持丰富的数据类型: 支持key-value,strings,lists,hashes,sets以及sorted sets等数据类型

  • 支持数据的持久化: 可以将内存中的数据保存在磁盘中,重启的时候可以在加载进行使用

  • 原子性: redis 所有的操作都是原子性的。

  • 支持数据备份: 及master-slave模式的数据备份

1.3 redis的应用场景

redis 作为基于内存运行的数据库,缓存是其最常应用的场景之一。除此之外,redis常见应用场景还包括获取最新N个数据的操作,排行榜类应用,计数器应用,存储关系,实时分析系统,日志记录等。

1.4 redis 为什么读写速度快

  1. redis 是一款纯内存结构,避免了磁盘 I/O等耗时操作

  2. redis 命令处理的核心模块是单线程,减少了锁竞争,以及频繁创建线程和销毁线程的代价,减少了线程上下文切换的消耗

  3. 采用了I/O多路复用机制,大大提升了并发效率。

1.5 关系型数据库

  • 关系型数据库是一个结构化的数据库,创建在关系模型(二维表格模型)基础上,一般面向与记录。

  • SQL语句(标准数据查询语句)就是一种基于关系型数据库的语言,用于执行对关系型数据库中数据的检索和操作。

  • 主流的关系型数据库包括 Oracle ; MySQL ; SQL Server ; Microsoft Access ; DB2 ; PostgreSQL

以上数据库在使用共的时候必须先建库建表,设计表结构,然后存储数据的时候按照表结构去存,如果数据与表结构不匹配,就会存储失败。

1.6 非关系型数据库

  • NoSQL(NoSQL = Not Only SQL),意思是“不仅仅是SQL”,是非关系型数据库的总称

  • 除了主流的关系型数据库外的数据库,都认为是非关系型

  • 不需要预先建库建表定义数据存储表结构,每条记录可以有不同的数据类型和字段个数(如微信群聊中的文字和图片,视频,音乐等)

  • 主流的NoSQL数据库有 Redis ; MongoDB ,Hbase ;Memcached;CouchDB 等

1.7 关系型数据库和非关系型数据库的区别

1.7.1 数据的存储方式不同

  • 关系型和非关系型数据库的主要差异是数据的存储方式。关系型数据库天然就是表格式的,因此存储在数据表的行和列中。数据表可以彼此关联写作存储,也很容易提取数据。

  • 与关系型数据库相反,非关系型数据库不适合存储在数据表的行和列中,而是大块组合在一起。非关系数据库通常存储在数据集中,就像文档,键值对或者图结构。

数据及其特性是选择数据存储和提取方式 的首要影响因素

1.7.2 扩展方式不同

SQL和NoSQL数据库最大的差别可能是在扩展方式上,要支持日益增长的欲求当然要扩展

  • 要支持更多并发量,SQL数据库是纵向扩展,也就是说提高梳理能力,使用速度更快的计算机,这样处理相同的数据集就更快了。因为数据集存储在关系表中,操作的性能瓶颈可能涉及到多个表,这都需要通过提高计算机性能来克服。虽然SQL数据有很大扩展空间,但是最终肯定会达到纵向扩展的上限

  • 而NoSQL数据库是横向扩展的。因为非关系型数据存储天然就是分布式的,NoSQL数据库的扩展可以通过给资源池添加更多的普通的数据库服务器(节点)来分担负载

1.7.3 对事务性的支持不同

  • 如果数据操作需要高事务陷阱或者复杂数据查询需要控制执行计划,那么传统的SQL数据库从性能和稳定性方面考虑是最佳选择。SQL数据库支持对数据原子性细粒度控制,并且易于回滚事务。

  • 翠然NoSQL数据库也可以使用事务操作,但是稳定性方面没法和关系型数据库比较,所以他们真正的闪亮的价值是在操作的扩展性和大数据量处理方面

1.8 非关系型数据库产生背景

可用于应对Web2.0纯动态网站类型的三高问题

  1. High performance ——对数据库高并发读写需求
  2. Huge Storage ——对海量数据高效存储与访问需求
  3. High Scalability && High Availability ——对数据库高可扩展性与高可用性需求

关系型数据库和非关系型数据库都有各自的特点与应用场景,两者紧密结合将会个Web2.0的数据库发展带来新的思路。让关系数据库关注在关系上,非关系型数据库关注在存储上。例如,在读写分离的MySQL数据库环境中,可以把经常访问的数据存储在非关系型数据库中,提升访问速度。

二、Redis安装部署的操作步骤

1、关闭防火墙和SElinux

systemctl stop firewalld
setenforce 0

2、安装gcc gcc-c++ 编译器

yum install -y gcc gcc-c++ make 

3、将redis-5.0.7.tar.gz压缩包上传到/opt目录中,解压,并编译安装

tar zxvf redis-5.0.7.tar.gz -C /opt/
 
cd /opt/redis-5.0.7/
make
make PREFIX=/usr/local/redis install

由于Redis源码包中直接提供了Makefile文件,所以在解压完软件包后,不用先执行./configure进行配置,可直接执行make与make install命令进行安装

4、执行软件包提供的installserver.sh脚本文件设置Redis服务所需要的相关配置文件

cd /opt/redis-5.0.7/utils
./install_server.sh
......
#一直回车.
Please select the redis executable path [/usr/local/bin/redis-server]
/usr/local/redis/bin/redis-server
#需要手动修改为/usr/local/redis/bin/redis-server 注意要一次性正确输入
 
Selected config:
Port : 6379 #默认侦听端口为6379
Config file : /etc/redis/6379.conf  #配置文件路径
Log file : /var/log/redis_6379.log  #日志文件路径
Data dir : /var/lib/redis/6379  #数据文件路径
Executable : /usr/local/redis/bin/redis-server  #可执行文件路径
Cli Executable : /usr/local/bin/redis-cli   #客户端命令工具  

5、把redis的可执行程序文件放入路径环境变量的目录中便于系统识别

ln -s /usr/local/redis/bin/* /usr/local/bin/
 
#当install_server.sh 脚本运行完毕,Redis 服务就已经启动,默认侦听端口为6379
netstat -natp | grep redis 

6、Redis服务控制

/etc/init.d/redis_6379 stop
#停止
/etc/init.d/redis_6379 start
#启动
/etc/init.d/redis_6379 restart
#重启
/etc/init.d/redis_6379 status
#状态 
chmod +x /etc/init.d/redis_6379                                #加入全局系统环境,使用systemctl命令管理
 
chkconfig --add /etc/init.d/redis_6379    
 
systemctl start redis_6379.service  

7、修改配置/etc/redis/6379.conf参数

vim /etc/redis/6379.conf
bind 127.0.0.1 192.168.10.22
#70行,添加监听的主机地址
port 6379
#93行,Redis默认的监听端口
daemonize yes
#137行,启用守护进程
pidfile /var/run/redis_6379.pid
#159行,指定PID文件
loglevel notice
#167行,日志级别
logfile /var/log/redis_6379.log
#172行,指定日志文件
 
/etc/init.d/redis_6379 restart

三:redis的命令工具

3.1 redis的bin目录下可执行文件

[root@mysql1 ~]# cd /usr/local/redis/bin/
[root@mysql1 bin]# ll
总用量 32768
-rwxr-xr-x 1 root root 4366224 9月  14 23:09 redis-benchmark
-rwxr-xr-x 1 root root 8125848 9月  14 23:09 redis-check-aof
-rwxr-xr-x 1 root root 8125848 9月  14 23:09 redis-check-rdb
-rwxr-xr-x 1 root root 4807408 9月  14 23:09 redis-cli
lrwxrwxrwx 1 root root      12 9月  14 23:09 redis-sentinel -> redis-server
-rwxr-xr-x 1 root root 8125848 9月  14 23:09 redis-server

redis 的bin目录下一共有6个文件。除去一个redis-sentinel 是redis-server的软连接外,其余的5个都是可执行文件

  • redis-server: 用于启动redis的工具

  • redis-benchmark: 用于检测redis在本机的运行效率

  • redis-check-aof: 修复AOF持久化文件

  • redis-check-rdb:修复RDB持久化文件

  • redis-cli:redis命令行工具

3.2 redis-cli 命令行工具

语法:  redis-cli -h host -p port -a password

选项释义
-h指定远程主机
-p指定redsi服务的端口号
-a指定密码。未设置数据库面,可以省略-a选项

如果不添加热河选项,则表示使用127.0.0.1:6379 连接本机上的redis数据库

#进入192.168.10.22主机的redis数据库,连接端口为6379
[root@mysql1 ~]# redis-cli -h 192.168.10.22 -p 6379
192.168.10.22:6379>    #当前连接提示符

#默认连接本机127.0.0.1的6379端口
[root@mysql1 ~]# redis-cli
127.0.0.1:6379>

3.3 redis-benchmark 测试工具

redis-benchmark 工具是官方自带的redsi性能测试工具。可以有效的测试redis服务的性能。

语法: redis-benchmark [选项] [选项值]

选项释义
-h指定服务器主机名
-p指定服务器端口
-s指定服务器socket
-c指定并发连接数
-n指定请求数
-d以字节的形式指定 SET/GET值的数据大小
-k1=keep alive , 0=reconnect
-rSET/GET/INCR 使用随机key,SADD使用随机值
-p通过管道传输请求
-q强制退出redis,仅显示query/sec值
--csv以CSV格式输出
-l(小写的L)生成循环,永久执行删除
-t仅运行以逗号分隔的测试命令列表
-I(大写的 i )Idle模式。仅打开N个idle连接并等待
#向ip为192.168.10.22 ,端口为6379的redis服务器发送100 个并发连接与100000个请求,测试性能
[root@mysql1 ~]# redis-benchmark  -h 192.168.10.22 -p 6379 -c 100 -n 100000


#测试存取大小为 100 字节的数据包的 性能
[root@mysql1 ~]# redis-benchmark -h 192.168.10.22 -p 6379 -q -d 100


#测试本机上Redis 服务正在进行set与;lpush操作时的性能
[root@mysql1 ~]# redis-benchmark  -t set,lpush -n 100000 -q

四 redis 数据库操作

4.1 set 存放数据,get获取数据

格式

set 存放数据:set key value

get 存放数据: get key

#设置 键 boss,值Wiewanglei
127.0.0.1:6379> set boss wanglei
OK

#获取 键boss的值
127.0.0.1:6379> get boss
"wanglei"

4.2 keys 查看键值列表

keys 命令可以获取符合规则的价值列表,通常情况可以结合 * 、? 等选项来使用


*:  匹配任意字符任意次数

?: 匹配任意字符一次


keys * 查看当前数据库中所有键

keys a* 查看当前数据库中所有以a 开头的数据

keys b? 查看当前数据库中所有b开头后面包含任意一位的数据

keys b?? 查看当前数据库中所有b 开头后面包含任意两位的数据

#先创建一下几个键值对
set a1 1
set a2 2
set a3 3
set b1 4
set b5 5
set b22 5

#查看当前数据库中所有键
127.0.0.1:6379> keys *
1) "boss"
2) "b1"
3) "a1"
4) "b22"
5) "a2"
6) "b5"
7) "a3"

#查看当前数据库中所有以a 开头的键
127.0.0.1:6379> keys  a*
1) "a1"
2) "a2"
3) "a3"

#查看b开头,后面包含任意一位的数据
127.0.0.1:6379> keys  b?
1) "b1"
2) "b5"

#查看b 开头,后面包含任意两位位的数据
127.0.0.1:6379> keys  b??
1) "b22"

4.3 exists , del ,type命令

exists命令可以判断键值是否存在。

  • existis key_name

    • 返回1 表示该键存在'
    • 返回0 表示改键不存在

del命令可以删除当前数据库的指定key

  • del key_name

    • 返回值表示删除键的数量

tyep命令可以获取key 对应的value 值类型

  • type key_name

    • 返回的值表示键的类型

#查看 boss键是否存在
127.0.0.1:6379> EXISTS boss
#返回1表示 boss键存在
(integer) 1

#查看键 hello是否存在
127.0.0.1:6379> EXISTS hello
#返回 0 表示不存在
(integer) 0



#删除键b5
127.0.0.1:6379> del b5
#返回值表示删除的键的数量
(integer) 1

#删除a1,a2键
127.0.0.1:6379> del a1 a2 
#返回2,表示删除了2个
(integer) 2

#c1,d1键不存在,所以命令执行后,返回0,表示删除了0个
127.0.0.1:6379> del c1 d1 
(integer) 0


#查看boss键的值类型(redis默认值类型是string)
127.0.0.1:6379> type boss
#string表示字符类型
string

#查看b22键的值类型
127.0.0.1:6379> type b22
string

4.4 rename,renamex重命名

rename 命令对已有的key进行重命名(覆盖)

renamex 命令的作用是对key 进行重命名,并检测新名是否存在,如果目标key存在,则不进行重命名(不覆盖)

使用rename 命令经行重命名时,无论目标key是否存在都进行重命名,且源key的值会覆盖目标key的值。在实际使用过程 中,建议先用exists 命令查看目标key是否存在,然后再决定是否执行rename 命令,以避免覆盖重要数据

格式:

rename或者renamex 源key_name 目标key_name

127.0.0.1:6379> keys *
1) "boss"
2) "b1"
3) "a1"
4) "a2"
5) "b22"
6) "a3"

#当前a1 值为“1”
127.0.0.1:6379> get a1
"1"
#将a1 重命名为 a11
127.0.0.1:6379> rename a1 a11
OK
#a11有值 "1",而a1 键则没有了
127.0.0.1:6379> get a11
"1"
127.0.0.1:6379> exists a1
(integer) 0

#当前b1键存在,且值为 ”4“
127.0.0.1:6379> get b1
"4"
# 将 键a11 重命名为b1
127.0.0.1:6379> rename a11 b1
OK
#查看b1 键的值,发现值被a11的值覆盖
127.0.0.1:6379> get b1
"1"
#原键 a11 不再存在
127.0.0.1:6379> exists a11
(integer) 0


#使用 renamex 将键 b1 重命名为 b11
127.0.0.1:6379> RENAMENX b1 b11
(integer) 1
#键b11 存在,值为”1“
127.0.0.1:6379> get b11
"1"

#当前键 b22 存在,且值为”5“
127.0.0.1:6379> get b22
"5"
#使用 renamex 将b11 键重命名为b22
127.0.0.1:6379> RENAMENX b11 b22
#可以从返回值为0看出失败了
(integer) 0
#查看键b22 和b11,都存在,且值没有改变,renamex重命名操作没有执行成功
127.0.0.1:6379> get b22
"5"
127.0.0.1:6379> get b11
"1"

4.5 dbsize统计key个数 

dbsize 命令的作用是查看当前数据库中key的数目,返回值表示key的数目

#查看所有key,可以看出一共有5个
127.0.0.1:6379> keys *
1) "boss"
2) "b11"
3) "b22"
4) "a2"
5) "a3"

#dbsize统计当前数据库的key个数,返回5表示有5个
127.0.0.1:6379> dbsize
(integer) 5

4.6 设置,查看,验证通过密码

设置密码: config set requirepass 密码

  • 一旦设置密码,必须先验证通过密码,否则所有操作不可用

查看密码: config get requirepass


验证通过密码: auth 密码

  • 退出redis数据库后,重连失效,要再次验证

  • 在连接数据库时,使用 -a 选项跟上密码可以不用auth验证

#设置密码abc123
127.0.0.1:6379> config set requirepass abc123
OK
#当没有验证通过时,命令不可用
127.0.0.1:6379> keys *
(error) NOAUTH Authentication required.

--------------------------

#验证通过密码
127.0.0.1:6379> auth  abc123
OK
#此时,命令可以使用
127.0.0.1:6379> keys *
1) "boss"
2) "b11"
3) "b22"
4) "a2"
5) "a3"

----------------------------------------------

#获取密码
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) "abc123"

-------------------------------------

#退出redis 数据库
127.0.0.1:6379> exit

#重新进入redis数据库 
[root@host103 ~]# redis-cli 

#再次使用命令,报错。因为auth验证通过,在退出数据库后失效
127.0.0.1:6379> keys
(error) ERR wrong number of arguments for 'keys' command
#重新使用auth 命令进行密码验证后,命令可用
127.0.0.1:6379> auth abc123
OK
127.0.0.1:6379> keys *
1) "boss"
2) "b11"
3) "b22"
4) "a2"
5) "a3"

------------------------------

#退出数据库
127.0.0.1:6379> exit

#在连接数据库时,使用 -a 选项指定密码,则可以不用auth验证
[root@mysql1 ~]# redis-cli  -a abc123
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
#在没有使用auth 命令验证的情况下,也可以正常使用数据库命令
127.0.0.1:6379> keys *
1) "boss"
2) "b11"
3) "b22"
4) "a2"
5) "a3"


--------------------------
#将密码设置为空
127.0.0.1:6379> config set  requirepass ''
OK
#退出连接后再进入数据库
[root@mysql1 ~]# redis-cli  
#此时也可以正常使用命令了
127.0.0.1:6379> set a123 123
OK

4.7 redis 多数据库常用命令

redis 支持多数据库,默认情况下包含16 个数据库,数据库名称是用数字0-15来依次命名的。

多数据库相互独立,互不干扰

4.7.1多数据库之间的切换

命令格式:  select 序号

使用redis-cli连接redis数据库后,默认使用的是0号数据库.

除了0号数据库,其余数据库会在提示符后面使用 [序号] 标明

#切换到 10 号数据库
127.0.0.1:6379> select 10
OK

#当前提示符后面有[10],表明是10号数据库
#切换到15号数据库
127.0.0.1:6379[10]> select 15
OK

#当前提示符后面有[15],表明是15号数据库
#切换到0号数据库
127.0.0.1:6379[15]> select 0
OK

#此时,0号数据库没有标识
#切换到16号数据库(没有这个序号的数据库)
127.0.0.1:6379> select 16
#报错提示,超出范围
(error) ERR DB index is out of range

4.7.2 多数据库之间移动数据

格式:  move 键值 序号

#再当前的0 号库,设置 k1 键,值为”100“
127.0.0.1:6379> set k1 100
OK
#当前可以获取到k1键的值
127.0.0.1:6379> get k1
"100"

#切换到 10 号库
127.0.0.1:6379> select 10
OK
#查看发现 k1 键不存在,因为多数据库相互独立
127.0.0.1:6379[10]> EXISTS k1
(integer) 0

-------------

#切换会 0号库
127.0.0.1:6379[10]> SELECT 0
OK

#将 当前库中的 k1 键 移动到 10 号库
127.0.0.1:6379> MOVE k1 10
(integer) 1
#当前库查看,k1 键不存在
127.0.0.1:6379> EXISTS k1
(integer) 0

#切换到10 号库
127.0.0.1:6379> SELECT 10
OK

#k1键存在,且值为"100"
127.0.0.1:6379[10]> EXISTS k1
(integer) 1
127.0.0.1:6379[10]> GET k1
"100"

4.7.3 清空数据库库

flushdb 清空当前数据库数据

flushall 清空所有数据库数据

#切换到 15 号库,创建键 k222,值为"2222"
127.0.0.1:6379> select 15
OK
127.0.0.1:6379[15]> set k222 2222
OK
127.0.0.1:6379[15]> keys *
1) "k222"

#切换到10号库,当前10号库有键 k1
127.0.0.1:6379[15]> select 10
OK
127.0.0.1:6379[10]> keys *
1) "k1"

#使用flushdb 命令,清空当前库数据
127.0.0.1:6379[10]> FLUSHDB 
OK
#当前10号库没有数据
127.0.0.1:6379[10]> keys *
(empty list or set)

#切换到15号库和0号库查看,数据都存在。flushdb命令没有影响其他库
127.0.0.1:6379[10]> select 15
OK
127.0.0.1:6379[15]> keys *
1) "k222"
127.0.0.1:6379[15]> select 0
OK
127.0.0.1:6379> keys *
1) "boss"
2) "b11"
3) "b22"
4) "a2"
5) "a3"

-------------------------------------------

#在 0 号库执行 flushall 命令,清空所有库的数据
127.0.0.1:6379> flushall 
OK
#查看,当前库数据为空
127.0.0.1:6379> keys *
(empty list or set)

#切换到15号库查看,数据也为空。flushall 命令影响到了所有的库
127.0.0.1:6379> select 15
OK
127.0.0.1:6379[15]> keys *
(empty list or set)

五:redis的性能管理

5.1 查看redis的内存

可以进入数据库中查看,也可以在linux 命令行中直接查看

进入数据库执行info memory 查看:

[root@mysql1 ~]# redis-cli   
127.0.0.1:6379> info memory

直接在linux命令行查看

复制[root@mysql1 ~]# redis-cli info memory

查询到的信息详解

指标含义
used_memory由 Redis 分配器分配的内存总量,包含了redis进程内部的开销和数据占用的内存,以字节(byte)为单位,即当前redis使用内存大小。
used_memory_human已更直观的单位展示分配的内存总量。
used_memory_rss向操作系统申请的内存大小,与 top 、 ps等命令的输出一致,即redis使用的物理内存大小。
used_memory_rss_human已更直观的单位展示向操作系统申请的内存大小。
used_memory_peakredis的内存消耗峰值(以字节为单位),即历史使用记录中redis使用内存峰值。
used_memory_peak_human以更直观的格式返回redis的内存消耗峰值
used_memory_peak_perc使用内存达到峰值内存的百分比,used_memory/ used_memory_peak) 100%,即当前redis使用内存/历史使用记录中redis使用内存峰值100%
used_memory_overheadRedis为了维护数据集的内部机制所需的内存开销,包括所有客户端输出缓冲区、查询缓冲区、AOF重写缓冲区和主从复制的backlog。
used_memory_startupRedis服务器启动时消耗的内存
used_memory_dataset数据实际占用的内存大小,即used_memory-used_memory_overhead
used_memory_dataset_perc数据占用的内存大小的百分比,100%*(used_memory_dataset/(used_memory-used_memory_startup))
total_system_memory整个系统内存
total_system_memory_human以更直观的格式显示整个系统内存
used_memory_luaLua脚本存储占用的内存
used_memory_lua_human以更直观的格式显示Lua脚本存储占用的内存
maxmemoryRedis实例的最大内存配置
maxmemory_human以更直观的格式显示Redis实例的最大内存配置
maxmemory_policy当达到maxmemory时的淘汰策略
mem_fragmentation_ratio碎片率,used_memory_rss/ used_memory。ratio指数>1表明有内存碎片,越大表明越多,<1表明正在使用虚拟内存,虚拟内存其实就是硬盘,性能比内存低得多,这是应该增强机器的内存以提高性能。一般来说,mem_fragmentation_ratio的数值在1 ~ 1.5之间是比较健康的。详解
mem_allocator内存分配器
active_defrag_running表示没有活动的defrag任务正在运行,1表示有活动的defrag任务正在运行(defrag:表示内存碎片整理)详解
lazyfree_pending_objects0表示不存在延迟释放的挂起对象

5.2 内存碎片率

查看Redis内存使用

    127.0.0.1:6379> info memory

----内存碎片率 --------

操作系统分配的内存值used_memory_rss除以Redis使用的内存值used_memoryit算得出

内存碎片是由操作系统低效的分配/回收物理内存导致的(不连续的物理内存分配)

跟踪内存碎片率对理解Redis实例的资源性能是非常重要的:·

  • 内存碎片率稍大于1是合理的,这个值表示内存碎片率比较低·

  • 内存碎片率超过1.5,说明Redis消耗了实际需要物理内存的150%,其中50%是内存碎片率。需要在redis-cli工具上输入shutdown save命令,并重启Redis服务器。

  • 内存碎片率低于1的,说明Redis内存分配超出了物理内存,操作系统正在进行内存交换。需要增加可用物理内存或减少Redis内存占用。

5.3 内存使用率

----内存使用率----

redis实例的内存使用率超过可用最大内存,操作系统将开始进行内存与swap空间交换。

避免内存交换发生的方法:

  • 针对缓存数据大小选择安装Redis实例

  • 尽可能的使用Hash数据结构存储

  • 设置key的过期时间

5.4 内回收key

----内回收key--

内存清理策略,保证合理分配redis有限的内存资源。

当达到设置的最大阀值时,需选择一种key的回收策略,默认情况下回收策略是禁止删除。

配置文件中修改maxmemory-policy属性值:

vim /etc/redis/6379.conf

--598--

maxmemory-policy noeviction

策略有

  • volatile-lru:使用LRU算法从已设置过期时间的数据集合中淘汰数据(移除最近最少使用的key,针对设置了TTL的key)
  • volatile-ttl:从已设置过期时间的数据集合中挑选即将过期的数据淘汰(移除最近过期的key)
  • volatile-random:从已设置过期时间的数据集合中随机挑选数据淘汰(在设置了TTL的key里随机移除)
  • allkeys-lru:使用IRU算法从所有数据集合中淘汰数据(移除最少使用的key,针对所有的key)
  • allkeys-random:从数据集合中任意选择数据淘汰(随机移除key)
  • noeviction:禁止淘汰数据(不删除直到写满时报错)

六、Redis 高可用

在web服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)。

但是在Redis语境中,高可用的含义似乎要宽泛一些,除了保证提供正常服务(如主从分离、快速容灾技术),还需要考虑数据容量的扩展,数据安全不会丢失等。

在Redis中,实现高可用的技术主要包括持久化、主从复制、哨兵和集群,作用如下:

持久化 :持久化是最简单的高可用方法(有时甚至不被归为高可用的手段),主要作用是数据备份,即将数据存储在硬盘,保证数据不会因进程退出而丢失。

主从复制 :主从复制是高可用Redis的基础,哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。

缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。

哨兵 :在主从复制的基础上,哨兵实现了自动化的故障恢复。缺陷 :写操作无法负载均衡;存储能力受到单机的限制。

集群 : 通过集群, Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善 的高可用方案。

七、Redis持久化

1、持久化的功能 :

Redis是内存数据库,数据都是存储在内存中,为了避免服务器断电等原因导致Redis进程异常退出后数据的永久丢失,需要定期将Redis中的数据以某种形式( 数据或命令)从内存保存到硬盘;当下次Redis重启时,利用持久化文件实现数据恢复。

除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置(NFS)

2、Redis提供两种方式持久化:

• RDB持久化 : 原理是将Reids在内存中的数据库记录定时保存到磁盘上

• AOF持久化(append only file) : 原理是将Reids的操作日志以追加的方式写入文件,类似于MySQL的binlog

由于AOF持久化的实时性更好,即当进程意外退出时丢失的数据更少,因此AOF是目前主流的持久化方式,不过RDB持久化仍然有其用武之地

八、RDB持久化

RDB持久化是指在指定的时间间隔内将内存中当前进程中的数据生成快照保存到硬盘(因此也称作快照持久化),用二进制压缩存储,保存的文件后缀是rdb;当Redis重新启动时,可以读取快照文件恢复数据

1、触发条件

RDB持久化的触发分为手动触发和自动触发两种

1.1 手动触发

• save命令和bgsave命令都可以生成RDB文件

• save命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在Redis服务器阻塞期间,服务器不能处理任何命令请求

•而bgsave命令会创建一个子进程,由子进程来负责创建RDB文件,父进程 (即Redis主进程) 则继续处理请求

• bgsave命令执行过程中,只有fork 子进程时会阻塞服务器,而对于save命令,整个过程都会阻塞服务器,因此save已基本被废弃,线上环境要杜绝save的使用!!!

往往生产环境 bgsave 依然不允许轻易使用

1.2 自动触发

• 在自动触发RDB持久化时,Redis也 会选择bgsave而不是save来进行持久化

save m n

• 自动触发最常见的情况是在配置文件中通过save m n,指定当m秒内发生n次变化时,会触发bgsave

vim /etc/redis/6379.conf
--219行--以下三个save条件满足任意一个时,都会引起bgsave的调用
save 900 1 :当时间到900秒时,如果redis数据发生了至少1次变化,则执行bgsave
save 300 10 :当时间到300秒时, 如果redis数据发生了至少10次变化,则执行bgsave
save 60 10000 :当时间到60秒时,如果redis数据发生了至少10000次变化, 则执行bgsave
--242行--是否开启RDB文件压缩
rdbcompression yes
--254行--指定RDB文件名
dbfilename dump.rdb
--264行--指定RDB文件和AOF文件所在目录
dir /var/lib/redis/6379

1.3 其他自动触发机制

除了 save m n 以外,还有一些其他情况会触发bgsave:

• 在主从复制场景下,如果从节点执行全量复制操作,则主节点会执行bgsave命令,并将rdb文件发送给从节点

• 执行shutdown命令时,自动执行rdb持久化

2、执行流程

(1) Redis父进程首先判断 :当前是否在执行save,或bgsave/bgrewriteaof的子进程,如果在执行,则bgsave命令直接返回bgsave/bgrewriteaof 的子进程不能同时执行,主要是基于性能方面的考虑:两个并发的子进程同时执行大量的磁盘写操作,可能引起严重的性能问题

(2) 父进程执行fork操作创建子进程,这个过程中父进程是阻塞的,Redis不能执行来自客户端的任何命令

(3) 父进程fork后,bgsave 命令返回”Background saving started" 信息并不再阻塞父进程,并可以响应其他命令

(4) 子进程创建RDB文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换

(5) 子进程发送信号给父进程表示完成,父进程更新统计信息

img

3、启动时加载

• RDB文件的载入工作是在服务器启动时自动执行的,并没有专门的命令。但是由于A0F的优先级更高,因此当AOF开启时,Redis会优先载入AOF文件来恢复数据;只有当A0F关闭时,才会在Redis服务器启动时检测RDB文件,并自动载入。服务器载入RDB文件期间处于阻塞状态,直到载入完成为止

• Redis载入RDB文件时,会对RDB文件进行校验,如果文件损坏,则日志中会打印错误,Redis启动失败

九、AOF持久化

• RDB持久化是将进程数据写入文件,而AOF持久化,则是将Redis执行的每次写、删除命令记录到单独的日志文件中,查询操作不会记录; 当Redis重启时再次执行AOF文件中的命令来恢复数据。

• 与RDB相比,AOF的实时性更好,因此已成为主流的持久化方案

1、开启AOF

Redis服务器默认开启RDB,关闭AOF: 要开启AOF,需要在配置文件中配置:

vim /etc/redis/6379.conf
- 700行--修改, 开启AOF
appendonly yes
--704行--指定A0F文件名称
appendfilename "appendonly.aof"
--796行--是否忽略最后一条可能存在问题的指令
aof-load-truncated yes
 
/etc/init.d/redis_6379 restart

2、执行流程

由于需要记录Redis的每条写命令,因此A0F不需要触发,AOF的执行流程如下:

2.1 AOF的执行流程包括:

• 命令追加(append): 将Redis的写命令追加到缓冲区aof_ buf;

• 文件写入(write)和文件同步(sync):根据不同的同步策略将aof_buf中的内容同步到硬盘;

• 文件重写(rewrite): 定期重写AOF文件,达到压缩的目的。

① 命令追加 (append)

Redis先将写命令追加到缓冲区,而不是直接写入文件,主要是为了避免每次有写命令都直接写入硬盘,导致硬盘IO成为Redis负载的瓶颈。

命令追加的格式是Redis命令请求的协议格式,它是一种纯文本格式,具有兼容性好、可读性强、容易处理、操作简单避免二次开销等优点。在A0F文件中,除了用于指定数据库的select命令 (如select0为选中0号数据库) 是由Redis添加的,其他都是客户端发送来的写命令

② 文件写入(write) 和文件同步 (sync)

Redis 提供了多种AOF缓存区的同步文件策略,策略涉及到操作系统的write函数和fsync函数,说明如下:

为了提高文件写入效率,在现代操作系统中,当用户调用write函数将数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区被填满或超过了指定时限后,才真正将缓冲区的数据写入到硬盘里。这样的操作虽然提高了效率,但也带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失;因此系统同时提供了fsync、fdatasync等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性

AOF缓存区的同步文件策略存在三种同步方式,它们分别是:

vim ``/etc/redis/6379``.conf``---729---``● appendfsync always:``命令写入aof_buf后立即调用系统fsync操作同步到AOF文件,fsync完成后线程返回。这种情况下,每次有写命令都要同步到AOF文件,硬盘IO成为性能瓶颈,Redis只能支持大约几百TPS写入,严重降低了Redis的性能;即便是使用固态硬盘(SSD),每秒大约也只能处理几万个命令,而且会大大降低SSD的寿命。` `● appendfsync no:``命令写入aof_buf后调用系统write操作,不对AOF文件做fsync同步;同步由操作系统负责,通常同步周期为30秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证。` `● appendfsynceverysec:``命令写入aof_buf后调用系统write操作,write完成后线程返回; fsync同步文件操作由专门的线程每秒调用一次。everysec是前述两种策略的折中,是性能和数据安全性的平衡,因此是Redis的默认配置,也是我们推荐的配置。

③ 文件重写 (rewrite)

• 随着时间流逝,Redis服务器执行的写命令越来越多,AOF文件也会越来越大:过大的AOF文件不仅会影响服务器的正常运行,也会导致数据恢复需要的时间过长。

• 文件重写是指定期重写AOF文件,减小AOF文件的体积。需要注意的是,AOF重写是把Redis进程内的数据转化为写命令,同步到新的AOF文件;不会对旧的AOF文件进行任何读取、写入操作!

• 关于文件重写需要注意的另一点是:对于AOF持久化来说,文件重写虽然是强烈推荐的,但并不是必须的;即使没有文件重写,数据也可以被持久化并在Redis启动的时候导入:因此在一些实现中,会关闭自动的文件重写,然后通过定时任务在每天的某一时刻定时执行

文件重写之所以能够压缩AOF文件,原因在于:

• 过期的数据不再写入文件
• 无效的命令不再写入文件:如有些数据被重复设值(set mykey v1, set mykey v2)、有些数据被删除了(sadd myset v1, del myset) 等。
• 多条命令可以合并为一个:如sadd myset v1, sadd myset v2, sadd myset v3可以合并为sadd myset v1 v2 v3。

通过上述内容可以看出,由于重写后AOF执行的命令减少了,文件重写既可以减少文件占用的空间,也可以加快恢复速度

• 手动触发:直接调用bgrewriteaof命令,该命令的执行与bgsave有些类似:都是fork子进程进行具体的工作,且都只有在fork时阻塞

• 自动触发:通过设置auto-aof - rewrite-min-size选项和auto- aof - rewrite- percentage选项来自动执行BGREWRITEAOF

只有当auto-aof- rewrite- -min-size和auto-aof -rewrite-percentage两个选项同时满足时,才会自动触发AOF重写,即bgrewriteaof操作

vim /etc/redis/ 6379. conf
----729----
● auto-aof- rewrite-percentage 100
:当前AOF文件大小(即aof_current_size)是上次日志重写时AOF文件大小(aof_base_size)两倍时,发生BGREWRITEAOF操作
● auto-aof - rewrite-min-size 64mb
:当前A0F文件执行BGREWRITEAOF命令的最小值,避免刚开始启动Reids时由于文件尺寸较小导致频繁的BGREWRITEAOF

关于文件重写的流程,有两点需要特别注意:

♢ 重写由父进程fork子进程进行;
♢ 重写期间Redis执行的写命令,需要追加到新的AOF文件中,为此Redis引入了aof_ rewrite_buf缓存

文件重写的流程如下:

(1) Redis父进程首先判断当前是否存在正在执行bgsave/bgrewriteaof的子进程,如果存在则bgrewriteaof命令直接返回,如果存在bgsave命令则等bgsave执行完成后再执行

(2) 父进程执行fork操作创建子进程,这个过程中父进程是阻塞的

(3.1) 父进程fork后,bgrewriteaof 命令返回"Background append only file rewrite started" 信息并不再阻塞父进程,并可以响应其他命令。Redis的所有写命令依然写入AOF缓冲区,并根据appendfsync策略同步到硬盘,保证原有A0F机制的正确

(3.2) 由于fork操作使用写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然在响应命令,因此Redis使用AOF重写缓冲区(aof_ rewrite_buf) 保存这部分数据,防止新AOF文件生成期间丢失这部分数据。也就是说,bgrewriteaof执行 期间,Redis的写 命令同时追加到aof_ buf和aof_ rewirte_ buf两个缓冲区

(4) 子进程根据内存快照,按照命令合并规则写入到新的AOF文件

(5.1) 子进程写完新的AOF文件后,向父进程发信号,父进程更新统计信息,具体可以通过info persistence查看

(5.2) 父进程把AOF重写缓冲区的数据写入到新的AOF文件,这样就保证了新AOF文件所保存的数据库状态和服务器当前状态一致

(5.3) 使用新的AOF文件替换老文件,完成AOF重写

img

3.启动时加载

• 当AOF开启时,Redis启 动时会优先载入AOF文件来恢复数据;只有当AOF关闭时,才会载入RDB文件恢复数据

• 当AOF开启,但AOF文件不存在时,即使RDB文件存在也不会加载

• Redis载入AOF文件时,会对AOF文件进行校验,如果文件损坏,则日志中会打印错误,Redis启动失败。但如果是AOF文件结尾不完整 (机器突然宕机等容易导致文件尾部不完整),且aof-load- truncated参数开启,则日志中会输出警告,Redis 忽略掉AOF文件的尾部,启动成功

• aof-load-truncated参数默认是开启的

十、RDB和AOF的优缺点

1.RDB持久化

优点:
•vRDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快很多。当然,与AOF相比, RDB最 重要的优点之一是对性能的影响相对较小

缺点:
• RDB文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此AOF持久化成为主流。此外,RDB文件需要满足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)

• 对于RDB持久化,一方面是bgsave在进行fork操作时Redis主进程会阻塞,另一方面,子进程向硬盘写数据也会带来IO压力

2.AOF持久化

• 与RDB持久化相对应,AOF的优点在于支持秒级持久化、兼容性好,缺点是文件大、恢复速度慢、对性能影响大

• 对于AOF持久化,向硬盘写数据的频率大大提高(everysec策略下为秒级),IO压力更大,甚至可能造成AOF追加阻塞问题

• AOF文件的重写与RDB的bgsave类似,会有fork时的阻塞和子进程的I0压力问题。相对来说,由于AOF向硬盘中写数据的频率更高,因此对Redis主进程性能的影响会更大

总结

1.常见的关系型数据库?

oracle、MySQL、SQL Server、Microsoft Access、DB2、PostgreSQL

2.常见的非关系型数据库?

Redis、MongBD、Hbase、Memcached、ElasticSearch(索引数据库)、TSDB(时间序列数据库)

3.什么是Redis?

Redis(远程字典服务器)是一个开源的、使用c语言编写的NosQL数据库。

Redis 基于内存运行并支持持久化,采用key-value(键值对)的存储形式,是目前分布式架构中不可或的一环。

4.为什么需要Redis?

Redis 适用于数据实时性要求高、数据存储有过期和淘汰特征的、不需要持久化或者只需要保证弱一致性、逻辑简单的场景。

5.Redis如何性能测试?

使用 redis-benchmark 测试工具。

6.Redis默认数据类型:string

7.Redis为什么这么快?

  • 1、Redis是一款纯内存结构,避免了磁盘 I/O 等耗时操作。(基于内存运行)
  • 2、Redis命令处理的核心模块为单线程,减少了锁竞争,以及频繁创建线程和销毁线程的代价,减少了线程上下文切换的消耗。(单线程模型)
  • 3、采用了 I/O 多路复用机制,大大提升了并发效率。(epoll模式)

8.Redis数据库命令

1)常用名命令

set 、get: 存放、获取数据

del: 删除键

keys: 获取key,可以结合通配符 * 和 ?

exists: 判断key是否存在

type: 查看数据类型

rename和renamenx: 重命名的两种,后者会进行判断,存在则不改

dbsize: 查看当前数据库中key的数目

2)多数据库操作

select 序号 : 切换库名(16个数据库,数据库名称是用数字0-15)

move 键值 序号: 多数据库间移动数据

FLUSHDB : 清空当前数据库数据

FLUSHALL : 清空所有数据库的数据,慎用!!!