Redis基础数据结构

Redis有5种基础数据结构:string字符串list列表set集合hash哈希zset有序集合
Redis的所有数据结构都是一个唯一的字符串类型key作为名称,然后通过这个key值获取相应的value,Redis中5种数据结构就是体现在value上的。
在这里插入图片描述

string(字符串)

string字符串时Redis最简单的数据结构,它的使用非常广泛;
常见场景:比如用于缓存用户信息,我们将用户信息结构体通过JSON序列化成字符串放进Redis中缓存,取用户信息时会经过一个反序列化。
单个键值对操作 set、get:

127.0.0.1:6379> set desc "today is 2019-01-26"
OK
127.0.0.1:6379> get desc
"today is 2019-01-26"
127.0.0.1:6379> exists desc
(integer) 1
127.0.0.1:6379> del desc
(integer) 1
127.0.0.1:6379> get desc
(nil)
127.0.0.1:6379>

批量键值对操作 mset、mget:可以批量对多个字符串进行读写,节省网络耗时开销

127.0.0.1:6379> set lang1 chinese
OK
127.0.0.1:6379> set lang2 english
OK
127.0.0.1:6379> mget lang1 lang2 lang3
1) "chinese"
2) "english"
3) (nil)
127.0.0.1:6379> mset book1 java book2 c++ book3 python
OK
127.0.0.1:6379> mget book1 book2 book3
1) "java"
2) "c++"
3) "python"

过期命令expire和setex,可以对key设置过期时间,到点后自动删除,这个功能经常用于设置缓存失效时间:

expire key secords
secords为过期时间,单位时秒

127.0.0.1:6379> set city guangzhou
OK
127.0.0.1:6379> get city
"guangzhou"
127.0.0.1:6379> expire city 5
(integer) 1
# 等待5s过后
127.0.0.1:6379> get city
(nil)

setex key secords value
secords为过期时间,单位时秒,等价于set + expire

127.0.0.1:6379> setex city 5 guangzhou
OK
127.0.0.1:6379> get city
"guangzhou"
# 等待5s过后
127.0.0.1:6379> get city
(nil)

set的其他扩展命令

setnx key value
当key不存在时执行set操作

127.0.0.1:6379> setnx num 001
(integer) 1
127.0.0.1:6379> get num
"001"
127.0.0.1:6379> setnx num 002
(integer) 0  				# 因为num已经存在,所以此处设置不成功
127.0.0.1:6379> get num
"001"					# num的值没有改变

原子计数:如果value值设置成一个整数,Redis还支持对它记性自增、自减操作,自增自减时有范围的,它的范围时signed long的最大最小值,超过这个范围Redis会报错。

127.0.0.1:6379> set age 25
OK
127.0.0.1:6379> incr age
(integer) 26
127.0.0.1:6379> incrby age 10
(integer) 36
127.0.0.1:6379> incrby age -5
(integer) 31
127.0.0.1:6379> set max 9223372036854775807
OK
127.0.0.1:6379> incr max
(error) ERR increment or decrement would overflow

list(列表)

Redis的list相当于Java中的LinkedList,它是一个链表结构而不是数组结构,因此它具备链表的优、缺点;
优点:list的插入和删除操作效率高,时间复杂度喂O(1);
缺点:list的查询或索引定位比较慢,时间复杂度喂O(n);
此外,列表的特性就是先进先出,当list弹出最后一个元素之后该数据结构自动被删除,同时内存被回收。
常见场景:Redis的列表结构常用于作为异步队列使用,线程1将需要延后处理的任务结构体序列化喂字符串放进list中,线程2从这个list中轮询取出数据进行处理。

  • 右进左出:队列
127.0.0.1:6379> RPUSH books java golang python
(integer) 3
127.0.0.1:6379> LLEN books
(integer) 3
127.0.0.1:6379> LPOP books
"java"
127.0.0.1:6379> LPOP books
"golang"
127.0.0.1:6379> LPOP books
"python"
127.0.0.1:6379> LPOP books
(nil)
  • 右进右出:栈
127.0.0.1:6379> RPUSH books java golang python
(integer) 3
127.0.0.1:6379> RPOP books
"python"
127.0.0.1:6379> RPOP books
"golang"
127.0.0.1:6379> RPOP books
"java"
127.0.0.1:6379> RPOP books
(nil)

set(集合)

Redis的set相当于Java中的HashSet,它存储的键值对是无序且唯一的;内部实现相当于一个特殊的Hash,一个所有value都为NULL的特殊Hash,当set中的最后一个元素被移除后,数据结构会自动删除,内存被回收。

127.0.0.1:6379> SADD books java
(integer) 1
127.0.0.1:6379> SADD books java
(integer) 0     # 这里重复插入失败,证明Set结构元素是唯一的
127.0.0.1:6379> SADD books golang python    # 批量add
(integer) 2
127.0.0.1:6379> SMEMBERS books      # 结果元素顺序跟插入时不一致,证明Set内元素是无序的
1) "python"
2) "java"
3) "golang"
127.0.0.1:6379> SISMEMBER books java    # 查询某个元素是否存在,相当于contains(element)
(integer) 1
127.0.0.1:6379> SISMEMBER books c++
(integer) 0
127.0.0.1:6379> SCARD books     # 获取集合长度,相当于count()
(integer) 3
127.0.0.1:6379> SPOP books      # 弹出一个元素
"python"

