Redis系列 - Redis基础数据结构

Redis安装

Window安装Redis只能安装3.x的低版本,最新的6.x根本无法尝鲜。从知乎的一个帖子得知可以在win10开启linux子系统支持来安装Linux,然后再安装Redis。注意不是虚拟机的模式,子系统要比虚拟机轻量的多。

具体过程:

1) 完成win10的linux子系统Ubuntu的安装,具体步骤参考:https://zhuanlan.zhihu.com/p/56374534

2)在win10运行Ubuntu,然后安装redis。采用的是从redis官网下载安装包,自己编译安装的过程。

3)wget http://download.redis.io/releases/redis-6.0.5.tar.gz   下载安装包

4)利用tar命令解压,tar xzf redis-6.0.5.tar.gz

5)复制:推荐放到usr/local目录下sudo mv redis-6.0.5 /usr/local/redis,进入redis目录 cd /usr/local/redis/

6)使用sudo make编译。注意这里坑比较多,首先要安装make,sudo apt-get install make,第一次安装可能不成功,再执行apt-get update,再执行sudo apt-get install make,这样make命令就安装成功了。

7)第二个坑点,如果继续执行sudo make还会报错,需要继续执行sudo apt-get install gcc

8)  第三个坑点,执行sudo make 还会报错,报错信息:

cc: error: ../deps/hiredis/libhiredis.a: No such file or directory
cc: error: ../deps/lua/src/liblua.a: No such file or directory,进入redis源码目录的deps目录,执行:make lua hiredis linenoise

9)执行sudo make成功

10)执行sudo make test,会报错,根据错误信息发现,需要安装tcl,sudo apt-get install tcl

11) 最后一步执行sudo make install 安装完成

12)执行redis-server启动成功

部分安装过程参考:https://blog.csdn.net/hzlarm/article/details/99432240

Redis数据结构

1. String

1.1 简单说明

字符串 string 是 Redis 最简单的数据结构。Redis 所有的数据结构都是以唯一的 key 字符串作为名称,然后通过这个唯一 key 值来获取相应的 value 数据。

1.2 使用场景

常见的使用场景,例如保存用户信息(JSON格式)、用来记录具体的业务访问次数等。

1.3 基本原理

Redis 的字符串是动态字符串,是可以修改的字符串,内部结构实现上类似于 Java 的 ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配。Redis字符串最大为512MB。

Redis 的字符串有两种存储方式,在长度特别短时,使用 emb 形式存储 (embeded),当长度超过 44 时,使用 raw 形式存储。

Raw格式,长度超过44

EmbStr格式,长度不超过44

1.4 常用命令

http://doc.redisfans.com/string/index.html

以上是String常用命令列表。列举几个比较重要的。

1.4.1 SETEX: SETEX key seconds value

将值 value 关联到 key ,并将 key 的生存时间设为 seconds (以秒为单位)。如果 key 已经存在, SETEX 命令将覆写旧值。这个命令类似于以下两个命令:

SET key value

EXPIRE key seconds # 设置生存时间

不同之处是, SETEX 是一个原子性(atomic)操作,关联值和设置生存时间两个动作会在同一时间内完成,该命令在 Redis 用作缓存时,非常实用。

127.0.0.1:6379> setex key1 5 aaa
OK
127.0.0.1:6379> get key1
"aaa"
127.0.0.1:6379> get key1
(nil)
127.0.0.1:6379>

1.4.2 SETNX: SETNX key value

将 key 的值设为 value ,当且仅当 key 不存在。

若给定的 key 已经存在,则 SETNX 不做任何动作。

SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。

经常用来做分布式锁。

127.0.0.1:6379> setnx key1 ajian
(integer) 1
127.0.0.1:6379> get key1
"ajian"
127.0.0.1:6379> setnx key1 ajian
(integer) 0
127.0.0.1:6379> get key1
"ajian"
127.0.0.1:6379>

2. List

2.1 简单说明

Redis 的列表相当于 Java 语言里面的 LinkedList,它是链表而不是数组。这意味着 list 的插入和删除操作非常快,时间复杂度为 O(1),但是索引定位很慢,时间复杂度为 O(n)。

2.2 使用场景

  • 队列

队列(先进先出):使用RPUSH,使用LPOP。右边进,左边出。RPUSH是压倒队尾,LPOP,是从左边弹出来。

具体操作case:

127.0.0.1:6379> rpush ajianlist 1
(integer) 1
127.0.0.1:6379> rpush ajianlist 2
(integer) 2
127.0.0.1:6379> rpush ajianlist 3
(integer) 3
127.0.0.1:6379> rpush ajianlist 4
(integer) 4
127.0.0.1:6379> lpop ajianlist
"1"
127.0.0.1:6379> lpop ajianlist
"2"
127.0.0.1:6379> lpop ajianlist
"3"

栈(先进后出):使用RPUSH,使用RPOP,右边进,右边出,RPUSH压倒队尾,RPOP从队尾弹出。

具体操作case:

