NoSQL之Redis配置与优化

发布于:2025-06-25 ⋅ 阅读:(19) ⋅ 点赞:(0)

Redis 介绍

Redis 数据库是一个非关系型数据库,在正式学习 Redis 之前,先来了解关系型数据库与非关系型数据库的概念。

关系数据库与非关系型数据库

数据库按照数据库的结构可以分为关系型数据库与其他数据库,而这些其他数据库我们将其统称为非关系型数据库。

关系型数据库

关系型数据库是一个结构化的数据库,创建在关系模型基础上,一般面向于记录。它借助于集合代数等数学概念和方法来处理数据库中的数据。关系模型就是指二维表格模型,因而一个关系型数据库就是由二维表及其之间的联系组成的一个数据组织。现实世界中,各种实体与实体之间的各种联系都可以用关系模型来表示。SQL 语句(标准数据查询语言)就是一种基于关系型数据库的语言,用于执行对关系型数据库中数据的检索和操作。
主流的关系型数据库包括 Oracle、MySQL、SQL Server、Microsoft Access、DB2 等等。

非关系型数据库

NoSQL (NoSQL = Not Only SQL),意思是 “不仅仅是 SQL”,是非关系型数据库的总称。主流的 NoSQL 数据库有 Redis、MongBD、Hbase、CoulDB 等等。以上这些非关系型数据库,他们的存储方式、存储结构以及使用的场景都是完全不同的。所以我们认为它是一个非关系型数据库的集合,而不是像关系型数据库一样,是一个统称。换言之,除了主流的关系型数据库以外的数据库,都可以认为是非关系型的。NoSQL 数据库凭借着其非关系型、分布式、开源及横向扩展等优势,被认为是下一代数据库产品。

非关系型数据库产生背景

关系型数据库已经诞生很久了,而且一直在使用。面对这样的情况,为什么还会产生 NoSQL?那么,下面就来介绍一下 NoSQL 产生的背景。
随着 Web2.0 网站的兴起,关系型数据库在应对 Web2.0 网站,特别是海量数据和高并发的 SNS(Social Networking Services,即社交网络服务)类型的 Web2.0 纯动态网站时,暴露出很多难以解决的问题,例如三高问题。

High performance—— 对数据库高并发读写需求

Web2.0 网站会根据用户的个性化信息来实时生成动态页面和提供动态信息,因此无法使用动态页面静态化技术。所以数据库的并发负载非常高,一般会达到 10000 次 /s 以上的读写请求。关系型数据库对于上万次的查询请求还是可以勉强支撑的,但出现上万次的写数据请求,硬盘 IO 就已经无法承受了。对于普通的 BBS 网站,往往也会存在高并发的写数据请求。

Huge Storage—— 对海量数据高效存储与访问需求

类似于 Facebook、Friendfeed 这样的 SNS 网站,每天会产生大量的用户动态信息。如 Friendfeed, 一个月就会产生不少于 2.5 亿条用户动态信息,对于关系型数据库来说,在一个包含 2.5 亿条记录的表中执行 SQL 查询,查询效率是非常低的。

High Scalability && High Availability—— 对数据库高可扩展性与高可

用性需求在 Web 架构中,数据库是最难进行横向扩展的。当应用系统的用户量与访问量与日俱增时,数据库是没办法像 Web 服务一样,简单地通过添加硬件和服务器节点来扩展其性能和负载能力的。尤其对于一些需要 24 小时对外提供服务的网站来说,数据库的升级与扩展往往伴随着停机维护与数据迁移,其工作量是非常庞大的。

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

数据存储方式不同 

关系型和非关系型数据库的主要差异是数据存储的方式。关系型数据天然就是表格式的,因此存储在数据表的行和列中。数据表可以彼此关联协作存储,也很容易提取数据。 与其相反,非关系型数据不适合存储在数据表的行和列中,而是大块组合在一起。非关系型数据通常存储在数据集中,就像文档、键值对或者图结构。你的数据及其特性是选择数据存储和提取方式的首要影响因素。
 

扩展方式不同 

SQL和NoSQL数据库最大的差别可能是在扩展方式上,要支持日益增长的需求当然要扩展。 要支持更多并发量,SQL数据库是纵向扩展,也就是说提高处理能力,使用速度更快速的计算机,这样处理相同的数据集就更快了。因为数据存储在关系表中,操作的性能瓶颈可能涉及很多个表,这都需要通过提高计算机性能来客服。虽然SQL数据库有很大扩展空间,但最终肯定会达到纵向扩展的上限。 而NoSQL数据库是横向扩展的。因为非关系型数据存储天然就是分布式的,NoSQL数据库的扩展可以通过给资源池添加更多普通的数据库服务器(节点)来分担负载。

对事务性的支持不同 

如果数据操作需要高事务性或者复杂数据查询需要控制执行计划,那么传统的SQL数据库从性能和稳定性方面考虑是你的最佳选择。SQL数据库支持对事务原子性细粒度控制,并且易于回滚事务。 虽然NoSQL数据库也可以使用事务操作,但稳定性方面没法和关系型数据库比较,所以它们真正闪亮的价值是在操作的扩展性和大数据量处理方面。

Redis基础介绍

Rendis介绍

Redis(RemoteDictionaryServer,远程字典型)是一个开源的、使用 C 语言编写的 NoSQL 数据库。Redis 基于内存运行并支持持久化,采用 key-value(键值对)的存储形式,是目前分布式架构中不可或缺的一环。

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

Redis 具有以下几个优点:

  • 具有极高的数据读写速度,数据读取的速度最高可达到 110000 次 /s,数据写入速度最高可达到 81000 次 /s。
  • 支持丰富的数据类型,不仅仅支持简单的 key-value 类型的数据,还支持 Strings, Lists, Hashes, Sets 及 Ordered Sets 等数据类型操作。
  • 支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  • 原子性,Redis 所有操作都是原子性的。
  • 支持数据备份,即 master-salve 模式的数据备份。

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

