学习Redis,是一种怎样的体验
兄弟们Redis撸起来!
前言
在上一章节中我们介绍了Redis
是什么,并且如何去安装。在本章中,我们会继续深入了解Redis
的工作原理。那么,让我们继续遨游在Redis的海洋中吧。
可执行文件
以在线安装方式为例,当我们安装完Redis后,进入/usr/bin
目录,我们会看到如下几个文件:
可执行文件名称 | 作用 |
---|---|
redis-server | 启动redis,服务端 |
redis-cli | redis命令行,客户端 |
redis-benchmark | 基准测试工具 |
redis-check-aof | AOF持久化文件检测和修复工具 |
redis-check-rdb | ROB持久化文件检测和修复工具 |
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 | 指定密码 |
-u | url格式的地址 |
-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
说明
选项 | 说明 |
---|---|
keys | server中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 值的数据大小 |
-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-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'
小结
以上就是本章的内容,由于作者水平有限, 欢迎大家能够反馈指正文章中错误不正确的地方, 感谢 🙏