Redis

Redis

1、常用命令梳理

1、String 字符串

命令事例说明
SETSET key value [EX seconds] [PX milliseconds] [NX|XX]将字符串值 value 关联到 key
GETGET key返回 key 所关联的字符串值
MSETMSET key value [key value …]同时设置一个或多个 key-value 对。
MGETMGET key [key …]返回所有(一个或多个)给定 key 的值。
GETSETGETSET key value将给定 key 的值设为 value ,并返回 key 的旧值(old value)。
STRLENSTRLEN key返回 key 所储存的字符串值的长度。
INCRNCR key将 key 中储存的数字值增一。 唯一Id
DECRDECR key将 key 中储存的数字值减一。
INCRBYINCRBY key increment将 key 所储存的值加上增量 increment 。
DECRBYDECRBY key decrement将 key 所储存的值减去减量 decrement 。
INCRBYFLOATINCRBYFLOAT key increment为 key 中所储存的值加上浮点数增量 increment
GETRANGEGETRANGE key start end返回 key 中字符串值的子字符串,字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)。
SETRANGESETRANGE key offset value用 value 参数覆写(overwrite)给定 key 所储存的字符串值,从偏移量 offset 开始。
SETNXSETNX key value将 key 的值设为 value ,当且仅当 key 不存在。 若给定的 key 已经存在,则 SETNX 不做任何动作 NX分布式锁的处理方式
MSETNXMSETNX key value [key value …]同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。 即使只有一个给定 key 已存在, MSETNX 也会拒绝执行所有给定 key 的设置操作
PSETEXPSETEX key milliseconds value以毫秒为单位设置 key 的生存时间
SETEXSETEX key seconds value将值 value 关联到 key ,并将 key 的生存时间设为 seconds (以秒为单位)。
APPENDAPPEND key value将 value 追加到 key 原来的值的末尾。

String中bit的操作

Redis中字符串的存储方式都是以二进制的方式存储的。BIT命令就是对这个二进制数据进行操作的。

命令事例说明
SETBITSETBIT key offset value对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
GETBITGETBIT key offset对 key 所储存的字符串值,获取指定偏移量上的位(bit)。
BITCOUNTBITCOUNT key [start] [end]计算给定字符串中,被设置为 1 的比特位的数量
BITOPBITOP operation destkey key [key …]对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上
bitpopsBITPOS 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 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。

命令事例说明
PFADDPFADD key element [element …]添加指定元素到 HyperLogLog 中。
PFCOUNTPFCOUNT key [key …]返回给定 HyperLogLog 的基数估算值。
PFMERGEPFMERGE destkey sourcekey [sourcekey …]将多个 HyperLogLog 合并为一个 HyperLogLog

2、Hash散列

命令事例说明
HSETHSET key field value将哈希表 key 中的域 field 的值设为 value 。
HGETHGET key field返回哈希表 key 中给定域 field 的值。
HGETALLHGETALL key返回哈希表 key 中,所有的域和值。
HMSETHMSET key field value [field value …]同时将多个 field-value (域-值)对设置到哈希表 key 中。
HMGETHMGET key field [field …]返回哈希表 key 中,一个或多个给定域的值。
HSETNXHSETNX key field value将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在
HKEYSHKEYS key返回哈希表 key 中的所有域
HVALSHVALS key返回哈希表 key 中所有域的值。
HLENHLEN key返回哈希表 key 中域的数量。
HDELHDEL key field [field …]删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。
HEXISTSHEXISTS key field查看哈希表 key 中,给定域 field 是否存在
HINCRBYHINCRBY key field increment哈希表 key 中的域 field 的值加上增量 increment 。
HINCRBYFLOATHINCRBYFLOAT key field increment为哈希表 key 中的域 field 加上浮点数增量 increment 。

3、List列表

