KV型内存数据库Redis

2022-08-18 20:08:10 浏览数 (1)

Redis是开源的高性能内存Key-Value数据库, 可以提供事务和持久化支持, 并提供了TTL(time to life)服务。

Redis采用单线程数据操作 非阻塞IO的模型,非阻塞IO提供了较高的IO性能,单线程操作保证了单条指令的原子性。

Redis使用简单灵活性能优异,常被用作缓存,分布式锁或者消息队列。

非特殊说明, 本文以Redis 3.0为标准进行介绍。

  • Redis数据结构
    • string
      • SET
      • GET
      • MGET
      • MSET
      • MSETNX
      • TYPE
      • INCR,DECR
      • INCRBY,DECRBY
      • INCRBYFLOAT
    • key
      • DEL
      • KEYS
      • EXISTS
      • RENAME
      • RENAMENX
      • EXPIRE
      • EXPIREAT
      • TTL
      • PERSIST
    • list
      • LPUSH
      • RPUSH
      • LLEN
      • LRANGE
      • LINDEX
      • LINSERT
      • LREM
      • LTRIM
      • LSET
      • LPOP, RPOP
    • set
      • SADD
      • SSCARD
      • SMEMBERS
      • SISMEMBER
      • SREM
      • SINTER, SUNION, SDIFF
      • SINTERSTORE, SUNIONSTORE, SDIFFSTORE
      • SPOP
      • SRANDMEMBER
    • hash
      • HSET
      • HSETNX
      • HGET
      • HMSET
      • HMGET
      • HDEL
      • HLEN
      • HEXISTS
      • HKEYS
      • HVALS
      • HGETALL
      • HINCRBY, HINCRBYFLOAT
    • zset
      • ZADD
      • ZREM
      • ZCARD
      • ZCOUNT
      • ZRANGE, ZREVRANGE
      • ZRANGEBYSCORE, ZREVRANGEBYSCORE
      • ZRANK, ZREVRANK
      • ZINCRBY
  • Redis应用进阶
    • 事务
    • pipeline
    • 发布订阅
    • SCAN
    • HyperLogLog

Ubuntu系统可以用包管理器安装Redis服务:

sudo apt-get install redis-server

并安装客户端:

sudo apt-get install redis-tools

进入Redis客户端

redis-cli

登录远程Redis服务

redis-cli -h host -p port -a password

Redis数据结构

通常情况下,在Redis中若key或field不存在则会作为空集合处理(写操作会将先初始化为空集合)不会抛出错误,若key指向了其它类型则会出现错误。

Redis中的线性集合(list和zset)的下标以0为底,且支持负数下标。即0指向第一个元素,1指向第二个元素,-1指向最后一个元素,-2指向倒数第二个元素。

线性集合通常用start和stop参数表示一个子序列,序列为闭区间即包含start和stop指向的元素(这点与很多编程语言不同)。

string

string是Redis中的基本类型。 除了增删改查之外,Redis提供了STRLEN,APPEND等简单字符串操作。

Redis没有专用的整数类型,所以key内储存的string可以被解释为十进制64位有符号整数进行计算。

字符串也可以解释为双精度浮点数,在作为浮点数时计算结果时最大保留17位小数,自动去除小数部分尾随的0,必要时还会将浮点数改为整数(比如3.0会被保存成3)。 浮点数可以使用像2.0e73e590e-2这样的指数符号来表示。

string的算术操作可以让我们方便的实现锁和计数器等功能。

SET
代码语言:javascript复制
SET key value [EX seconds] [PX milliseconds] [NX|XX]
SET one 1
SET one 1 XX
SET two 2 NX

将key指向字符串值value,若不存在key则新建键值对,若key存在默认情况下会覆盖旧值,无视旧值的类型。

SET设置成功会返回OK, 失败会返回nil。

SET key value NX只有在key不存在时才会设置,若key已存在则不进行任何操作。

SET key value XX只有key存在时才会设置, 若key不存在则不进行任何操作。

SET key value EX second: 设置键的过期时间为 second 秒。

SET key value PX millisecond: 设置键的过期时间为 millisecond 毫秒。

因为SET命令可以通过参数来实现SETNX、SETEX和PSETEX三个命令的效果,Redis官方称可能在将来的版本中废弃并最终移除SETNX、SETEX和PSETEX这三个命令。

GET
代码语言:javascript复制
GET key
GET one

