string
Redis命令
命令 | 说明 | 备注 |
---|---|---|
set key value | 设置键值对 | |
get key | 通过键获取值 | |
del key | 通过key,删除键值对 | 删除命令,返回删除数 |
strlen key | 求key执行字符串长度 | |
getset key value | 修改原来key的对应值,并将旧值返回 | 如果原来值为空,则返回空 |
getrange key start end | 获取子串 | 既字符串长度为len,把字符串看作一个数组,而Redis是以0开始计数的,所以start和end的取值范围0到len-1 |
append key value | 将新的字符串value加入到原来key指向的字符串 | 返回key指向新字符串的长度 |
string的内部编码
- int 8个字节的长整型
- embstr 小于等于39个字节的字符串
- raw 大于39个字节的字符串
Redis会根据当前值的类型和长度决定使用那种内部编码实现
list
有两种实现方式:
- 压缩链表
压缩列表(ziplist)是Redis为了节省内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型数据结构,
一个压缩列表可以包含任意多个节点(entry),每个节点可以保存一个字节数组或者一个整数值。重点是内存连续.
- 双端链表 prev和next两个指针 , 重点是可以从前往后也可以从后往前 , 这就可以实现lpush rpush这些指令了
因为用的链表 , 所以这也就导致了lindex指令 , 获取某个索引值的元素 , 需要遍历链表才可以获取到 , 时间复杂度是 O(n)
当列表对象可以同时满足下列两个条件时,列表对象采用压缩链表编码:
(1)列表对象保存的所有字符串元素的长度都小于64字节;
(2)列表元素保存的元素数量小于512个;
以上两个条件的上限值可以在配置文件中修改 list-max-ziplist-value选项和 list-max-ziplist-entries选项
否则采用双端链表编码
redis3.2版本以后采用的快速列表
quicklist 是一个双向链表,并且是一个ziplist的双向链表,也就是说quicklist的每个节点都是一个ziplist。结合了两者的优点
hash
概念
Redis 中哈希结构就如同 Java 的 map 一样 , 一个对象里面有许多键值对,它是特别适合存储对象的.
如果内存足够大 ,那么一个 Redis 的 hash 结构可以存储2的32次方-1个键值对 ( 40多亿)。
在 Redis 中, hash 是一个 String 类型的 field 和 value 的映射表,因此我们存储的数据实际在 Redis 内存中都是一个个字符串而己。
hash 结构命令
命令 | 说明 | 备注 |
---|---|---|
hdel key feild 1[field2 ...] | 删除hash结构中的某个(些)字段 | 可以进行多个字段的删除 |
hexists key field | 判断hash结构中是否存在field字段 | 存在返回1,否则返回0 |
hgetall key | 获取所有hash结构中的键值 | 返回键和值 |
hincrby key field increment | 指定给hash结构中的某一字段加上一个整数 | 要求该字段也是整数字符串 |
hincrbyfloat key field increment | 指定给hash结构中的某一字段加上一个浮点数 | 要求该字段是数字型字符串 |
hkeys key | 返回hash中所有键 | |
hlen key | 返回hash中键值对的数量 | |
hmget key field 1 [field2 ...] | 返回hash中指定的键的值,可以是多个 | 依次返回值 |
hmset key field1 value1 [field2 value2 ...] | hash结构设置多个键值对 | |
hset key field value | 在hash结构中设置键值对 | 单个设置 |
hsetnx key field value | 当hash结构中不存在对应的键,才设置值 | |
hvals key | 获取hash结构中所有的值 |
在Redis中的hash结构和字符串有着比较明显的不同.
- 命令都是以h开头,代表操作的是hash结构
- 大多数命令多了一个层级field,这是hash结构的一个内部键,也就是说Redis需要通过key索引到对应的hash结构,再通过field来确定使用hash结构的哪个键值对
注意事项
- hash结构的大小,如果hash结构是个很大的键值对,那么使用它就要十分注意.尤其是关于hkeys,hgetall,hvals等返回所有hash结构数据的命令,会造成大量数据的读取.需要考虑性能和读取数据大小对JVM内存的影响
- 对于数字的操作命令hincrby而言,要求存储的也是整数型字符串
- 对于hincrbyfloat而言,则要求使用浮点数或整数,否则命令失败
- 在Redis中,hash是一个String类型的field和value的映射表.Spring对Redis进行了封装,所以有必要对RedisTemplate的配置项进行修改.修改defaultSerializer-ref.
linked-list
概念
- 链表结构是Redis中一个常用的结构,它可以存储多个字符串
- 它是有序的
- 能够存储2的32次方减一个节点(超过40亿个节点)
- Redis链表是双向的,因此即可以从左到右,也可以从右到左遍历它存储的节点
- 链表结构查找性能不佳,但是插入和删除速度很快
由于是双向链表,所以只能够从左到右,或者从右到左地访问和操作链表里面的数据节点。 但是使用链表结构就意味着读性能的丧失,所以要在大量数据中找到一个节点的操作性能是不佳的,因为链表只能从一个方向中去遍历所要节点,比如从查找节点 10000 开始查询,它需要按照节点1 、节点 2、节点 3……直至节点 10000,这样的顺序查找,然后把一个个节点和你给出的值比对,才能确定节点所在。如果这个链表很大,如有上百万个节点,可能需要遍历几十万次才能找到所需要的节点,显然查找性能是不佳的。
链表结构的优势在于插入和删除的便利 ,因为链表的数据节点是分配在不同的内存区域的,并不连续,只是根据上一个节点保存下一个节点的顺序来索引而己,无需移动元素。
因为是双向链表结构,所以 Redis 链表命令分为左操作和右操作两种命令,左操作就意味着是从左到右,右操作就意味着是从右到左。
命令 | 说明 | 备注 |
---|---|---|
lpush key node1 ... | 把节点node1加入到链表最左边 | 如果是node1,node2...node n这样加入,那么链表开头从左到右就是 node n... node2 node1 |
rpush key node1 ... | 同上只是方向相反 | |
lindex key index | 读取下标为index 的节点 | 返回节点字符串,从0开始 |
llen key | 返回链表长度 | 返回链表节点数 |
lpop key | 删除左边第一个节点,并将其返回 | |
rpop key | 同上方向相反 | |
linsert key before/after pivot node | 插入一个节点node,并且可以指定在值为pivot的节点前面或后面 | 如果list不存在报错,如果没有对应的值pivot也会插入失败返回-1 |
lpushx list node | 如果存在key为list的链表,则插入节点node,并且作为从左到右的最后一个节点 | 如果list不存在则报错 |
rpushx list node | 同上方向相反 | |
lrange list start end | 获取链表list 从start下标到end下标的节点值 | 包含start和end |
lrem list count value | 如果count为0,则删除所有值等于value的节点,count不为0,则先对count取绝对值,假设记为abs,然后从左到右删除不大于abs个等于value的节点 | 注意,count为整数 |
lset key index node | 设置列表下标为index的节点为node | |
ltrim key start stop | 修剪链表,只保留start到stop的区间的节点,其余的都删除掉 | 包含start和end的下标 |
对于很多个节点同时操作的,需要考虑其花费的时间,链表数据结构对于查找而言并不适合于大数据。我们需要考虑插入和删除内容的大小,因为这将是十分消耗性能的命令,会导致 Redis 服务器的卡顿 。对于不允许卡顿的一些服务器,可以进行分批次操作,以避免出现卡顿。
set
概念
Redis 的集合不是一个线性结构,而是一个哈希表结构,它的内部会根据 hash 分子来存储和查找数据,理论上一个集合可以存储2的32次方减一(约42亿)个元素。
因为采用哈希表结构,所以对于 Redis 集合的插入、删除和查找的复杂度都是 0(1),只是需要注意 3 点
- 对于集合而言,它的每一个元素都是不能重复的,当插入相同记录的时候会失败
- 集合是无序的
- 集合的每一个元素都是String数据结构类型
Redis的集合可以对于不同的集合进行操作,比如求出两个或者以上集合的交集,差集和并集等
命令 | 说明 | 备注 |
---|---|---|
sadd key member1 ... | 给键为key的集合增加成员 | 可以同时增加多个 |
scard key | 统计键为key的集合成员数 | |
sdiff key1 [key2] | 找出两个集合的差集 | 参数如果是单个key,那么Redis就返回这个key的所有元素 |
sdiffstore des key1 [key2] | 先按sdiff命令的规则,找出key1和key2的差集,然后将其保存到des集合 | |
sinter key1 [key2] | 求key1和key2的交集 | 参数如果是单key,那么Redis就返回这个key的所有元素 |
sinterstore des key1 key2 | 先按sinter命令的规则,找出key1和key2的交集,然后保存到des中 | |
smembers key | 返回集合所有成员 | |
smove src des member | 将成员member从集合src迁移到集合des中 | |
spop key | 随机弹出集合的一个元素 | 注意其随机性,因为集合是无序的 |
srandmember key [count] | 随机返回集合中一个或者多个元素,count为限制返回总数,如果count为负数,则先求其绝对值 | count为整数,默认为1,如果count大于等于集合总数,则返回整个集合 |
srem key member1 .... | 移除集合中的元素,可以是多个元素 | 对于很大的集合可以通过它删除部分元素,避免大量数据引发Redis停顿 |
sunion key1 [key2] | 求两个集合并集 | 参数如果是单key,那么Redis就返回这个key的所有元素 |
sunionstore des key1 key2 | 先执行sunion命令求出并集,然后保存到键为des的集合中 |
上述命令的前缀都包含 了 一个 s,用来表达这是集合的命令 , 集合是无序的 , 并且支持并集 、 交集和差集的运算。
zset
概念
有序集合和集合类似,只是说它是有序的,和无序集合的主要区别在于每一个元素除了值之外,它还会多一个分数。
- 分数是一个浮点数,在 Java 中是使用双精度表示的,根据分数, Redis 就可以支持对分数从小到大或者从大到小的排序
- 和无序集合一样,对于每一个元素都是唯一的 ,但是对于不同元素而言,它的分数可以一样
- 元素也是 String 数据类型,也是一种基于 hash 的存储结构。
- 集合是通过哈希表实现的,所以添加、删除、 查找的复杂度都是 0(1)
- 集合中最大的成员数为 2的32次方减 1 ( 40 多亿个成员)
有序集合是依赖 key 标示它是属于哪个集合,依赖分数进行排序,所以值和分数是必须的,而实际上不仅可以对分数进行排序,在满足一定的条件下,也可以对值进行排序 。
Redis有序集合的部分命令
有序集合和无序集合的命令是接近的,只是在这些命令的基础上,会增加对于排序的操作,这些是我们在使用的时候需要注意的细节.
有些时候 Redis 借助数据区间的表示方法来表示包含或者不包含,比如在数学的区间表示中[2,5 ]表示包含 2,但是不包含 5 的 区间。
命令 | 说明 | 备注 |
---|---|---|
zadd key score1 value1 [score2 value2 ...] | 向有序集合的key,增加一个或多个成员 | 如果不存在对应的key,则创建键为key的有序集合 |
zcard key | 获取有序集合的成员数 | |
zcount key min max | 根据分数分会对应的成员列表 | min最小值,max最大值,默认包含min和max,采用数据区间表示法,如果需要不包含则在分数前加"("不支持"[" |
zincrby key increment member | 给有序集合成员值为member的分数增加increment | |
zinterstore desKey nurnKeys key1 ... | 求多个有序集合的交集,并且将结果保存到des key中 | numkeys是一个整数,表示多少个有序集合 |
zlexcount key min max | 求有序集合key成员值在min和max的范围 | 这里范围为key的成员值,Redis借助数据区间表示法 |
zrange key start stop[withscores] | 按照分值的大小从小到大返回成员,加入start和stop参数可以截取某一段返回.如果输入withscores,则连同分数一起返回 | 这里既集合最大长度为len,Redis会将集合排序后,形成一个从0到len-1的下标,然后根据start和stop控制的下标(包含start和stop)返回 |
zrank key member | 按从小到大求有序集合的排行 | 排名第一为0,第二为1... |
zrangebylex key min max[limit offset count] | 根据值的大小,从小到大排序,min为最小值,max为最大值;limit选项可选,当Redis求出范围集合后,会产生下标0到n,然后根据偏移量offset和限定返回数count,返回对应成员 | 这里范围为key的成员值,redis借助数学区间的表示方法. |
zrangebyscore key min max [withscores] [limit offset count] | 根据分数大小,从小到大取值范围 | |
zremrangebyscore key start stop | 根据分数区间进行删除 | 根据score进行排序,然后排除0到len-1的下标,然后根据start和stop进行删除 |
zremrangebyrank key start stop | 按照分数排行从小到大的排序删除,从0开始计算 | |
zremrangebylex key min max | 按照值的分布进行删除 | |
zrevrange key start stop[withscores] | 从大到小的按照分数排序 | 与zrange相同,只是排序方式相反 |
zrevrangebyscore key max min [withscores] | 按从大到小的排序,求元素排行 | |
zscore key member | 返回成员的分数值 | |
zunionstore desKey numKeys key1 ... | 求多个有序集合的并集,其中numKeys 是有序集合的个数 |
在对有序集合、下标、区间的表示方法进行操作的时候,需要十分小心命令,注意它是操作分数还是值,稍有不慎就会出现问题。
HyperLogLog
概念
基数是一种算法。
举个例子 , 一本英文著作由数百万个单词组成,你的内存却不足以存储它们,那么我们先分析一下业务。英文单词本身是有限的,在这本书的几百万个单词中有许许多多重复单词 ,扣去重复的单词,这本书中也就是几千到一万多个单词而己,那么内存就足够存储它们 了。比如数字集合{1,2,5,7,9, 1,5,9 }的基数集合为{ 1,2,5,7,9}那么基数(不重复元素)就是 5 , 基数的作用是评估大约需要准备多少个存储单元去存储数据,但是基数的算法一般会存在一定的误差(一般是可控的)。
Redis 对基数数据结构的支持是从版本 2.8.9 开始的。
基数并不是存储元素,存储元素消耗内存空间比较大,而是给某一个有重复元素的数据集合( 一般是很大的数据集合〉评估需要的空间单元数,所以它没有办法进行存储 ,加上在工作中用得不多 ,所以简要介绍一下 Redis的HyperLogLog 命令就可以了.
Redis的Hyperloglog命令
命令 | 说明 | 备注 |
---|---|---|
pfadd key element | 添加指定元素到HyperLogLog中 | 如果已经存在,则返回0,添加失败 |
pfcount key | 返回HyperLogLog的基数值 | |
pfmerge desKey key1 ... | 合并多个HyperLogLog,并将其保存在desKey中 |