Redis 安装部署

Redis 的安装相对于其他服务来说比较简单 。首先需要到 Redis 官网(https://www.redis.io)下载相应的源码软件包,然后上传至 Linux 系统的服务器中进行解压、安装。本章中以 redis-4.0.9.tar.gz 为例进行 Redis 服务的安装和配置讲解。

通常情况下,在 Linux 系统中进行源码编译安装,需要先执行./configure 进行环境检查与配置,从而生成 Makefile 文件,再执行 make && make install 命令进行编译安装。而 Redis 源码包中直接提供了 Makefile 文件,所以在解压完软件包后,可直接进入解压后的软件包目录,执行 make 与 make install 命令进行安装。

[root@localhost src]# dnf -y install tar gcc make
[root@localhost src]# tar xvzf redis-4.0.9.tar.gz
[root@localhost src]# cd redis-4.0.9/
[root@localhost redis-4.0.9]# make
[root@localhost redis-4.0.9]# make PREFIX=/usr/local/redis install
[root@localhost ~]# ln -s /usr/local/redis/bin/* /usr/local/bin/

make install 只是安装了二进制文件到系统中,并没有启动脚本和配置文件。 软件包中默认提供了一个 install_server.sh 脚本文件,通过该脚本文件可以 设置 Redis 服务所需要的相关配置文件。当脚本运行完毕,Redis 服务就已经 启动,默认侦听端口为 6379。

[root@localhost redis-4.0.9]# cd utils/
[root@localhost utils]# ./install_server.sh
Welcome to the redis service installer
This script will help you easily set up a running redis server
Please select the redis port for this instance: [6379]
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf]
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log]
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379]
Selected default - /var/lib/redis/6379  //持久化
Please select the redis executable path [] /usr/local/redis/bin/redis -server
//需要手动输入
Selected config:
Port : 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/redis/bin/redis-cli  //客户端命令行工具
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
[root@localhost utils]# netstat -lnupt | grep redis
tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 5494/redis-server 

 Redis 安装完成,可通过 Redis 的服务控制脚本/etc/init.d/redis_6379 来对 Redis 服务进行控制,如停止 Redis 服务、启动 Redis 服务、重启 Redis 服务、查看 Redis 运行状态。

[root@localhost ~]# /etc/init.d/redis_6379 stop
Stopping ...
Redis stopped
[root@localhost ~]# /etc/init.d/redis_6379 start
Starting Redis server...
[root@localhost ~]# /etc/init.d/redis_6379 restart
Stopping ...
Redis stopped
Starting Redis server...
[root@localhost ~]# /etc/init.d/redis_6379 status
Redis is running (28894)

配置参数

Redis 主配置文件为 /etc/redis/6379.conf,由注释行与设置行两部分组成。与大多数 Linux 配置文件一样,注释性的文字以 “#” 开始,包含了对相关配置内容进行的说明和解释。除了注释行与空行以外的内容即为设置行。可根据生产环境的需求调整相关参数,如下:

[root@localhost ~]# vi /etc/redis/6379.conf
bind 127.0.0.1 192.168.10.161 //监听的主机地址
port 6379 //端口
daemonize yes //启用守护进程
pidfile /var/run/redis_6379.pid //指定 PID 文件

loglevel notice //日志级别
logfile /var/log/redis_6379.log //指定日志文件

[root@localhost ~]# /etc/init.d/redis_6379 restart
Stopping ...
Redis stopped
Starting Redis server...

除了上述配置参数外,Redis 主配置文件中还包含很多其它的配置参数。

参数 作用 补充说明
timeout 300 当客户端闲置多长时间后关闭连接,如果指定为 0,表示关闭该功能 - 单位是 “秒”,主要用于释放长期闲置客户端占用的连接资源;
- 若客户端有心跳保活机制(如定期发送 PING ),可避免触发该超时;
- 需结合业务场景设置,比如短连接场景可适当调低,长连接场景(如订阅业务)可设为 0 关闭
dbfilename dump.rdb 指定本地数据库文件名,默认值为 dump.rdb - 是 RDB 持久化生成快照文件的名称;
- 若修改名称,需确保 dir 参数指定目录有写入权限,且重启 Redis 后新快照会用新名称;
- 可配合 save 指令(如 save 900 1 )触发 RDB 持久化
dir /var/lib/redis/6379 指定本地数据库存放目录 - 用于存储 RDB 快照文件、AOF 重写临时文件(若开启 AOF )等;
- 需保证 Redis 进程对该目录有读写权限,否则持久化会失败;
- 生产环境建议单独挂载存储分区,避免磁盘满影响 Redis 运行
maxclients 10000 设置同一时间最大客户端连接数,默认为 10000 。Redis 可以同时打开的客户端连接数为 Redis 进程可以打开的最大文件描述符数,如果设置 maxclients 0 ,表示不限制。当客户端连接数到达限制时,Redis 会关闭新的连接并向客户端返回 max number of clients reached 错误信息 - 受系统级 “最大文件描述符限制” 约束(可通过 ulimit -n 查看 / 调整),若系统限制低于 maxclients ,实际生效以系统限制为准;
- 高并发场景需提前规划,结合业务峰值连接数、服务器资源(内存、CPU )调整;
- 需注意,Redis 自身管理连接也会占用资源,并非设置越大越好
rdbcompression yes 指定存储至本地数据库时是否压缩数据,默认为 yes ,Redis 采用 LZF 压缩,如果为了节省 CPU 资源,可以关闭该选项,但会导致数据库文件变的巨大 - LZF 压缩是 “空间换 CPU” 的典型,压缩后文件小但消耗少量 CPU ,关闭则反之;
- 若 Redis 部署在 CPU 资源紧张(如单核小内存机器)、但磁盘空间充足场景,可考虑关闭;
- 对压缩比要求极高的场景(如数据重复率低),关闭后文件膨胀可能更明显,需测试权衡

