【Redis】4.基本全局命令

文章目录

  • [2. Redis 常见数据类型](#2. Redis 常见数据类型)
    • [2.1 基础知识](#2.1 基础知识)
      • [2.1.1 基本命令](#2.1.1 基本命令)
        • [2.1.1.1 SET](#2.1.1.1 SET)
        • [2.1.1.2 GET](#2.1.1.2 GET)
      • [2.1.2 基本全局命令](#2.1.2 基本全局命令)
        • [2.1.2.1 KEYS](#2.1.2.1 KEYS)
        • [2.1.2.2 EXISTS](#2.1.2.2 EXISTS)
        • [2.1.2.3 DEL](#2.1.2.3 DEL)
        • [2.1.2.4 EXPIRE](#2.1.2.4 EXPIRE)
        • [2.1.2.5 TTL](#2.1.2.5 TTL)
        • [2.1.2.6 TYPE](#2.1.2.6 TYPE)

2. Redis 常见数据类型

Redis 提供了 5 种数据结构,理解每种数据结构的特点对于 Redis 开发运维非常重要,同时掌握每种数据结构的常见命令,会在使用 Redis 的时候做到游刃有余。本章内容如下:

  • 预备知识:几个全局(generic)命令,数据结构和内部编码,单线程模式机制分析。
  • 5 种数据结构的特点、命令使用、应用场景示例。
  • 键遍历、数据库管理。
    redis客户端有很多种形态:
  1. 命令行客户端。redis-cli
  2. 图形化界面客户端。桌面程序,web程序(有可能连不上redis,因为中间会经历很多跳板机,壁垒机,权限校验)
  3. 基于redisapi自行开发客户端(工作中最主要的形态)类似于MySQLC语言APIJDBC

2.1 基础知识

在正式介绍 5 种数据结构之前,了解一下 Redis 的一些全局命令、数据结构和内部编码、单线程命令处理机制是十分必要的,它们能为后面内容的学习打下一个良好的基础。

主要体现在两个方面:

  1. Redis 的命令有上百个,如果纯靠死记硬背比较困难,但是如果理解 Redis 的一些机制,会发现这些命令有很强的通用性。
  2. Redis 不是万金油,有些数据结构和命令必须在特定场景下使用,一旦使用不当可能对 Redis 本身或者应用本身造成致命伤害。

2.1.1 基本命令

2.1.1.1 SET

设置key以保存字符串值。如果key已经保存了一个值,则不管其类型如何,它都将被覆盖。

SET操作成功时,先前与该键关联的任何存活时间都将被丢弃。

语法:

mysql 复制代码
SET key value [NX | XX | IFEQ ifeq-value | IFNE ifne-value |
  IFDEQ ifdeq-digest | IFDNE ifdne-digest] [GET] [EX seconds |
  PX milliseconds | EXAT unix-time-seconds |
  PXAT unix-time-milliseconds | KEEPTTL]

命令有效版本:1.0.0 之后

时间复杂度:O(N)

返回值:无

实例:

mysql 复制代码
127.0.0.1:6379> set key1 value1
OK
127.0.0.1:6379> set key2 value2
OK
127.0.0.1:6379> set "key3" value2
OK
127.0.0.1:6379> get key1
"value1"
127.0.0.1:6379> get value2
(nil)
127.0.0.1:6379> get key2
"value2"
127.0.0.1:6379> get key3
"value2"
127.0.0.1:6379> 

2.1.1.2 GET

获取key的值。如果键不存在,则返回nil。和null/NULL是一个意思。

如果存储在key处的值不是字符串,则返回错误,因为GET只处理字符串值。

语法:

mysql 复制代码
GET key

命令有效版本:1.0.0 之后

时间复杂度:O(N)

返回值:key的值。

实例:

mysql 复制代码
127.0.0.1:6379> set key1 value1
OK
127.0.0.1:6379> set key2 value2
OK
127.0.0.1:6379> set "key3" value2
OK
127.0.0.1:6379> get key1
"value1"
127.0.0.1:6379> get value2
(nil)
127.0.0.1:6379> get key2
"value2"
127.0.0.1:6379> get key3
"value2"
127.0.0.1:6379> 

2.1.2 基本全局命令

Redis5 种数据结构,但它们都是键值对种的值,对于键来说有一些通用的命令。

redis中的命令不区分大小写。


2.1.2.1 KEYS

返回所有满足样式(pattern)的 key。支持如下统配样式:

  1. h?llo 匹配 hello , hallohxllo
  2. h*llo 匹配 hlloheeeello
  3. h[ae]llo 匹配 hellohallo 但不匹配 hillo
  4. h[^e]llo 匹配 hallo , hbllo , ... 但不匹配 hello
  5. h[a-b]llo 匹配 hallohbllo(匹配ab范围内的字符)

上述规则这些不用刻意去背,有个印象就行了。要用的时候去查一下就行。

注意:keys的时间复杂度是O(N),所以在一些生产环境上会禁止使用keys命令,尤其是keys *

因为生产环境上的key可能会非常多,而redis是一个单线程服务器,执行keys *的时间非常长,就会使得redis服务器被阻塞,无法给其他客户提供服务。这样的后果可能是灾难性的。

因为redis经常会做缓存,挡在MySQL前面,替MySQL负重前行。万一redis被一个keys *阻塞住了,其他的查询redis操作就超时了。这些请求就会直接查数据库,突然一堆请求过来,MySQL措手不及就可能挂掉。整个系统基本就挂了,如果没有及时发现的话,年终奖就飞走啦。(银手镯应该不至于)

语法:

mysql 复制代码
 KEYS pattern

命令有效版本:1.0.0 之后

时间复杂度:O(N)

返回值:匹配 pattern 的所有 key

示例:

mysql 复制代码
127.0.0.1:6379> MSET firstname Jack lastname Stuntman age 35keys *  
OK
127.0.0.1:6379> KEYS *name*
1) "firstname"
2) "lastname"
127.0.0.1:6379> KEYS a??
1) "age"
127.0.0.1:6379> KEYS *
1) "firstname"
2) "lastname"
3) "backup3"
4) "age"
127.0.0.1:6379> 

2.1.2.2 EXISTS

判断某个 key 是否存在。

语法:

mysql 复制代码
EXISTS key [key ...]

命令有效版本:1.0.0 之后

时间复杂度:O(1)

返回值:key 存在的个数。

实例:

mysql 复制代码
127.0.0.1:6379> SET key1 "Hello"
OK
127.0.0.1:6379> exists key1
(integer) 1
127.0.0.1:6379> exists nosuchkey
(integer) 0
127.0.0.1:6379> set key2 "World"
OK
127.0.0.1:6379> exists key1 key2 nosuchkey
(integer) 2
127.0.0.1:6379> exists key1 key2
(integer) 2
127.0.0.1:6379> 

2.1.2.3 DEL

删除指定的 key

语法:

mysql 复制代码
DEL key [key ...]

命令有效版本:1.0.0 之后

时间复杂度:O(1)

返回值:删除掉的 key 的个数。

不过不小心删一两个倒是没事,一不小心全删掉或者删掉大半,就会有很大的影响了。请求都打给MySQL就可能把MySQL搞挂掉。

如果把redis作为数据库,误删的影响就大了。

如果把redis作为消息队列,误删的影响需要具体情况具体分析。

示例:

mysql 复制代码
127.0.0.1:6379> SET key1 "Hello"
"OK"
127.0.0.1:6379> SET key2 "World"
"OK"
127.0.0.1:6379> DEL key1 key2 key3
(integer) 2
127.0.0.1:6379>

2.1.2.4 EXPIRE

为指定的 key 添加秒级的过期时间(Time To Live TTL

语法:

mysql 复制代码
EXPIRE key seconds

命令有效版本:1.0.0 之后

时间复杂度:O(1)

返回值:1 表示设置成功。0 表示设置失败。
其实很多业务都有时间限制。

例如:

  1. 手机验证码几分钟内有效

  2. 外卖优惠卷几号后过期

  3. 基于redis实现分布式锁,为了避免不能正确解锁的情况(比如解锁的数据丢了),通常都会在加锁的时候设置一下过期时间。

    其实所谓的redis实现分布式锁,就是给redis里面写一个特殊的key value

示例:

mysql 复制代码
127.0.0.1:6379> SET mykey "Hello"
OK
127.0.0.1:6379> get mykey
"Hello"
127.0.0.1:6379> expire mykey 10
(integer) 1
127.0.0.1:6379> ttl mykey
(integer) 7
127.0.0.1:6379> get mykey
"Hello"
127.0.0.1:6379> ttl mykey
(integer) 1
127.0.0.1:6379> ttl mykey
(integer) -2
127.0.0.1:6379> get mykey
(nil)
127.0.0.1:6379> 

2.1.2.5 TTL

获取指定 key 的过期时间,秒级。

语法:

mysql 复制代码
TTL key

命令有效版本:1.0.0 之后

时间复杂度:O(1)

返回值:剩余过期时间。-1 表示没有关联过期时间,-2 表示 key 不存在。

示例:

mysql 复制代码
127.0.0.1:6379> SET mykey "Hello"
OK
127.0.0.1:6379> get mykey
"Hello"
127.0.0.1:6379> expire mykey 10
(integer) 1
127.0.0.1:6379> ttl mykey
(integer) 7
127.0.0.1:6379> get mykey
"Hello"
127.0.0.1:6379> ttl mykey
(integer) 1
127.0.0.1:6379> ttl mykey
(integer) -2
127.0.0.1:6379> get mykey
(nil)
127.0.0.1:6379> 

EXPIRETTL 命令都有对应的支持毫秒为单位的版本:PEXPIREPTTL
键的过期机制:

  1. 定期删除:每次抽取一部分,进行验证过期时间。保证这个抽取检查的过程,足够快。因为如果把所有的key都抽取一边就太耗时了。

    为啥这里对于定期删除的时间,有明确的要求呢?

    因为redis是单线程的程序。主要的任务是处理每个命令的任务,刚才扫描过期key,如果扫描过期key 消耗的时间太多了,就可能导致正常处理请求命令就被阻塞了。(产生了类似于执行keys *这样的效果,外界看起来就像redis挂了一样)

  2. 惰性删除:假设这个key已经到过期时间了,但是暂时还没删它,key还存在.紧接着,后面又一次访问,正好用到了这个key,于是这次访问就会让redis服务器触发删除key的操作,同时再返回一个nil

    类似于:有一个杂货铺老板,店里有一堆东西,但是不知道哪些过期了。你买东西的时候,他发现过期了,就会丢掉商品不让你买。

下图是定期删除:

注意:

redis中没有采取定时器的方式来实现过期key删除。
虽然没有采取定时器,但是有两种高效的定时器方案可以看一下:(下面两个方案并不在redis中采用)

方案一:基于优先级队列/堆

正常的队列是先进先出,优先级队列则是按照指定的优先级,先出。

这个优先级高可以自定义。

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

现在假定有很多key 设置了过期时间,就可以把这些key加入到一个优先级队列中,指定优先级规则是过期时间早的,先出队列,队首元素,就是最早的要过期的key

比如:

key1:12:00

key2:13:00

key3:14:00

key1先过期,先进队列,key2其次,key3最后

此时定时器中只要分配一个线程,让这个线程去检查队首元素,看是否过期即可。如果队首元素还没过期,后续元素一定没过期。此时扫描线程 不需要遍历所有key只盯住这一个队首元素即可。

另外在扫描线程检查队首元素过期时间的时候,也不能检查的太频繁,此时做法就是可以根据当前时刻和队首元素的过期时间,设置一个等待。当时间差不多到了,系统再唤醒这个线程。此时扫描线程不需要高频扫描队首元素,把cpu的开销也节省下来了。

万一在线程休眠的时候,来了一个新的任务,是11:30要执行,可以在新任务添加的时候,唤醒一下刚才的线程~~重新检查一下队首元素,再根据时间差距重新调整阻塞时间即可。
方案二:基于时间轮实现的定时器

把时间划分成很多小段。(划分的粒度,看实际需求)


2.1.2.6 TYPE

返回 key 对应的值的数据类型。

语法:

mysql 复制代码
TYPE key

命令有效版本:1.0.0 之后

时间复杂度:O(1)

返回值: none , string , list , set , zset , hash and stream ...

示例:

mysql 复制代码
127.0.0.1:6379> SET key1 "value"
OK
127.0.0.1:6379> LPUSH key2 "value"
(integer) 1
127.0.0.1:6379> SADD key3 "value"
(integer) 1
127.0.0.1:6379> TYPE key1
string
127.0.0.1:6379> TYPE key2
list
127.0.0.1:6379> TYPE key3
set
127.0.0.1:6379> 
相关推荐
王八八。2 小时前
Navicat 17破解版下载安装教程 附安装激活步骤(2026 最新版)
数据库·navicat
Jelena157795857923 小时前
电商运营分析数据比价接口实战:多平台价格监控与智能决策系统
java·大数据·数据库
流星白龙4 小时前
【Redis】3.Redis安装与命令行客户端
数据库·redis·缓存
凌虚5 小时前
基于 PostgreSQL WAL 构建 CDC 系统:原理与工程实现
数据库·后端·postgresql
BullSmall5 小时前
PostgreSQL 14 pg_dumpall 完整备份指南
数据库·postgresql·oracle
一只枫林6 小时前
MySQL内、外连接知识点汇总
java·前端·数据库
暮暮祈安6 小时前
Celery 新手入门指南
java·数据库·python·flask·httpx
xiaowang1234shs7 小时前
怪兽轻断食技术深度测评:从断食计时引擎到AI识别算法的工程实践解析
数据库·人工智能·算法·macos·机器学习·p2p·visual studio
Quincy_Freak7 小时前
银河麒麟 aarch64 环境下轻量 SQLite 管理方案实践:SQLiteGo 落地体验
数据库·sqlite·sqlitego