Redis简单了解

1. 前言

Redis不是简单的键值存储,它实际上是一个数据结构服务器,支持不同类型的值。在传统键值存储中,键和值都是字符串,而在Redis中,值不仅限于简单的字符串,还可以容纳更复杂的数据结构。

2. Redis的数据类型

Redis中的键

Redis的键是二进制安全的,这意味着您可以使用任何二进制序列作为键,从“ foo”之类的字符串到JPEG文件的内容。 空字符串也是有效的键。

需要注意的是:

  1. 尽量不要使用过长的键。例如,一个1024字节的键会占用较大的内存,而且在比较键的过程中代价更高。更好的方法是,将该值hash之后再作为键。
  2. 尽量不要使用过短的键。尽管较短的键占用更少的内存,但是可读性更差。例如: “user:1000:followers” 比 “u1000flw” 作为键更合适。
  3. 键的模式最好保持一致。 例如,“ object-type:id”是一个好主意,例如“ user:1000”。 点或破折号通常用于多词字段,例如“ comment: 1234:reply.to”或“ comment: 1234:reply-to”。
  4. 键的大小不能超过512 MB

2.1 String

Redis 中最简单的数据类型就是 String 了,而它也是 Memcached 中唯一的数据类型。
由于Redis 中的键都是 String 类型的,当值也是 String 时,其实就是将一个 String 映射到另一个 String
值的最大值不能超过512MB
String类型是二进制安全的,表示redisstring 可以包含任何数据。如数字,字符串,jpg图片或者序列化的对象。

# 如果原来的key已经存在了,那么再使用set会给key设置一个新的值。
set 键 值
get 键
# 该键的值加1(原子性递增),将原键的值解析为一个整数,然后加1,将加1后的结果SET为该键的新值
incr 键
# 在原来键的值得基础上,追加数据
append 键 "append value"
# 获取字符串的值得分片, [start, end]
getrange 键 start end
# 设置字符串的值的分片,从索引为start开始 用新值开始替换
setrange 键 start 新值

INCR, DECR, INCRBY原子性操作,也就是说不会类似多线程的现象。例如,多线程中,A和B同时让共享变量x(值为10)加1,结果可能会是11,而不是12,而两个 redis-cli 同时使用incr对某键加1,最终的结果一定是12。

1条命令 SETGET 多个键的值。

mset key1 value1 key2 value2 key3 value3

mget key1 key2 key3

# EXISTS返回1或者0作为信号,表示该键是否存在
exists 键
# DEL删除指定键和其值
del

mget的返回值是一个数组。

2.2 Lists

Redis 中的 lists 是通过双端链表实现的。这意味着不管 list 中的元素有多少,在列头和列尾添加一个新元素都能在常数时间,即O(1),内完成。lists 中的元素都是字符串。

1个 Redis list 的最大长度限制为 232 - 1

扫描二维码关注公众号,回复: 12683417 查看本文章

之所以使用链表实现,就是因为常常需要在较短时间内从很长很长的 list 中添加或删除元素(头、尾都行)。
还有一个优点是,Redis 中的 Lists 在常数时间,即O(1),内获取固定长度的list

但是缺点是获取元素比数组实现的 list 要慢,尤其是获取中间的元素,这是一个O(N)操作。

# 添加一个新元素或多个元素到列头
lpush list名 值
lpush list名 值123

# 添加一个新元素或多个元素到列尾
rpush list名 值
rpush list名 值123

# 从列表中获取一定范围的数据,[start, end]
lrange list名 start end
# 返回list中的所有元素
lrange list0 -1

# 弹出(获取+删除)list中的元素
# 从列头删除1个元素
lpop list# 从列尾删除1个元素
rpop list

需要注意的是LRANGE命令中,[start, end]区间两边都是闭合的。
使用LPOP或者RPOP删除list中元素,若list已经为空,则返回值是NULL

常见用例

  • 记录用户发布到社交网络上的最近更新。
  • 生产者-消费者模式。生产者生产消息并写入 list 中,消费者消费消息。

