Redis 用的很溜,了解过它用的什么协议吗?

我是风筝,公众号「古时的风筝」,一个兼具深度与广度的程序员鼓励师,一个本打算写诗却写起了代码的田园码农!
文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在里面。

有个小伙伴面试回来说面试官问了他一些 Redis 问题,但是他好像没有回答上来。

我说,你 Redis 不是用的很溜吗,什么问题难住你了。

他说,事情是这样的,刚开始,问了一些基础的问题,比如 Redis 的几种基本数据类型和使用场景,以及主从复制和集群的一些问题,这些都还好。

然后问 Redis 的两种持久化方式,我说与 RDB 和 AOF 两种方式,RDB 数据文件小,恢复速度快,但是对性能有影响,而且不适合实时存储。而 AOF 是现在最常用的持久化方式,它的一大优点就是实时性,并且对 Redis 半身性能影响最小。

那面试又问了,你知道 AOF 持久化之后的文件是什么格式吗?

答:好像就是文本文件吧?

好,文本文件,那你知道它有什么规则吗?或者说,它和 Redis 的协议有什么关系吗?

答:啊,这个,恩,不太清楚呢。

现在就来看一下 AOF 和 RESP 协议的关系

  1. 从两种持久化方式说起。
  2. RESP 协议是什么
  3. 动手实现一个简单的协议解析命令行工具

Redis 用的很溜,了解过它用的什么协议吗?

先从持久化说起,虽然一提到 Redis,首先想到的就是缓存,但是 Redis 不仅仅是缓存这么简单,它的定位是内存型数据库,可以存储多种类型的数据结构,还可以当做简单消息队列使用。既然是数据库,持久化功能是必不可少的。

Redis 的两种持久化方式

Redis 提供了两种持久化方式,一种是 RDB 方式,另外一种是 AOF 方式,AOF 是目前比较流行的持久化方案。

RDB 方式

RDB持久化是通过快照的方式,在指定的时间间隔内将内存中的数据集快照写入磁盘。它以一种紧凑压缩的二进制文件的形式出现。可以将快照复制到其他服务器以创建相同数据的服务器副本,或者在重启服务器后恢复数据。RDB是Redis默认的持久化方式,也是早期版本的必须方案。

RDB 由下面几个参数控制。

设置 dump 的文件名
dbfilename dump.rdb

持久化文件的存储目录
dir ./

900秒内,如果至少有1个key发生变化,就会自动触发bgsave命令创建快照
save 900 1

300秒内,如果至少有10个key发生变化,就会自动触发bgsave命令创建快照
save 300 10

60秒内,如果至少有10000个key发生变化,就会自动触发bgsave命令创建快照
save 60 10000

持久化流程

上面说到了配置文件中的几个触发持久化的机制,比如 900 秒、300秒、60秒,当然也可以手动执行命令 savebgsave进行触发。 bgsave是非阻塞版本,通过 fork 出子进程的方式来进行快照生成,而 save会阻塞主进程,不建议使用。

1、首先 bgsave命令触发;

2、父进程 fork 出一个子进程,这一步是比较重量级的操作,也是 RDB 方式性能不及 AOF 的一个重要原因;

3、父进程 fork 出子进程后就可以正常的相应客户端发来的其他命令了;

4、子进程开始进行持久化工作,对现有数据进行完整的快照存储;

5、子进程完成操作后,通知父进程;

Redis 用的很溜,了解过它用的什么协议吗?

RDB的优点:

  • RDB是一个紧凑压缩的二进制文件,代表Redis在某个时间点上的数据 快照。非常适用于备份,全量复制等场景。比如每6小时执行bgsave备份, 并把RDB文件拷贝到远程机器或者文件系统中(如hdfs),用于灾难恢复。
  • Redis加载RDB恢复数据远远快于AOF的方式。

RDB的缺点:

  • RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运 行都要执行fork操作创建子进程,属于重量级操作,频繁执行成本过高。
  • RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式 的RDB版本,存在老版本Redis服务无法兼容新版RDB格式的问题。