若想进一步深入,还可结合这些参数与 Redis 持久化策略(RDB、AOF )、高可用架构(哨兵、集群 )的关联逻辑拓展,比如 RDB 相关参数如何影响灾备恢复效率,maxclients 对集群节点连接数的整体规划等,能更好支撑生产环境 Redis 调优~

参数格式 作用说明 补充细节 & 实践建议
slaveof <masterip> <masterport> 当本机为从服务器时,设置主服务的 IP 地址及端口。在 Redis 启动时,从服务器会自动从主服务进行数据同步 主从切换:若主节点故障,需手动修改配置重新指定新主节点(Redis 哨兵 / 集群模式可自动实现故障转移);
数据同步:首次同步会全量复制 RDB 文件,需注意网络带宽、主节点压力;
只读特性:从节点默认只读,可通过 slave-read-only yes(默认)控制,避免从节点误写
masterauth <master-password> 当主服务设置了密码保护时,从服务连接主服务的密码 配套使用:需与主节点 requirepass 配合,确保主从认证一致;
安全加固:主从、哨兵、集群环境下,务必配置密码,防止未授权访问;
动态修改:可通过 config set masterauth <密码> 实时调整,无需重启
requirepass foobared 设置 Redis 连接密码,如果配置了连接密码,客户端在连接 Redis 时需要通过 AUTH <password> 命令提供密码,默认关闭 客户端适配:所有客户端(Redis - cli、应用程序)连接时必须携带 AUTH 指令,否则拒绝访问;
密码强度:生产环境建议设置复杂密码(字母 + 数字 + 特殊字符),避免弱密码被暴力破解;
风险点:若忘记密码,需修改配置文件重启 Redis 清除,会短暂影响服务
maxmemory <bytes> 指定 Redis 最大内存限制。Redis 在启动时会把数据加载到内存中,达到最大内存后,Redis 会先尝试清除已到期或即将到期的 Key,当此方法处理后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作 内存策略:需配合 maxmemory - policy(如 volatile - lruallkeys - lru 等)决定 Key 淘汰规则;
监控预警:通过 info memory 监控内存使用率,接近阈值(如 90% )时提前扩容或清理数据;
特殊场景:若作为纯缓存(数据可丢失),可激进设置;若存重要数据,需预留内存避免写阻塞
appendonly no 指定是否在每次更新操作后进行日志记录,Redis 在默认情况下是异步地把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 Redis 本身同步数据文件是按上面 save 条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为 no AOF 与 RDB 选择appendonly yes 开启 AOF 持久化,可与 RDB 配合使用(AOF 更实时,RDB 做全量备份);
性能影响always 刷盘策略(结合 appendfsync )会严重影响性能,一般选 everysec 平衡安全与性能;
数据恢复:AOF 文件记录操作指令,恢复时 Redis 会重新执行指令,需注意指令冗余(可通过 bgrewriteaof 重写优化)
appendfilename appendonly.aof 指定更新日志文件名,默认为 appendonly.aof 路径关联:文件名需与 dir 参数指定的目录配合,文件实际存储路径为 dir + appendfilename
重写机制:AOF 重写(bgrewriteaof )会生成新的紧凑 AOF 文件,旧文件会被替换,需确保目录有足够读写权限
appendfsync everysec 指定更新日志条件,共有 3 个可选值:
no:表示等操作系统进行数据缓存同步到磁盘(快)
always:表示每次更新操作后手动调用 fsync() 将数据写到磁盘(慢,安全)
everysec:表示每秒同步一次(折衷,默认值)
性能对比no 性能最高但丢数据风险最大(依赖系统缓存刷盘);always 最安全但吞吐量最低;everysec 是多数生产环境首选;
故障场景everysec 模式下,若机器突然断电,最多丢失 1 秒数据,需结合业务容忍度选择;
磁盘压力:高频写场景下,always 会大幅增加磁盘 IO ,可能引发性能瓶颈
activerehashing yes 指定是否激活重置哈希,默认为开启 哈希表扩容:Redis 哈希表扩容时会进行渐进式 rehash ,activerehashing 控制是否启用自动触发;
内存优化:开启后可及时释放旧哈希表内存,避免内存碎片化;
极端情况:若 Redis 频繁阻塞(如大量 Key 同时过期 + rehash ),可临时关闭观察,但不建议长期禁用
include /path/to/local.conf 指定包含其它的配置文件,可以在同一主机上多个 Redis 实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件 配置复用:适合多实例部署场景,公共配置(如密码、内存策略)写在公共文件,实例特有配置(如端口、日志路径)写在单独文件;
加载顺序include 的配置会被后续同参数覆盖,需注意配置优先级;
维护便捷:修改公共配置只需改一个文件,减少重复配置工作量

这些参数覆盖了 Redis 主从复制、安全认证、持久化、内存管理等核心功能,实际部署时,要结合业务需求(如数据安全等级、性能要求、高可用架构 )灵活组合配置,同时做好监控(内存、持久化、连接数 )和应急预案(如密码丢失、主从切换 ),保障 Redis 稳定运行~

Redis命令工具

Redis 软件提供了多个命令工具。安装 Redis 服务时,所包含的软件工具会同时被安装到系统中,在系统中可以直接使用。这些命令工具的作用分别。

  • redis-server:用于启动 Redis 的工具;
  • redis-benchmark:用于检测 Redis 在本机的运行效率;
  • redis-check-aof:修复 AOF 持久化文件;
  • redis-check-rdb:修复 RDB 持久化文件;
  • redis-cli:Redis 命令行工具。

 redis-cli 命令行工具