举个例子,假设你的微博主页显示了你发布的一些最新照片,并且你希望主页的访问速度要尽可能的快。利用 Redis 中的 list 来实现:

  • 每次用户发布新照片时,我们都会使用LPUSH将其照片id添加到list中。
  • 当用户访问主页时,我们使用LRANGE 0 9来获取最新发布的10个照片。

Capped lists

在许多情况,我们只是想使用Redis中的list来存储最新的数据,不管这些数据是社交网络更新数据、日志数据还是其它什么数据。

只记录最新的N个数据,使用LTRIM丢弃所有旧的数据。LTRIM命令指定一个范围,这个范围之外的元素都会被删掉。

# 向某list中写入5个元素
rpush list1 2 3 4 5
# 设置最新值的范围是[0, 2],两边都是闭合的,所以有3个元素
ltrim list0 2
# 展示该list中的所有元素
lrange list0 -1

# Redis中的Sorted sets
在Redis中获取集合中间某部分的元素是很常见的,这就需要使用Sorted sets。

list的阻塞操作

Redis中的list 实现队列非常合适,这是因为list有一个特性:阻塞操作,并且通常用作进程间通信系统时的阻塞。

  • 生产者调用LPUSH命令推送一些数据到list中
  • 消费者调用RPOP从该list中抽取/处理这些数据

但是,有时list可能为空(没有任何要处理的数据),因此RPOP会返回NULL。 在这种情况下,消费者被迫等待一段时间,然后使用RPOP重试。这被称为轮询,在这种情形有几个缺点:

  • Redisclients会处理这些读命令,但这并有什么卵用,因为压根就没有数据了。
  • 由于添加了数据处理的延迟,当1个消费者获取到一个NULL后,会缩短延迟的时间,这样会导致更多无用命令的调用。

Redis使用BRPOPBLPOP可以解决上述问题。BRPOPBLPOPRPOPLPOP的阻塞版本,当list是空的之后,会阻塞获取数据。仅当将新元素添加到list中或达到用户指定的超时时间了,它们才会返回结果给调用方。

可以同时等待多个list

# 意思是等待该list中的元素,但如果5秒钟后没有可用元素,则返回
brpop list5
# 等待时间设置为0s,表示永远等待
brpop list0
  • clients 按照顺序享受服务。当该list中有可用元素之后,会优先服务第一个阻塞的 client。
  • 返回值与RPOP相比有所不同。BRPOP的返回值是一个数组,由键名和值,因为BRPOPBLPOP能够同时等待多个list,所以需要指明list名。
  • 如果超时了,则会返回NULL

自动创建和删除键

我们不必去创建空list,只需要向该list中添加元素即可。我们也不用移除空list,这些都是Redis自己的工作。Streams, Sets, Sorted SetsHashes 也是这样。

  1. 当我们添加元素到一个聚合数据类型StreamsSetsSorted SetsHashes),如果该键并不存在,则Redis会先建一个空的该聚合数据类型作为键,然后将元素添加进去。
    在这里插入图片描述
  2. 当我们从一个聚合数据类型中删除了最后一个元素之后,Redis会自动删除该键。Stream数据类型是个例外。
    在这里插入图片描述
  3. 对一个空的 list 调用只读命令(如LLEN,返回list的长度)或者写命令移除元素时,效果如下。
    在这里插入图片描述

2.3 Hashes

Redis 哈希是字符串字段和字符串值之间的映射,1个 hash 常用来表示1个对象(可以有许多 field 和 对应的 value)下面的例子中,键是"user:1000",剩下是一对一对的字段和值。
在这里插入图片描述
每一个hash 可以存储 232 -1 个 field/value 对。

# 为某hash键设置字段的值
hmset 键 field1 value1 field2 value2
# 获取该hash键的某一个字段的值
hget 键 field1
hget 键 field2
# 获取该hash键的多个字段的值,返回的是一个数组
hmget 键 field1 field3 field2
# 获取该hash键的所有字段和其值
hgetall 键
# 有些命令可以单独在hash键的某字段上进行操作,如HINCRBY(理解为h-incr-by)
hincrby 键 field1 10 # 让该hash键的field1字段的值加10

需要注意的是,比较值比较小的hashes使用了特殊的编码方式,使得其在内存中的存储效率更高。

2.4 Sets