命令事例说明
LPUSHLPUSH key value [value …]将一个或多个值 value 插入到列表 key 的表头, 存储顺序为 左读:v3,v2,v1
LPUSHXLPUSHX key value [value …]当key已经有元素时才会进行插入,如果key时空集合则不进行插入 左插入
RPUSHRPUSH key value [value …]将一个或多个值 value 插入到列表 key 的表尾(最右边) 存储顺序 左读:v1 v2 v3
RPUSHXRPUSHX key value当key已经有元素时才会进行插入,如果key时空集合则不进行插入 右插入
LINSERTLINSERT key BEFORE|AFTER pivot value将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。
LSETLSET key index value将列表 key 下标为 index 的元素的值设置为 value 。
LLENLLEN key返回列表 key 的长度。
LINDEXLINDEX key index返回列表 key 中,下标为 index 的元素
LRANGELRANGE key start stop返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定
LPOPLPOP key COUNT移除并返回列表 key 的头元素。 count 不填则删除并返回第一个元素
RPOPRPOP key移除并返回列表 key 的尾元素
LTRIMLTRIM key start stop对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除
LREMLREM key count value根据参数 count 的值,移除列表中与参数 value 相等的元素。 count表示删除的个数,如果count大于总数,删除全部
BLPOPBLPOP key [key …] timeoutBLPOP 是列表的阻塞式(blocking)弹出原语。是 LPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BLPOP 命令阻塞,直到等待超时或发现可弹出元素为止。 当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。
BRPOPBRPOP key [key …] timeoutBRPOP 是列表的阻塞式(blocking)弹出原语
RPOPLPUSHRPOPLPUSH source destination将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。 将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。
BRPOPLPUSHBRPOPLPUSH source destination timeoutBRPOPLPUSH 是 RPOPLPUSH 的阻塞版本,当给定列表 source 不为空时, BRPOPLPUSH 的表现和 RPOPLPUSH 一样。

4、Set集合

命令事例说明
SADDSADD key member [member …]将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
SPOPSPOP key [count]移除并返回集合中的count个随机元素
SRANDMEMBERSRANDMEMBER key [count]如果命令执行时,只提供了 key 参数,那么返回集合中的一个随机元素。 不删除 如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合。 如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值
SCARDSCARD key返回集合 key 的基数(集合中元素的数量)。
SMEMBERSSMEMBERS key返回集合 key 中的所有成员。
SISMEMBERSISMEMBER key member判断 member 元素是否集合 key 的成员 1=y 0 =n
SMOVESMOVE source destination member将 member 元素从 source 集合移动到 destination 集合
SREMSREM key member [member …]移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。
SINTERSINTER key [key …]返回一个集合的全部成员,该集合是所有给定集合的交集。不存在的 key 被视为空集
SINTERSTORESINTERSTORE destination key [key …]这个命令类似于 SINTER 命令,但它将结果保存到 destination 集合,而不是简单地返回结果集,如果 destination 集合已经存在,则将其覆盖
SDIFFSDIFF key [key …]返回一个集合的全部成员,该集合是所有给定集合之间的差集。前面的集合比对后面的系列集合
SDIFFSTORESDIFFSTORE destination key [key …]这个命令的作用和 SDIFF 类似,但它将结果保存到 destination 集合,而不是简单地返回结果集。如果 destination 集合已经存在,则将其覆盖
SUNIONSUNION key [key …]返回一个集合的全部成员,该集合是所有给定集合的并集。
SUNIONSTORESUNIONSTORE destination key [key …]这个命令类似于 SUNION 命令,但它将结果保存到 destination 集合,而不是简单地返回结果集。

5、Zset有序集合

命令事例说明
ZADDZADD key score member [[score member] [score member] …]将一个或多个 member 元素及其 score 值加入到有序集 key 当中
ZINCRBYZINCRBY key increment member为有序集 key 的成员 member 的 score 值加上增量 increment 。
ZCARDZCARD key返回有序集 key 的基数。
ZSCOREZSCORE key member返回有序集 key 中,成员 member 的 score 值。
ZRANGEZRANGE key start stop [WITHSCORES]返回有序集 key 中,指定区间内的成员。
ZRANGEBYSCOREZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。
ZREVRANGEBYSCOREZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]返回有序集 key 中, score 值介于 max 和 min 之间(默认包括等于 max 或 min )的所有的成员。有序集成员按 score 值递减(从大到小)的次序排列。
ZREVRANGEZREVRANGE key start stop [WITHSCORES]返回有序集 key 中,指定区间内的成员。
ZCOUNTZCOUNT key min max返回有序集 key 中, score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量。
ZRANKZRANK key member返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列。 小到大
ZREVRANKZREVRANK key member返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递减(从大到小)排序。 大到小
ZUNIONSTOREZUNIONSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX]计算给定的一个或多个有序集的并集,其中给定 key 的数量必须以 numkeys 参数指定,并将该并集(结果集)储存到 destination 。
ZINTERSTOREZINTERSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX]计算给定的一个或多个有序集的交集,其中给定 key 的数量必须以 numkeys 参数指定,并将该交集(结果集)储存到 destination 。
ZREMZREM key member [member …]移除有序集 key 中的一个或多个成员,不存在的成员将被忽略。
ZREMRANGEBYRANKZREMRANGEBYRANK key start stop移除有序集 key 中,指定排名(rank)区间内的所有成员。
ZREMRANGEBYSCOREZREMRANGEBYSCORE 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发布订阅

