> 技术文档 > Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘


前言

在当今这个追求极致性能和高并发的互联网时代,Redis已然成为后端技术栈中不可或缺的“瑞士军刀”。无论是作为高速缓存、分布式锁,还是实现消息队列,它无处不在。但你是否曾好奇,小小的Redis为何能拥有如此惊人的性能?它赖以成名的单线程模型,究竟是如何“单枪匹马”地处理数以万计的并发请求的?
本文将带你开启一场Redis的深度探索之旅。我们不谈空洞的理论,而是从零开始,手把手教你如何在Linux上搭建环境、修改配置。随后,我们将深入浅出地讲解set、keys、expire等一系列核心命令,并重点剖析keys *命令在生产环境中的潜在风险。最后,我们将直面那个“百万美元”的面试题——Redis为什么这么快?通过对其底层数据结构、单线程模型和IO多路复用机制的层层剖析,让你不仅知其然,更知其所以然。准备好了吗?让我们一起揭开Redis高性能的神秘面纱!

环境搭建

我们安装的Redis5版本

在Linux中进行安装

Redis官方是不支持Windows版本的

打开Linux,先切换到root用户

然后使用apt命令来搜索Redis相关的软件包

apt search redis

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

这里我们已经安装好了

apt install redis

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

安装好了之后,我们可以输入命令进行查询Redis是否在运行中

netstat -app |grep redis

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
我们这里的ip是0.0.0.0说明别的主机也是可以进行访问的

但是你如果一开始是127.0.0.1的话,绑定这个127.0.0.1的ip意味着只能由当前主机上的客户端访问,跨主机就访问不了

那么我们就得进行配置文件的修改操作了,不然的话别的主机是访问不了你的redis的

我们输入命令进入到配置文件路径下

cd /etc/redis/

可以看到一个redis.conf文件,这个就是redis的配置文件
Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

进入到文件中,找到这个bind
Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
改成我这个样子0.0.0.0
然后我们还需要将保护模式给关闭了
将后面改成no
Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
这里的端口号是6379

我们的redis是不需要配置密码的
虽然我们没有密码,但是非常安全

因为我们的数据不值钱

在修改配置文件之后,如果想生成改变的话,我们得重新启动redis服务器

srevice redis-server restart

输入命令之后,看到active running就说明你重启成功了

使用redis自带的客户端链接服务器

在终端输入命令

redis-cli

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
为了验证是否链接成功,我们这里发送一个ping命令,成功的话会显示一个PONG的
Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
如果想退出redis的话,我们输入ctrl d即可进行退出操作了

Ctrl c也可以退出

Redis的客户端也有很多的形态
1、自带了命令行客户端

redis-cli

如果想要连接别的redis的话
-h就是ip地址,-p是端口号

redis-cli -h 127.0.0.1 -p 6379

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

2、图形化界面的客户端
(桌面程序,web程序)

我们谈到mysql这样的快,是相对于mysql这样的关系型数据库的

如果我们直接和内存中的操作变量相比的话,就没有优势了,甚至更慢了

使用hash mcp的话是直接操作内存
而我们使用redis是先通过网络,再操作内存

是否使用redis,要结合实际的需求来确定

未来要扩展分布式系统,使用redis是更佳的

redis核心命令

get和set

Redis中最核心的两个命令

get #根据key来取valueset #把key和value存储进去

redis是按照键值对的方式存储数据的

set key value

这里的key和value必须都是字符串Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
redis中的命令是不区分大小写的

get命令直接输入key就能得到value
Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
如果key不存在的话,会返回一个nil,和null/NULL是一个意思
Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

使用简单,学习成本很低
将redis当成一个网络版本的哈希表

keys(全局命令)

redis支持很多种数据结构

整体来说,redis是键值对结构,key固定就是字符串,valude实际上会有很多种类型(字符串、哈希表、列表、集合、有序集合)

操作不同的数据结构,就会有不同的命令

全局命令,就是能够搭配任意一个数据结构来使用的命令

keys 用来查询当前服务器上匹配的key

通过一些特殊符号(通配符)来描述key的摸样,匹配上述摸样的key就能被查询出来

语法结构

keys pattren

pattren存在的意义,是去描述另外的字符串长啥样

  • ?匹配任意一个字符
    我们这里插入了三个键值对,然后使用?通配符进行查找
    Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
    • 匹配一个或者n个相同字符
      Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
  • [ae]只能匹配到a或者e,别的不行,相当于给出固定的选项
    Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

  • [^e]排除e,只有e匹配不了,其他的都能匹配
    Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

  • [a-c]a到c中间的字母都是可以的,包含a和c

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

keys命令的时间复杂度是O(N)
因为在执行这个命令的时候会遍历我们所有的key
所以在生产环境上,一般都会禁止使用keys命令
尤其是大杀器keys *

因为生产环境上的key可能非常多,而redis是一个单线程的服务器

