Redis
1、常用命令梳理
1、String 字符串
命令 | 事例 | 说明 |
---|---|---|
SET | SET key value [EX seconds] [PX milliseconds] [NX|XX] | 将字符串值 value 关联到 key |
GET | GET key | 返回 key 所关联的字符串值 |
MSET | MSET key value [key value …] | 同时设置一个或多个 key-value 对。 |
MGET | MGET key [key …] | 返回所有(一个或多个)给定 key 的值。 |
GETSET | GETSET key value | 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。 |
STRLEN | STRLEN key | 返回 key 所储存的字符串值的长度。 |
INCR | NCR key | 将 key 中储存的数字值增一。 唯一Id |
DECR | DECR key | 将 key 中储存的数字值减一。 |
INCRBY | INCRBY key increment | 将 key 所储存的值加上增量 increment 。 |
DECRBY | DECRBY key decrement | 将 key 所储存的值减去减量 decrement 。 |
INCRBYFLOAT | INCRBYFLOAT key increment | 为 key 中所储存的值加上浮点数增量 increment |
GETRANGE | GETRANGE key start end | 返回 key 中字符串值的子字符串,字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)。 |
SETRANGE | SETRANGE key offset value | 用 value 参数覆写(overwrite)给定 key 所储存的字符串值,从偏移量 offset 开始。 |
SETNX | SETNX key value | 将 key 的值设为 value ,当且仅当 key 不存在。 若给定的 key 已经存在,则 SETNX 不做任何动作 NX分布式锁的处理方式 |
MSETNX | MSETNX key value [key value …] | 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。 即使只有一个给定 key 已存在, MSETNX 也会拒绝执行所有给定 key 的设置操作 |
PSETEX | PSETEX key milliseconds value | 以毫秒为单位设置 key 的生存时间 |
SETEX | SETEX key seconds value | 将值 value 关联到 key ,并将 key 的生存时间设为 seconds (以秒为单位)。 |
APPEND | APPEND key value | 将 value 追加到 key 原来的值的末尾。 |
String中bit的操作
Redis中字符串的存储方式都是以二进制的方式存储的。BIT命令就是对这个二进制数据进行操作的。
命令 | 事例 | 说明 |
---|---|---|
SETBIT | SETBIT key offset value | 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。 |
GETBIT | GETBIT key offset | 对 key 所储存的字符串值,获取指定偏移量上的位(bit)。 |
BITCOUNT | BITCOUNT key [start] [end] | 计算给定字符串中,被设置为 1 的比特位的数量 |
BITOP | BITOP operation destkey key [key …] | 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上 |
bitpops | BITPOS key bit [start] [end] | 返回字符串里面第一个被设置为1或者0的bit位 |
operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种:
BITOP AND destkey key [key …] ,对一个或多个 key 求逻辑并,并将结果保存到 destkey 。
BITOP OR destkey key [key …] ,对一个或多个 key 求逻辑或,并将结果保存到 destkey 。
BITOP XOR destkey key [key …] ,对一个或多个 key 求逻辑异或,并将结果保存到 destkey 。
BITOP NOT destkey key ,对给定 key 求逻辑非,并将结果保存到 destkey 。
除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入。
String的HyperLogLog操作
Redis 在 2.8.9 版本添加了 HyperLogLog 结构。
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
命令 | 事例 | 说明 |
---|---|---|
PFADD | PFADD key element [element …] | 添加指定元素到 HyperLogLog 中。 |
PFCOUNT | PFCOUNT key [key …] | 返回给定 HyperLogLog 的基数估算值。 |
PFMERGE | PFMERGE destkey sourcekey [sourcekey …] | 将多个 HyperLogLog 合并为一个 HyperLogLog |
2、Hash散列
命令 | 事例 | 说明 |
---|---|---|
HSET | HSET key field value | 将哈希表 key 中的域 field 的值设为 value 。 |
HGET | HGET key field | 返回哈希表 key 中给定域 field 的值。 |
HGETALL | HGETALL key | 返回哈希表 key 中,所有的域和值。 |
HMSET | HMSET key field value [field value …] | 同时将多个 field-value (域-值)对设置到哈希表 key 中。 |
HMGET | HMGET key field [field …] | 返回哈希表 key 中,一个或多个给定域的值。 |
HSETNX | HSETNX key field value | 将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在 |
HKEYS | HKEYS key | 返回哈希表 key 中的所有域 |
HVALS | HVALS key | 返回哈希表 key 中所有域的值。 |
HLEN | HLEN key | 返回哈希表 key 中域的数量。 |
HDEL | HDEL key field [field …] | 删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。 |
HEXISTS | HEXISTS key field | 查看哈希表 key 中,给定域 field 是否存在 |
HINCRBY | HINCRBY key field increment | 哈希表 key 中的域 field 的值加上增量 increment 。 |
HINCRBYFLOAT | HINCRBYFLOAT key field increment | 为哈希表 key 中的域 field 加上浮点数增量 increment 。 |
3、List列表
命令 | 事例 | 说明 |
---|---|---|
LPUSH | LPUSH key value [value …] | 将一个或多个值 value 插入到列表 key 的表头, 存储顺序为 左读:v3,v2,v1 |
LPUSHX | LPUSHX key value [value …] | 当key已经有元素时才会进行插入,如果key时空集合则不进行插入 左插入 |
RPUSH | RPUSH key value [value …] | 将一个或多个值 value 插入到列表 key 的表尾(最右边) 存储顺序 左读:v1 v2 v3 |
RPUSHX | RPUSHX key value | 当key已经有元素时才会进行插入,如果key时空集合则不进行插入 右插入 |
LINSERT | LINSERT key BEFORE|AFTER pivot value | 将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。 |
LSET | LSET key index value | 将列表 key 下标为 index 的元素的值设置为 value 。 |
LLEN | LLEN key | 返回列表 key 的长度。 |
LINDEX | LINDEX key index | 返回列表 key 中,下标为 index 的元素 |
LRANGE | LRANGE key start stop | 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定 |
LPOP | LPOP key COUNT | 移除并返回列表 key 的头元素。 count 不填则删除并返回第一个元素 |
RPOP | RPOP key | 移除并返回列表 key 的尾元素 |
LTRIM | LTRIM key start stop | 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除 |
LREM | LREM key count value | 根据参数 count 的值,移除列表中与参数 value 相等的元素。 count表示删除的个数,如果count大于总数,删除全部 |
BLPOP | BLPOP key [key …] timeout | BLPOP 是列表的阻塞式(blocking)弹出原语。是 LPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BLPOP 命令阻塞,直到等待超时或发现可弹出元素为止。 当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。 |
BRPOP | BRPOP key [key …] timeout | BRPOP 是列表的阻塞式(blocking)弹出原语 |
RPOPLPUSH | RPOPLPUSH source destination | 将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。 将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。 |
BRPOPLPUSH | BRPOPLPUSH source destination timeout | BRPOPLPUSH 是 RPOPLPUSH 的阻塞版本,当给定列表 source 不为空时, BRPOPLPUSH 的表现和 RPOPLPUSH 一样。 |
4、Set集合
命令 | 事例 | 说明 |
---|---|---|
SADD | SADD key member [member …] | 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。 |
SPOP | SPOP key [count] | 移除并返回集合中的count个随机元素 |
SRANDMEMBER | SRANDMEMBER key [count] | 如果命令执行时,只提供了 key 参数,那么返回集合中的一个随机元素。 不删除 如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合。 如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值 |
SCARD | SCARD key | 返回集合 key 的基数(集合中元素的数量)。 |
SMEMBERS | SMEMBERS key | 返回集合 key 中的所有成员。 |
SISMEMBER | SISMEMBER key member | 判断 member 元素是否集合 key 的成员 1=y 0 =n |
SMOVE | SMOVE source destination member | 将 member 元素从 source 集合移动到 destination 集合 |
SREM | SREM key member [member …] | 移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。 |
SINTER | SINTER key [key …] | 返回一个集合的全部成员,该集合是所有给定集合的交集。不存在的 key 被视为空集 |
SINTERSTORE | SINTERSTORE destination key [key …] | 这个命令类似于 SINTER 命令,但它将结果保存到 destination 集合,而不是简单地返回结果集,如果 destination 集合已经存在,则将其覆盖 |
SDIFF | SDIFF key [key …] | 返回一个集合的全部成员,该集合是所有给定集合之间的差集。前面的集合比对后面的系列集合 |
SDIFFSTORE | SDIFFSTORE destination key [key …] | 这个命令的作用和 SDIFF 类似,但它将结果保存到 destination 集合,而不是简单地返回结果集。如果 destination 集合已经存在,则将其覆盖 |
SUNION | SUNION key [key …] | 返回一个集合的全部成员,该集合是所有给定集合的并集。 |
SUNIONSTORE | SUNIONSTORE destination key [key …] | 这个命令类似于 SUNION 命令,但它将结果保存到 destination 集合,而不是简单地返回结果集。 |
5、Zset有序集合
命令 | 事例 | 说明 |
---|---|---|
ZADD | ZADD key score member [[score member] [score member] …] | 将一个或多个 member 元素及其 score 值加入到有序集 key 当中 |
ZINCRBY | ZINCRBY key increment member | 为有序集 key 的成员 member 的 score 值加上增量 increment 。 |
ZCARD | ZCARD key | 返回有序集 key 的基数。 |
ZSCORE | ZSCORE key member | 返回有序集 key 中,成员 member 的 score 值。 |
ZRANGE | ZRANGE key start stop [WITHSCORES] | 返回有序集 key 中,指定区间内的成员。 |
ZRANGEBYSCORE | ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] | 返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。 |
ZREVRANGEBYSCORE | ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count] | 返回有序集 key 中, score 值介于 max 和 min 之间(默认包括等于 max 或 min )的所有的成员。有序集成员按 score 值递减(从大到小)的次序排列。 |
ZREVRANGE | ZREVRANGE key start stop [WITHSCORES] | 返回有序集 key 中,指定区间内的成员。 |
ZCOUNT | ZCOUNT key min max | 返回有序集 key 中, score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量。 |
ZRANK | ZRANK key member | 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列。 小到大 |
ZREVRANK | ZREVRANK key member | 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递减(从大到小)排序。 大到小 |
ZUNIONSTORE | ZUNIONSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX] | 计算给定的一个或多个有序集的并集,其中给定 key 的数量必须以 numkeys 参数指定,并将该并集(结果集)储存到 destination 。 |
ZINTERSTORE | ZINTERSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX] | 计算给定的一个或多个有序集的交集,其中给定 key 的数量必须以 numkeys 参数指定,并将该交集(结果集)储存到 destination 。 |
ZREM | ZREM key member [member …] | 移除有序集 key 中的一个或多个成员,不存在的成员将被忽略。 |
ZREMRANGEBYRANK | ZREMRANGEBYRANK key start stop | 移除有序集 key 中,指定排名(rank)区间内的所有成员。 |
ZREMRANGEBYSCORE | ZREMRANGEBYSCORE key min max | 移除有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。 |
命令解释:ZUNIONSTORE zs 2 z1 z2 weights 1 0.5 aggregate MAX
numkeys:指定目标有序集合个数 z1,z2 两个集合 则该值必须为2
WEIGHTS:合并因子 即合并式score* 合并因子再进行后续函数比对 ,有几个集合必须配置几个合并因子 不配默认1
AGGREGATE: 合并函数 默认sum min取score小的 max取score大的
6、Pub/Sub发布订阅
命令 | 事例 | 说明 |
---|---|---|
PUBLISH | PUBLISH channel message | 将信息 message 发送到指定的频道 channel 。 |
SUBSCRIBE | SUBSCRIBE channel [channel …] | 订阅给定的一个或多个频道的信息。 精确匹配 |
PSUBSCRIBE | PSUBSCRIBE pattern [pattern …] | 订阅一个或多个符合给定模式的频道。 模糊匹配* |
UNSUBSCRIBE | UNSUBSCRIBE [channel [channel …]] | 指示客户端退订给定的频道。 精确退订 如果没有频道被指定,也即是,一个无参数的 UNSUBSCRIBE 调用被执行,那么客户端使用 SUBSCRIBE 命令订阅的所有频道都会被退订。在这种情况下,命令会返回一个信息,告知客户端所有被退订的频道。 |
PUNSUBSCRIBE | PUNSUBSCRIBE [pattern [pattern …]] | 指示客户端退订所有给定模式。模糊退订 如果没有模式被指定,也即是,一个无参数的 PUNSUBSCRIBE 调用被执行,那么客户端使用 PSUBSCRIBE 命令订阅的所有模式都会被退订。在这种情况下,命令会返回一个信息,告知客户端所有被退订的模式。 |
PUBSUB | PUBSUB [argument [argument …]] | PUBSUB:返回一个或多个给定频道的订阅者数量。 1:PUBSUB CHANNELS pattern]:返回一个或多个匹配给定模式的频道的列表。 2:PUBSUB NUMSUB[channel-1 … channel-N]:返回一个或多个给定频道的订阅者数量。 3:PUBSUB NUMPAT:返回当前已订阅模式的数量 |
7、Stream
Redis Stream 是 Redis 5.0 版本新增加的数据结构。 Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。 简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。 而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。
命令 | 事例 | 说明 |
---|---|---|
xadd | XADD key [NOMKSTREAM] [MAXLEN|MINID [=|~] threshold [LIMIT count]] *|id field value [field value …] | 添加消息到末尾; * 表示系统生成id NOMKSTREAM如果存在则加入否则不加入 |
xlen | XLEN key | 获取流包含的元素数量,即消息长度 |
xrange | XRANGE key start end [COUNT count] | 获取消息列表,会自动过滤已经删除的消息 -最小 +最大 |
xtrim | XTRIM key MAXLEN|MINID [=|~] threshold [LIMIT count] | 对流进行修剪,限制长度 |
xdel | XDEL key id [id …] | 删除消息 |
xread | XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key …] id [id …] | 以阻塞或非阻塞方式获取消息列表 |
xrevrange | XREVRANGE key end start [COUNT count] | 反向获取消息列表,ID 从大到小 |
xgroup createconsumer | XGROUP CREATECONSUMER key groupname consumername | 创建消费者 |
xgroup create | XGROUP CREATE key groupname id|$ [MKSTREAM] [ENTRIESREAD entries_read] | 创建消费者组 |
xgroup setid | XGROUP SETID key groupname id|$ [ENTRIESREAD entries_read] | 为消费者组设置新的最后递送消息ID |
xgroup delconsumer | XGROUP DELCONSUMER key groupname consumername | 删除消费者 |
xgroup destroy | XGROUP DESTROY key groupname | 删除消费者组 |
xreadgroup group | XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key …] id [id …] | 读取消费者组中的消息 |
xack | XACK key group id [id …] | 将消息标记为"已处理" |
xpending | XPENDING key group [[IDLE min-idle-time] start end count [consumer]] | 显示待处理消息的相关信息 |
xclaim | XCLAIM key group consumer min-idle-time id [id …] [IDLE ms] [TIME unix-time-milliseconds] [RETRYCOUNT count] [FORCE] [JUST | 转移消息的归属权 |
xinfo consumer | XINFO CONSUMERS key groupname | 打印消费者信息 |
xinfo group | XINFO GROUPS key | 打印消费者组的信息 |
xinfo stream | XINFO STREAM key [FULL [COUNT count]] | 打印流信息 |
8、GEO
Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作,该功能在 Redis 3.2 版本新增.
经度(longitude)、纬度(latitude)、位置名称(member)
m :米,默认单位。 km :千米。 mi :英里。 ft :英尺。
WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。
WITHCOORD: 将位置元素的经度和纬度也一并返回。
WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
COUNT 限定返回的记录数。 ASC: 查找结果根据距离从近到远排序。 DESC: 查找结果根据从远到近排序。
命令 | 事例 | 说明 |
---|---|---|
geoadd | GEOADD key longitude latitude member [longitude latitude member …] | 添加地理位置的坐标。 |
geopos | GEOPOS key member [member …] | 获取地理位置的坐标。 |
geodist | GEODIST key member1 member2 [m|km|ft|mi] | 计算两个位置之间的距离。 |
georadius | GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key] | 根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。 |
georadiusbymember | GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key] | 根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合。 |
geohash | GEOHASH key member [member …] | 返回一个或多个位置对象的 geohash 值。 |
9、Transaction事务
命令 | 说明 |
---|---|
MULTI | 标记一个事务块的开始。 事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性(atomic)地执行。 |
EXEC | 执行所有事务块内的命令 假如某个(或某些) key 正处于 WATCH 命令的监视之下,且事务块中有和这个(或这些) key 相关的命令,那么 EXEC 命令只在这个(或这些) key 没有被其他命令所改动的情况下执行并生效,否则该事务被打断(abort) |
DISCARD | 取消事务,放弃执行事务块内的所有命令 如果正在使用 WATCH 命令监视某个(或某些) key,那么取消所有监视,等同于执行命令 UNWATCH 。 |
WATCH | 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。 |
UNWATCH | 取消 WATCH 命令对所有 key 的监视。 如果在执行 WATCH 命令之后, EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行 UNWATCH 了。 因为 EXEC 命令会执行事务,因此 WATCH 命令的效果已经产生了;而 DISCARD 命令在取消事务的同时也会取消所有对 key 的监视,因此这两个命令执行之后,就没有必要执行 UNWATCH 了。 |
10、通用命令
命令 | 事例 | 说明 |
---|---|---|
KEYS | KEYS pattern | 查找所有符合给定模式 pattern 的 key *表示多个通配符 ?表示一个通配符 |
EXISTS | EXISTS key | 检查给定 key 是否存在。 |
PTTL | PTTL key | 这个命令类似于 TTL 命令,但它以毫秒为单位返回 key 的剩余生存时间,而不是像 TTL 命令那样,以秒为单位。 |
TTL | TTL key | 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。 当 key 不存在时,返回 -2 。 当 key 存在但没有设置剩余生存时间时,返回 -1 。 否则,以秒为单位,返回 key 的剩余生存时间 |
TYPE | TYPE key | 返回 key 所储存的值的类型。 |
DEL | DEL key [key …] | 删除给定的一个或多个 key 。不存在的 key 会被忽略。 |
PEXPIRE | PEXPIRE key milliseconds | 这个命令和 EXPIRE 命令的作用类似,但是它以毫秒为单位设置 key 的生存时间,而不像 EXPIRE 命令那样,以秒为单位。 |
EXPIRE | EXPIRE key seconds | 为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。 |
PEXPIREAT | PEXPIREAT key milliseconds-timestamp | 这个命令和 EXPIREAT 命令类似,但它以毫秒为单位设置 key 的过期 unix 时间戳,而不是像 EXPIREAT 那样,以秒为单位 |
EXPIREAT | EXPIREAT key timestamp | EXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置生存时间。 不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。 |
PERSIST | PERSIST key | 移除给定 key 的生存时间,将这个 key 从『易失的』(带生存时间 key )转换成『持久的』(一个不带生存时间、永不过期的 key )。 |
SORT | SORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern …]] [ASC | DESC] [ALPHA] [STORE destination] | 返回或保存给定列表、集合、有序集合 key 中经过排序的元素 |
RENAME | RENAME key newkey | 将 key 改名为 newkey 。 |
RENAMENX | RENAMENX key newkey | 当且仅当 newkey 不存在时,将 key 改名为 newkey 。 |
SCAN | SCAN cursor [MATCH pattern] [COUNT count] | 基于游标的迭代器(cursor based iterator): SCAN 命令每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。 当 SCAN 命令的游标参数被设置为 0 时, 服务器将开始一次新的迭代, 而当服务器向用户返回值为 0 的游标时, 表示迭代已结束 |
DUMP | DUMP key | 序列化给定 key ,并返回被序列化的值,使用 RESTORE 命令可以将这个值反序列化为 Redis 键。 |
RESTORE | RESTORE key ttl serialized-value | 反序列化给定的序列化值,并将它和给定的 key 关联。 |
OBJECT | OBJECT subcommand [arguments [arguments]] | OBJECT 命令允许从内部察看给定 key 的 Redis 对象 OBJECT REFCOUNT 返回给定 key 引用所储存的值的次数。此命令主要用于除错。 OBJECT ENCODING 返回给定 key 锁储存的值所使用的内部表示(representation)。 OBJECT IDLETIME 返回给定 key 自储存以来的空转时间(idle, 没有被读取也没有被写入),以秒为单位。 |
MOVE | MOVE key db | 将当前数据库的 key 移动到给定的数据库 db 当中 |
MIGRATE | MIGRATE host port key destination-db timeout [COPY] [REPLACE] | 将 key 原子性地从当前实例传送到目标实例的指定数据库上,一旦传送成功, key 保证会出现在目标实例上,而当前实例上的 key 会被删除 |
RANDOMKEY | RANDOMKEY | 从当前数据库中随机返回(不删除)一个 key 。 |
2、服务与集群
1、数据备份
Redis 是一个内存数据库,为了保证数据的持久性,它提供了三种持久化方案:
RDB 方式(默认)
AOF 方式
混合持久化模式(4.0增加,5.0默认开启-当开启AOF时候,它也开启了)它是AOF的一个补充
# save "" 不使用RDB存储
# save 3600 1 表示15分钟(900秒钟)内至少1个键被更改则进行快照
# save 300 100 表示5分钟(300秒)内至少10个键被更改则进行快照
# save 60 10000 表示1分钟内至少10000个键被更改则进行快照
# appendonly yes 开启 AOF
# appendfilename "appendonly.aof" 文件存储名称
# AOP同步频率
# appendfsync always 每次执行写入都会进行同步, 这个是最安全但是是效率比较低的方式
# appendfsync everysec 每一秒执行(默认)
# appendfsync no 不主动进行同步操作,由操作系统去执行,这个是最快但是最不安全的方式
#aof-use-rdb-preamble yes 开启混合持久化
# replicaof <masterip> <masterport>
1、RDB模式
RDB 是 Redis 默认采用的持久化方式。通过快照( snapshotting )的方式完成,当符合一定条件时 Redis 会自动将内存中的数据进行
快照并持久化到硬盘。
触发时机 | 操作 |
---|---|
符合指定配置的快照规则 | redis.conf配置save规则 |
执行save或bgsave命令 save主线程去快照 bgsave 调用异步线程去快照 | save/bgsave |
执行flushall 或flushdb | flushdb/flushall |
执行主从复制操作 |
2、AOF
默认情况下 Redis 没有开启 AOF ( append only file )方式的持久化。
开启 AOF 持久化后,每执行一条会更改 Redis 中的数据的命令, Redis 就会将该命令写入硬盘中的 AOF 文件
3、混合持久化方式
RDB 可能会导致一定时间内的数据丢失,而 AOF 由于文件较大则会影响Redis 的启动速度,为了能同时拥有 RDB 和 AOF 的优点,Redis 4.0 之后新增了混合持久化的方式,因此我们在必须要进行持久化操作时,应该选择混合持久化的方式
查看是否开启:config get aof-use-rdb-preamble
2、集群
1、主从
master不需要特殊配置
slave需要修改redis.conf配置文件 # replicaof
2、哨兵
3、集群
/**集群配置读写分离*/
@Bean
public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){
return new LettuceClientConfigurationBuilderCustomizer() {
@Override //设置读优先读从机
public void customize(LettuceClientConfiguration.LettuceClientConfigurationBuilder clientConfigurationBuilder) {
clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}
};
}
/**这里的ReadFrom是配置Redis的读取策略,是一个枚举,包括下面选择:
MASTER:从主节点读取
MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica
REPLICA:从slave(replica)节点读取
REPLICA _PREFERRED:优先从slave(replica)节点读取,所有的slave都不可用才读取master*/
3、Java
引入jar:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.2.0</version>
</dependency>
1、Jedis
@Test
void testJedis(){
Jedis jedis = new Jedis("localhost",16379);
Set<String> keys = jedis.keys("*");
keys.stream().forEach(System.out::println);
}
2、JedisPool
@Test
void testJedisPool(){
JedisPool jedisPool = new JedisPool("localhost",16379);
Jedis resource = jedisPool.getResource();
String name = resource.get("name");
System.out.println(name);
}
3、SpringBoot
spring: #单机连接配置
redis:
host: localhost
port: 6379
password: root
lettuce:
pool:
max-active: 200 #连接池最大连接数(使用负值表示没有限制)
max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 #连接池中的最大空闲连接
min-idle: 0 #连接池中的最小空闲连接
timeout: 1000 #连接超时毫秒数
--- #集群连接配置
spring:
redis:
password: root
cluster:
nodes: 192.168.0.203:7000,192.168.0.203:7001,192.168.0.203:7002 #节点
max-redirects: 3 #在集群中执行命令时要遵循的最大重定向数。
lettuce:
pool:
max-idle: 16
max-active: 32
min-idle: 8
max-wait: -1
@Configuration
public class RedisConfig{
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
//设置redis连接工厂
template.setConnectionFactory(factory);
//序列化实例方式
GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
RedisSerializer<String> stringRedisSerializer = RedisSerializer.string();
//Key使用String序列化
template.setKeySerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
// 值采用json序列化
template.setValueSerializer(jsonRedisSerializer);
template.setHashValueSerializer(jsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
使用:
@Autowired
private RedisTemplate redisTemplate;
private ValueOperations<String, String> valueOperations;
private HashOperations hashOperations;
private ListOperations listOperations;
private SetOperations setOperations;
private ZSetOperations zSetOperations;
private HyperLogLogOperations hyperLogLogOperations;
private GeoOperations geoOperations;
private StreamOperations streamOperations;
@BeforeEach
public void init() {
valueOperations = redisTemplate.opsForValue(); // String操作
hashOperations = redisTemplate.opsForHash();// hash操作
listOperations = redisTemplate.opsForList();// list操作
setOperations = redisTemplate.opsForSet();// set操作
zSetOperations = redisTemplate.opsForZSet();// zset操作
hyperLogLogOperations = redisTemplate.opsForHyperLogLog();// hyperlog操作
geoOperations = redisTemplate.opsForGeo();//geo操作
streamOperations = redisTemplate.opsForStream();//消息队列操作
}
4、配合spring的缓存使用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>2.7.14</version>
</dependency>
cache:
type: redis #缓存类型
redis:
time-to-live: 100 #缓存存活时间 ms
cache-null-values: true #是否缓存空值
java代码中通过 @EnableCaching激活 通过注解使用具体缓存方式
1、@Cacheable:在方法执行前查看是否有缓存对应的数据,如果有直接返回数据,如果没有调用方法获取数据返回,并缓存起来。
2、@CacheEvict:将一条或多条数据从缓存中删除。
3、@CachePut:将方法的返回值放到缓存中
4、@EnableCaching:开启缓存注解功能
5、@Caching:组合多个缓存注解;
6、@CacheConfig:统一配置@Cacheable中的value值
4、缓存相关
1、缓存击穿
问题:缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击
方案:1、互斥锁 当同个业务不同线程访问redis未命中时,先获取一把互斥锁,然后进行数据库操作,此时另外一个线程未命中时,拿不到锁,等待一段时间后重新查询缓存,此时之前的线程已经重新把数据加载到redis之中了,线程二就直接缓存命中。这样就不会使得大量访问进入数据库。
优点:没有额外的内存消耗,保证一致性,实现简单 缺点:线程需要等待,性能受影响,可能有死锁风险
2、逻辑过期 将热点数据设置永不过期,同时给有效数据增加一个逻辑过期时间。当这个时间过期时,缓存里面的数据是不会消失的,但是我们只需要根据这个假设的过期时间。来进行经常的动态的缓存数据的更新。可以对缓存击穿起一定的预防作用。
优点:线程无需等待,性能较好 缺点:不保证一致性,有额外内存消耗,实现复杂
2、缓存穿透
问题:缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。
方案:1、给不同的Key的TTL,添加随机值
2、利用Redis集群提高服务的可用性
3、给缓存业务添加降级限流策略
4、给业务添加多级缓存
3、缓存雪崩
问题:缓存穿透是指用户请求的数据在缓存中和数据库中都不存在,不断发起这样的请求,给数据库带来巨大压力
方案:1、缓存null值
2、布隆过滤 布隆过滤器是由一个固定大小的二进制向量或者位图(bitmap)和一系列映射函数组成的。在初始状态时,对于长 度为 m 的位数组,它的所有位都被置为0。当有变量被加入集合时,通过映射函数将这个变量映射成位图中的某个点,把它们置为 1。如果值为 0,则被查询变量一定不在;如果值是 1,则被查询变量很可能存在。为什么说是可能存在,而不是一定存在呢?那是因为映射函数本身就是散列函数,散列函数是会有碰撞的。 三种方式实现: 1、使用redis String bitmap 自己处理 2、google的Guava工具类BloomFilter 3、Redisson的工具类RBloomFilter
3、增强id的复杂度,避免被猜测id规律
4、做好数据的基础格式校验
5、加强用户权限校验
6、做好热点参数的限流
4、唯一ID
全局唯一Id的特性: 安全性、唯一性、高可用、 高性能 、可读性
常用方法:1、UUID java.util下的UUID.randomUUID().toString() 缺点:不可读,传输数据量大 ,没有排序,无法保证趋势递增,存储空间大,查询效率低
2、Redis自增 INCR 使用时间戳作为Key,(可以进行位运算设定多少位 常设置32位 和|运算)数据库自增,唯一Id也可以这么处理
public long uniqueId(String keyPrefix){
// 1.生成时间戳
LocalDateTime now = LocalDateTime.now();
long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
long timestamp = nowSecond - DateTimeConstant.BEGIN_TIMESTAMP_S;
// 2.生成序列号
// 2.1.获取当前日期,精确到天
String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
// 2.2.自增长
long count = redisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);
// 3.拼接并返回
return timestamp << CommonConstant.BIT_COUNT | count;
}
3、数据库自增 数据库自增长序列或字段
4、Twitter公司的雪花算法snowflake 可以使用hutool工具去直接使用
雪花算法原理就是生成一个的64位比特位的 long 类型的唯一 id。
-
最高1位固定值0,因为生成的 id 是正整数,如果是1就是负数了。
-
接下来41位存储毫秒级时间戳,2^41/(1000606024365)=69,大概可以使用69年。
-
再接下10位存储机器码,包括5位 datacenterId 和5位 workerId。最多可以部署2^10=1024台机器。
-
最后12位存储序列号。同一毫秒时间戳时,通过这个递增的序列号来区分。即对于同一台机器而言,同一毫秒时间戳下,可以生成2^12=4096个不重复 id。
可以将雪花算法作为一个单独的服务进行部署,然后需要全局唯一 id 的系统,请求雪花算法服务获取 id 即可
5、利用zookeeper生成唯一ID
zookeeper主要通过其znode数据版本来生成序列号,可以生成32位和64位的数据版本号,客户端可以使用这个版本号来作为唯一的序列号 。很少会使用zookeeper来生成唯一ID。主要是由于需要依赖zookeeper,并且是多步调用API,如果在竞争较大的情况下,需要考虑使用分布式锁。因此,性能在高并发的分布式环境下,也不甚理想。
5、分布式锁
分布式锁,即分布式系统中的锁。在单体应用中我们通过锁解决的是控制共享资源访问的问题,而分布式锁,就是解决了分布式系统中控制共享资源访问的问题。与单体应用不同的是,分布式系统中竞争共享资源的最小粒度从线程升级成了进程
特性:
-
在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行
-
高可用的获取锁与释放锁
-
高性能的获取锁与释放锁
-
具备可重入特性(可理解为重新进入,由多于一个任务并发使用,而不必担心数据错误)
-
具备锁失效机制,即自动解锁,防止死锁
-
具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败
实现方式:1、数据库排他锁
2、redis setnx 最简单的实现方式
/**redis获取锁*/ public boolean tryLock(String keyPrefix){ Boolean success = redisTemplate.opsForValue().setIfAbsent(keyPrefix + ":lock", 1, 10, TimeUnit.MINUTES); return Boolean.TRUE.equals(success); } /**redis释放锁*/ public void unlock(String keyPrefix){ redisTemplate.delete(keyPrefix + ":lock"); }
3、zookeeper 核心思想:当客户端要获取锁,则创建节点,使用完锁,则删除该节点。
1、客户端获取锁时,在lock节点下创建临时顺序节点。然后获取lock下面的所有子节点,客户端获取到所有的子节点之后,如果发现自己创建的子节点序号最小,那么就认为该客户端获取到了锁。
2、使用完锁后,将该节点删除。如果发现自己创建的节点并非lock所有子节点中最小的,说明自己还没有获取到锁,此时客户端需要找到比自己小的那个节点,同时对其注册事件监听器,监听删除事件。
3、如果发现比自己小的那个节点被删除,则客户端的 Watcher会收到相应通知,此时再次判断自己创建的节点 是否是lock子节点中序号最小的,如果是则获取到了锁, 如果不是则重复以上步骤继续获取到比自己小的一个节点 并注册监听。
6、redisson
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.15.6</version>
</dependency>
spring: #单机连接配置
redis:
host: localhost
port: 6379
password: root
redisson:
file: classpath:redisson.yml
lettuce:
pool:
max-active: 200 #连接池最大连接数(使用负值表示没有限制)
max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 #连接池中的最大空闲连接
min-idle: 0 #连接池中的最小空闲连接
timeout: 1000 #连接超时毫秒数
# 单节点配置
singleServerConfig:
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 连接超时,单位:毫秒
connectTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 命令失败重试次数,如果尝试达到 retryAttempts(命令失败重试次数) 仍然不能将命令发送至某个指定的节点时,将抛出错误。
# 如果尝试在此限制之内发送成功,则开始启用 timeout(命令等待超时) 计时。
retryAttempts: 3
# 命令重试发送时间间隔,单位:毫秒
retryInterval: 1500
# 密码
#password: redis.shbeta
# 单个连接最大订阅数量
subscriptionsPerConnection: 5
# 客户端名称
#clientName: axin
# # 节点地址
address: redis://127.0.0.1:6379
# 发布和订阅连接的最小空闲连接数
subscriptionConnectionMinimumIdleSize: 1
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
# 最小空闲连接数
connectionMinimumIdleSize: 32
# 连接池大小
connectionPoolSize: 64
# 数据库编号
database: 6
# DNS监测时间间隔,单位:毫秒
dnsMonitoringInterval: 5000
# 线程池数量,默认值: 当前处理核数量 * 2
#threads: 0
# Netty线程池数量,默认值: 当前处理核数量 * 2
#nettyThreads: 0
# 编码
codec: !<org.redisson.codec.JsonJacksonCodec> {}
# 传输模式
transportMode : "NIO"
#集群配置
clusterServersConfig:
idleConnectionTimeout: 10000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
failedSlaveReconnectionInterval: 3000
failedSlaveCheckInterval: 60000
password: null
subscriptionsPerConnection: 5
clientName: null
loadBalancer: !<org.redisson.connection.balancer.RoundRobinLoadBalancer> {}
subscriptionConnectionMinimumIdleSize: 1
subscriptionConnectionPoolSize: 50
slaveConnectionMinimumIdleSize: 24
slaveConnectionPoolSize: 64
masterConnectionMinimumIdleSize: 24
masterConnectionPoolSize: 64
readMode: "SLAVE"
subscriptionMode: "SLAVE"
nodeAddresses:
- "redis://127.0.0.1:7004"
- "redis://127.0.0.1:7001"
- "redis://127.0.0.1:7000"
scanInterval: 1000
pingConnectionInterval: 0
keepAlive: false
tcpNoDelay: false
threads: 16
nettyThreads: 32
codec: !<org.redisson.codec.MarshallingCodec> {}
transportMode: "NIO"
具体使用参考juc的lock (ReentrantLock,ReentrantReadWriteLock,CountDownLantchd等)
@Autowired
private RedissonClient redissonClient;
public void test() {
RLock lock = redissonClient.getLock("lock");
RReadWriteLock rwlock = redissonClient.getReadWriteLock("rwlock");
RCountDownLatch countdown = redissonClient.getCountDownLatch("countdown");
while (lock.tryLock()) {
break;
}
lock.unlock();
RLock rLock = rwlock.readLock();
RLock rLock1 = rwlock.writeLock();
}
7、秒杀系统
参考:https://zhuanlan.zhihu.com/p/554190807
![img](https://pics2.baidu.com/feed/a71ea8d3fd1f4134bf94f4acf28564c1d3c85ee3.jpeg@f_auto?token=a2116ce9372d3bcd6e7510af1f000280)
核心要求
高性能 | 秒杀涉及大量的并发读和并发写,因此秒系统必须能支持高并发访问,而且RT(响应时间)需要在一定的范围内,通常是200ms |
---|---|
一致性 | 秒杀系统中通常会使用缓存,如何保证缓存和数据库中库存数据的一致性,保证商品库存的准确性 |
高可用 | 秒杀系统会在瞬间收到大量的读写操作,如何能保证服务能稳定的运行,设计系统时是否考虑到系统容灾问题,保证服务的高可用 |
可扩展性 | 当服务达到瓶颈时,如何能实现快速扩容 |
解决方案:
前端优化:
1、动静分离 静态数据的存储在服务端 动态数据后台交互
2、动态数据进行队列交互,不要一次性压到后台
后端优化:核心 异步解耦 削峰填谷
1、缓存redis
2、MQ
3、分布式
4、单独拉出集群进行业务秒杀
5、分布式锁
6、docker部署
8、达人探店
zset
9、好友关注
set