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深度历险》