Redis 数据库系统也是一个典型的 C/S(客户端 / 服务器端)架构的应用,要访问 Redis 数据库需要使用专门的客户端软件。Redis 服务的客户端软件就是其自带的 redis-cli 命令行工具。使用 redis-cli 连接指定数据库,连接成功后会进入提示符为 “远程主机 IP 地址:端口号” 的数据库操作环境,例如 “127.0.0.1:6379>”。用户可以输入各种操作语句对数据库进行管理。如执行 ping 命令可以检测 Redis 服务是否启动。

[root@localhost ~]# /usr/local/redis/bin/redis-cli //连接本机 Redis 数据库
127.0.0.1:6379> ping //检测 redis 服务是否启动
PONG
127.0.0.1:6379>

在进行数据库连接操作时,可以通过选项来指定远程主机上的 Redis 数据库。命令语法为 redis-cli -h host -p port -a password,其中-h 指定远程主机、-p 指定 Redis 服务的端口号、-a 指定密码。若不添加任何选项表示连接本机上的 Redis 数据库;若未设置数据库密码可以省略 -a 选项。例如执行以下命令可连接到主机为 192.168.10.161,端口为 6379 的 Redis 数据库,并查看 Redis 服务的统计信息。若要退出数据库操作环境,执行 “exit” 或 “quit” 命令即可返回原来的 Shell 环境。

[root@localhost ~]# redis-cli -h 192.168.10.161 -p 6379
192.168.10.161:6379> info
# Server
redis_version:4.0.9
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:7f55f2c1a630cbe5
......
//省略部分内容
192.168.10.161:6379> exit
[root@localhost ~]#

在数据库操作环境中,使用 help 命令可以获取命令类型的帮助。有三种获取命令帮助的方式。

  • help @<group>:获取 <group> 中的命令列表;
  • help <command>:获取某个命令的帮助;
  • help <tab>:获取可能帮助的主题列表。
  • ping:乒乓机制,输入什么就返回什么。
[root@localhost ~]# redis-cli
127.0.0.1:6379> help @list //查看所有与 List 数据类型的相关命令
BLPOP key [key ...] timeout
summary: Remove and get the first element in a list, or block until one is available.
since: 2.0.0
BRPOP key [key ...] timeout
summary: Remove and get the last element in a list, or block until one is available.
since: 2.0.0
BRPOPLPUSH source destination timeout
......
//省略部分内容
127.0.0.1:6379> help set //查看 set 命令的命令帮助
SET key value [EX seconds] [PX milliseconds] [NX|XX]
summary: Set the string value of a key
since: 1.0.0
group: string

redis-benchmark 测试工具

redis-benchmark 是官方自带的 Redis 性能测试工具,可以有效的测试 Redis 服务的性能。基本的测试语法为 redis-benchmark [option] [option value]。常用选项。

选项 作用描述
-h 指定服务器主机名
-p 指定服务器端口
-s 指定服务器 socket
-c 指定并发连接数
-n 指定请求数
-d 以字节的形式指定 SET/GET 值的数据大小
-k 1=keep alive 0=reconnect
-r SET/GET/INCR 使用随机 key,SADD 使用随机值
-P 通过管道传输<numreq>请求
-q 强制退出 redis,仅显示 query/sec 值
--csv 以 CSV 格式输出
-l 生成循环,永久执行测试
-t 仅运行以逗号分隔的测试命令列表
-I Idle 模式,仅打开 N 个 idle 连接并等待

结合上述选项,可以针对某台 Redis 服务器进行性能检测,如执行 redis-benchmark -h 192.168.10.161 -p 6379 -c 100 -n 100000 命令即可向 IP 地址为 192.168.10.161、端口为 6379 的 Redis 服务器发送 100 个并发连接与 100000 个请求测试性能。

[root@localhost ~]# redis-benchmark -h 192.168.10.161 -p 6379 -c 100 -n 100000
...... //省略部分内容
8225.04 requests per second
====== MSET (10 keys) ======
100000 requests completed in 1.57 seconds
100 parallel clients
3 bytes payload
keep alive: 1
24.75% <= 1 milliseconds
99.02% <= 2 milliseconds
99.57% <= 3 milliseconds
99.90% <= 4 milliseconds
99.98% <= 5 milliseconds
100.00% <= 5 milliseconds
63653.72 requests per second

执行 redis-benchmark -h 192.168.10.161 -p 6379 -q -d 100 命令的作用是测试存取大小为 100 字节的数据包的性能。

redis-benchmark -h 192.168.10.161 -p 6379 -q -d 100
PING_INLINE: 88261.25 requests per second
PING_BULK: 90991.81 requests per second
SET: 83612.04 requests per second
GET: 84961.77 requests per second
INCR: 83682.01 requests per second
LPUSH: 76745.97 requests per second
RPUSH: 78247.26 requests per second
LPOP: 77519.38 requests per second
RPOP: 79691.27 requests per second
SADD: 83125.52 requests per second
SPOP: 85543.20 requests per second
LPUSH (needed to benchmark LRANGE): 78864.35 requests per second
LRANGE_100 (first 100 elements): 30931.02 requests per second
LRANGE_300 (first 300 elements): 9437.52 requests per second
LRANGE_500 (first 500 elements): 5541.39 requests per second
LRANGE_600 (first 600 elements): 3824.38 requests per second
MSET (10 keys): 64184.86 requests per second

还可以测试某些操作的性能,例如执行 redis_benchmark -t set, lpush -n 100000  - q  命令的作用是测试本机上Redis 服务在进行 set 与 lpush 操作时的性能。

[root@localhost ~]#redis-benchmark -t set,lpush -n 100000 -q
SET: 85763.29 requests per second
LPUSH: 86580.09 requests per second

 Redis 数据库常用命令

前面提到 Redis 数据库采用 key-value(键值对)的数据存储形式。所使用的命令是 set 与 get 命令。

  • set:存放数据,基本的命令格式为 set key value。
  • get:获取数据,基本的命令格式为 get key。

