日升时奋斗,日落时自省
注:命令区分有点细,择取自己需要的即可
目录
3.1、应用(Application)/系统(System)
3.9、吞吐(Throughput)vs并发(Concurrent)
在官方文档开头,redis作用就存储数据,但是不同于数据库的是“内存中存储”
redis可以做的角色有很多:可以做数据库、缓存、消息队列、消息代理(针对这不同角色解释)
数据库:MySQL(我们常见的数据库)最大的问题在于,访问速度比较慢很多互联网产品中,对于性能要求是很高,Redis作为数据库的话,相较于MySQL的访问速度快
注:经由对比,才能说Redis很快,但是既然是内存中操作,拿数据量就小,承受能力有限,光快但是能存储的数据量不大
如何能做到快速且容量大??
解决方案:Redis和MySQL结合起来使用
不是所有数据都直接经过MySQL,存储肯定都是存储在MySQL中的,有足够大的容量来接收数据,redis操作数据更快
针对所谓数据都有常用数据,不常用数据,也就衍生出了“二八原则”,20%的热点数据,能满足80%的访问需求(不是说一定就是20%,按照业务需求来定夺分配,“一九”也不是没有)
注:系统的复杂程度大大提升,分布式如果数据发生修改,还涉及到Redis和MySQL之间的数据同步问题
消息队列:Redis的初心,最初就是用来作为一个“消息中间件”的(消息队列),分布式系统下的生产者消费者模型,因为redis功能不是完全做消息队列的中间件的
Redis是在分布式系统中才会起的作用,如果只是单击程序,直接通过变量存储数据的方式,就不用使用了Redis
1、单机架构
单机架构,只有一台服务器,这个服务器负责所有的工作(也就是常规请求)
单机程序中,其实靠的不就是数据库信息的拉取嘛,但是数据库也不是不能去掉,光服务器负责所有操作(单机架构是比较常见架构使用,因为只有数据量够大的情况才会使用redis)
一台主机的硬件资源是有上限的,CPU、内存、硬盘、网络每次请求都会收到一个请求,都是需要消耗上述的一些资源,现在一台主机都够用(不行了其实也可以增加硬件资源,但是肯定硬件资源不能在加了就开始使用分布式)
2、数据库和应用分离
一个应用服务器节点就要承受大量的请求一时是处理不了的,影响到用户的体验感,所以这里就针对大量数据做出优化措施:
引入更多的应用服务器节点分匹配请求量就分开处理,提高处理效率,这里就提及到负载均衡器
负载均衡器:主要作用就是任务分配(请求分配),具体的算法
应用服务器是要吃资源的CPU和内存要承受的了,负载均衡器就分配给多个应用服务器,解决资源问题,这里有两个应用服务器,如果是1w的请求量,那可以每个服务器处理5k,如同多线程
注:这里只有展示了两个应用服务器,但实际上不一定就是两个,可以是多个
执行过程:用户--(大量请求)-->负载均衡器--(请求量分配)-->应用服务器-->存储服务器
3、分布式基本概念
3.1、应用(Application)/系统(System)
一个应用,就是一个/组服务器程序
3.2、模块(Module)/组件(Component)
一个应用,里面有很多个功能,每个独立的功能,就可以称为是一个模块/组件
3.3、分布式(Distributed)
引入多个主机/服务器,协同配合完成一系列的工作(物理上的多个主机)
3.4、集群(Cluster)
引入多个主机/服务器,协同配合完成一系列的工作(逻辑上的多个主机)
3.5、主(Master) /从(Slave)
分布式系统中一种比较典型的结构
多个服务器节点,其中一个是主,剩下的都是从节点,从节点的数据要从主节点这里同步过来,这里的从节点也可能是其他从节点的主节点
3.6、中间件(Middleware)
相通业务的服务(功能更通用的服务):数据库、缓存、消息队列、负载均衡、安全认证、同步数据
3.7、可用性(Availability)
系统整体可用的时间/总的时间 一年能可用多长时间:360/365=98.63%
3.8、响应时长(Response Time RT)
衡量服务器的性能 和具体服务器要做的业务密切相关的 (越小越好)
3.9、吞吐(Throughput)vs并发(Concurrent)
吞吐:指系统在单位时间内处理的请求数或者说单位时间内处理的字节数
并发:则是指同时访问系统的用户数量
衡量系统的处理请求的能力,衡量性能的一种方式
4、命令行客户端
4.1、连接redis
(1)交互式方式:redis-cli -h 127.0.0.1 -p 6379
是否连接上,ping一下,响应PONG
(2)命令方式交互:redis-cli -h 127.0.0.1 -p 6379 ping
当然后面命令不是就这一种,只要是redis的命令就可以
注:-h {host} -p {port}
4.1.1、全局命令
redis中5种常见数据结构,他们都是键值对的形式,对于键来说有些通用的命令
(1)KEYS:满足样式(pattern)的key
命令操作: keys pattern
注:这里keys *是全部都去查询的,所以尽量不要使用,大量的查询也会吃掉很多的网络带宽,这时如果客户端来了信息就不一定能接收得到了
(2)EXISTS
判断某个key是否存在
操作命令:EXISTS key (这里可以是多个,redis1.0版本之后都是可以的)
返回的是查询的个数,查到的有几个
(3)DEL 删除命令
删除命令:del key (可以指定多个key)
(4)EXPIRE 设定过期时间
指定这个key的过期时间,秒级的过期时间
操作命令:EXPIEX key 秒数
设置之前 这个key是需要存在的,才能设置时间 TTL 是显示key当前还剩下多少时间(如果是-1表示没有设置过期时间,-2表示没有这个key)
(5)TYPE 数据类型
操作命令:TYPE key
4.2、String字符串
字符串类型是Redis最基础的数据类型,关于字符串需要特别注意;首先redis所有的键类型都是字符串类型,而且其他几种数据结构也都是在字符串类似基础上构建的
4.2.1、创建键值对
操作命令:set key value [expiration EX seconds | PX milliseconds] [NX|XX]
expiration这个关键词已经介绍过了就是过期时间,如果不设置时间的话,就是以秒为单位的,如果以PX 开头的话为就是毫秒级别的
EX seconds 使用秒为单位进行设置过期时间
PX milliseconds 使用毫秒为单位设置过期时间
NX 只在key不存在时才能设置,,如果存在key之前已经存在 设置不执行
XX 只在key存在时才进行设置,既如果key之前不存在,设置不执行
命令就直接拿来练(set 是设置命令 get是获取key对应的value)
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> EXISTS mykey
(integer) 0
127.0.0.1:6379> set mykey "hello"
OK
127.0.0.1:6379> get mykey
"hello"
127.0.0.1:6379> set mykey "world" NX
(nil)
127.0.0.1:6379> del mykey
(integer) 1
127.0.0.1:6379> set mykey "world" NX
OK
127.0.0.1:6379> get mykey
"world"
127.0.0.1:6379> get mykey
"world"
127.0.0.1:6379> set mykey "will expire in 10s" EX 10
OK
127.0.0.1:6379> ttl mykey
(integer) 6
127.0.0.1:6379> ttl mykey
(integer) 5
127.0.0.1:6379> get mykey
(nil)
以上是一些演示环节,友友们直接自行操作即可 最后的四行命令主要展示的是在设置键值对的时候就开始了设置过期时间
EX 这里演示意思是:如果mykey值是有的,但是我能给你覆盖掉,并且设定一个过期时间
注:redis进行命令操作的时候一般都是有提示的,所以不用硬记命令
4.2.2、一次获取多个值
MGET命令操作:mget key (这里可以写多个key) 一次获取多个key的value
下面开始命令演示:
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set key1 "hello"
OK
127.0.0.1:6379> set key2 "world"
OK
127.0.0.1:6379> mget key1 key2 key3
1) "hello"
2) "world"
3) (nil)
mget 获取不同个key的value值 会对应进行显示如果这个key值不存在的话就会直接打印一个nil
注:nil就相当于C语言中的NULL 也就相当于 Java中的null 就是没有的意思
4.2.3、一次创建多个键值对
一次设置多个key 的值
MSET 操作命令:MSET key value (设置多组key-value)
127.0.0.1:6379> MSET key3 "hello" key4 "world"
OK
127.0.0.1:6379> MGET key3 key4
1) "hello"
2) "world"
mget/mset有效减少网络时间,所以性能相较更高,假设网络消耗1毫秒,执行时间消耗0.1毫秒
例如:1000次get 耗时:1000*1 +1000*0.1=1100毫秒
1次mget1000个 耗时: 1*1+1000*0.1=101毫秒
命令是向服务器发送请求的而不是当前直接执行命令,命令交给服务器进行执行,所以这里mset发送命令的时候,发送1次消耗的时间,减少了网络传输的时间,网络传输的时间是比较慢的,同时也是比较珍贵的资源
4.2.4、覆盖创建键值对
设置key-value 允许在key之前不存在的情况下
127.0.0.1:6379> SETNX mykey "hello"
(integer) 1
127.0.0.1:6379> SETNX mykey "world"
(integer) 0
127.0.0.1:6379> get mykey
"hello"
SET、SETNX、SETXX其实一个set也就够用了,后面两个完全不需要去记,只要会set 相关的命令后面两个命令都很简单
4.3、计数命令
4.3.1、单增命令
key对应string表示的数字加一如果key不存在,则视为key对应的value是0,这里key可以是string类型创建的,但是他必须是一个整型或者不超过64位符号整型
操作命令:incr key (下面演示的是正常情况)
返回值:加1后的值
127.0.0.1:6379> set key5 1
OK
127.0.0.1:6379> EXISTS key5
(integer) 1
127.0.0.1:6379> INCR key5
(integer) 2
127.0.0.1:6379> get key5
"2"
如果是非整型类型的数据
127.0.0.1:6379> get key2
"world"
127.0.0.1:6379> INCR key2
(error) ERR value is not an integer or out of range
这里就拿string类型的来演示
4.3.2、n增命令
单增的情况是比较常见的,但是一次增加一个数也不少见使用INCRBY命令操作
操作命令:INCRBY key 数值
返回值:加后的值
127.0.0.1:6379> EXISTS key5
(integer) 1
127.0.0.1:6379> get key5
"2"
127.0.0.1:6379> INCRBY key5 10
(integer) 12
127.0.0.1:6379> get key5
"12"
注:INCRBY命令返回的是一个数值,进行加法后的数值(同样如果不是一个整型也会报错的)
4.3.3、单减命令
DECR就是key对应string表示的数字减一,key不存在,则key对应的value是0
返回值:减1后的值
127.0.0.1:6379> get key5
"12"
127.0.0.1:6379>
root@ubuntu22:~# redis-cli
127.0.0.1:6379> EXISTS key5
(integer) 1
127.0.0.1:6379> get key5
"12"
127.0.0.1:6379> DECR key5
(integer) 11
127.0.0.1:6379> get key5
"11"
4.3.4、n减命令
DECRBY就是针对确定的数字进行减法的
操作命令:DECRBY key 数值
返回值:减后的值
127.0.0.1:6379> EXISTS key5
(integer) 1
127.0.0.1:6379> get key5
"11"
127.0.0.1:6379> DECRBY key5 10
(integer) 1
127.0.0.1:6379> get key5
"1"
4.3.5、浮点数加减
INCRBYFLOAT命令就是针对浮点小数的加减的
操作命令:INCRBYFLOAT key 浮点数
返回值:加减完后的值
127.0.0.1:6379> EXISTS key5
(integer) 1
127.0.0.1:6379> get key5
"1"
127.0.0.1:6379> INCRBYFLOAT key5 0.1
"1.1"
127.0.0.1:6379> get key5
"1.1"
127.0.0.1:6379> INCRBYFLOAT key5 -0.5
"0.6"
127.0.0.1:6379> get key5
"0.6"
注:INCRBYFLOAT后面跟值是正数就进行 “+” 如果是负数 “-”
4.4、string获取相关命令
4.4.1、末尾追加命令
操作命令: APPEND key value
返回值:追加后整个string的长度
127.0.0.1:6379> EXISTS key2
(integer) 1
127.0.0.1:6379> get key2
"world"
127.0.0.1:6379> APPEND key2 "hello"
(integer) 10
127.0.0.1:6379> get key2
"worldhello"
4.4.2、获取string指定区间
操作命令:GETRANGE key start end
127.0.0.1:6379> set mykey "this is a people"
OK
127.0.0.1:6379> GETRANGE mykey 0 4
"this "
127.0.0.1:6379> GETRANGE mykey -5 -1
"eople"
127.0.0.1:6379> GETRANGE mykey 0 -1
"this is a people"
GETRANGE区间的选定的是比较类似于Python的可以支持负数这里(0 到 -1 表示的就是到最后一个位置 -1 也表示当前字符串的最大长度,该命令类似于子串的截取)
4.4.3、子串的覆盖
操作命令:SETRANGE key offset value
offset 就是偏移量 value就是string内容
返回值:替换后string的长度
127.0.0.1:6379> set key1 "Hello world" xx
OK
127.0.0.1:6379> get key1
"Hello world"
127.0.0.1:6379> SETRANGE key1 6 "redis"
(integer) 11
127.0.0.1:6379> get key1
"Hello redis"
注:这里第一条命令使用了 xx 是因为我这里位置直接覆盖原来的内容,方便演示,前面对xx提到过。
4.4.4、获取string长度
操作命令:STRLEN key
127.0.0.1:6379> get mykey
"this is a people"
127.0.0.1:6379> STRLEN mykey
(integer) 16
127.0.0.1:6379> STRLEN hello
(integer) 0
注:如果当前key值存在会打印出对应的key的长度,如果不存在的话就直接返回0
4.4.5、内部编码
其实string针对不同长度和字符类型是有一个定区别的
字符串类型的内部编码有三种:
int : 8个字节的长整型(如果是数值的字符串会以int的形式存在的,内部会存储为二进制形式)embstr:小于等于 39 个字节的字符串,浮点小数也是(数值都是可以设置,所以这里只是提下)
raw:大于39个字节的字符串
查看类型操作命令:object encoding key
127.0.0.1:6379> get key5
"0.6"
127.0.0.1:6379> object encoding key5
"embstr"
127.0.0.1:6379> set key6 1
OK
127.0.0.1:6379> object encoding key6
"int"
127.0.0.1:6379> set key7 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
OK
127.0.0.1:6379> object encoding key7
"raw"
4.5、Hash哈希
注:Hash很多命令都和string命令很相似,印象记忆即可
基本学习编程语言得都会接触到哈希,redis也是一样都是以键值对的形式存在的
字符串和哈希进行对比:
4.5.1、创建哈希键值对
操作命令:HSET key field value (这里可以设置多组field value) 最低版本2.0
返回值:添加的字段的个数
127.0.0.1:6379> HSET myhash say1 "hello"
(integer) 1
127.0.0.1:6379> HGET myhash say1
"hello"
4.5.2、删除键值对
操作命令:HDEL key field (field可以是多个)
返回值:本次操作删除的字段个数
127.0.0.1:6379> HSET myhash field1 "world" field2 "world2"
(integer) 2
127.0.0.1:6379> HEXISTS myhash field1
(integer) 1
127.0.0.1:6379> HDEL myhash field1
(integer) 1
127.0.0.1:6379> HKEYS myhash
1) "say1"
2) "field2"
注:这里HEXISTS就是看一下哈希键中存不存在值,存在就可以进行删除了,使用类似于StringKEYS命令就可以进行查看(hash采用HKEYS)
4.5.3、获取hash中所有值
操作命令:HVALS key
返回值:所有值
127.0.0.1:6379> HVALS myhash
1) "hello"
2) "world2"
4.5.4、获取所有字段和对应值
操作命令:HGETALL key
返回值:所有字段和对应值
127.0.0.1:6379> HSET myhash field "hello"
(integer) 1
127.0.0.1:6379> HSET myhash field1 "world"
(integer) 1
127.0.0.1:6379> HGETALL myhash
1) "field"
2) "hello"
3) "field1"
4) "world"
注:这里的返回值奇数位是field 偶数位是 value ,上下对应的
4.5.5、一次获取hash多个字段值
操作命令:HMGET key field (可以获取多个field对应的值)
返回值:字段对应值或者是nil
127.0.0.1:6379> hset myhash field2 "hello" field3 "world"
(integer) 2
127.0.0.1:6379> HMGET myhash field2 field3 say
1) "hello"
2) "world"
3) (nil)
注:我这里会时不时删除myhash中的field,为了方便演示
4.5.6、hash所有字段的个数
操作命令:HLEN key
返回值:字段个数
127.0.0.1:6379> HSET myhash field4 "xiaoxu"
(integer) 1
127.0.0.1:6379> HSET myhash field5 "xiaoli"
(integer) 1
127.0.0.1:6379> HKEYS myhash
1) "field2"
2) "field3"
3) "field4"
4) "field5"
127.0.0.1:6379> HLEN myhash
(integer) 4
注:这里给友友们提供了常见命令,例如剩下的HSETNX、HINCRBY、HINCRBYFLOAT等命令可以自己去官网上看看了解一下;
4.5.7、内部编码
哈希的内部编码有两种:
ziplist(压缩链表):配置文件会有这两个值hash-max-ziplist-entries 512、hash-max-ziplist-value 64是作为限制的(都是可以配置,数字是可以进行更改的);当哈希类型元素个数小于hash-max-ziplist-entries 配置512 同时所有值都小于hash-max-ziplist-value配置 64,redis会将ziplist作为哈希内部实现,如果不能满足,就会使用hastable,前者比较省内存
hashtable(哈希表):当哈希类是无法满足ziplist的时候,redsi就会使用hashtable作为哈希的内部实现,为了读写效率,hashtable此时的读写效率仍旧是O(1)
127.0.0.1:6379> HMSET hashkey f1 v1 f2 v2
OK
127.0.0.1:6379> object encoding hashkey
"ziplist"
127.0.0.1:6379> hset hashkey f3 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
(integer) 1
127.0.0.1:6379> object encoding hashkey
"hashtable"
注:这里只演示了如果值字节大小超过了64,会变成hashtable,512就不演示了,这里友友们可押进行尝试一下,可以进行修改后再去尝试,毕竟512实在是太多了
4.6、List列表
列表类型是用来存储多个有序的字符串,Redis中可以列表的两端进行插入和弹出,还可以获取指定范围的元素列表、获取指定索引下标饿元素等,列表是一种的比较灵活的数据结构,它可以充当栈和队列的角色;
左端和右端可进可出,灵活性高,可以适合很多的应用场景,在于自己构造
注:列表允许存在重复元素
4.6.1、左侧插入
操作命令:LPUSH key element (多个元素)
返回值:插入后list的长度
127.0.0.1:6379> LPUSH mylist "world"
(integer) 1
127.0.0.1:6379> LPUSH mylist "hello"
(integer) 2
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello"
2) "world"
注:返回值显示的list的长度,不是内容长度 左侧插入第一个是world ,第二次插入一个hello,hello插入在world左侧,所以显示出来就是先hello 后 world
4.6.2、右侧插入
操作命令:RPUSH
将一个或者多个元素从的右侧放入到list中
返回值:插入后list的长度
127.0.0.1:6379> RPUSH mylist "world"
(integer) 1
127.0.0.1:6379> RPUSH mylist "hello"
(integer) 2
127.0.0.1:6379> LRANGE mylist 0 -1
1) "world"
2) "hello"
注:打印出来的刚好是与LPUSH显示相反的
4.6.3、显示所有的list列表
操作命令:LARANGE key
返回值:key中所有的值
4.6.4、左侧抛出元素
操作命令:LPOP key
返回值:抛出元素打印
127.0.0.1:6379> RPUSH mylist "one" "two" "three" "four" "five"
(integer) 5
127.0.0.1:6379> LPOP mylist
"one"
127.0.0.1:6379> LPOP mylist
"two"
127.0.0.1:6379> LPOP mylist
"three"
127.0.0.1:6379> LRANGE mylist 0 -1
1) "four"
2) "five"
注:这里采用右侧插入,左侧抛出,相当于是队列
4.6.5、右侧抛出元素
操作命令:RPOP key
返回值:取出的元素或者nil
127.0.0.1:6379> RPUSH mylist "one" "two" "three" "four" "five"
(integer) 5
127.0.0.1:6379> RPOP mylist
"five"
127.0.0.1:6379> LRANGE mylist 0 -1
1) "one"
2) "two"
3) "three"
4) "four"
注:这里是右侧输出
4.6.6、获取index位置元素
操作命令:LINDEX key index
返回值:取出的元素或者nil
127.0.0.1:6379> LPUSH mylist "world"
(integer) 1
127.0.0.1:6379> LPUSH mylist "hello"
(integer) 2
127.0.0.1:6379> LINDEX mylist 0
"hello"
127.0.0.1:6379> LINDEX mylist 1
"world"
127.0.0.1:6379> LINDEX mylist -1
"world"
127.0.0.1:6379> LINDEX mylist 10
(nil)
注:redis是支持负数的访问,相当于是倒序访问,如果不存在的话访问结果为nil
4.6.7、特定位置插入元素
操作命令:LINSERT key <BEFORE | AFTER> pivot element
BEFORE:在指定元素之前插入
AFTER:在指定元素之后插入
pivot:指定的元素
element:新的元素
注:大部分参数都是英文翻译过来就能理解,这里也是一样的
返回值:插入后的list长度
127.0.0.1:6379> RPUSH mylist "hello"
(integer) 1
127.0.0.1:6379> RPUSH mylist "world"
(integer) 2
127.0.0.1:6379> LINSERT mylist BEFORE "world" "There"
(integer) 3
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello"
2) "There"
3) "world"
4.6.8、扩展命令
(1)LLEN是计算这个list的元素个数的,也就是长度
(2)阻塞相关命令:BLPOP、BRPOP这两个阻塞命令友友们可以去看看(redis官网),可以使用redis作为一个阻塞队列,当然消息队列是有其他更合的中间件
4.6.9、内部编码
list的内部编码也有两种:ziplist压缩列表,linkedlist链表(针对redis 3.2以下的版本)
ziplist(压缩列表):列表的元素个数⼩于list-max-ziplist-entries配置(默认512个),同时
列表中每个元素的⻓度都⼩于list-max-ziplist-value配置(默认64字节)时,Redis会选⽤
ziplist来作为列表的内部编码实现来减少内存消耗注:不要记数值!!! 数值是可以自行配置的
LinkedList(链表):当列表类无法满足ziplist的时候,redis会使用linkedlist作为list列表实现
127.0.0.1:6379> RPUSH mylist "hello"
(integer) 1
127.0.0.1:6379> OBJECT encoding mylist
"ziplist"
127.0.0.1:6379> RPUSH mylist "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
(integer) 2
127.0.0.1:6379> OBJECT encoding mylist
"linkedlist"
quicklist(快速列表)是针对redis3.2以上的版本,综合了前面两种数据结构
127.0.0.1:6379> RPUSH mylist "hello"
(integer) 1
127.0.0.1:6379> OBJECT encoding mylist
"quicklist"
4.7、Set集合
集合类型也是保存多个字符串类型的元素的,但和列表类型不同的是,集合中1)元素之间是⽆序
的2)元素不允许重复;Redis除了⽀持集合内的增删查改操作,同时还⽀持多个集合取交集、并集、差集,合理地使⽤好集合类型;
4.7.1、添加元素
操作命令:SADD key member (可以有多个元素)
返回值:本次添加的元素个数
127.0.0.1:6379> SADD myset "hello"
(integer) 1
127.0.0.1:6379> SADD myset "world"
(integer) 1
127.0.0.1:6379> SADD myset "world"
(integer) 0
127.0.0.1:6379> SMEMBERS myset
1) "hello"
2) "world"
注:这里不难看出world在同一个键中存了两次,第二次存的时候返回值是0,表示失败
SMEMBERS:打印指定key的所有值,这个显示是无序的
4.7.2、判断key是否存在
操作命令:SISMEMBER key member
返回值:1表示元素存在,0表示元素不存在
127.0.0.1:6379> SADD myset "one"
(integer) 1
127.0.0.1:6379> SADD myset "two"
(integer) 1
127.0.0.1:6379> SISMEMBER myset "two"
(integer) 1
127.0.0.1:6379> SISMEMBER myset "three"
(integer) 0
4.7.3、获取集合内的个数
操作命令:SCARD key
返回值:set内的元素个数
127.0.0.1:6379> SCARD myset
(integer) 2
4.7.4、随机元素
注:这里的删除是随机删除,有set内的元素是无序的 时间复杂度:O(1)
返回值:取出的元素
127.0.0.1:6379> SADD myset "one"
(integer) 1
127.0.0.1:6379> SADD myset "two"
(integer) 1
127.0.0.1:6379> SADD myset "three"
(integer) 1
127.0.0.1:6379> SPOP myset
"two"
127.0.0.1:6379> SMEMBERS myset
1) "one"
2) "three"
127.0.0.1:6379> SADD myset "four"
(integer) 1
127.0.0.1:6379> SADD myset "five"
(integer) 1
127.0.0.1:6379> SPOP myset 3
1) "one"
2) "five"
3) "three"
127.0.0.1:6379> SMEMBERS myset
1) "four"
注:如果是全部照敲的话,大概率应该是跟我不一样的,SPOP是随机抛出的
4.7.5、指定元素删除
时间复杂度:O(N)
操作命令:SREM key member (可以设置多个)
127.0.0.1:6379> SADD myset "one"
(integer) 1
127.0.0.1:6379> SADD myset "two"
(integer) 1
127.0.0.1:6379> SADD myset "thre"
(integer) 1
127.0.0.1:6379> SREM myset "thre"
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "one"
2) "two"
注:这里就是说删谁就删谁,但是会消耗掉时间,所以时间复杂度相较于随机删除就慢一点
4.7.6、移动元素
注:从一个键中移到另外一个键里
操作命令:SMOVE source destination member
source:原键
destination:目标键
member:原键的值
返回值:1表示移动成功,0表示移动失败
127.0.0.1:6379> SADD myset "one"
(integer) 1
127.0.0.1:6379> SADD myset "two"
(integer) 1
127.0.0.1:6379> SADD myotherset "three"
(integer) 1
127.0.0.1:6379> SMOVE myset myotherset "two"
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "one"
127.0.0.1:6379> SMEMBERS myotherset
1) "two"
2) "three"
注: 关键代码翻译: 从myset移动到myotherset的值为two
4.7.7、内部编码
集合类型的内部编码有两种:
intset(整数集合):当集合中的元素都是整数并且元素的个数⼩于set-max-intset-entries配置
(默认512个)时,Redis会选⽤intset来作为集合的内部实现,从⽽减少内存的使⽤,这个值是可以设置的hashtable(哈希表):当集合类型⽆法满⾜intset的条件时,Redis会使⽤hashtable作为集合的内部实现
127.0.0.1:6379> SADD setkey 1 2 3
(integer) 3
127.0.0.1:6379> object encoding setkey
"intset"
127.0.0.1:6379> SADD setkey 4 5
(integer) 2
127.0.0.1:6379> object encoding setkey
"hashtable"
127.0.0.1:6379> SCARD setkey
(integer) 5
注:这里是因为我修改了配置文件set-max-intset-entries 个数为4,关闭redis后重启就可以了这里是为了给友友们展示(知道即可,不需要这样)
4.8、Zset有序集合
有序集合中的元素是不能重复的,但分数允许重复。类⽐于⼀次考试之后,每个⼈⼀定有⼀
个唯⼀的分数,但分数允许相同
注:下面会很长用到一个查询命令:ZRANGE key start end (和前面基本很相似)
4.8.1、添加元素
操作命令:ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member可以多个]
别看参数多,这里只介绍常用的
XX:仅仅添加更新已经存在的元素,不会添加新元素
NX:仅哟弄过于添加新元素,不会更新已经存在的元素
CH:默认情况,ZADD返回的是是本次添加元素个数,但指定这个选项之后,就会还包含本次更新的元素个数
INCR:此时命令类似ZINCRBY的效果,将元素的分数加上指定的分数,此时只能指定一个元素和分数
score :表示的是一个分数(zset就是根据这个分数进行排序的)
member:是元素每个元素都带有一个分数
下面我我就会就开始挨个看 [] (括号内的是可以不写的,可以省略的)
127.0.0.1:6379> ZADD myzset 1 "one"
(integer) 1
127.0.0.1:6379> ZADD myzset 1 "uno"
(integer) 1
127.0.0.1:6379> ZADD myzset 2 "two" 3 "three"
(integer) 2
127.0.0.1:6379> ZRANGE myzset 0 -1 withscores
1) "one"
2) "1"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"
127.0.0.1:6379> ZADD myzset 10 one 20 two 30 three
(integer) 0
127.0.0.1:6379> ZRANGE myzset 0 -1 withscores
1) "uno"
2) "1"
3) "one"
4) "10"
5) "two"
6) "20"
7) "three"
8) "30"
注:这里是基本的命令,还有就是针对zset不可重复进行展示,设置过的键值,不加特殊处理是不能进行修改的
演示CH 、XX 参数选项
127.0.0.1:6379> ZADD myzset CH 100 one 200 two 300 three
(integer) 3
127.0.0.1:6379> ZRANGE myzset 0 -1 withscores
1) "uno"
2) "1"
3) "one"
4) "100"
5) "two"
6) "200"
7) "three"
8) "300"
127.0.0.1:6379> ZADD myzset XX 99 one 200 two 300 three
(integer) 0
127.0.0.1:6379> ZRANGE myzset 0 -1 withscores
1) "uno"
2) "1"
3) "one"
4) "99"
5) "two"
6) "200"
7) "three"
8) "300"
注:XX是不能添加新元素的,因为添加不进去
NX:只能添加新元素,半不能更改元素内容
127.0.0.1:6379> ZADD myzset NX 100 one 200 two 300 three 400 four 500 five
(integer) 2
127.0.0.1:6379> ZRANGE myzset 0 -1 withscores
1) "uno"
2) "1"
3) "one"
4) "99"
5) "two"
6) "200"
7) "three"
8) "300"
9) "four"
10) "400"
11) "five"
12) "500"
注:注意细节one还是99 并没有改为100,因为NX只能负责添加新元素,已有的保持不变
INCR:进行元素添加添加添加分数 对应的键
127.0.0.1:6379> ZADD myzset incr 10 one
"109"
127.0.0.1:6379> ZRANGE myzset 0 -1 withscores
1) "uno"
2) "1"
3) "one"
4) "109"
5) "two"
6) "200"
7) "three"
8) "300"
9) "four"
10) "400"
11) "five"
12) "500"
注:这里是添加给one,这里就会看到one是对应分数109
给友友们看一下无限大和无限小
127.0.0.1:6379> ZADD myzset -inf "first" +inf "last"
(integer) 2
127.0.0.1:6379> ZRANGE myzset 0 -1 withscores
1) "first"
2) "-inf"
3) "uno"
4) "1"
5) "one"
6) "109"
7) "two"
8) "200"
9) "three"
10) "300"
11) "four"
12) "400"
13) "five"
14) "500"
15) "last"
16) "inf"
4.8.2、获取一个zset的个数
操作命令:ZCARD key
返回值:zset内的元素
127.0.0.1:6379> ZCARD myzset
(integer) 8
4.8.3、取指定分数区间
操作命令:ZCOUNT key min max
返回值:满足条件的元素列表个数
127.0.0.1:6379> ZRANGE myzset 0 -1 withscores
1) "first"
2) "-inf"
3) "uno"
4) "1"
5) "one"
6) "109"
7) "two"
8) "200"
9) "three"
10) "300"
11) "four"
12) "400"
13) "five"
14) "500"
15) "last"
16) "inf"
127.0.0.1:6379> ZCOUNT myzset 50 400
(integer) 4
注:redis采用的是左闭右闭的结构,所以这里包括400在内的都会被算进去
4.8.4、按照降序进行排列
操作命令:ZREVRANGE key start stop [withscores]
返回值:区间内的所有元素
127.0.0.1:6379> ZRANGE myzset 0 -1 withscores
1) "first"
2) "-inf"
3) "uno"
4) "1"
5) "one"
6) "109"
7) "two"
8) "200"
9) "three"
10) "300"
11) "four"
12) "400"
13) "five"
14) "500"
15) "last"
16) "inf"
127.0.0.1:6379> ZREVRANGE myzset 0 -1 withscores
1) "last"
2) "inf"
3) "five"
4) "500"
5) "four"
6) "400"
7) "three"
8) "300"
9) "two"
10) "200"
11) "one"
12) "109"
13) "uno"
14) "1"
15) "first"
16) "-inf"
注:这里只是降序打印
4.8.5、只返回元素列表
操作命令:ZRANGEBYSCORE key min max
返回值: 区间内的元素列表
127.0.0.1:6379> ZRANGEBYSCORE myzset -inf +inf
1) "first"
2) "uno"
3) "one"
4) "two"
5) "three"
6) "four"
7) "five"
8) "last"
4.8.6、内部编码
有序集合类型的内部编码有两种:
ziplist(压缩列表):当有序集合的元素个数小于zset-max-ziplist-entries配置 默认128,同时每个元素的值都小于zset-max-ziplist-value配置默认 64,redis会用ziplist来作为有序集合的内部实现,ziplist可以有效减少内存的使用
skiplist(跳表):当ziplist条件不满足时,有序集合会使用skiplist作为内部实现,因为此时ziplist效率会下降
127.0.0.1:6379> zadd myzset 100 one 200 two 300 three
(integer) 3
127.0.0.1:6379> object encoding myzset
"ziplist"
127.0.0.1:6379> zadd myzset 400 four 500 five
(integer) 2
127.0.0.1:6379> object encoding myzset
"skiplist"
注:这里我们修改了配置文件为了方便显示,友友知道即可;ZSET命令还有很多友友们可以去官网看看;