hash(哈希)

  • Redis中的hash相当于Java 1.8之前中的HashMap,它是无序字典在内部结构的实现上跟HashMap是一样的,都是数组+链表的二维结构;在第一维hash的数组位置碰撞时,就会使用链表将碰撞的元素串联起来。
  • hash结构可用于存储用户信息,不同于字符串需要一次性对整个对象序列化,hash结构可以对用户信息中的每个字段单独存储,这样方便我们在获取用户信息时进行部分获取,减少网络传输消耗。
  • hash的缺点是它的储存消耗要高于单个字符串结构,至于在实际应用中使用哪种结构,需要大家根据实际情况进行选择。
127.0.0.1:6379> HSET books java "Thinking in Java"      # 在命令行中如果字符串包含空格,需要用引号括起来
(integer) 1
127.0.0.1:6379> HSET books golang "Concurrency in go"
(integer) 1
127.0.0.1:6379> HSET books python "Python cookbook"
(integer) 1
127.0.0.1:6379> HGETALL books       # entries(),key和value间隔出现
1) "java"
2) "Thinking in Java"
3) "golang"
4) "Concurrency in go"
5) "python"
6) "Python cookbook"
127.0.0.1:6379> HLEN books
(integer) 3
127.0.0.1:6379> HGET books java
"Thinking in Java"
127.0.0.1:6379> HSET books golang "Learning go programming"
(integer) 0     # 因为是更新操作,所以这里返回0
127.0.0.1:6379> HGET books golang
"Learning go programming"
127.0.0.1:6379> HMSET books java "Effective java" golang "Modern golang programming" python "Learning python"       # 批量set操作
OK

zset(有序集合)

  • Redis中的zset结构类似于Java中的SortedSet和HashMap的结合体,一方面它是一个set,保证了内部元素value的唯一性;另一方面,它可以给每个元素value赋予一个score,表示这个value的排序权重。
  • zset在实际应用中可以用来存储排行榜数据,value值存储用户名称或ID,score存储分数,我们可以按照按照分数正/反序对用户列表进行排序。
127.0.0.1:6379> ZADD ranking 22.22 "zhangsan"
(integer) 1
127.0.0.1:6379> ZADD ranking 33.33 "lisi"
(integer) 1
127.0.0.1:6379> ZADD ranking 11.11 "wangwu"
(integer) 1
127.0.0.1:6379> ZRANGE ranking 0 -1     # 按score正序列出,参数区间为排名范围
1) "wangwu"
2) "zhangsan"
3) "lisi"
127.0.0.1:6379> ZREVRANGE ranking 0 -1  # 按score逆序列出,参数区间为排名范围
1) "lisi"
2) "zhangsan"
3) "wangwu"
127.0.0.1:6379> ZCARD ranking       # 等同于count()
(integer) 3
127.0.0.1:6379> ZSCORE ranking zhangsan     # 获取指定value的score值
"22.219999999999999"                        # 内部score使用double类型存储,所以存储小数点精度问题
127.0.0.1:6379> ZRANK ranking "zhangsan"    # 获取指定value的排名,从0开始
(integer) 1
127.0.0.1:6379> ZRANK ranking "wangwu"
(integer) 0
127.0.0.1:6379> ZRANK ranking "lisi"
(integer) 2
127.0.0.1:6379> ZRANGEBYSCORE ranking 0 30  # 根据score区间列出zset元素
1) "wangwu"
2) "zhangsan"
127.0.0.1:6379> ZRANGEBYSCORE ranking -inf 30 withscores    # inf为infinite缩写,-inf为负无穷,withscores参数表示将score一同列出
1) "wangwu"
2) "11.109999999999999"
3) "zhangsan"
4) "22.219999999999999"
127.0.0.1:6379> ZREM ranking "zhangsan"     # 删除value
(integer) 1
127.0.0.1:6379> ZRANGE ranking 0 -1
1) "wangwu"
2) "lisi"

其他高级命令

1. KEYS:全局遍历键
KEYS pattern
查找所有符合给定模式pattern的key;特殊符号用\隔开;keys命令的速度非常快,但在一个大的数据库中使用它仍然可能造成性能问题,要尽量避免使用。

127.0.0.1:6379> MSET one 1 two 2 three 3 four 4     # 一次设置 4 个 key
OK
127.0.0.1:6379> KEYS *o*
1) "four"
2) "two"
3) "one"
127.0.0.1:6379> KEYS t??
1) "two"
127.0.0.1:6379> KEYS t[w]*
1) "two"
127.0.0.1:6379> KEYS *      # 匹配数据库内所有key
1) "four"
2) "three"
3) "two"
4) "one"

