KV型内存数据库Redis

Posted Finley

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了KV型内存数据库Redis相关的知识,希望对你有一定的参考价值。

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

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

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

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

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

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

GET key
GET one

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

MGET

MGET key [key key ...]

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

MSET

MSET key value [key value ...]
MSET one 1 two 2

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

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

MSETNX

MSETNX key value [key value ...]
MSET one 1 two 2

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

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

TYPE

TYPE key

返回key指向的类型:

  • none: key不存在
  • string: 字符串
  • list: 列表
  • set: 集合
  • zset: 有序集
  • hash: 哈希表

INCR,DECR

INCR key
DECR key

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

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

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

INCRBY,DECRBY

INCRBY key value
INCRBY count 2
DECRBY count 3

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

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

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

INCRBYFLOAT

INCRBYFLOAT key value
INCRBYFLOAT one 1.23

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

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

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

key

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

DEL

DEL key [key ...]
DEL one two

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

KEYS

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

EXISTS key
EXISTS one

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

RENAME

RENAME key newkey
RENAME one ONE

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

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

RENAMENX

RENAMENX key newkey
RENAMENX one ONE

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

EXPIRE

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

EXPIREAT key timestamp

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

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

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

TTL

TTL key

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

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

PERSIST

PERSIST key

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

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

list

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

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

LPUSH

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

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

LLEN key

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

LRANGE

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

LINDEX key index

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

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

LINSERT

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

LREM key count value

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

count的值可以是以下几种:

  • count > 0: 从表头开始向表尾搜索,移除与value相等的元素,数量为count。
  • count < 0: 从表尾开始向表头搜索,移除与value相等的元素,数量为count的绝对值。
  • count = 0: 移除表中所有与value相等的值。

LTRIM

LTRIM key start stop

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

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

LSET

LSET key index value

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

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

LPOP, RPOP

LPOP key

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

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

set

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

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

SADD

SADD key member [member ...]

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

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

SSCARD

SSCARD key

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

SMEMBERS

SMEMBERS key

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

SISMEMBER

SISMEMBER key member

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

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

SREM

SREM key member [member ...]

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

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

SINTER, SUNION, SDIFF

SINTER key [key ...]
SUNION key [key ...]
SDIFF key [key ...]

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

SINTERSTORE, SUNIONSTORE, SDIFFSTORE

SINTER dest key [key ...]
SUNION dest key [key ...]
SDIFF dest key [key ...]

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

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

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

SPOP

SPOP key

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

SRANDMEMBER

SRANDMEMBER key [count]

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

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

若提供了count参数:

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

hash

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

HSET

HSET key field value

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

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

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

HSETNX

HSETNX key field value

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

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

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

HGET

HGET key field

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

HMSET

HMSET key field value [field value ...]

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

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

HMGET

HMGET key field [field ...]

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

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

HDEL

HDEL key field [field ...]

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

HLEN

HLEN key

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

HEXISTS

HEXISTS key field 

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

HKEYS

HKEYS key

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

HVALS

HVALS key

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

HGETALL

HGETALL key

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

> HMSET hash a 1 b 2
OK
> HGETALL hash
1) "a"
2) "1"
3) "b"
4) "2"

HINCRBY, HINCRBYFLOAT

HINCRBY key field increment

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

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

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

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

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

zset

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

ZADD

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

ZREM key member [member ...]

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

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

ZCARD

ZCARD key

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

ZCOUNT

ZCOUNT key min max

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

ZRANGE, ZREVRANGE

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。

> 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

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

ZRANK key member

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

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

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

ZINCRBY

ZINCRBY key increment member

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

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

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

Redis应用进阶

事务

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。

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不会阻止在事务中修改被监视的键。

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

示例(伪代码):

> 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的示例:

>>> 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频道:

SUBSCRIBE chat

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

127.0.0.1:6379> PUBLISH chat "Hi there"
(integer) 1

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

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

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命令用于取消订阅的频道:

UNSUBSCRIBE [channel [channel ...]]

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

PSUBSCRIBE pattern [pattern ...]
PUNSUBSCRIBE [pattern [pattern ...]]

SCAN

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

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

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), 包括元素成员和元素分值
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中:

PFADD key element [element ...] 

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

PFCOUNT key [key ...]

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

PFMERGE destkey sourcekey [sourcekey ...]

以上是关于KV型内存数据库Redis的主要内容,如果未能解决你的问题,请参考以下文章

Redis与KV存储(RocksDB)融合之编码方式

Linux自学笔记——redis

知识分享:值得学习的三大C++语言经典开源项目

内存KV缓存/数据库,可以选择它? | 1分钟系列

redis为什么快

Redis为什么使用单进程单线程方式