返回key所关联的字符串值,若key不存在返回nil, 若key指向其它数据类型则会返回一个错误信息。

MGET
代码语言:javascript复制
MGET key [key key ...]

返回所有(一个或多个)给定key的值。若其中有某个key不存在或指向其它类型,那么这个key返回nil。

MSET
代码语言:javascript复制
MSET key value [key value ...]
MSET one 1 two 2

同时设置一个或多个key-value对, 如果某个给定key已经存在,那么MSET会用新值覆盖原来的旧值。该命令不会返回错误信息,总是返回OK。

和其它指令一样,该操作是原子性的。

MSETNX
代码语言:javascript复制
MSETNX key value [key value ...]
MSET one 1 two 2

同时设置一个或多个key-value对, 如果某个给定key已经存在,那么MSETNX不会设置任何一个key-value。

该操作是原子性的,要么全部设置要么全不被设置。

TYPE
代码语言:javascript复制
TYPE key

返回key指向的类型:

  • none: key不存在
  • string: 字符串
  • list: 列表
  • set: 集合
  • zset: 有序集
  • hash: 哈希表
INCR,DECR
代码语言:javascript复制
INCR key
DECR key

INCR命令将key中储存的数字值增1, 若key不存在则先被初始化为0,然后再执行操作。 返回操作后key指向的值。

若值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。

类似地有DECR命令,用于将存储的数字减1。

INCRBY,DECRBY
代码语言:javascript复制
INCRBY key value
INCRBY count 2
DECRBY count 3

将key所储存的值加上增量value, 返回操作后的值。value可以为0或负值。

若值包含错误的类型,或字符串类型的值不能表示为整数,那么返回一个错误。

类似地有DECRBY用于将存储的数字减去给定值。

INCRBYFLOAT
代码语言:javascript复制
INCRBYFLOAT key value
INCRBYFLOAT one 1.23

将key所储存的值加上浮点增量value, 返回操作后的值。value可以为0或负值。

若值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。

目前版本的Redis中没有DECRBYFLOAT指令,可以使用加负数进行减运算。

key

本节介绍对key通用的操作。

DEL
代码语言:javascript复制
DEL key [key ...]
DEL one two

删除给定的一个或多个key, 不存在的key将会忽略返回被删除的key的数量。

KEYS
代码语言:javascript复制
KEYS pattern
KEYS *

查找所有符合给定模式pattern的key:

  • KEYS *: 匹配数据库中所有key 。
  • KEYS h?llo: 匹配hello,hallo 和 hxllo 等。
  • KEYS h*llo: 匹配 hllo 和 heeeeello 等。
  • KEYS h[ae]llo: 匹配 hello 和 hallo,但不匹配 hillo 。
EXISTS
代码语言:javascript复制
EXISTS key
EXISTS one

检查给定key是否存在, 若存在返回 1,否则返回 0。

RENAME
代码语言:javascript复制
RENAME key newkey
RENAME one ONE

将key改名为newkey, 当newkey已经存在时,RENAME命令将覆盖旧值。成功时返回OK,失败时返回一个错误。

当key和newkey相同,或者key不存在时,返回一个错误。

RENAMENX
代码语言:javascript复制
RENAMENX key newkey
RENAMENX one ONE

当newkey不存在时, 将key改名为newkey。成功时返回1,若newkey已存在返回0。

EXPIRE
代码语言:javascript复制
EXPIRE key seconds
EXPIRE one 1000

为给定key设置生存时间(TTL),当key过期时(生存时间为0),它会被自动删除。

使用SET命令等覆盖一个键值对将会移除TTL, 但是INCR,LPUSH, HSET等命令不会修改生存时间。

RENAME命令不会修改生存时间,若RENAME key key2命令使得key覆盖了带有TTL的key2, 那么新的key2的生存时间设置和原来的key相同。

PEXPIRE命令和EXPIRE命令的作用类似,但是它以毫秒为单位设置key的生存时间。

EXPIREAT
代码语言:javascript复制
EXPIREAT key timestamp

EXPIREAT的作用和EXPIRE类似,都用于为key设置生存时间。

不同在于EXPIREAT命令接受的时间参数是UNIX时间戳。

PEXPIREAT和EXPIREAT命令类似,但它的参数是以毫秒为单位的unix时间戳。

TTL
代码语言:javascript复制
TTL key