例如,在 Redis 的命令行模式下执行”set teacher zhanglong”,表示在当前数据库下存放一个 key 为 teacher,value 为 zhanglong 的数据,而执行 “getteacher“命令即可查看刚才存放的数据。

127.0.0.1:6379>set teacher zhanglong
OK
127.0.0.1:6379>get teacher
"zhanglong"

除了数据存储与获取命令之外,Redis 数据库还包含其它常见的数据管理命令。

 key 相关命令

在 Redis 数据库中,与 key 相关的命令主要包含以下几种。

keys

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

127.0.0.1:6379>set k1 1
OK
127.0.0.1:6379>set k2 2
OK
127.0.0.1:6379>set k3 3
OK
127.0.0.1:6379>set v1 4
OK
127.0.0.1:6379>set v5 5
OK
127.0.0.1:6379>KEYS * //查看当前数据库中所有键
1) "teacher"
2) "k1"
3) "k2"
4) "k3"
5) "v1"
6) "v5"
127.0.0.1:6379>set v22 5
OK
127.0.0.1:6379>KEYS v* //查看当前数据库中以 v 开头的数据
1) "v1"
2) "v5"
3) "v22"
127.0.0.1:6379>KEYS v? 
//查看当前数据库中以 v 开头后面包含任意一位的数据
1) "v1"
2) "v5"
127.0.0.1:6379>KEYS v?? 
//查看当前数据库中以 v 开头 v 开头后面包含任意两位的数据
1) "v22"

exists

exists 命令可以判断键值是否存在。
127.0.0.1:6379>exists teacher
// 判断 teacher 键是否存在
(integer) 1
// 表示 teacher 键是存在
127.0.0.1:6379>exists tea
(integer) 0
// 表示 tea 键不存在

del

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

127.0.0.1:6379>keys *

1)"teacher"
2)"v1"
3)"v22"
4)"k3"
5)"k1"
6)"k2"
7)"v5"
127.0.0.1:6379> del v5
(integer) 1
127.0.0.1:6379>get v5
(nil)

type

使用唐渝鹏命令可以获取 key 对应的 value 值类型。

127.0.0.1:6379>type k1

rename

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

127.0.0.1:6379>keys v*
127.0.0.1:6379>rename v22 v2
127.0.0.1:6379>keys v*
127.0.0.1:6379>get v1
127.0.0.1:6379>get v2
127.0.0.1:6379>rename v1 v2
127.0.0.1:6379>get v1
dbsize

dbsize 命令的作用是查看当前数据库中 key 的数目。

127.0.0.1:6379>dbsize
(integer) 5

 多数据库常用命令

多数据库间切换

Redis 支持多数据库,Redis 在没有任何改动的情况下默认包含 16 个数据库,数据库名称是用数字 0 - 15 来依次命名的。使用 select 命令可以进行 Redis 的多数据库之间的切换,命令格式为 select index,其中 index 表示数据库的序号。而使用 redis-cli 连接 Redis 数据库后,默认使用的是序号为 0 的数据库。使用 select 命令切换数据库后,会在前端的提示符中显示当前所在的数据库序号如 “127.0.0.1:6379 [10]” 表示当前使用的是序号为 10 的数据库。若当前使用的数据库是序号为 0 的数据库,提示符中则不显示序号,如 “127.0.0.1:6379” 表示当前使用的是序号为 0 的数据库。

127.0.0.1:6379>select 10  //切换至序号为 10 的数据库
OK
127.0.0.1:6379[10]>select 15  //切换至序号为 15 的数据库
OK
127.0.0.1:6379[15]>select 0  //切换至序号为 0 的数据库
OK
127.0.0.1:6379>

多数据库间移动数据

Redis 的多数据库在一定程度上是相对独立的,例如在数据库 0 上面存放 k1 的数据,在其它 1 - 15 的数据库上是无法查看到的。

127.0.0.1:6379>set k1 100
OK
127.0.0.1:6379>get k1
"100"
127.0.0.1:6379>select 1
OK
127.0.0.1:6379[1]>get k1
(nil)

Redis 数据库提供了一个 move 的命令,可以进行多数据库之间的数据移动。命令的基本语法格式为 “move key dbindex” 。其中 “key” 表示当前数据库的目标键,“dbindex” 表示目标数据库的序号。

127.0.0.1:6379[1]>select 0 //切换至目标数据库 0
OK
127.0.0.1:6379>get k1 //查看目标数据是否存在
"100"
127.0.0.1:6379>move k1 1 //将数据库 0 中 k1 移动到数据库 1 中
(integer) 1
127.0.0.1:6379>select 1 //切换至目标数据库 1
OK
127.0.0.1:6379[1]>get k1 //查看被移动数据
"100"
127.0.0.1:6379[1]> select 0
OK
127.0.0.1:6379> get k1 //在数据库 0 中无法查看到 k1 的值
(nil)

清除数据库内数据

Redis 数据库的整库数据删除主要分为两个部分:清空当前数据库数据,使用 FLUSHDB 命令实现;清空所有数据库的数据,使用 FLUSHALL 命令实现。但是,数据清空操作比较危险,生产环境下一般不建议使用。

Redis 持久化

Redis 是一种高级 key-value 数据库。它跟 Memcached 类似,不过数据可以持久化,而且支持的数据类型很丰富,有字符串、列表、集合和有序集合。支持在服务器端计算集合(difference)等,还支持多种排序功能。所以 Redis 也可以被看成是一个数据结构服务器。

Redis 的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为 “半持久化模式”);也可以把每一次数据变化都写入到一个 append only file(aof)里面(这称为 “全持久化模式”)。

由于 Redis 的数据都存放在内存中,如果没有配置持久化,Redis 重启后数据就会丢失了。所以,需要开启 Redis 的持久化功能,将数据保存到磁盘上,当 Redis 重启后,可以从磁盘中恢复数据。Redis 提供两种方式进行持久化,一种是 RDB 持久化(原理是将 Redis 在内存中的数据库记录定时 dump 到磁盘上的 RDB 持久化),另外一种是 AOF(append only file)持久化(原理是将 Reids 的操作日志以追加的方式写入文件)。那么这两种持久化方式有什么区别呢?在实际使用的时候该如何选择呢?下面简单介绍一下二者的区别。