2. SCAN:增量/渐进式遍历键
SCAN cursor [MATCH pattern] [COUNT count]

  • cursor:游标,整型值。
  • MATCH pattern:正则表达式,对redis的所有key过滤,可选。
    需要注意的是, 对元素的模式匹配工作是在命令从数据集中取出元素之后, 向客户端返回元素之前的这段时间内进行的, 所以如果被迭代的数据集中只有少量元素和模式相匹配, 那么迭代命令或许会在多次执行中都不返回任何元素。
  • COUNT count:每次迭代遍历多少个key,输出结果的key个数不保证与等于count。

SCAN 命令是一个基于游标的迭代器(cursor based iterator): SCAN 命令每次被调用之后, 都会向用户返回一个新的游标cursor, 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数cursor, 以此来延续之前的迭代过程。

当 SCAN 命令的游标参数cursor被设置为 0 时, 服务器将开始一次新的迭代, 而当服务器向用户返回值为 0 的游标时, 表示迭代已结束。

以下是一个 SCAN 命令的迭代过程示例:

127.0.0.1:6379> scan 0      # 游标设置为0
1) "17"                     # 返回新的游标,作为下次迭代的cursor参数
2)  1) "key:12"
    2) "key:8"
    3) "key:4"
    4) "key:14"
    5) "key:16"
    6) "key:17"
    7) "key:15"
    8) "key:10"
    9) "key:3"
    10) "key:7"
    11) "key:1"
127.0.0.1:6379> scan 17     # 上轮返回的游标
1) "0"                      # 当迭代返回的游标值为0时,说明redis中的所有key已经遍历完成
2) 1) "key:5"
   2) "key:18"
   3) "key:0"
   4) "key:2"
   5) "key:19"
   6) "key:13"
   7) "key:6"
   8) "key:9"
   9) "key:11"

Redis存储键值对实际使用的是HashTable的数据结构
在这里插入图片描述

3. INFO:查看redis服务运行信息
INFO [section]:通过给定可选的参数 section ,可以让命令只返回某一部分的信息。

  • server : 一般 Redis 服务器信息,包含以下域:

    • redis_version : Redis 服务器版本
    • redis_git_sha1 : Git SHA1
    • redis_git_dirty : Git dirty flag
    • os : Redis 服务器的宿主操作系统
    • arch_bits : 架构(32 或 64 位)
    • multiplexing_api : Redis 所使用的事件处理机制
    • gcc_version : 编译 Redis 时所使用的 GCC 版本
    • process_id : 服务器进程的 PID
    • run_id : Redis 服务器的随机标识符(用于 Sentinel 和集群)
    • tcp_port : TCP/IP 监听端口
    • uptime_in_seconds : 自 Redis 服务器启动以来,经过的秒数
    • uptime_in_days : 自 Redis 服务器启动以来,经过的天数
    • lru_clock : 以分钟为单位进行自增的时钟,用于 LRU 管理
  • clients : 已连接客户端信息,包含以下域:

    • connected_clients : 已连接客户端的数量(不包括通过从属服务器连接的客户端)
    • client_longest_output_list : 当前连接的客户端当中,最长的输出列表
    • client_longest_input_buf : 当前连接的客户端当中,最大输入缓存
    • blocked_clients : 正在等待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客户端的数量
  • memory : 内存信息,包含以下域:

    • used_memory : 由 Redis 分配器分配的内存总量,以字节(byte)为单位
    • used_memory_human : 以人类可读的格式返回 Redis 分配的内存总量
    • used_memory_rss : 从操作系统的角度,返回 Redis 已分配的内存总量(俗称常驻集大小)。这个值和 top 、 ps 等命令的输出一致。
    • used_memory_peak : Redis 的内存消耗峰值(以字节为单位)
    • used_memory_peak_human : 以人类可读的格式返回 Redis 的内存消耗峰值
    • used_memory_lua : Lua 引擎所使用的内存大小(以字节为单位)
    • mem_fragmentation_ratio : used_memory_rss 和 used_memory 之间的比率
    • mem_allocator : 在编译时指定的, Redis 所使用的内存分配器。可以是 libc 、 jemalloc 或者 tcmalloc 。

    在理想情况下, used_memory_rss 的值应该只比 used_memory 稍微高一点儿。
    当 rss > used ,且两者的值相差较大时,表示存在(内部或外部的)内存碎片。
    内存碎片的比率可以通过 mem_fragmentation_ratio 的值看出。
    当 used > rss 时,表示 Redis 的部分内存被操作系统换出到交换空间了,在这种情况下,操作可能会产生明显的延迟。
    Because Redis does not have control over how its allocations are mapped to memory pages, high used_memory_rss is often the result of a spike in memory usage.

    当 Redis 释放内存时,分配器可能会,也可能不会,将内存返还给操作系统。
    如果 Redis 释放了内存,却没有将内存返还给操作系统,那么 used_memory 的值可能和操作系统显示的 Redis 内存占用并不一致。
    查看 used_memory_peak 的值可以验证这种情况是否发生。

  • persistence : RDB 和 AOF 的相关信息

  • stats : 一般统计信息

  • replication : 主/从复制信息

  • cpu : CPU 计算量统计信息

  • commandstats : Redis 命令统计信息

  • cluster : Redis 集群信息

  • keyspace : 数据库相关的统计信息

更多命令详解请参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值