以秒为单位,返回给定 key 的剩余生存时间,当key不存在时,返回-2, 当key存在但没有设置剩余生存时间时,返回-1。

PTTL命令类似于TTL命令,但它以毫秒为单位返回key的剩余生存时间。

PERSIST
代码语言:javascript复制
PERSIST key

移除给定key的生存时间设置,使其成为永久的key。

当生存时间移除成功时,返回1。如果key不存在或key没有设置生存时间,返回0。

list

列表(list)是一个线性容器,可以根据下标访问元素。

Redis中list的元素只能是字符串,不支持其它类型。

LPUSH
代码语言:javascript复制
LPUSH key value1 value2 
LPUSH arr a b c

将一个或多个值value插入到列表key的头部(左侧),返回操作后列表的长度。

如果key不存在,将会创建一个空列表并执行LPUSH操作,当key存在但不是列表类型时,返回一个错误。

对空列表arr执行LPUSH arr a b c指令后,arr的内容为c b a。相当于原子性的执行了LPUSH arr a, LPUSH arr b, LPUSH arr c三条指令。

RPUSH
代码语言:javascript复制
RPUSH key value1 value2
RPUSH arr a b c

将一个或多个值value插入到列表key的尾部(左侧),返回操作后列表的长度。

如果key不存在,将会创建一个空列表并执行RPUSH操作,当key存在但不是列表类型时,返回一个错误。

对空列表arr执行RPUSH arr a b c指令后,arr的内容为a b c。相当于原子性的执行了RPUSH arr a, RPUSH arr b, RPUSH arr c三条指令。

LLEN
代码语言:javascript复制
LLEN key

返回列表的长度,若key不存在返回0, 若key指向其它类型则返回一个错误。

LRANGE
代码语言:javascript复制
LRANGE key start stop
LRANGE arr 0 -1

返回列表key中指定区间内的元素,区间以偏移量start和stop指定。

下标以0为底,即0表示列表中的第一个元素, 1表示第二个元素。也可以使用负数下标,-1表示最后一个元素, -2表示倒数第二个元素。

stop下标也在LRANGE命令的取值范围之内(闭区间),LRANGE arr 0 2会返回下标为0,1,2的三个元素。

超出范围的下标值不会引起错误,如果start比列表的最大下标还要大那么返回一个空列表,如果stop下标比最大下标还要大,stop的值将被设为最大下标。

LINDEX
代码语言:javascript复制
LINDEX key index

返回列表key中,下标为index的元素。若index超出范围或者key指向空列表(key不存在)则会返回nil, 若key指向其它类型则返回错误。

下标以0为底,即0表示列表中的第一个元素, 1表示第二个元素。也可以使用负数下标,-1表示最后一个元素, -2表示倒数第二个元素。

LINSERT
代码语言:javascript复制
LINSERT key BEFORE|AFTER pivot value
RPUSH arr "World"
LINSERT arr BEFORE "World" "HELLO"

将值value插入到列表key中,位于值pivot之前或之后。当pivot不存在于列表key时,不执行任何操作。当key不存在时,key被视为空列表,不执行任何操作。

如果命令执行成功,返回插入操作完成之后列表的长度。如果没有找到pivot返回-1,如果key不存在或为空列表,返回0。

LREM
代码语言:javascript复制
LREM key count value

根据参数count的值,移除列表中与参数value相等的元素,返回被移除元素的数量。

count的值可以是以下几种:

  • count > 0: 从表头开始向表尾搜索,移除与value相等的元素,数量为count。
  • count < 0: 从表尾开始向表头搜索,移除与value相等的元素,数量为count的绝对值。
  • count = 0: 移除表中所有与value相等的值。
LTRIM
代码语言:javascript复制
LTRIM key start stop

让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除, start和stop指定区间的规则与LRANGE相同。

若删除成功或key不存在则返回OK,若key指向其它类型则返回错误。

LSET
代码语言:javascript复制
LSET key index value

将列表key中下标为index的元素的值设置为value,下标以0为底,可以使用负数下标。

当index参数超出范围,或对一个空列表(key不存在或指向其它类型)进行LSET时,返回一个错误。

LPOP, RPOP
代码语言:javascript复制
LPOP key

移除并返回列表key的头元素, key不存在时返回nil。key指向其它类型时返回错误。

类似地有RPOP命令,移除并返回列表key的尾元素。