AOF 方式

AOF 由下面几个参数控制。

appendonly参数开启AOF持久化
appendonly yes

AOF持久化的文件名,默认是appendonly.aof
appendfilename "appendonly.aof"

AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的
dir ./

同步策略
appendfsync always
appendfsync everysec
appendfsync no

aof重写期间是否同步
no-appendfsync-on-rewrite no

重写触发配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

加载aof出错如何处理
aof-load-truncated yes

文件重写策略
aof-rewrite-incremental-fsync yes

针对RDB不适合实时持久化的问题,Redis提供了AOF 持久化方式来解决,AOF 也是目前最流程的持久化方式。

AOF(append only file),以独立日志的方式记录每次写命令, 重启时再重新执行AOF文件中的命令达到恢复数据的目的。

1、所有的写入命令会追加到aof_buf(缓冲区)中;

2、AOF缓冲区根据对应的策略向硬盘做同步操作;

3、随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的;

4、当Redis服务器重启时,可以加载AOF文件进行数据恢复;

Redis 用的很溜,了解过它用的什么协议吗?

AOF 文件里存的是什么

我在本地的测试 redis 环境中随便刷了几条命令,然后打开 appendonly.aof 文件查看,发现里面的内容像下面这样子。

Redis 用的很溜,了解过它用的什么协议吗?

RESP 协议

Redis客户端与服务端通信,使用 RESP 协议通信,该协议是专门为 Redis 设计的通信协议,但也可以用于其它客户端-服务器通信的场景。

RESP 协议有如下几个特点:

  • 实现简单;
  • 快速解析;
  • 可阅读;

客户端发送命令给服务端,服务端拿到命令后进行解析,然后执行对应的逻辑,之后返回给客户端,当然了,这一发一回复都是用的 RESP 协议特点的格式。

一般情况下我们会使用 redis-cli或者一些客户端工具连接 Redis 服务端。

./redis-cli

然后整个交互过程的命令发送和返回结果像下面这样,绿色部分为发送的命令,红色部分为返回的结果。

Redis 用的很溜,了解过它用的什么协议吗?

这就是我们再熟悉不过的部分了。但是,这并不能看出 RESP 协议的真实面貌。

用 telnet 试试

RESP 是基于 TCP 协议实现的,所以除了用各种客户端工具以及 Redis 提供的 redis-cli工具,还可以用 telnet 查看,用 telnet 就可以看出 RESP 返回的原始数据格式了。

我本地的 Redis 是用的默认 6379 端口,并且没有设置 requirepass ,我们来试一下用 telnet 连接。

telnet 127.0.0.1 6379

然后执行与前面相同的几条命令,发送和返回的结果如下,绿色部分为发送的命令,红色为返回的结果。

Redis 用的很溜,了解过它用的什么协议吗?

怎么样,有些命令的返回还好,但是像 get str:hello这条,返回的结果除了 world值本身,上面还多了一行 $5,是不是有点迷糊了。

协议规则

请求命令

一条客户端发往服务器的命令的规则如下:

* CR LF
$ CR LF
 CR LF
...

$ CR LF
 CR LF

RESP 用 \r\n作为分隔符,会表明此条命令的具体参数个数,在命令上看来,空格分隔的都表示一个参数,例如 set str:hello world 这条命令就是3个参数,会表明每个参数的字符数和具体内容。

用这条命令举例,对应到 RESP 协议规则上就会变成下面这个样子:

*3\r\n$3\r\nset\r\n$9str:hello\r\n$5world\r\n

Redis 用的很溜,了解过它用的什么协议吗?

服务端回复

Redis 命令会返回多种不同类型的回复。

通过检查服务器发回数据的第一个字节, 可以确定这个回复是什么类型:

1、状态回复(status reply)的第一个字节是 "+"

比如 ping命令的回复, +PONG\r\n

