zoukankan      html  css  js  c++  java
  • Redis基本数据结构

    Redis系列:

    1. Redis安装和配置
    2. Redis基本数据结构
    3. Redis核心原理
    4. Redis集群演变和集群部署
    5. Redis高可用集群之水平扩展

    Redis 有 5 种基础数据结构,分别为:string (字符串)、list (列表)、set (集合)、hash (哈希) 和 zset (有序集合)。

    image-20200317224020905

    一、String字符串

    字符串 string 是 Redis 最简单的数据结构。Redis 所有的数据结构都是以唯一的 key 字符串作为名称,然后通过这个唯一 key 值来获取相应的 value 数据。不同类型的数据结构的差异就在于 value 的结构不一样。字符串结构使用非常广泛,一个常见的用途就是缓存用户信息。我们将用户信息结构体使用 JSON 序列化成字符串,然后将序列化后的字符串塞进 Redis 来缓存。同样,取用户信息会经过一次反序列化的过程。

    键值对:

    127.0.0.1:6379> set name lin
    OK
    127.0.0.1:6379> get name
    "lin"
    127.0.0.1:6379> exists name
    (integer) 1
    127.0.0.1:6379> del name
    (integer) 1
    127.0.0.1:6379> get name
    (nil)
    

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

    127.0.0.1:6379> set name1 lin
    OK
    127.0.0.1:6379> set name2 jin
    OK
    127.0.0.1:6379> mget name1 name2 name3 # 返回一个列表
    1) "lin"
    2) "jin"
    3) (nil)
    127.0.0.1:6379> mset name1 boy name2 girl name3 aaa
    OK
    127.0.0.1:6379> mget name1 name2 name3
    1) "boy"
    2) "girl"
    3) "aaa"
    

    过期和 set 命令扩展:可以对 key 设置过期时间,到点自动删除,这个功能常用来控制缓存的失效时间

    127.0.0.1:6379> set name lin
    OK
    127.0.0.1:6379> get name
    "lin"
    127.0.0.1:6379> expire name 5 # 5s后过期
    (integer) 1	# 等待5s后
    127.0.0.1:6379> get name
    (nil)
    127.0.0.1:6379> setex name 5 lin # 直接在set时候设置5s过期
    OK
    127.0.0.1:6379> get name
    "lin" # 等待5s后
    127.0.0.1:6379> get name
    (nil)
    127.0.0.1:6379> setnx name lin	# 如果name不存在就执行set创建
    (integer) 1
    127.0.0.1:6379> get name
    "lin"
    127.0.0.1:6379> setnx name jin
    (integer) 0 # set失败,因为name已经存在
    127.0.0.1:6379> get name # name的值没有改变
    "lin"
    

    原子计数:如果 value 值是一个整数,还可以对它进行自增操作。自增是有范围的,它的范围是 signed long 的最大最小值,超过了这个值,Redis 会报错

    127.0.0.1:6379> set age 30
    OK
    127.0.0.1:6379> incr age
    (integer) 31
    127.0.0.1:6379> incrby age 5
    (integer) 36
    127.0.0.1:6379> incrby age -5
    (integer) 31
    127.0.0.1:6379> set lin 9223372036854775807 # Long.Max
    OK
    127.0.0.1:6379> incr lin
    (error) ERR increment or decrement would overflow
    

    二、list (列表)

    Redis 的列表相当于 Java 语言里面的 LinkedList,注意它是链表而不是数组。这意味着 list 的插入和删除操作非常快,时间复杂度为 O(1),但是索引定位很慢,时间复杂度为 O(n),这点让人非常意外。 当列表弹出了最后一个元素之后,该数据结构自动被删除,内存被回收。

    Redis 的列表结构常用来做异步队列使用。将需要延后处理的任务结构体序列化成字符串塞进 Redis 的列表,另一个线程从这个列表中轮询数据进行处理。

    右边进左边出:队列

    127.0.0.1:6379> rpush books python java golang
    (integer) 3
    127.0.0.1:6379> llen books
    (integer) 3
    127.0.0.1:6379> lpop books
    "python"
    127.0.0.1:6379> lpop books
    "java"
    127.0.0.1:6379> lpop books
    "golang"
    127.0.0.1:6379> lpop books
    (nil)
    

    右边进右边出:栈

    127.0.0.1:6379> rpush books python java golang
    (integer) 3
    127.0.0.1:6379> rpop books
    "golang"
    127.0.0.1:6379> rpop books
    "java"
    127.0.0.1:6379> rpop books
    "python"
    127.0.0.1:6379> rpop books
    (nil)
    

    三、hash (字典)

    Redis 的字典相当于 Java 语言里面的 HashMap,它是无序字典。内部实现结构上同 Java 的 HashMap 也是一致的,同样的数组 + 链表二维结构。第一维 hash 的数组位置碰撞时,就会将碰撞的元素使用链表串接起来。

    hash 结构也可以用来存储用户信息,不同于字符串一次性需要全部序列化整个对象,hash 可以对用户结构中的每个字段单独存储。这样当我们需要获取用户信息时可以进行部分获取。而以整个字符串的形式去保存用户信息的话就只能一次性全部读取,这样就会比较浪费网络流量。 hash 也有缺点,hash 结构的存储消耗要高于单个字符串,到底该使用 hash 还是字符串,需要根据实际情况再三权衡。

    127.0.0.1:6379> hset books java "think in java"
    (integer) 1
    127.0.0.1:6379> hset books golang "think in go"
    (integer) 1
    127.0.0.1:6379> hset books python "think in python"
    (integer) 1
    127.0.0.1:6379> hgetall books
    1) "java"
    2) "think in java"
    3) "golang"
    4) "think in go"
    5) "python"
    6) "think in python"
    127.0.0.1:6379> hlen books
    (integer) 3
    127.0.0.1:6379> hget books java
    "think in java"
    127.0.0.1:6379> hset books python "learning python"
    (integer) 0	# 更新操作,返回0
    127.0.0.1:6379> hget books python
    "learning python"
    127.0.0.1:6379> hmset books java "effect java" python "effect python"	# 列表插入
    OK
    

    四、set (集合)

    Redis 的集合相当于 Java 语言里面的 HashSet,它内部的键值对是无序的唯一的。它的内部实现相当于一个特殊的字典,字典中所有的 value 都是一个值NULL。 当集合中最后一个元素移除之后,数据结构自动删除,内存被回收。

    127.0.0.1:6379> sadd books python
    (integer) 1
    127.0.0.1:6379> sadd books python	# 因为set不可重复,返回0
    (integer) 0
    127.0.0.1:6379> sadd books java golang
    (integer) 2
    127.0.0.1:6379> smembers books # 顺序跟插入不一样,因为set是无序的。
    1) "java"
    2) "golang"
    3) "python"
    127.0.0.1:6379> sismember books java	# 查询某个value是否存在
    (integer) 1
    127.0.0.1:6379> sismember books rust
    (integer) 0
    127.0.0.1:6379> scard books	# 获取set的大小
    (integer) 3
    127.0.0.1:6379> spop books	# 弹出一个value
    "java"
    127.0.0.1:6379> scard books
    (integer) 2
    127.0.0.1:6379> smembers books
    1) "golang"
    2) "python"
    

    五、zset (有序集合)

    zset 类似于 Java 的 SortedSet 和 HashMap 的结合体,一方面它是一个 set,保证了内部 value 的唯一性,另一方面它可以给每个 value 赋予一个 score,代表这个 value 的排序权重。

    zset 可以用来存粉丝列表,value 值是粉丝的用户 ID,score是关注时间。我们可以对粉丝列表按关注时间进行排序。

    zset 还可以用来存储学生的成绩,value 值是学生的 ID,score 是他的考试成绩。我们可以对成绩按分数进行排序就可以得到他的名次。

    127.0.0.1:6379> zadd books 9.0 "think in java"
    (integer) 1
    127.0.0.1:6379> zadd books 8.9 "java concurrency"
    (integer) 1
    127.0.0.1:6379> zadd books 8.6 "java cookbook"
    (integer) 1
    127.0.0.1:6379> zrange books 0 -1 # 按score排序输出,范围指定与python相似
    1) "java cookbook"
    2) "java concurrency"
    3) "think in java"
    127.0.0.1:6379> zcard books	# zset的大小
    (integer) 3
    127.0.0.1:6379> zscore books "java concurrency" # 获取指定value的score
    "8.9000000000000004"	# score使用double存储,存在小数点精度问题
    127.0.0.1:6379> zrank books "java concurrency" # 排名
    (integer) 1
    127.0.0.1:6379> zrangebyscore books 0 8.91 # 根据分值区间便利zset
    1) "java cookbook"
    2) "java concurrency"
    127.0.0.1:6379> zrem books "java concurrency" # 删除value
    (integer) 1
    127.0.0.1:6379> zrange books 0 -1
    1) "java cookbook"
    2) "think in java"
    

    六、其他高级命令

    keys:全量遍历键,用来列出所有满足特定正则字符串规则的key,当redis数据量比较大时,性能比较差,要避免使用

    127.0.0.1:6379> set lin2 2
    OK
    127.0.0.1:6379> set lin1 1
    OK
    127.0.0.1:6379> set li1n 1
    OK
    127.0.0.1:6379> set li2n 2
    OK
    127.0.0.1:6379> keys *
    1) "li1n"
    2) "li2n"
    3) "lin1"
    4) "lin2"
    127.0.0.1:6379> keys lin*
    1) "lin1"
    2) "lin2"
    127.0.0.1:6379> keys li*n
    1) "li1n"
    2) "li2n"
    

    scan:渐进式遍历键,scan 参数提供了三个参数,第一个是 cursor 整数值,第二个是 key 的正则模式,第三个是遍历的 limit hint。第一次遍历时,cursor 值为 0,然后将返回结果中第一个整数值作为下一次遍历的 cursor。一直遍历到返回的 cursor 值为 0 时结束。

    127.0.0.1:6379> scan 0 match lin* count 4
    1) "6" # 下一次的cursor
    2) 1) "lin8"
       2) "lin4"
       3) "lin"
       4) "lin3"
    127.0.0.1:6379> scan 6 match lin* count 4
    1) "13"
    2) 1) "lin6"
       2) "lin7"
       3) "lin1"
       4) "lin5"
    127.0.0.1:6379> scan 13 match lin* count 4
    1) "0" # 输出0,代表遍历结束
    2) 1) "lin9"
       2) "lin2"
    

    Redis存储键值对实际使用的是hashtable的数据结构

    image-20200318114720937

    Info:查看redis服务运行信息,分为 9 大块,每个块都有非常多的参数,这 9 个块分别是:

    • Server 服务器运行的环境参数
    • Clients 客户端相关信息
    • Memory 服务器运行内存统计数据
    • Persistence 持久化信息
    • Stats 通用统计数据
    • Replication 主从复制相关信息
    • CPU CPU 使用情况
    • Cluster 集群信息
    • KeySpace 键值对统计数量信息
    127.0.0.1:6379> info
    # Server
    redis_version:5.0.7
    redis_git_sha1:00000000
    redis_git_dirty:0
    redis_build_id:d05eea3b42d1beac
    redis_mode:standalone
    os:Darwin 19.3.0 x86_64
    arch_bits:64
    multiplexing_api:kqueue
    atomicvar_api:atomic-builtin
    gcc_version:4.2.1
    process_id:31716
    run_id:c63a31238057cc2a67844f29784014664d11a3ca
    tcp_port:6379
    uptime_in_seconds:5766
    uptime_in_days:0
    hz:10
    configured_hz:10
    lru_clock:7444886
    executable:/Users/jinchengll/soft/redis-5.0.7/./src/redis-server
    ......
    
  • 相关阅读:
    AJAX注册
    文件上传加水印
    邮箱
    AJAX完整操作
    跨窗体操作
    容器布局
    EF异常类
    SQL查出字段横向拼接,如:1,2,3,4
    asp.net三层结构中,SQL助手类DbHelperSQL
    正则抓取页面信息
  • 原文地址:https://www.cnblogs.com/jinchengll/p/12521028.html
Copyright © 2011-2022 走看看