执行Keys * 的时间非常长,就使redis服务器被阻塞了,无法给其他客户端提供服务Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
整个系统基本瘫痪

exists(判断Key是否存在)

判断某个key是否存在

返回的是key存在的个数

针对多个key来说是很有用的

时间复杂度是O(1)

reids组织这些key就是按照哈希表的方式来组织的

redis支持很多数据结构=》指的是一个value可以是一些复杂的数据结构

redis自身的键值对值通过哈希表来组织的

redis具体的某个值,又可以是一些数据结构

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
返回对应key的个数
上面我们是分开的写法,会产生更多轮次的网络通信,成本高,效率低

下面是合并在一起的,直接返回两个Key存在的总数值

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
redis的很多命令都是支持一次就能操作多个key的Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

del(删除key)

删除指定的key
可以一次删除一个或者多个Key

返回值是删除掉的Key的个数

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
如果redis存储的是全量数据的话,那么误删数据问题就很大了

如果是热点数据的话误删一两个还是无所谓的

expire(设置过期时间)

给指定的key设置过期时间
key存活的值超过这个指定的时间就会被自动删除了

很多的业务场景都是有时间限制的,比如说手机验证码

基于redis实现分布式锁,为了避免出现不能正常解锁的情况,通常都会在加锁的时候设置一下过期时间(所谓的使用redis作为分布式锁,就是给redis里写一个特殊的额key value)我们将这个Key value删除掉就相当于自动解锁

使用格式如下:

expire key seconds

如果给不存在的key进行过期时间的设置的话是会设置失败的,那么就会返回0

如果返回0就说明你设置失败了,如果是1的话就说明成功了

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

ttl(查询存活时间)

查看当前key的过期时间还剩多少

TTL key

返回的是过期时间

返回值是剩余过期时间

-1表示没有关联过期时间 ,-2表示key不存在
Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

key的过期策略的实现

redis怎么知道那些Key要过期,那些key要被删除,哪些key还没过期?

如果直接遍历所有的key,他的效率是很低的

redis整体的策略是:
定期删除
比喻理解:超时老板会定期检查过期的产品,每次抽取一部分进行验证过期时间,保证这个抽取检查的过程,足够快
惰性删除
假设这个Key已经到了过期时间了,但是还没删除他,key还存在,紧接着,后面又一次访问用到这个key,于是这次访问就让redis服务器触发删除key的操作,同时再返回一个nil
比喻理解:当我买东西的时候,结账的时候老板发现过期了,然后不卖了

为什么这里对于定期删除的时间,有明确的要求呢?
因为redis是单线程的程序

如果扫描过期key消耗的时间太多了,就可能导致正常请求命令就被阻塞了(产生了类似执行与keys * 的效果)

redis为了对上述进行补充,还提供了一系列的内存淘汰策略

redis中并没有采取定时器的方式来实现过期key删除
如果有多个key过期,也可以通过一个定时器来高效/节省CPU的前提下来处理多个key

我们目前还不知道为啥redis没有采取这种定时器的方式

定时器的实现,势必就得引入多线程了

redis的早起版本就奠定了单线程的基调,引入多线程就打破了作者的初衷了

定时器的实现原理

在某个时间到达之后,执行指定的任务

基于优先级队列/堆
正常的队列是先进先出
优先级队列是啊按照指定的优先级,先出
啥叫优先级高,这个是我们自定义的

在redis过期key的场景中,就可以通过过期时间越早,就是优先级越高

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
针对队首元素即可,不用遍历所有的key

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

第二种基于时间轮实现的定时器

把时间划分为很多的小块儿Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
这两种方法都是比较高效的定时器实现方案

type(查看value的类型)

返回key对应的value的类型

key都是string类型的,但是value可能存在多种类型

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

总结

上面我们已经学习了几个简单的命令Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

下面就围绕每个数据结构来介绍相关的命令了Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

常用数据结构

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
redis底层在实现上述数据结构的时候,会在源码层面,针对上述实现 进行特定的优化,来达到节省时间/空间的效果

内部的具体实现的具体实现结构(编码方式),会有变数

数据结构:redis承诺给你的,也可以理解成数据类型
编码方式:redis内部底层的实现

同一个数据类型,背后可能得编码实现方式是不同的,会根据特定场景优化
Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
raw是最基本的字符串,底层就是持有一个char数组

int类型:redis通常也可以实现一些计数这样的功能
当value就是一个整数的时候,此时可能吧redis会直接使用int来保存

embstr针对短字符串进行的特殊优化

hashtable是最基本的哈希表

ziplist叫做压缩列表:在哈希表里面元素较少的时候,可能就优化成ziplist了
压缩列表,节省空间

那么为啥要压缩呢?
redis上可能有很多的key
可能某些key的value是key

linkedlist:链表,一个节点指向另一个节点