2、错误回复(error reply)的第一个字节是 "-"

比如输入一个 redis 中不存在的命令,或者给某些命令设置错误的参数,例如输入 auth,auth 命令后面需要有一个密码参数的,如果不输入就会返回错误回复类型。

-ERR wrong number of arguments for 'auth' command\r\n

3、整数回复(integer reply)的第一个字节是 ":"

例如 INCRDECR 自增自减命令,返回的结果是这样的 :2\r\n

4、批量回复(bulk reply)的第一个字节是 "$"

例如对 string 类型执行 get 操作, $5\r\nworld\r\n$后面的数字 5 表示返回的结果有 5 个字符,后面是返回结果的实际内容。

5、多条批量回复(multi bulk reply)的第一个字节是 "*"

例如 LRANGE key start stop或者 hgetall等返回多条结果的命令,比如 lrange命令返回的结果:

*2\r\n$6\r\nnews-2\r\n$6\r\nnews-1\r\n

多条批量回复和前面说的客户端发送命令的格式是一致的。

实现一个简单的 Redis 交互工具

了解了 Redis 的协议规则,我们就可以自己写一个简单的客户端了。当然,通过官网我们可以看到已经有各种语言,而且每种语言有不止一个客户端工具了。

Redis 用的很溜,了解过它用的什么协议吗?

比如 Java 语言的客户端就有这么多种,其中 Jedis 应该是用的最多了,既然已经有这么好用的轮子了,当然没必要重复造轮子,主要还是为了加深印象。

Redis 用的很溜,了解过它用的什么协议吗?

RESP 协议基于 TCP 协议,可以使用 socket 方式进行连接。

public Socket createSocket() throws IOException {
  Socket socket = null;
  try {
    socket = new Socket();
    socket.setReuseAddress(true);
    socket.setKeepAlive(true);
    socket.setTcpNoDelay(true);
    socket.setSoLinger(true, 0);

    socket.connect(new InetSocketAddress(host, port), DEFAULT_TIMEOUT);
    socket.setSoTimeout(DEFAULT_TIMEOUT);
    outputStream = socket.getOutputStream();
    inputStream = socket.getInputStream();
    return socket;
  } catch (Exception ex) {
    if (socket != null) {
      socket.close();
    }
    throw ex;
  }
}

然后剩下的就是对返回的结果进行字符串的解析了,我做的工具就到简陋的到这一步了,下面是一些简单命令的返回输出。

Redis 用的很溜,了解过它用的什么协议吗?

代码已放到 github 上,有兴趣的可以 clone 下来看一下。
https://github.com/huzhicheng/medis

这位英俊潇洒的少年,如果觉得还不错的话,给个推荐可好!

公众号「古时的风筝」,Java 开发者,全栈工程师,bug 杀手,擅长解决问题。
一个兼具深度与广度的程序员鼓励师,本打算写诗却写起了代码的田园码农!坚持原创干货输出,你可选择现在就关注我,或者看看历史文章再关注也不迟。长按二维码关注,跟我一起变优秀!

Redis 用的很溜,了解过它用的什么协议吗?

