Redis响应严重延迟,如何解决?( 四 )

观察一会儿 , 有没有发现什么有趣的现象呢?
事实上 , 从系统调用来看 ,  epoll_pwait、read、write、fdatasync 这些系统调用都比较频繁 。
那么 , 刚才观察到的写磁盘 , 应该就是 write 或者 fdatasync 导致的了 。
接着再来运行 lsof 命令 , 找出这些系统调用的操作对象:
$ lsof -p 9085redis-ser 9085 systemd-network    3r     FIFO   0,12      0t0 15447970 piperedis-ser 9085 systemd-network    4w     FIFO   0,12      0t0 15447970 piperedis-ser 9085 systemd-network    5u  a_inode   0,13        0    10179 [eventpoll]redis-ser 9085 systemd-network    6u     sock    0,9      0t0 15447972 protocol: TCPredis-ser 9085 systemd-network    7w      REG    8,1  8830146  2838532 /data/appendonly.aofredis-ser 9085 systemd-network    8u     sock    0,9      0t0 15448709 protocol: TCP现在你会发现 , 描述符编号为 3 的是一个 pipe 管道 , 5 号是 eventpoll , 7 号是一个普通文件 , 而 8 号是一个 TCP socket 。
结合磁盘写的现象 , 我们知道 , 只有 7 号普通文件才会产生磁盘写 , 而它操作的文件路径是 /data/appendonly.aof , 相应的系统调用包括 write 和 fdatasync 。
如果你对 Redis 的持久化配置比较熟 , 看到这个文件路径以及 fdatasync 的系统调用 , 你应该能想到 , 这对应着正是 Redis 持久化配置中的 appendonly 和 appendfsync 选项 。很可能是因为它们的配置不合理 , 导致磁盘写比较多 。
接下来就验证一下这个猜测 , 我们可以通过 Redis 的命令行工具 , 查询这两个选项的配置 。
继续在终端一中 , 运行下面的命令 , 查询 appendonly 和 appendfsync 的配置:
$ docker exec -it redis redis-cli config get 'append*'1) "appendfsync"2) "always"3) "appendonly"4) "yes"从这个结果你可以发现 , appendfsync 配置的是 always , 而 appendonly 配置的是 yes 。
这两个选项的详细含义 , 你可以从 Redis Persistence 的文档中查到 , 这里我做一下简单介绍 。

Redis 提供了两种数据持久化的方式 , 分别是快照和追加文件 。
快照方式 , 会按照指定的时间间隔 , 生成数据的快照 , 并且保存到磁盘文件中 。
  • 为了避免阻塞主进程 , Redis 还会 fork 出一个子进程 , 来负责快照的保存 。这种方式的性能好 , 无论是备份还是恢复 , 都比追加文件好很多 。
不过 , 它的缺点也很明显 。在数据量大时 , fork 子进程需要用到比较大的内存 , 保存数据也很耗时 。所以 , 你需要设置一个比较长的时间间隔来应对 , 比如至少 5 分钟 。这样 , 如果发生故障 , 你丢失的就是几分钟的数据 。
  • 追加文件 , 则是用在文件末尾追加记录的方式 , 对 Redis 写入的数据 , 依次进行持久化 , 所以它的持久化也更安全 。
此外 , 它还提供了一个用 appendfsync 选项设置 fsync 的策略 , 确保写入的数据都落到磁盘中 , 具体选项包括 always、everysec、no 等 。
  • always 表示 , 每个操作都会执行一次 fsync , 是最为安全的方式;
  • everysec 表示 , 每秒钟调用一次 fsync  , 这样可以保证即使是最坏情况下 , 也只丢失 1 秒的数据;
  • 而 no 表示交给操作系统来处理 。
【Redis响应严重延迟,如何解决?】回忆一下我们刚刚看到的配置 , appendfsync 配置的是 always , 意味着每次写数据时 , 都会调用一次 fsync , 从而造成比较大的磁盘 I/O 压力 。
当然 , 你还可以用 strace  , 观察这个系统调用的执行情况 。比如通过 -e 选项指定 fdatasync 后 , 你就会得到下面的结果:
$ strace -f -p 9085 -T -tt -e fdatasyncstrace: Process 9085 attached with 4 threads[pid  9085] 14:22:52.013547 fdatasync(7) = 0 <0.007112>[pid  9085] 14:22:52.022467 fdatasync(7) = 0 <0.008572>[pid  9085] 14:22:52.032223 fdatasync(7) = 0 <0.006769>...


推荐阅读