ziplist就是压缩列表,如果列表中元素个数少,就使用ziplist
如果元素多的话就使用linkedlist

在redis3.2开始,引入了新的实现方式quicklist同时兼顾了linkedlist和ziplist的优点
quicklist就是一个链表,每个元素又是一个ziplist
这样把空间和效率都兼顾到了
类似于C++中的std::deque

intset :集合中存的都是整数的话,那么就会优化会intset

skiplist:跳表也是链表,不同于普通的链表,每个节点上有多个指针域,巧妙的搭配这些指针域的指向,就可以做到,从跳表啥啊昂查询元素的时间复杂度是O(logn)

我们可以使用object encoding key查看key对应的value对应的编码类型
Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
redis会自动根据当前情况选择内部的编码方式

redis单线程模型

单线程模型的工作过程

redis只使用一个线程,处理所有的命令请求

不是说一个redis服务器进程内部真的就只有一个线程
其实也有多个线程,多个线程是在处理网络IO
Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘
这里我们的两个客户端访问服务器中的Key对应的value ,让value进行自增,

在多线程中,针对于类似的场景,两个线程尝试同时对一个变量进行自增,表面上是自增两次,实际上可能是一次
当前这两个客户端,也相当于并发的发起上述的请求
此时就意味着服务器这边也会存在类似的线程安全问题呢?

幸运的是,并不会,redis服务器实际上是单线程模型,保证了当前收到的这多个请求是串行执行的

这两个请求在排队,依次进行执行,顺序执行

多个请求同时到达redis服务器,也是在队列中进行排队

redis能够使用单线程模型很好的工作,原因主要在于redis的核心业务逻辑都是短平快的,不太消耗CPU资源也不太吃多核了

redis要特别小心,某个操作占用时间长,就会阻塞其他命令的执行,比如说keys *

redis为什么这么快(重要面试题)

为什么效率这么高,速度为什么这么快

谈到快以及效率高,都是我们和其他的关系型数据库进行对比的

我们参照物是数据库

1、redis访问内存,数据库则是访问硬盘,

2、redis核心功能,比数据库的核心功能更简单
数据库对于数据的插入删除查询,都有更复杂的功能支持,这样的功能势必要花费更多的开销,针对插入删除,数据库中的各种约束,都会使数据库做额外的工作,Redis干的活少,提供的功能相较于redis也是少了不少了
3、redis采取单线程模型,避免了一些不必要的线程竞争开销
redis每个操作都是短平快的,就是简单操作一下内存数,不是特别小号cpu的操作,就算是搞多个线程,也提升不大
4、处理网络IO的时候,使用了epoll这样的IO多路复用机制
一个线程就可以管理多个socket
针对tcp来说,服务器这边每次要服务一个客户端,都需要给这个客户安排一个socket

一个服务器服务很多客户端,同时就有很多的socket
这些socket上都是无时无刻的在传输数据么?

很多情况下,每个客户端和服务器之前的通信也没有那么频繁
此时这么socket大部分时间都是静默的,上面是没有数据需要传输的

同一时刻,只有少数socket是活跃的

最开始介绍TCP服务器的时候,有一个版本就是每个客户端给分配一个线程
客户端多了,线程就多了,系统开销就大了

通过IO多路复用,一个线程来处理多个socket

Redis从入门到精通:一文搞定环境搭建、核心命令与高性能奥秘

总结

总的来说,本文为我们提供了一份从实践到理论的Redis核心知识图谱。
我们从最基础的环境搭建入手,详细走过了在Linux上安装、配置Redis的全过程,确保你能顺利启动并连接到自己的Redis服务器。
接着,我们深入学习了Redis的核心全局命令,包括最基本的GET/SET,用于模式匹配的KEYS(及其性能警告),判断存在的EXISTS,以及实现业务场景必不可少的EXPIRE和TTL。这些命令是日常开发中使用频率最高的利器。
随后,文章进一步揭示了Redis高效的秘密——其丰富的数据结构与巧妙的内部编码。我们了解到,Redis对外提供统一的数据类型(如List, Hash),但在底层会根据数据规模和特点,智能地选择ziplist、skiplist等最优的编码方式,以此在空间和时间效率上达到极致平衡。
最后,我们集中探讨了Redis架构的精髓——单线程模型,并完美解答了“Redis为什么这么快”这一经典面试题。其核心优势可归结为四点:
纯内存操作:所有操作均在内存中完成,速度远超磁盘I/O。
功能相对简单:核心功能聚焦于数据读写,避免了关系型数据库的复杂逻辑。
单线程模型:避免了多线程带来的上下文切换和锁竞争的开销。
I/O多路复用:采用epoll等机制,单个线程即可高效处理大量网络连接。
通过这篇文章,你不仅掌握了Redis的实用操作技巧,更深入理解了其背后的设计哲学与高性能原理,为你在实际项目应用和技术面试中增添了充足的信心。