命令事例说明
PUBLISHPUBLISH channel message将信息 message 发送到指定的频道 channel 。
SUBSCRIBESUBSCRIBE channel [channel …]订阅给定的一个或多个频道的信息。 精确匹配
PSUBSCRIBEPSUBSCRIBE pattern [pattern …]订阅一个或多个符合给定模式的频道。 模糊匹配*
UNSUBSCRIBEUNSUBSCRIBE [channel [channel …]]指示客户端退订给定的频道。 精确退订 如果没有频道被指定,也即是,一个无参数的 UNSUBSCRIBE 调用被执行,那么客户端使用 SUBSCRIBE 命令订阅的所有频道都会被退订。在这种情况下,命令会返回一个信息,告知客户端所有被退订的频道。
PUNSUBSCRIBEPUNSUBSCRIBE [pattern [pattern …]]指示客户端退订所有给定模式。模糊退订 如果没有模式被指定,也即是,一个无参数的 PUNSUBSCRIBE 调用被执行,那么客户端使用 PSUBSCRIBE 命令订阅的所有模式都会被退订。在这种情况下,命令会返回一个信息,告知客户端所有被退订的模式。
PUBSUBPUBSUB [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 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。

命令事例说明
xaddXADD key [NOMKSTREAM] [MAXLEN|MINID [=|~] threshold [LIMIT count]] *|id field value [field value …]添加消息到末尾; * 表示系统生成id NOMKSTREAM如果存在则加入否则不加入
xlenXLEN key获取流包含的元素数量,即消息长度
xrangeXRANGE key start end [COUNT count]获取消息列表,会自动过滤已经删除的消息 -最小 +最大
xtrimXTRIM key MAXLEN|MINID [=|~] threshold [LIMIT count]对流进行修剪,限制长度
xdelXDEL key id [id …]删除消息
xreadXREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key …] id [id …]以阻塞或非阻塞方式获取消息列表
xrevrangeXREVRANGE key end start [COUNT count]反向获取消息列表,ID 从大到小
xgroup createconsumerXGROUP CREATECONSUMER key groupname consumername创建消费者
xgroup createXGROUP CREATE key groupname id|$ [MKSTREAM] [ENTRIESREAD entries_read]创建消费者组
xgroup setidXGROUP SETID key groupname id|$ [ENTRIESREAD entries_read]为消费者组设置新的最后递送消息ID
xgroup delconsumerXGROUP DELCONSUMER key groupname consumername删除消费者
xgroup destroyXGROUP DESTROY key groupname删除消费者组
xreadgroup groupXREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key …] id [id …]读取消费者组中的消息
xackXACK key group id [id …]将消息标记为"已处理"
xpendingXPENDING key group [[IDLE min-idle-time] start end count [consumer]]显示待处理消息的相关信息
xclaimXCLAIM key group consumer min-idle-time id [id …] [IDLE ms] [TIME unix-time-milliseconds] [RETRYCOUNT count] [FORCE] [JUST转移消息的归属权
xinfo consumerXINFO CONSUMERS key groupname打印消费者信息
xinfo groupXINFO GROUPS key打印消费者组的信息
xinfo streamXINFO 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: 查找结果根据从远到近排序。

命令事例说明
geoaddGEOADD key longitude latitude member [longitude latitude member …]添加地理位置的坐标。
geoposGEOPOS key member [member …]获取地理位置的坐标。
geodistGEODIST key member1 member2 [m|km|ft|mi]计算两个位置之间的距离。
georadiusGEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。
georadiusbymemberGEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合。
geohashGEOHASH 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、通用命令

命令事例说明
KEYSKEYS pattern查找所有符合给定模式 pattern 的 key *表示多个通配符 ?表示一个通配符
EXISTSEXISTS key检查给定 key 是否存在。
PTTLPTTL key这个命令类似于 TTL 命令,但它以毫秒为单位返回 key 的剩余生存时间,而不是像 TTL 命令那样,以秒为单位。
TTLTTL key以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。 当 key 不存在时,返回 -2 。 当 key 存在但没有设置剩余生存时间时,返回 -1 。 否则,以秒为单位,返回 key 的剩余生存时间
TYPETYPE key返回 key 所储存的值的类型。
DELDEL key [key …]删除给定的一个或多个 key 。不存在的 key 会被忽略。
PEXPIREPEXPIRE key milliseconds这个命令和 EXPIRE 命令的作用类似,但是它以毫秒为单位设置 key 的生存时间,而不像 EXPIRE 命令那样,以秒为单位。
EXPIREEXPIRE key seconds为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。
PEXPIREATPEXPIREAT key milliseconds-timestamp这个命令和 EXPIREAT 命令类似,但它以毫秒为单位设置 key 的过期 unix 时间戳,而不是像 EXPIREAT 那样,以秒为单位
EXPIREATEXPIREAT key timestampEXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置生存时间。 不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。
PERSISTPERSIST key移除给定 key 的生存时间,将这个 key 从『易失的』(带生存时间 key )转换成『持久的』(一个不带生存时间、永不过期的 key )。
SORTSORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern …]] [ASC | DESC] [ALPHA] [STORE destination]返回或保存给定列表、集合、有序集合 key 中经过排序的元素
RENAMERENAME key newkey将 key 改名为 newkey 。
RENAMENXRENAMENX key newkey当且仅当 newkey 不存在时,将 key 改名为 newkey 。
SCANSCAN cursor [MATCH pattern] [COUNT count]基于游标的迭代器(cursor based iterator): SCAN 命令每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。 当 SCAN 命令的游标参数被设置为 0 时, 服务器将开始一次新的迭代, 而当服务器向用户返回值为 0 的游标时, 表示迭代已结束
DUMPDUMP key序列化给定 key ,并返回被序列化的值,使用 RESTORE 命令可以将这个值反序列化为 Redis 键。
RESTORERESTORE key ttl serialized-value反序列化给定的序列化值,并将它和给定的 key 关联。
OBJECTOBJECT subcommand [arguments [arguments]]OBJECT 命令允许从内部察看给定 key 的 Redis 对象 OBJECT REFCOUNT 返回给定 key 引用所储存的值的次数。此命令主要用于除错。 OBJECT ENCODING 返回给定 key 锁储存的值所使用的内部表示(representation)。 OBJECT IDLETIME 返回给定 key 自储存以来的空转时间(idle, 没有被读取也没有被写入),以秒为单位。
MOVEMOVE key db将当前数据库的 key 移动到给定的数据库 db 当中
MIGRATEMIGRATE host port key destination-db timeout [COPY] [REPLACE]将 key 原子性地从当前实例传送到目标实例的指定数据库上,一旦传送成功, key 保证会出现在目标实例上,而当前实例上的 key 会被删除
RANDOMKEYRANDOMKEY从当前数据库中随机返回(不删除)一个 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 或flushdbflushdb/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工具去直接使用

ae.png

​ 雪花算法原理就是生成一个的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

核心要求

高性能秒杀涉及大量的并发读和并发写,因此秒系统必须能支持高并发访问,而且RT(响应时间)需要在一定的范围内,通常是200ms
一致性秒杀系统中通常会使用缓存,如何保证缓存和数据库中库存数据的一致性,保证商品库存的准确性
高可用秒杀系统会在瞬间收到大量的读写操作,如何能保证服务能稳定的运行,设计系统时是否考虑到系统容灾问题,保证服务的高可用
可扩展性当服务达到瓶颈时,如何能实现快速扩容

解决方案:

前端优化:

​ 1、动静分离 静态数据的存储在服务端 动态数据后台交互

​ 2、动态数据进行队列交互,不要一次性压到后台

后端优化:核心 异步解耦 削峰填谷

​ 1、缓存redis

​ 2、MQ

​ 3、分布式

​ 4、单独拉出集群进行业务秒杀

​ 5、分布式锁

​ 6、docker部署

8、达人探店

​ zset

9、好友关注

​ set

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值