集合类型也是用来保存多个字符串的元素,可以理解成python中的set。具有以下特性:

  1. 没有重复的元素
  2. 集合中的元素是无序的,不能通过索引下标获取元素
  3. 支持集合间的操作,可以取多个集合取交集、并集、差集

Redis 中的 Sets 是字符串的无序集合。它支持集合间的操作(交集、并集、差集)和成员检查等操作。

1个 Redis set 的最大长度限制为 232 - 1

常见用例

  • 跟踪指定博客的所有IP地址,会自动去重。
  • Redis sets 可以很好的表示某些关系。用 set 来表示每一个tag
  • 可以从 set 中获取随机元素。
# 向set中添加一个或多个新元素
sadd set名 value1 value2 value3
# 查看某set键中的所有元素
smembers set# 判断某元素是否在该set中
sismember set名 value
# 求交集
sinter set1 set2 set3
# 求并集
sunion set1 set2 set3
sunionstore 新setset1 set2 # 将几个set的并集存到一个新的set
# 求差集
# 弹出集合中随机一个元素
spop set# 获取集合中随机一个元素但是不删除
srandmember set# 集合的基数,即集合中元素数量
scard set

例如,打标签。

# 表示给id为1000的新闻文章打了标签号为1,2,5,77的标签。
sadd news:1000:tags 1 2 5 77
# 也可以反过来,记录该标签标记了哪些新闻文章
sadd tag:1:news 1000
sadd tag:2:news 1000
sadd tag:5:news 1000
sadd tag:77news 1000

2.5 Sorted Sets

Sorted Sets 即有序的set。这个有序是通过给每个元素关联一个名为score的浮点数来实现的,score 是可以相同的,也就是score可以重复。

排序规则如下:

  • A和B是两个不同score的元素,如果A.score > B.score,则A > B
  • 如果A和B的score相同,比较A和B的字符串大小,若A的字符串大于B,则A > B

Sorted set的特点可以简单总结为:添加、删除、更新快,元素有序,成员检查快,获取中间元素快。