RDB 和 AOF 的区别

RDB 持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是 fork 一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。

AOF 持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。

RDB 和 AOF 的优缺点

RDB 优点

  • 文件备份友好:Redis 数据库持久化后仅生成单个文件 ,便于按策略(如每小时备份近 24 小时数据、每天备份近 30 天数据 )做文件备份,系统遇灾难故障时,恢复便捷。
  • 灾难恢复性优:适合灾难恢复场景,可轻松将单个压缩后的 RDB 文件转移到其他存储介质,用于数据恢复 。
  • 性能最大化:Redis 主进程执行持久化时,仅需 fork 子进程,由子进程完成持久化操作,主进程无需执行 IO 操作,对性能影响小 。
  • 启动效率高:数据量大时,相比 AOF 机制,RDB 因是数据集快照形式,Redis 启动加载数据的效率更高 。

RDB 缺点

  • 数据完整性弱:若需保障数据高可用性、避免数据丢失,RDB 并非佳选。系统若在定时持久化前宕机,宕机前未写入磁盘的数据会全部丢失 。
  • 服务短暂阻塞风险:RDB 依赖 fork 子进程做持久化,数据集大时,fork 操作可能让服务器停止服务几百毫秒甚至 1 秒,影响业务连续性 。

AOF 优缺点

AOF 优点

  • 数据安全性高:提供每秒同步、每次修改同步、不同步 3 种策略,保障数据持久性。每秒同步为异步,系统宕机可能丢 1 秒内数据;每次修改同步实时落盘,效率虽低但数据最安全 。
  • 日志完整性好:用 append 模式写日志,即便写操作中宕机,也不破坏已有日志内容。若写一半系统崩溃,下次启动可通过 redis-check-aof 工具修复数据一致性 。
  • 日志可优化重构:日志过大时,Redis 自动触发 rewrite 机制。以 append 模式写旧文件同时,新建文件记录修改命令,切换 rewrite 能保障数据安全 。
  • 日志可读性强:日志文件格式清晰,记录所有修改操作,可直接用于数据重建恢复 。

AOF 缺点

  • 文件体积与恢复效率弱:同数据量下,AOF 文件比 RDB 大;恢复大数据集时,RDB 速度更快 。
  • 运行效率有差异:因同步策略,AOF 运行效率通常低于 RDB。每秒同步策略效率较高,每次修改同步策略效率低,仅同步写策略效率与 RDB 相当 。

二者选择标准

看需求权衡:想牺牲部分性能换缓存一致性(如标准写操作场景),选 AOF;想追求高性能,不用备份保障,等手动执行 save 再做 RDB 备份,可选 RDB 。

RDB 持久化配置

Redis 会将数据集的快照 dump 到 dump.rdb 文件中。此外,也可以通过配置文件来修改 Redis 服务器 dump 快照的频率。在打开 6379.conf 文件之后,搜索 save,可以看到如下所示配置信息。

  • save 900 1:在 900 秒(15 分钟)内,如果至少有 1 个 key 发生变化,则 dump 内存快照。
  • save 300 10:在 300 秒(5 分钟)内,如果至少有 10 个 key 发生变化,则 dump 内存快照。
  • save 60 10000:在 60 秒(1 分钟)内,如果至少有 10000 个 key 发生变化,则 dump 内存快照。

 AOF 持久化配置

appendonly no 改为 yes 开启 aof。
在 Redis 的配置文件中存在三种同步方式,它们分别是:

  • appendfsync always:每次有数据修改发生时都会写入 AOF 文件。
  • appendfsync everysec:每秒钟同步一次,该策略为 AOF 的缺省策略。
  • appendfsync no:从不同步,高效但是数据不会被持久化。

AOF 重写

Redis 会不断地将被执行的命令记录到 AOF 文件里面,所以随着 Redis 不断运行,AOF 文件的体积也会不断增长。在极端情况下,体积不断增大的 AOF 文件甚至可能会用完硬盘的所有可用空间。Redis 在重启之后需要通过重新执行 AOF 文件记录的所有写命令来还原数据集,所以如果 AOF 文件的体积非常大,那么还原操作执行的时间就可能会非常长。

为了解决 AOF 文件体积不断增大的问题,用户可以向 Redis 发送 BGREWRITEAOF 命令。BGREWRITEAOF 命令会通过移除 AOF 文件中的冗余命令来重写(rewrite)AOF 文件,使 AOF 文件的体积尽可能地变小。

BGREWRITEAOF 的工作原理和 BGSAVE 创建快照的工作原理非常相似:Redis 会创建一个子进程,然后由子进程负责对 AOF 文件进行重写。因为 AOF 文件重写也需要用到子进程,所以快照持久化因为创建子进程而导致的性能问题和内存占用问题,在 AOF 持久化中也同样存在。

与快照持久化通过设置 save 选项来自动执行 BGSAVE 一样,AOF 持久化也可以通过设置 auto-aof-rewrite-percentage 选项和 auto-aof-rewrite-min-size 选项来自动执行 BGREWRITEAOF。

举个例子,假设用户对 Redis 设置了配置选项 auto-aof-rewrite-percentage 100 和 auto-aof-rewrite-min-size 64mb,并且启动了 AOF 持久化,那么当 AOF 文件的体积大于 64MB,并且 AOF 文件的体积比上一次重写之后的体积大了至少一倍(100%)的时候,Redis 将执行 BGREWRITEAOF 命令。如果 AOF 重写执行的过于频繁的话,用户可以考虑将 auto-aof-rewrite-percentage 选项的值设置为 100 以上,这种做法可以让 Redis 在 AOF 文件的体积变得更大之后才执行重写操作,不过也会让 Redis 在启动时还原数据集所需的时间变得更长。