Original: https://www.cnblogs.com/fengzheng/p/14028520.html
Author: 风的姿态
Title: Redis 用的很溜,了解过它用的什么协议吗?

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/529298/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • cron 表达式

    cron 表达式 1.简介:一个cron表达式最少有5个空格来分割时间元素,总共有7个元素,分别如下: ① 秒(0-59) ② 分钟(0-59) ③ 小时(0-23) ④ 天(月的…

    Linux 2023年6月7日
    064
  • 【电子取证:镜像仿真篇】Windows Server镜像仿真、vmdk镜像仿真

    Windows Server镜像仿真、vmdk镜像仿真 时间过得真快呀!–【suy999】 一、qemu-img镜像转换工具 qemu-img(v2.3.0.0)镜像转…

    Linux 2023年6月13日
    094
  • mysql select语句查询流程是怎么样的

    mysql select查询的数据是查询内存里面,如果没有查询的数据没有在内存,就需要mysql的innodb引擎读取磁盘,将数据加载的内存后在读取。这就体现了,mysql查询大量…

    Linux 2023年6月8日
    085
  • zabbix用户,角色,权限,模板管理

    zabbix用户,角色,权限,模板管理 zabbix用户,角色,权限,模板管理 用户组用户角色右上角是创建角色用户lnh@1234使用刚才创建的用户登录模板组模板模板的监控项可以自…

    Linux 2023年6月6日
    095
  • 最小化安装killall不可用

    最小化安装killall不可用 最小化安装 Centos7.4后,发现killall命令不可用使用了以下命令,查看软件包名: yum search killall 查找后发现应使用…

    Linux 2023年6月13日
    091
  • Linux 如何设置开机自启动脚本

    https://blog.csdn.net/weixin_40343504/article/details/82457990 Original: https://www.cnblo…

    Linux 2023年6月13日
    097
  • 如何使用CMake构建c++项目

    1. c++项目构建与CMake简介 在Windows系统上我们通常使用 Visual Studio(VS)来生成我们的c++项目。我们只需在VS相应的层次目录中添加相应的文件即可…

    Linux 2023年6月14日
    0100
  • 统计算法_探索性统计

    最近不知道写什么了,基本python的各种功能百度一下,都能搜到一大把,最近itchat好像很火,不过对这个不是很感冒,等以后有兴趣或者用的上的时候研究研究准备把统计方面的东西再看…

    Linux 2023年6月6日
    080
  • 如何使用IDEA进行DOCKER调试

    引言在日常的开发过程中我们使用的开发环境通常与正式环境并不一致,这样就比较容易出现一些意外。于是我们通常会借助docker来让我们的开发和正式环境一致。那如何在docker中进行运…

    Linux 2023年6月14日
    0103
  • 正则表达式在grep中的使用

    GREP用法 grep "after" profile #查找文件内的包含after单词的行 grep -n "after" profile…

    Linux 2023年6月11日
    087
  • 容器编排,跨集群部署(脚踩2只船)问题研究

    —【前言】— https://www.cnblogs.com/cmt/p/14306142.html 问题来自于博客园,讨论容器编排,跨集群部署(脚踩2只船…

    Linux 2023年6月14日
    0105
  • 全新UI西游H5决战天宫游戏详细图文架设教程

    前言 想体验经典Q版西游霸服快乐吗?想体验满级VIP的尊贵吗?想体验一招秒杀的爽快吗?各种极品炫酷时装、坐骑、翅膀、宠物通通给你,就在全新UI西游H5决战天宫! 本文讲解决战天宫架…

    Linux 2023年6月7日
    091
  • 编程模式-表驱动编程

    刚开始编程时,往往会碰到一些根据不同条件执行不同功能的情况,通常都是采用if-else或者switch-case的方式,如果有很多的情况需要区分,则会有很多的 else if 或者…

    Linux 2023年6月7日
    0106
  • 让SpringBoot也用上Fluent Validator

    前言 在使用SpringBoot的时候经常需要对客户端传入的参数进行合法性的校验,校验的方法基本上都是使用SpringBoot提供的注解,有时候遇上注解不能满足需求的时候还需要在业…

    Linux 2023年6月14日
    082
  • ASP.NET Web API实现POST报文的构造与推送

    毕设和OAuth协议相关,而要理解OAuth协议就必须理解HTTP GET/POST方法。因此研究了一下如何使用Web API或MVC构造POST报文并实现客户端与服务器端的交互。…

    Linux 2023年6月13日
    082
  • springboot整合redis的发布订阅模式

    所谓发布订阅模式,就是发布了消息丢到通道中,消费者进行消费 看代码: 1 首先需要配置这个连接工厂 ,这地方可能有人有疑问,为什么需要单独做一个类呢,是由与这个连接工厂其他地方需要…

    Linux 2023年5月28日
    091
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球