set

集合(set)是一种无序容器,不存在重复元素,可以用于判断元素是否存在或者进行交并差运算。

Redis中集合的元素类型只能是字符串,不支持其它类型。

SADD
代码语言:javascript复制
SADD key member [member ...]

将一个或多个member元素加入到集合key当中,返回添加到集合中新元素的数量,已经存在于集合的元素将被忽略。

若key不存在先初始化一个空集合然后添加成员,若key指向了非集合类型则会产生错误。

SSCARD
代码语言:javascript复制
SSCARD key

返回集合中元素的数量,key不存在时返回0,key指向其它类型时返回一个错误。

SMEMBERS
代码语言:javascript复制
SMEMBERS key

返回key指向的集合中的所有成员,若key不存在返回空集,若key指向其它类型则返回一个错误。

SISMEMBER
代码语言:javascript复制
SISMEMBER key member

判断member元素是否集合key的成员, 若元素是集合的成员返回1,若元素不是集合的成员或者集合不存在则返回0。

若key指向其它类型则返回一个错误。

SREM
代码语言:javascript复制
SREM key member [member ...]

移除集合中的一个或多个元素,不存在的元素会被忽略,返回被成功移除的元素的个数。

若key不存在则作为空集处理,返回0。若key指向其它类型则返回一个错误。

SINTER, SUNION, SDIFF
代码语言:javascript复制
SINTER key [key ...]
SUNION key [key ...]
SDIFF key [key ...]

返回给定集合的交集(SINTER),并集(SUNION)和差集(SDIFF),若key不存在则作为空集处理,若key指向其它类型则返回一个错误。

SINTERSTORE, SUNIONSTORE, SDIFFSTORE
代码语言:javascript复制
SINTER dest key [key ...]
SUNION dest key [key ...]
SDIFF dest key [key ...]

计算给定集合的交集(SINTERSTORE),并集(SUNIONSTORE)和差集(SDIFFSTORE),并将结果存入dest集合,若dest集合已存在则将其覆盖。

若key不存在则作为空集处理,若key指向其它类型则返回一个错误。

dest可以是某个参与计算的key,dest可以指向其它类型,计算结束后dest中的值会被覆盖。

SPOP
代码语言:javascript复制
SPOP key

SPOP移除并返回集合中的一个随机元素,当key不存在或key是空集时返回nil,若key指向其它类型则返回一个错误。

SRANDMEMBER
代码语言:javascript复制
SRANDMEMBER key [count]

若只提供了key参数,那么返回集合中的一个随机元素。

当key不存在或key是空集时返回nil,若key指向其它类型则返回一个错误。

若提供了count参数:

  • 若count 为正数,且小于集合基数,那么返回一个包含count个元素的数组,数组中的元素各不相同。
  • 若count 大于等于集合中元素数,那么返回整个集合。
  • 若count为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为count的绝对值。

hash

哈希表(hash)是key-value结构, key和value的类型为字符串。

HSET
代码语言:javascript复制
HSET key field value

将哈希表key中的域field的值设为value。

如果key不存在, 将创建一个新的哈希表并进行HSET操作。如果域field已经存在于哈希表中,旧值将被覆盖。

HSET设置了一个新域则返回1,若覆盖了一个已有的域则返回0。

HSETNX
代码语言:javascript复制
HSETNX key field value

将哈希表key中的域field的值设为value。

如果key不存在, 将创建一个新的哈希表并进行HSET操作。如果域field已经存在于哈希表中,则不进行任何操作。

HSETNX设置了一个新域则返回1,若域已经存在则返回0。

HGET
代码语言:javascript复制
HGET key field

返回哈希表key中指定域field的值,若哈希表key不存在或其域field不存在则返回nil。

HMSET
代码语言:javascript复制
HMSET key field value [field value ...]

同时将多个field-value(域-值)对设置到哈希表key中。若field已存在则会被覆盖。

若key不存在,则创建一个空哈希表并执行HMSET操作

HMGET
代码语言:javascript复制
HMGET key field [field ...]

返回哈希表key中一个或多个给定域的值,若field不存在则返回nil。

若key不存在则作为空哈希表处理,每个field都会返回一个nil值。

HDEL
代码语言:javascript复制
HDEL key field [field ...]

删除哈希表key中一个或多个指定域,不存在的域将被忽略,返回实际被删除域的数目。