性能管理

Redis 性能管理需要关注的数据指标有内存使用率、内存碎片率、回收 key 等。这其中有些数据可以通过进入 info 命令进行查看。需要查看某一项的值就后面跟具体参数,执行以下命令查看 Redis 使用内存值。

192.168.9.236:7001>info memory
# Memory
used_memory:1789108864
used_memory_human:1.67G
used_memory_rss:1834389504
used_memory_rss_human:1.71G
used_memory_peak:4657473880
used_memory_peak_human:4.34G
used_memory_peak_perc:38.41%
used_memory_overhead:626859900
used_memory_startup:791432
used_memory_dataset:1162248964
used_memory_dataset_perc:64.99%

内存碎片

上述信息中的 mem_fragmentation_ratio 给出了内存碎片率的数据指标,它是由操作系统分配的内存 used_memory_rss 除以 Redis 使用的内存值 used_memory 得出的。内存值 used_memory_rss 中的 rss 是 Resident Set Size 的缩写,表示该进程所占物理内存的大小,即为操作系统分配给 Redis 实例的内存大小。

除了用户定义的数据和内部开销以外,used_memory_rss 指标还包含了内存碎片的开销,内存碎片是由操作系统低效的分配 / 回收物理内存导致的。操作系统负责分配物理内存给各个应用进程,Redis 使用的内存与物理内存的映射是由操作系统上虚拟内存管理器完成的。

举例来说:Redis 需要分配连续内存块来存储 1G 的数据集。如果物理内存上没有超过 1G 的连续内存块,该操作系统就不得不使用多个不连续的小内存块来分配并存储这 1G 数据,该操作就会导致内存碎片的产生。

内存分配器另一个复杂的层面是,系统会预先分配一下内存区块给应用程序,这样可以加快应用程序运行速度,但会产生另外一个问题,就是预先分配内存区块大小的问题。比如运行一个 5G 大小应用,需要 5 个 1G 大小的内存区块,结果系统就分配了 5 个 2G 的内存区块,这样就浪费了 5G 的运行内存空间,同样就产生内存碎片率。

内存碎片率对理解 Redis 实例的资源性能是非常重要的。内存碎片率稍大于 1 是合理的,这个值表示内存碎片率比较低,也说明 Redis 没有发生内存交换。但如果内存碎片率超过 1.5,那就说明 Redis 消耗了实际需要物理内存的 150%,其中 50% 是内存碎片率。若是内存碎片率低于 1 的话,说明 Redis 内存分配超出了物理内存,操作系统正在进行内存交换。内存交换会引起非常明显的响应延迟。

若生产环境内存碎片率过高,会导致 Redis 性能降低。解决该情况的常见方案有三种。

内存碎片率超过 1.5

重启 Redis 服务器可以让额外产生的内存碎片失效并重新作为新内存来使用,使操作系统恢复高效的内存管理。额外碎片的产生是由于 Redis 释放了内存块,但内存分配器并没有返回内存给操作系统,这个内存分配器是在编译时指

定的,可以是 libc、jemalloc 或者 tcmalloc 。通过比较 used_memory_peak、used_memory_rss 和 used_memory_metrics 的数据指标值可以检查额外内存碎片的占用。从名字上可以看出,used_memory_peak 是过去 Redis 内存使用的峰值,而不是当前使用内存的值。如果 used_memory_peak 和 used_memory_rss 的值大致相等,而且二者明显超过了 used_memory 值,这说明额外的内存碎片正在产生。在重启服务器之前,需要在 redis-cli 工具上输入 shutdown save 命令,表示强制让 Redis 数据库执行保存操作并关闭 Redis 服务,这样做能保证在 Redis 关闭时不丢失任何数据。在重启后 Redis 会从硬盘上加载持久化的文件,以确保数据集持续可用。

  • 如果内存碎片率低于 1

Redis 实例可能会把部分数据交换到硬盘上。内存交换会严重影响 Redis 的性能,所以应该增加可用物理内存或减少 Redis 内存占用。

  • 修改内存分配
    Redis 支持 libc、jemallocl、tcmalloc 三种不同的内存分配器,每个分配器在内存分配和碎片上都有不同的实现。不建议运维人员修改 Redis 默认内存分配器,因为这需要完全理解这几种内存分配器的差异,也要重新编译 Redis。这个方法更多的是让其了解 Redis 内存分配器所做的工作。

内存使用率

内存使用率是 Redis 服务最关键的一部分。如果一个 Redis 实例的内存使用率超过可用最大内存,那么操作系统开始进行内存与 swap 空间交换,把内存中旧的或不再使用的内容写入硬盘(硬盘上的这块空间叫 swap 分区),以便腾出新的物理内存给新页或活动页 (page) 使用。

used_memory 字段数据表示的是由 Redis 分配器分配的内存总量,以字节为单位。其中 used_memory_human 上的数据和 used_memory 是一样的值,它以 M 为单位显示,目的是为了方便阅读。

used_memory 是 Redis 内使用的内存总量,它包含了实际缓存占用的内存和 Redis 自身运行所占用的内存(如元数据、lua)。它是由 Redis 使用内存分配器分配的内存,所以这个数据并没有把内存碎片浪费掉的内存给统计进去。Redis 默认最大使用内存是可用物理内存剩余的所有内存,0 代表没有限制。

在硬盘上进行读写操作要比在内存上进行读写操作慢很多。如果 Redis 进程上发生内存交换,那么 Redis 和依赖 Redis 数据的应用会受到严重的性能影响。通过查看 used_memory 指标可知道 Redis 上正在使用的内存情况,如果 used_memory 大于可用最大内存,那就说明 Redis 实例正在进行内存交换或者已经完成内存交换。运维人员应该根据这个情况执行相应的应急措施。