127.0.0.1:6379> rpush chengjianlist 1
(integer) 1
127.0.0.1:6379> rpush chengjianlist 2
(integer) 2
127.0.0.1:6379> rpush chengjianlist 3
(integer) 3
127.0.0.1:6379> rpush chengjianlist 4
(integer) 4
127.0.0.1:6379> rpop chengjianlist
"4"
127.0.0.1:6379> rpop chengjianlist
"3"
127.0.0.1:6379> rpop chengjianlist
"2"
127.0.0.1:6379> rpop chengjianlist
"1"

2.3 基本原理

在列表元素较少的情况下会使用一块连续的内存存储,这个结构是 ziplist,也即是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当数据量比较多的时候才会改成 quicklist。因为普通的链表需要的附加指针空间太大,会比较浪费空间,而且会加重内存的碎片化。比如这个列表里存的只是 int 类型的数据,结构上还需要两个额外的指针 prev 和 next 。所以 Redis 将链表和 ziplist 结合起来组成了 quicklist。也就是将多个 ziplist 使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。

2.4 常用命令

http://doc.redisfans.com/list/index.html

3. HASH

3.1 简单说明

redis内的hash就相当于java内的hashmap,是无序的。数据结构也同java内的hashmap一样的。不同之处是做hash扩容,java内是一次性直接扩容,redis为了性能采用渐进式rehash。Redis内hash的值只能是字符串。

3.2 使用场景

  • 对于复杂场景的用户信息,例如,用户信息内有age,name,hash结构可以做到支持修改局部,而使用String的话需要全部取出。

3.3 基本原理

关于渐进式rehash,这个文章说的还是比较清楚:http://redisbook.com/preview/dict/incremental_rehashing.html

渐进式rehash的好处:

1)渐进式 rehash 的好处在于它采取分而治之的方式, 将 rehash 键值对所需的计算工作均滩到对字典的每个添加、删除、查找和更新操作上, 从而避免了集中式 rehash 而带来的庞大计算量。

2)可以在某一时刻,最终把数据搬迁完。

渐进式rehash的几个点:

1)在渐进式 rehash 进行期间, 字典的删除(delete)、查找(find)、更新(update)等操作会在两个哈希表上进行

2)比如说, 要在字典里面查找一个键的话, 程序会先在 ht[0] 里面进行查找, 如果没找到的话, 就会继续到 ht[1] 里面进行查找。

3)在渐进式 rehash 执行期间, 新添加到字典的键值对一律会被保存到 ht[1] 里面, 而 ht[0] 则不再进行任何添加操作: 这一措施保证了 ht[0] 包含的键值对数量会只减不增, 并随着 rehash 操作的执行而最终变成空表。

3.4 常用命令

http://doc.redisfans.com/hash/index.html

127.0.0.1:6379> hmset ajianHash age 18 name chengjian
OK
127.0.0.1:6379> hmget ajianHash age name
1) "18"
2) "chengjian"

4. SET

4.1 简单说明

Redis 的集合相当于 Java 语言里面的 HashSet,它内部的键值对是无序的唯一的。它的内部实现相当于一个特殊的字典,字典中所有的 value 都是一个值NULL

4.2 使用场景

  • 在去重的场景使用的比较多。例如之前做爬虫,对url进行去重,当然大批量的去重的话,可以考虑布隆过滤器,虽然有一定的误判。

4.3 常用命令

http://doc.redisfans.com/set/index.html

5. SortedSet

5.1 简单说明

它类似于 Java 的 SortedSet 和 HashMap 的结合体,一方面它是一个 set,保证了内部 value 的唯一性,另一方面它可以给每个 value 赋予一个 score,代表这个 value 的排序权重。它的内部实现用的是一种叫做「跳跃列表」的数据结构。

5.2 使用场景

这个的使用场景就太多了,例如关于各种权重的排序,假如说爬虫程序把一堆url放入sortset,按照最终的解析顺序,应该是先解析list页,再解析详情页,那就可以通过设置不同的score值来实现。

5.3 基本原理

Redis 的 zset 是一个复合结构,一方面它需要一个 hash 结构来存储 value 和 score 的对应关系,另一方面需要提供按照 score 来排序的功能,还需要能够指定 score 的范围来获取 value 列表的功能,这就需要另外一个结构「跳跃列表」。

具体原理,参考:https://juejin.im/book/5afc2e5f6fb9a07a9b362527/section/5b5ac63d5188256255299d9c

5.4 常用命令

按照分数从小到大排序

127.0.0.1:6379> zadd ajianZSet 10 java
(integer) 1
127.0.0.1:6379> zadd ajianZSet 9 php
(integer) 1
127.0.0.1:6379> zadd ajianZSet 8 javascript
(integer) 1
127.0.0.1:6379> zadd ajianZSet 7 c++
(integer) 1
127.0.0.1:6379> zrange ajianZSet 0 -1
1) "c++"
2) "javascript"
3) "php"
4) "java"

按照分数从大到小排序

127.0.0.1:6379> zrevrange ajianZSet 0 -1
1) "java"
2) "php"
3) "javascript"
4) "c++"

总结

1)redis在window安装坑不少,有钱还是用mac,可以暂时用windows的子系统方式解决。

2)redis的五大数据结构,String, List, Hash, Set, SortedSet,以及在各个场景中应该如何使用。具体内部的原理,可以深入参考掘金小册《Redis深度历险》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值