HLEN
代码语言:javascript复制
HLEN key

返回哈希表key中域的数量,若key不存在则返回0。

HEXISTS
代码语言:javascript复制
HEXISTS key field 

判断哈希表key中域field是否存在,若存在返回1。若哈希表key不存在或其中不存在域field则返回0。

HKEYS
代码语言:javascript复制
HKEYS key

以列表的形式返回哈希表key中所有域的名称。

HVALS
代码语言:javascript复制
HVALS key

返回哈希表key中所有域的值。

HGETALL
代码语言:javascript复制
HGETALL key

以列表的形式返回哈希表key中所有的键和值,前一个元素为键其后的元素为它的值。

代码语言:javascript复制
> HMSET hash a 1 b 2
OK
> HGETALL hash
1) "a"
2) "1"
3) "b"
4) "2"
HINCRBY, HINCRBYFLOAT
代码语言:javascript复制
HINCRBY key field increment

为哈希表key中的域field的值加上增量increment, 增量可以为负数进行减法操作。

若哈希表中不存在域field则现将该域初始化为0,然后进行加法操作。

若哈希表key不存在,则将创建一个空哈希表,然后按上一条规则执行。

若key指向其它类型或域的值不能解释为整数则返回一个错误。

类似地,HINCRBYFLOAT可以进行浮点数运算。

zset

有序集合(SortedSet, zset)是一种特殊的集合类型,它不允许重复元素,可以根据每个元素的score进行排序。

ZADD
代码语言:javascript复制
ZADD key [NX|XX] [FH] [INCR] score member [[score member] [score member] ...]

将一个或多个member元素及其score值加入到有序集key当中, 若元素已经在集合中则更新它的score,score值可以是整数值或浮点数。

返回新添加的元素的数量,不包括被更新的元素的数量。

当key存在但不是有序集类型时,返回一个错误。

ZADD命令支持一些选项:

  • NX: 不更新存在的成员,仅添加新成员
  • XX: 不添加新成员,仅更新存在的成员
  • CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数(CH=changed)
  • INCR: 对成员的值进行增加操作而不是设置操作,等同于ZINCRBY命令
ZREM
代码语言:javascript复制
ZREM key member [member ...]

移除有序集 key 中的一个或多个成员,不存在的成员将被忽略, 返回实际被移除的元素数量。

当 key 存在但不是有序集类型时,返回一个错误。

ZCARD
代码语言:javascript复制
ZCARD key

返回有序集key中元素的数目,若key不存在则返回0,若key指向其它类型则返回一个错误。

ZCOUNT
代码语言:javascript复制
ZCOUNT key min max

返回有序集key中,score值在min和max之间(包括等于min或max)的元素数量。

ZRANGE, ZREVRANGE
代码语言:javascript复制
ZRANGE key start stop [WITHSCORES]

返回有序集key中,指定区间内的成员。start和stop用于指定元素的排名,它们以0为底且支持负下标,指定的是闭区间。

即0代表集合中score最小的元素,-1代表最大的元素。

其中成员的位置按score值递增(从小到大)来排序, 具有相同score值的成员按字典序来排列。

ZRANGE key 0 -1可以返回集合中所有元素递增排列的序列。

若start的值大于集合中元素的个数 或者 start大于stop值 则返回一个空列表;若stop大于集合中元素的个数则当做该集合的最大下标处理。

默认情况下ZRANGE命令仅返回元素,若添加了WITHSCORES选项则会将score一并返回。返回列表中元素和score成对出现,前一个为元素后一个为score。

代码语言:javascript复制
> zrange z 0 -1
1) "a"
2) "b"
3) "c"
> zrange z 0 -1 WITHSCORES
1) "a"
2) "1"
3) "b"
4) "2"
5) "c"
6) "5"

类似地,ZREVRANGE指令按照score递减排序(从大到小)。

ZRANGEBYSCORE, ZREVRANGEBYSCORE
代码语言:javascript复制
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

返回有序集key中score在min和max(包括等于min和max)之间的的元素,按照score值递增排列。

默认情况下ZRANGEBYSCORE命令仅返回元素,若添加了WITHSCORES选项则会将score一并返回。返回列表中元素和score成对出现,前一个为元素后一个为score。

可选的LIMIT参数指定返回结果的数量及区间,类似于SQL中的SELECT offset, count,offset为跳过元素的数量,count为返回元素的最大数量。