如何避免内存交换发生,主要有以下三点。

针对缓存数据大小选择

如果缓存数据小于 4GB,就使用 32 位的 Redis 实例。因为 32 位实例上的指针大小只有 64 位的一半,它的内存空间占用空间会更少些。这样有一个坏处就是,假设物理内存超过 4GB,那么 32 位实例使用的内存仍然会被限制在 4GB 以下。要是有同时也共享给其他一些应用使用的话,那可能需要更高效的 64 位 Redis 实例,这种情况下切换到 32 位是不可取的。不管使用哪种方式,Redis 的 dump 文件在 32 位和 64 位之间是互相兼容的,因此倘若有减少占用内存空间的需求,可以尝试先使用 32 位,后面再切换到 64 位上。

使用 Hash 数据结构

因为 Redis 在储存小于 100 个字段的 Hash 结构上,其存储效率是非常高的。所以在不需要集合(set)操作或 list 的 push/pop 操作时,尽可能的使用 Hash 结构。例如在一个 Web 应用程序中,需要存储一个对象表示用户信息,使用单个 key 表示一个用户,其每个属性存储在 Hash 的字段里,这样要比给每个属性单独设置一个 key-value 要高效的多。通常情况下倘若有数据使用 string 结构,用多个 key 存储时,那么应该转换成单个 key 多字段的 Hash 结构。如上所述中介绍的 Hash 结构应包含单个对象的属性或者单个用户各种各样的资料。Hash 结构的操作命令是 HSET (key, fields, value) 和 HGET (key, field),使用它可以存储或从 Hash 中取出指定的字段。

设置 key 的过期时间

一个减少内存使用率的简单方法就是,每当存储对象时确保设置 key 的过期时间。倘若 key 在明确的时间周期内使用或者旧 key 不大可能被使用时,就可以用 Redis 过期时间命令(expire, expireat, pexpire, pexpireat)去设置过期时间,这样 Redis 会在 key 过期时自动删除 key 。假如知道每秒钟有多少个新 key-value 被创建,那么可以调整 key 的存活时间,并指定阈值去限制 Redis 使用的最大内存。

回收 key

当内存使用达到设置的最大阈值时,需要选择一种 key 的回收策略,可在 redis.conf 配置文件中修改 “maxmemory-policy” 属性值。默认情况下回收策略是禁止删除,若是 Redis 数据集中的 key 都设置了过期时间,那么 “volatile-ttl” 策略是比较好的选择。但如果 key 在达到最大内存限制时没能够迅速过期,或者根本没设置过期时间。那么设置为 “allkeys-lru” 值比较合适,它允许 Redis 从整个数据集中挑选最近最少使用的 key 进行删除(LRU 淘汰算法)。Redis 还提供了一些其他淘汰策略:

  • volatile-lru:使用 LRU 算法从已设置过期时间的数据集合中淘汰数据;
  • volatile-ttl:从已设置过期时间的数据集合中挑选即将将过期的数据淘汰;
  • volatile-random:从已设置过期时间的数据集合中随机挑选数据淘汰;
  • allkeys-lru:使用 LRU 算法从所有数据集合中淘汰数据;
  • allkeys-random:从数据集合中任意选择数据淘汰;
  • no-eviction:禁止淘汰数据。

info 统计信息说明:info stats 信息中的 evicted_keys 字段显示的是因为 maxmemory 限制导致 key 被回收删除的数量。当 Redis 由于内存压力需要回收一个 key 时,Redis 首先考虑的不是回收最旧的数据,而是在最近最少使用的 key 或即将过期的 key 中随机选择一个 key,从数据集中删除。

192.168.9.236:7001> info stats
# Stats
total_connections_received:473156108
total_commands_processed:4180290178
instantaneous_ops_per_sec:375
total_net_input_bytes:14676967575477
total_net_output_bytes:102221322391862
instantaneous_input_kbps:1465.97
instantaneous_output_kbps:7011.15
rejected_connections:0
sync_full:1
sync_partial_ok:0
sync_partial_err:1
expired_keys:34158591
expired_stale_perc:0.40
expired_time_cap_reached_count:0
evicted_keys:0
keyspace_hits:3089647498
keyspace_misses:94699798
pubsub_channels:3
pubsub_patterns:2
latest_fork_usec:51400
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0

通过统计定位性能问题:通过以上文字描述和参数对比,可以根据 key 的回收来定位性能问题,通过回收 key 可以保证合理分配 Redis 有限的内存资源。因此 evicted_keys 值经常超过 0,那么应会看到客户端命令响应延迟时间增加,因为 Redis 不但要处理客户端过来的命令请求,还要频繁的回收满足条件的 key。

回收策略与内存交换选择:需要注意的是,回收 key 对性能的影响远没有内存交换严重,若是在强制内存交换和设置回收策略做一个选择的话,则放弃强制内存交换是比较合理的。

因为把内存数据交换到硬盘上对性能影响非常大。既然频繁的回收 key 也会导致性能问题,需要减少回收 key 来提升性能,根据经验如果开启快照功能,maxmemory 需要设置成物理内存的 45%,这几乎不会有引发内存交换的危险。若是没有开启快照功能,设置系统可用内存的 95% 是比较合理的。

另外一种分片技术是把数据集划分成适合大小,分别存放在不同的 Redis 实例上,每一个实例都包含整个数据集的一部分。通过分片可以把很多服务器联合起来存储数据,相当于增加总的物理内存,使其在没有内存交换和回收 key 的策略下也能存储更多的 key。假设有一个非常大的数据集,maxmemory 已经设置,实际内存使用也已经超过了推荐设置的阈值,通过数据分片能明显减少 key 的回收,从而提高 Redis 的性能。当然 Redis 性能管理远远比上面列出的几种复杂的多,需要多加学习。


网站公告

今日签到

点亮在社区的每一天
去签到