更新分数只需要zadd为该元素设置新的score即可,但是在更新score之后,Sorted set需要O(log(N)的时间复杂度进行重新排序。因此,当有大量更新时,使用sorted set是一个合适的选择。

# 给某Sorted set添加一个或多个元素
zadd zset名 score1 value1 score2 value2 score3 value3
# 查看某Sorted set中的所有元素,分数从小到大
zrange zset名 0 -1
#  查看某Sorted set中的所有元素,分数从大到小
zrevrange zset名 0 -1
# 使用withscores返回元素的同时也返回其分数
zrange zset名 0 -1 withscores

############# 范围操作 #############################

# 返回score在[负无穷,100] 左右区间都包括,这个范围的元素
zrangebyscore zset名 -inf 100
zrangebyscore zset名 100 +inf # [100, +inf]

# 移除某范围[start, end] 左右区间都包括,的元素,并返回
zremrangebyscore zset名 start end

# 获得值为value的元素在该sorted set中的排名
zrank zset名 value
zrevrank zset名 value # 逆序的排名

############# 按字典顺序(字符串大小顺序)获取范围 #############################
# 当分数都相同时,按照字符串的大小顺序有序。

zrangebylex zset名 min max
zrevrangebylex zset名 min max
zremrangebylex zset名 min max
zlexcount zset名 min max

常见用例

  • 大型在线游戏的排行榜。使用ZADD可以很容易地更新用户的score,还可以用ZRANGE获取排名前几的用户,用ZRANK获取某用户的排名。
  • 索引数据。比如,我有很多代表用户的hash,那么可以将用户的ID作为Sorted set 的值,用户的年龄作为 Sorted setscore 。然后使用 ZRANGEBYSCORE 就可以快速获取指定年龄范围的用户了。

2.6 Bitmaps

位图。并不是一种实际的数据类型,而是在String类型上定义的一组面向位的操作。

位操作分为两类:常数时间的单个位操作(如将一个位设置为1或0或获取其值),以及对一组位的操作,例如,计算给定位范围内位为1或者0的数量 (例如,人口计数)。

位图的最大优点之一是,它们在存储信息时通常可以节省大量空间。 例如,在以增量用户ID表示不同用户的系统中,仅使用512 MB内存就可以记住40亿用户的一位信息(例如,知道用户是否要接收新闻通讯)。

如果设置或者获取的位数超过了当前String的长度,那么Redis会自动扩大该String的长度。

########### 单个位上的操作 #######################
setbit 某key 第几位 值 # 例如: setbit mykey 10 1. 意思第10位设为1
# 这是该key第10位的值为1
setbit 某key 10 1
# 获取第10位的值
getbit 某key 10
# 因为第11位没有设置,所以是0
getbit 某key 11

########### 多个位上的操作 #######################

# 在不同String上,实现按位运算,如AND OR XOR NOT操作
# 对一个或多个保存二进制位的字符串key进行位元操作,并将结果保存到destkey上。
bitop 操作 destkey key1 key2 key3
# 统计为1的位的数量
bitcount 某key
# 查找第一为0或者为1的位
bitpos 某key 0或者1

2.7 HyperLogLogs

HLL是一种概率数据结构,旨在对唯一事物进行计数。

RedisHLL被编码为Redis字符串,所以我们可以用GET命令来序列化HLL,可以用SET命令来反序列化成HLL

从概念上讲,HLL API有些类似Set。 因为它跟 set 一样不会含有重复元素。

# 将新元素添加到该hll键中
pfadd hll键 value1 value2 value3
# 该hll键的值的数量
pfcount hll键

常见用例

  • 统计每天用户在搜索表单中执行的唯一查询。

2.8 Streams

StreamRedis5.0之后引入的新数据类型。提供抽象日志数据的append-only 数据结构。从概念上讲,因为Redis是流式传输在内存中表示的抽象数据类型,所以它们实现了更强大的操作,以克服日志文件本身的限制。

consumer group: 允许一组客户端合作使用同一消息流的不同部分。

3. Redis过期

Redis中的键都有存活时间。这与Redis中的数据结构无关。我们可以为键设置一个过期时间,当超过这个过期时间会自动删除这个键和其值,就像使用DEL删除了这个键一样。

默认永不过期

  • 过期时间的精度可以是s或者ms。
  • 只要超过过期时间1ms则认为过期。
  • 过期信息是复制并以时间戳格式持久化在磁盘中的,所以就算Redis挂了,只要重启了,仍然会在预计的时间过期。

设置过期时间,过期时间的默认单位是S

# 设置过期时间
set 键 值
expire 键 过期时间的s值
pexpire 键 过期时间的ms值
或者使用SET命令的ex选项
set 键 值 ex 过期时间的s值

# 查看某键还有多少时间过期
ttl 键 # s
pttl 键 # ms

# 让某键用不过期
persist 键

3.1 修改过期时间

使用DEL,SET,GETSET,PERSIST, EXPIRE命令可以修改过期时间。不使用DEL或者新值替换旧值,则过期时间不改变(除了这期间的时间消耗)。例如,使用INCR命令让一个键的值加1,或者向一个list中push一个元素,或者修改一个hash中某字段的值。

使用RENAME修改了某个键的名字,其过期时间仍然不改变(除了这期间的时间消耗)

设置一个负数的过期时间,则Redis会直接删除该key。

需要注意的是,如果将一个Redis实例的RDB文件复制给另一个Redis实例,必须要确保这两台计算机的本地时间一致,否则,可能存在某些键在新的这个Redis实例中直接就过期了。

3.2 Redis如何删除过期的键?

两种方式:

  • 被动删除。当 client 获取已过期的键时,删除这个键。
  • 主动删除。仅仅被动删除肯定不够,因为有的键可能一直都会再被访问了,就一直占用内存。因此,Redis每10秒执行如下操作1次:
    • 从设置了过期时间的键中随机抽取20个键,判断是否过期。
    • 删除所有发现的已过期的键。
    • 如果超过25%的键已过期,请从步骤1重新开始。

3.3 当键过期了,如何让主从保持一致

当键过期时,会将对应的DEL操作写入AOF文件中,这样在该master 和 slave中不会出现不一致的情况。

参考文献

[1] Redis 官方文档

猜你喜欢

转载自blog.csdn.net/besmarterbestronger/article/details/96296645