类似地,ZREVRANGEBYSCORE命令可以按照score值递减排列。

ZRANK, ZREVRANK
代码语言:javascript复制
ZRANK key member

返回有序集key中成员member的排名。其中有序集成员按score值递增(从小到大)顺序排列。

排名以0为底,score值最小的成员排名为0。

使用 ZREVRANK 命令可以获得成员按 score 值递减(从大到小)排列的排名。

ZINCRBY
代码语言:javascript复制
ZINCRBY key increment member

为有序集key的成员member的score值加上增量increment,increment可以为负值,可以为整数或者浮点数��

当key不存在,或 member不是key的成员时,ZINCRBY会初始化空集合,或者将成员初始化为0。

当key指向其它类型时,则会返回一个错误。

Redis应用进阶

事务

代码语言:javascript复制
127.0.0.1:6379> RPUSH a 1 2 3
QUEUED
127.0.0.1:6379> LRANGE a 0 -1
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 3
2) 1) "1"
   2) "2"
   3) "3"

Redis提供了事务机制,支持原子性地执行多条指令。

MULTI命令进入事务模式,其后的命令进入队列缓存,直到EXEC命令执行队列中的命令,或者DISCARD命令放弃事务执行。

EXEC命令会以列表的形式返回事务中所有命令的返回值。

若事务的指令队列中存在语法错误则整个事务都会放弃执行。若队列中某条指令出现了运行时错误(如哈希指令操作了列表), Redis会继续执行事务中的后续指令。

Redis保证在事务的原子性,事务执行期间不会有其它客户端的指令插入。

Redis事务不支持回滚必须由使用者保证一致性。

因为Redis是单线程执行的,总是能保证事务的隔离性。Redis事务不提供额外的持久化机制,持久性由持久化配置决定。

WATCH命令应在事务开始前执行,用于监视某个键的值是否改变。 若在执行WATCHEXEC指令中间,任意一个被监视的键发生改变或被删除那么事务将中止执行,EXEC命令会返回nil。

代码语言:javascript复制
127.0.0.1:6379> WATCH lock
OK
# 若此时其它客户端修改了lock的值,那么事务不会开始执行。
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET b 1
QUEUED
127.0.0.1:6379> GET b
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) "1"

WATCH的监视到EXEC开始执行事务为止,因此WATCH不会阻止在事务中修改被监视的键。

代码语言:javascript复制
127.0.0.1:6379> WATCH lock
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET lock 1
QUEUED
127.0.0.1:6379> GET lock
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) "1"

WATCH命令主要用于保证事务开始执行时的状态正确,典型的"秒杀"应用中,多个客户端首先使用WATCH命令监视锁,随后执行购买事务。

WATCH命令和事务执行之间若有其它客户端成功执行事务,使得锁发生变化则当前客户端无法执行事务,即抢购失败。

示例(伪代码):

代码语言:javascript复制
> SET remains 100
> SET empty 0
> WATCH empty
# 此时可能已有其它客户端抢先执行事务
> MULTI
> DECR remains
> if (remains == 0): SET empty 1 # 修改锁,阻止其它客户端抢购  
# 此处还应有写购买记录和修改余额等操作
> EXEC

UNWATCH命令用于取消WATCH命令对所有key的监视。

pipeline

Redis采用请求/响应式协议进行与服务端的交互,通常情况下一次请求只包含一条指令。

pipeline模式可以一次请求执行多条指令,减少IO的开销。

这里给出一个Python客户端使用pipeline的示例:

代码语言:javascript复制
>>> connect = redis.Redis(host='127.0.0.1', port=6379)
>>> pipe = connect.pipeline(transaction=False)
>>> pipe.set("x", "1")
Pipeline<ConnectionPool<Connection<host=127.0.0.1,port=6379,db=0>>>
>>> pipe.set("y", "2")
Pipeline<ConnectionPool<Connection<host=127.0.0.1,port=6379,db=0>>>
>>> pipe.execute()
[True, True]

pipeline不是原子性的,执行过程中可能会有来自其他客户端的指令执行。不要使用pipeline发送多条SET/GET指令代替MSET/MGET。

pipeline会占据整个连接,在完成前无法执行其它指令。客户端应配置好连接池防止被pipeline阻塞。

发布订阅

