学习Redis,是一种怎样的体验(2) - 入门篇

320 阅读10分钟

学习Redis,是一种怎样的体验

兄弟们Redis撸起来!

前言

在上一章节中我们介绍了Redis是什么,并且如何去安装。在本章中,我们会继续深入了解Redis的工作原理。那么,让我们继续遨游在Redis的海洋中吧。

可执行文件

以在线安装方式为例,当我们安装完Redis后,进入/usr/bin 目录,我们会看到如下几个文件:

可执行文件名称作用
redis-server启动redis,服务端
redis-cliredis命令行,客户端
redis-benchmark基准测试工具
redis-check-aofAOF持久化文件检测和修复工具
redis-check-rdbROB持久化文件检测和修复工具
redis-sentienl启用哨兵模式

redis-server

redis-server是服务器启动命令,我们可以使用 redis-server --help获取命令的参数

参数说明备注
-v--version
-从stdin中读取配置
--port指定Redis服务监听的端口6379
-a指定密码
--sentinel设置哨兵系统启动
/path选择指定的配置文件启动
--test-memory检测当前操作系统能否稳定地分配指定容量的内存给 Redis单位是M
--slaveof将当前Redis设置为从库,为他设置主库地址
--masterauth如果主库设置了主从密码, 从库需要用该参数指定主从密码
--loglevel设置日志等级verbose,debug,notice,warning,

使用示例如下:

  • 默认配置:redis-server, 日志输出版本信息,默认端口 6379
  • 运行启动:redis-server --port 6380 指定端口启动
  • 配置文件启动: redis-server /opt/redis/redis.conf 指定配置文件启动

redis-cli

redis-cli是客户端命令,我们可以使用 redis-cli --help获取命令的参数

参数说明
-h指定Redis server地址
-p指定Redis server端口号
-s指定服务器套接字(覆盖主机名和端口)。
-a指定密码
-uurl格式的地址
-r将命令重复执行N次
-i每隔N秒执行一次命令,必须与-r一起使用。
-n选择库号
-x代表从标准输入读取数据作为该命令的最后一个参数。
-d原始格式中的多块分隔符(默认值:\n)。
-c连接cluster集群结点时用的,此选项可防止moved和ask异常。
--csv将数据导出为CSV格式的文件
--scan获取服务器所有的键
--pattern指定scan获取的key的pattern,正则表达式用于scan命令后过滤.
--slave当前客户端模拟成当前redis节点的从节点,可用来获取指定redis节点的更新操作
--rdb导出rdb文件,保存导到指定的位置
--pipe将命令封装成redis通信协议定义的数据格式,批量发送给redis执行。
--pipe-timeout设置管道超时时间
--bigkeys统计bigkey的分布,使用scan命令对redis的键进行采样,从中找到内存占用比较大的键
--hotkeys找出server中热点key
--stat实时获取redis的统计信息。istat和info相比可以看到一些增加的数据,如:每秒请求数
--raw显示格式化的效果
--no-raw要求返回原始格式
--eval用于执行lua脚本
--latency持续采样服务器延迟
--latency-history持续采样服务器延迟并每隔(15秒)输出一个记录; 可以使用-i 更改间隔时间
--latency-dist使用彩色终端显示一系列延时特征
--intrinsic-latency固有延迟,由于操作系统或虚拟机/容器带来的延迟,需要在redis-server的本器上进行测量.
--ldb与--eval一起使用可以启用Redis Lua调试器
--ldb-sync-mode比如--ldb,但是使用了同步Lua调试器, 此模式将阻塞服务器并更改脚本
--lru-test-

redis-cli stat说明

选项说明
keysserver中key的数量
mem键值对的总内存量
clients当前连接的总clients数量
blocked正在等待执行阻塞命令(BLPOP、BRPOP、BRPOPLPUSH 等等)的客户端数量
requests服务器请求总次数 (+1) 截止上次请求增加次数
connections服务器连接次数

使用示例如下:

  • 交互式:redis-cli -h {host} -p {prot}连接到 redis 服务,没有 h 默认连 127.0.0.0,没有 p 默认连 6379
  • 命令式:redis-cli -h 127.0.0.1 -p 6379 get hello 获取 key为hello 的 value
  • 停止redis服务: redis-cli shutdown 。注意:
    • 关闭时:断开连接,持久化文件生成,相对安全
    • 还可以用 kill 关闭,此方式不会做持久化,还会造成缓冲区非法关闭,可能会造成AOF和丢失数据
    • 关闭前生成持久化文件: 使用 redis-cli -a 123456 登录进去,再 shutdown nosave|save

redis-benchmark

redis-benchmark是性能测试工具,不属于redis-cli而是Redis的其他工具,默认在Redis目录下,我们可以使用 redis-benchmark --help获取命令的参数

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

redis-check-aof

