一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
Redis学习笔记系列文章共六篇:
-
Redis学习笔记:数据安全和性能优化
-
Redis学习笔记:集群方案
-
Redis学习笔记:springboot实战(附封装完成代码)
-
Redis学习笔记:常见面试题及答案
写这个系列文章一是为了查漏补缺,二是帮助更多小伙伴快速掌握Redis核心知识,本文是第三篇,现在开始吧。
在上一篇核心概念中,我们了解了发布/订阅、排序、Redis事务、过期密钥等核心概念。
本篇从主要讲述以下几个问题。
一、持久化机制
二、复制原理
三、常见性能优化方案
一、持久化机制
在Redis中,提供了 RDB 和 AOF 两种持久化机制:
- RDB 将数据库的快照(snapshot)以二进制的方式保存到磁盘中。
- AOF 以协议文本的方式,将所有对数据库进行过写入的命令(及其参数)记录到 AOF 文件,以此达到记录数据库状态的目的。
1.RDB
通过快照创建内存中数据的某一时刻副本,当快照创建后,可以对这些快照进行备份、复制到其他服务器。如果Redis、系统或者硬件崩溃,从上次快照完成之后写入Redis的数据将会丢失。
快照方法是把redis内存中的数据在隔一段时间之后,fork一个子进程,在子进程中将内存中的数据写入存储。当然这种模式下,如果系统异常退出会出现数据的丢失,更严重的是因为要fork子进程,内存的消耗会在短时间内突然倍增。
2.AOF
Redis 将所有对数据库进行过写入的命令(及其参数)记录到 AOF 文件, 以此达到记录数据库状态的目的, 为了方便起见, 我们把这种记录过程叫做同步。
同步命令到 AOF 文件的整个过程可以分为三个阶段:
- 命令传播:Redis 将执行完的命令、命令的参数、命令的参数个数等信息发送到 AOF 程序中。
- 缓存追加:AOF 程序根据接收到的命令数据,将命令转换为网络通讯协议的格式,然后将协议内容追加到服务器的 AOF 缓存中。
- 文件写入和保存:AOF 缓存中的内容被写入到 AOF 文件末尾,如果设定的 AOF 保存条件被满足的话, fsync 函数或者 fdatasync 函数会被调用,将写入的内容真正地保存到磁盘中。
Redis 目前支持三种 AOF 保存模式,分别是:
- AOF_FSYNC_NO :不保存。
- AOF_FSYNC_EVERYSEC :每一秒钟保存一次。
- AOF_FSYNC_ALWAYS :每执行一个命令保存一次。
AOF 文件保存了 Redis 的数据库状态, 而文件里面包含的都是符合 Redis 通讯协议格式的命令文本。
这也就是说, 只要根据 AOF 文件里的协议, 重新执行一遍里面指示的所有命令, 就可以还原 Redis 的数据库状态了。
Redis 读取 AOF 文件并还原数据库的详细步骤如下:
- 创建一个不带网络连接的伪客户端(fake client)。
- 读取 AOF 所保存的文本,并根据内容还原出命令、命令的参数以及命令的个数。
- 根据命令、命令的参数和命令的个数,使用伪客户端执行该命令。
- 执行 2 和 3 ,直到 AOF 文件中的所有命令执行完毕。
二、复制
尽管 Redis 很快,但在某些情况下,一台 Redis 服务器运行速度不够快。特别是,操作超过数百万个项目时,集合操作可能需要几秒钟才能完成,而不是毫秒或微秒。即使单个命令可以在 10 毫秒内完成,单个 Redis 实例也有 100 个命令/秒的限制。
所以我们可以设置额外的服务器从 Redis 服务器保存数据集副本。在从主服务器接收到数据的初始副本后,当客户端将数据写入主服务器时,从服务器会实时保持最新状态。通过主/从设置,客户端将连接到其中一个从属设备以读取其数据(通常以随机方式选择尝试平衡负载),而不是连接到主控设备以读取数据。
主从复制过程:
| 步骤 | 主操作 | 从属操作 |
|---|---|---|
| 1 | 等待命令 | (重新)连接到主机;发出 SYNC 指令。 |
| 2 | 开始BGSAVE操作;保持BGSAVE后发送的所有写命令的backlog。 | 提供旧数据(如果有的话),或向命令返回错误(取决于配置)。 |
| 3 | 完成 BGSAVE;开始将快照发送到从站;继续backlog写命令 | 丢弃所有旧的数据(如果有的话);开始加载收到的转储数据 |
| 4 | 完成向从站发送快照;开始向从站发送backlog的写命令 | 完成解析转储;再次开始正常响应命令 |
| 5 | 完成发送backlog工作;在写入命令发生时开始实时流式传输 | 完成从 master 执行backlog的写命令;继续执行命令 |
三、常见性能优化方案
1. TCP-KeepAlive
Keepalive是一种允许同一TCP连接进行HTTP对话的方法,而不是在每个新的请求中打开一个新的连接。
简单来说,如果 keepalive 关闭,Redis 将为每个请求打开一个新连接,这会降低其性能。如果 keepalive 开启,那么 Redis 将对请求使用相同的 TCP 连接。
要启用TCP keepalive,操作如下:
vim /etc/redis/redis.conf
# Update the value to 0
tcp-keepalive 0
2.Pipelining(管道)
redis是典型的C/S架构,客户端与服务端通信是通过TCP协议进行。在使用redis进行一次存/取数据的过程中,总的耗时是由三部分组成:发送请求到服务器、redis服务器存/取/处理数据、返回结果到客户端。
由于redis操作数据是在内存中进行的,所以速度相当快,大量时间花在网络传输上。如果只是低频存取数据,影响不大。在短时间内做多次存取操作时,网络瓶颈非常明显。
为了解决这个问题,Redis引入了管道技术,管道技术可以将多次操作的指令放在一次传输中进行,然后再将多次操作的结果封装在一起一次性返回,当需要大量存取数据时,使用管道技术可以大大减少网络传输总耗时。
3.Max-Connection
Max-connection 是用于定义 Redis 服务器的最大连接限制的参数。修改方式如下:
sudo vim /etc/rc.local
# make sure this line is just before of exit 0.
sysctl -w net.core.somaxconn=65365
4.Overcommit memory
Overcommit memory 是一个内核参数,用于检查内存是否可用。如果Overcommit memory值为 0,那么 Redis 可能会出现 OOM(内存不足)错误。
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
5.关闭THP(Transparent Huge Page)
大多数人都不知道THP。为了实现物理和虚拟内存的转换,内核使用了分页的概念。这个功能被定义为加强内存映射过程,但是,THP减慢了基于内存数据库的速度。为了克服这个问题,可以禁用THP。
sudo vim /etc/rc.local # Add this line before exit 0 echo never > /sys/kernel/mm/transparent_hugepage/enabled