Redis的发布订阅模式允许客户端监听某些频道,发布者在该频道上发布消息后,消息会被推送到订阅了该频道的客户端。

发布订阅模式允许服务端主动通知客户端,无需客户端轮询状态变化,因此Redis可以实现消息队列的功能。

首先打开一个客户端订阅chat频道:

代码语言:javascript复制
SUBSCRIBE chat

打开另一个客户端发布一条消息:

代码语言:javascript复制
127.0.0.1:6379> PUBLISH chat "Hi there"
(integer) 1

PUBLISH命令的返回值是接收到该消息的订阅者的数量。

订阅了该频道的客户端会受到消息推送:

代码语言:javascript复制
127.0.0.1:6379> SUBSCRIBE chat
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "chat"
3) (integer) 1

1) "message"
2) "chat"
3) "Hi there"

UNSUBSCRIBE命令用于取消订阅的频道:

代码语言:javascript复制
UNSUBSCRIBE [channel [channel ...]]

PSUBSCRIBE和PUNSUBSCRIBE可以使用模式匹配来订阅和取消订阅频道。

代码语言:javascript复制
PSUBSCRIBE pattern [pattern ...]
PUNSUBSCRIBE [pattern [pattern ...]]

SCAN

KEYS命令处理大数据库或者SMEMBERS命令处理大集合时可能阻塞数据库数秒之久,这在生产环境下是无法介绍的。

SCANSSCAN命令可用分页迭代的方式遍历大数据集,每次迭代仅返回少量数据不会阻塞服务器:

代码语言:javascript复制
SCAN cursor [MATCH pattern] [COUNT count]
127.0.0.1:6379> SCAN 0
1) "20"
2)  1) "1125677473485562817"
    2) "5537448729649573447"
    3) "2854796168938416843"
    4) "7439346733403784473"
    5) "-6333572342266574627"
    6) "-9080851294203022766"
    7) "1125677473485562817"
    8) "820904952218043889"
    9) "1125677473485562827"
   10) "1125677473485562837"
127.0.0.1:6379> SCAN 20
1) "0"
2)  1) "1125677473485562817"
    2) "-1053519331922297522"
    3) "7439346733403784473"
    4) "-2594669955628668552"
    5) "-4053026386633294784"
    6) "7439346733403784473"
    7) "-1053519331922297522"
    8) "2649406091729268560"
    9) "7439346733403784473"
   10) "1053519331903186673"

SCAN命令的返回值包含两部分,第一部分为下次迭代的游标,第二部分为本次迭代取得的键。

SCAN cursor MATCH pattern可以像KEYS命令一样使用通配符筛选需要迭代的键。SCAN cursor COUNT count可以设置每次迭代返回键的数量。

使用0作为游标表示开始一次新的迭代,当SCAN命令返回的游标为0时表示本次迭代已经结束。

SCAN命令保证在整个迭代期间一直存在于数据库中的键一定会被返回。如果一个元素是在迭代过程中被添加到数据集的, 又或者是在迭代过程中从数据集中被删除的, 那么这个元素可能会被返回, 也可能不会, 这是未定义的。

SCAN命令可能会将一个键返回多次,由应用程序处理重复的元素。

Redis中提供了几个类似的命令用于遍历大集合:

  • SSCAN: 遍历集合(set)
  • HSCAN: 遍历哈希表(hash)
  • ZSCAN: 遍历有序集合(zset), 包括元素成员和元素分值
代码语言:javascript复制
127.0.0.1:6379> zadd z 1 a 2 b 3 c
(integer) 0
127.0.0.1:6379> zscan z 0
1) "0"
2) 1) "a"
   2) "1"
   3) "b"
   4) "2"
   5) "c"
   6) "3"

HyperLogLog

一个集合中不重复元素的个数称为集合的基数,如集合{a, b, c}的基数为3。

HyperLogLog是一种估计大集合基数的算法,Redis封装了该算法:

PFADD命令将元素添加到HyperLogLog中:

代码语言:javascript复制
PFADD key element [element ...] 

PFCOUNT命令返回基数估计值,当给定了多个key时则返回它们基数之和(不是并集的基数):

代码语言:javascript复制
PFCOUNT key [key ...]

PFMERGE命令将多个HyperLogLog合并,destKey的基数即为sourceKey并集的基数:

代码语言:javascript复制
PFMERGE destkey sourcekey [sourcekey ...]

0 人点赞