服务器可能在程序正对AOF文件写入时出现故障了, 造成AOF文件出错, 那么Redis在重启时会拒绝载入这个 AOF 文件。为了确保数据的一致性不会被破坏,这时候可以先使用 Redis 附带的 redis-check-aof命令对原来的AOF文件进行修复,进而再启动redis。使用命令:redis-check-aof --fix AOF文件。同理,redis-check-rdb的作用也一样,这里就不在说明了。

上面我们对redis的各个执行文件进行了讲解,有兴趣的同学可以练习一下这些命令。那接下来我们看一下redis是怎么工作的。

Redis工作原理

我们应该有很多疑问,当我们执行一条redis命令时,redis经历了哪些过程,用到了哪些通信协议,是如何完成工作的。那就以一个简单的命令set key 123来解开这些疑问。

127.0.0.1:6379> set key 123
OK
127.0.0.1:6379> 

执行过程

一般情况下我们都知道reds执行过程总共经历了三个步骤:1.发送指令 -> 2.执行命令 -> 3.返回结果,如下图所示 但是知道这些是远远不够的,对于执行细节却避而不谈,当继续追问服务器端是如何执行的,大多数人都不能详细的回答出来,这未免让人有些遗憾。那么,我们将上图中的执行流程再完善一下,补充一些细节,这样就有了一条完整的redis命令执行过程。如下图所示:

一条Redis命令的执行过程有很多细节,大体分为:

  • 应用程序输入Redis命令
  • 客户端将命令转化为 Redis相关的通讯协议(RESP协议)
  • socket连接的方式将内容发送给服务器端
  • 服务器端在接收到相关内容之后,先将内容转化为具体的执行命令
  • 判断用户授权信息和其他相关信息,当验证通过之后会执行最终命令
  • 命令执行完之后,会进行相关的信息记录和数据统计
  • 然后再把执行结果发送给客户端

这些执行过程是通过事件机制串联了,在 Redis 启动阶段首先要注册socket连接建立事件处理器:

  • 当客户端发来建立socket的连接的请求时,对应的处理器方法会被执行,建立连接阶段的相关处理就会进行,然后注册socket读取事件处理器
  • 当客户端发来命令时,读取事件处理器方法会被执行,对应处理阶段的相关逻辑都会被执行,然后注册socket写事件处理器
  • 当写事件处理器被执行时,就是将返回值写回到socket中。

那么问题下一个问题就出现了,Redis为什么那么快

Redis为什么那么快

总体来说Redis是一个单线程应用,所说的单线程指的是Redis使用单个线程处理客户端的请求。虽然Redis是单线程的应用,但是即便不通过部署多个Redis实例和集群的方式提升系统吞吐, 从官网给出的数据可以看出,Redis处理速度非常快。 Redis性能非常高的原因主要有以下几点:

纯内存操作

绝大部分请求是纯粹的内存操作,减少直接读取磁盘数据,redis将数据储存在内存里面,读写数据的时候都不会受到硬盘 I/O 速度的限制

单线程

其中执行命令阶段,由于Redis是单线程来处理命令的,所有每一条到达服务端的命令不会立刻执行,所有的命令都会进入一个队列中,然后逐个被执行。并且多个客户端发送的命令的执行顺序是不确定的。但是可以确定的是不会有两条命令被同时执行,不会产生并发问题,这就是Redis的单线程基本模型。并且单线程操作,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。

I/O 多路复用

多路I/O复用模型是利用 select、poll、epoll 可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有 I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll 是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。
这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗),且 Redis 在内存中操作数据的速度非常快,也就是说内存内的操作不会成为影响Redis性能的瓶颈。

RESP协议 Redis 的客户端和服务端之间采取了一种独立的名为 RESP(REdis Serialization Protocol) 的协议,它是⼀种直观的⽂本协议,优势在于实现异常简单,解析性能极好。

以下是这个协议的一般形式:

*<参数数量> CR LF
$<参数 1 的字节数量> CR LF
<参数 1 的数据> CR LF
...
$<参数 N 的字节数量> CR LF
<参数 N 的数据> CR LF

举个例子, 以下是一个命令协议的打印版本:

*3   //表示后面有三个命令字符 (set  mykey  myvalue这三个)/(也可以理解后面会出现三个 $)
$3  //表示后面的字符串长度是3
SET
$3  //表示后面的字符串长度是3
key
$5  //表示后面的字符串长度是5
value

通过官网可以查询到RESP的信息规则如下:

  • 单行回复:回复的第一个字节是 “+”
  • 错误信息:回复的第一个字节是 “-“
  • 整形数字:回复的第一个字节是 “:”
  • 多行字符串:回复的第一个字节是 “$”
  • 数组:回复的第一个字节是 “*”
  • 每行信息已\r\n结尾 比如:
+OK\r\n
#redis-cli显示
OK

#服务端实际回复
-ERR unknown command 'xxxxx'\r\n
#redis-cli显示
(error) ERR unknown command 'xxxxx' 	

小结

以上就是本章的内容,由于作者水平有限, 欢迎大家能够反馈指正文章中错误不正确的地方, 感谢 🙏