目录
前言:
基本全局命令
KEYS
EXISTS
DEL
EXPIRE
TTL
TYPE
数据结构和内部编码
内部编码:
单线程架构
引出单线程模型:
为什么单线程还这么快?
String字符串
字符串数据类型:
常见命令:
SET
GET
MGET
MSET
SETNX
计数命令:
INCR
INCRBY
INCRBYFLOAT
其他命令:
APPEND
GETRANGE
SETRANGE
STRLEN
内部编码:
前言:
Redis提供了5种数据结构,理解每种数据结构的特点对于Redis开发运维⾮常重要
- 预备知识:几个全局命令,数据结构,内部编码,单线程模式机制分析
- 5种数据结构的特点、命令使用、应用场景示例
- 键遍历、数据库管理
基本全局命令
KEYS
- h?llo 匹配 hello , hallo和hxllo等
- h*llo 匹配 hllo,heeeello
- h[ae]llo 只匹配hallo,hello
- h[^e]llo 匹配hallo,hbllo...不匹配hello
- h[a-b]llo 匹配hallo到hbllo
语法:
KEYS pattern
返回值:
匹配pattern的所有key
从上面可以看出
? 只能匹配单个字符,且不能为空
* 可以匹配0到多个字符
[xyz] 可以单独匹配x与y与z,能够匹配[]中的单个字符
^ 就代表非的意思
[a-b] 中间有 ' - '就是a到b的意思即字符在a-b之间的都能匹配
EXISTS
判断某个key是否存在
语法:
EXISTS key [key ...]
返回值:key存在的个数
示例:
DEL
删除指定的key
语法:
DEL key [key ...]
返回值:删除掉的key的个数
EXPIRE
为指定的key添加秒级的过期时间(Time To Live TTL)
语法:
EXPIRE key seconds
返回值:1表示设置成功,0表示设置失败
TTL
获取指定key的过期时间,秒级
语法:
TTL key
返回值:
剩余过期时间,-1表示没有关联过期时间,-2表示key不存在
TYPE
返回key对应的数据类型
语法:
TYPE key
返回值:none、string、list、set、zset、hash、stream
示例:
数据结构和内部编码
type 命令实际返回的就是当前键的数据结构类型,它们分别是:string(字符串)、list(列表)、hash(哈希)、set(集合)、zset(有序集合),但这些只是Redis对外的数据结构
内部编码:
可以看到每种数据结构都有⾄少两种以上的内部编码实现,例如list数据结构包含了linkedlistziplist两种内部编码。同时有些内部编码,例如ziplist,可以作为多种数据结构的内部实现,可以通
过object encoding命令查询内部编码
这样设计有两个好处:
- 可以改进内部编码的同时,对外的数据结构和命令使用毫无影响,对用户来说基本无感知
- 多种编码可以实现在不同场景发挥各自的优势,例如ziplist节省内存,但是在列表元素比较多的情况下性能会下降,这时候Redis就会根据配置选项将列表类型的内部转化成linkedlist,整个过程用户感受不到
单线程架构
Redis使⽤了单线程架构来实现⾼性能的内存数据库服务
引出单线程模型:
现在开启三个redis-cli客户端同时在一个redis-server下同时执行命令
客户端1:set hello world
客户端2:incr counter
客户端3:incr counter
虽然这三个命令时同时发送的,但是从微观上看,这些命令还是线性的方式执行的,只是原则上的执行顺序不定,但是一定不会有两条命令同时执行,这就可以想象redis内部只有一个服务窗口,多个客户端按照 他们达到的先后顺序排队在串口前,依次接受Redis的服务,所以客户端2和客户端3同时对counter自增,并不会产生并发问题。
为什么单线程还这么快?
通常来讲,单线程处理能⼒要⽐多线程差,那为什么Redis使用单线程模型会达到万级的处理能力呢?
可以归结为一下三点
1.纯内存访问。内存响应时间大约为100纳秒
2.非阻塞IO。Redis使用epoll作为I/O多路复用技术的实现,不在网络I/O上浪费过多时间
3.单线程避免了线程切换和线程竞争产生的小号,简化了模型。
虽然单线程给Redis带来很多好处,但还是有⼀个致命的问题:对于单个命令的执⾏时间都是有
要求的。如果某个命令执⾏过⻓,会导致其他命令全部处于等待队列中,迟迟等不到响应,造成⼾
端的阻塞,对于Redis这种⾼性能的服务来说是⾮常严重的,所以Redis是⾯向快速执⾏场景的数据库。
String字符串
⾸先Redis中所有的键的类型都是字符串类型,⽽且其他⼏种数据结构也都是在字符串类似基础上构建的,例如列表和集合的元素类型是字符串类型,所以字符串类型能为其他4种数据结构的学习奠定基础
TIPS:由于Redis内部存储字符串完全是按照⼆进制流的形式保存的,所以Redis是不处理字符集编码问题的,客⼾端传⼊的命令中使⽤的是什么字符集编码,就存储什么字符集编码
字符串数据类型:
常见命令:
SET
将string类型的value设置到key中。如果key之前存在,则覆盖,⽆论原来的数据类型是什么。之前关于此key的TTL也全部失效。
语法:
SET key value [expiration EX seconds|PX milliseconds] [NX|XX]
选项:
- EX seconds : 使用秒级作为单位设置key的过期时间
- PX milliseconds : 使用毫秒作为单位设置key的过期时间
- NX : 只在key不存在时才进行设置,如果之前key已经存在就不设置了
- XX : 只在key存在的时候再进行设置,如果之前key不存在,就不设置
返回值:
- 成功返回OK
- 如果由于SET指定NX或者XX不满足条件,SET不会执行并返回nil
GET
获取key对应的value。如果不存在就返回nil,如果key的类型不是string就会报错
语法:
GET key
返回值:key对应的value,或者nil当key不存在
MGET
⼀次性获取多个key的值。如果对应的key不存在或者对应的数据类型不是string,返回nil。
语法:
MGET key [key ...]
返回值:对应value的列表
示例:
MSET
⼀次性设置多个key的值
语法:
MSET key value [key value ...]
返回值:永远是OK
示例:
SETNX
设置key-value但只允许在key之前不存在的情况下
语法:
SETNX key value
返回值:1表示设置成功,0表示设置失败
示例:
SETXX也是同理~~
计数命令:
INCR
将key对应的string表⽰的数字加⼀。如果key不存在,则视为key对应的value是0。如果key对应的string不是⼀个整型或者范围超过了64位有符号整型,则报错。
语法:
INCR key
返回值:integer类型的加完后的值
示例:
DECR同理,但DECR是减一
INCRBY
将key对应的string表⽰的数字加上对应的值。如果key不存在,则视为key对应的value是0。如果key对应的string不是⼀个整型或者范围超过了64位有符号整型,则报错。
语法:
INCRBY key decrement
返回值:integer类型加完后的数值
示例:
DECRBY同理,不过是减去对应的值
INCRBYFLOAT
将key对应的string表⽰的浮点数加上对应的值。如果对应的值是负数,则视为减去对应的值。如果
key不存在,则视为key对应的value是0。如果key对应的不是string,或者不是⼀个浮点数,则报
错。允许采⽤科学计数法表⽰浮点数。
语法:
INCRBYFLOAT key increment
返回值:加/减完之后的值
其他命令:
APPEND
如果key已经存在并且是⼀个string,命令会将value追加到原有string的后边。如果key不存在,
则效果等同于SET命令。
语法:
APPEND key value
GETRANGE
返回key对应的string的⼦串,由start和end确定(左闭右闭)(start,end)。可以使⽤负数表⽰倒数。-1代表
倒数第⼀个字符,-2代表倒数第⼆个,其他的与此类似。超过范围的偏移量会根据string的⻓度调整成正确的值
语法:
GETRANGE key start end
返回值:string类型的字符串
示例:
SETRANGE
覆盖字符串的一部分,从指定的偏移开始
语法:
SETRANGE key offset value
返回值:替换后的string长度
示例:
STRLEN
获取key对应的string的⻓度。当key存放的类似不是string时,报错
语法:
STRLEN key
返回值:
string的长度,或当key不存在的时候,返回0
示例:
内部编码:
字符串的内部编码有三种:
- int:8个字节长整型
- embstr:小于等于39个字节的字符串
- raw:大于39个字节的字符串
Redis会根据当前值的类型和⻓度动态决定使⽤哪种内部编码实现。
示例: