Redis数据结构 根据官方文档内容介绍
五种基本数据结构 String, List, Hash, Set, Set
String key和value最大都是512MB,推荐设置成“user:1000”这样有意义的key。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 set <key> <value>set key value nx 如果已经存在,则设置失败,返回nilset key value xx 如果存在,才能设置成功,返回OKset key value ex 10 过期时间 get key expire key 5 设置key的过期时间 ttl key 查看key的time to live(默认单位:秒) del key 删除键 pexpire pttl
1 2 3 4 5 6 7 8 9 10 计数器 > set counter 100 OK > incr counter (integer ) 101 > incr counter (integer ) 102 > incrby counter 50 (integer ) 152
type key
查看key的value是什么类型,如果key不存在返回none
多设置,多获取(避免多次单次设置的网络延迟)
可以一次性获取多个值,一次性设置多个值
List 创建List,左右添加元素 lpush key <元素列表> rpush
阻塞获取元素 lpop,rpop,blpop,brpop
blpop key 5 默认时间是秒 也可以阻塞获取多个key列表的元素 返回的是一个二元组,存在元素的key和key中的value,如果时间到了尚未获取到元素,则返回nil
将source列表中的最左侧或者最右侧移动到dest的末尾,过去是lpoprpush指令 lmove source dest <right|left> <right|left>
Hash hash的结构 key, pair<field,value>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 hset user :1000 username antirez birthyear 1977 verified 1 (integer ) 3 hget user :1000 username "antirez" hget user :1000 birthyear "1977" hgetall user :1000 1 ) "username"2 ) "antirez"3 ) "birthyear"4 ) "1977"5 ) "verified"6 ) "1"
可放入hash的field数量并没有做实际限制,除了物理上可用的内存。
hset,hget,hgetall
hmget
可以获取多个field的值
增加值类型位数值 field 的数值hincrby
Set 基于哈希表实现的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 sadd myset 1 2 3 (integer ) 3 smembers myset 1. 3 2. 1 3. 2 sismember myset 3 (integer ) 1 sismember myset 30 (integer ) 0 sadd news:1000:tags 1 2 5 77 (integer ) 4 smembers news:1000:tags sadd tag:1:news 1000 (integer ) 1 sadd tag:2:news 1000 (integer ) 1 sadd tag:5:news 1000 (integer ) 1 sadd tag:77:news 1000 (integer ) 1 sadd deck C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 CJ CQ CK D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 DJ DQ DK H1 H2 H3 H4 H5 H6 H7 H8 H9 H10 HJ HQ HK S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 SJ SQ SK sunionstore game:1:deck deck scard game:1:deck spop game:1:deck srandmember game:1:deck
Sorted Set ZSet数据结构 有序集合是通过两种数据结构实现的
压缩列表 ziplist ziplist是为了提高存储效率而设计的一种特殊编码的双向链表。它可以存储字符串或者整数,存储整数时是采用整数的二进制而不是字符串形式存储。它能在O(1)的时间复杂度下完成list两端的push和pop操作。但是因为每次操作都需要重新分配ziplist的内存,所以实际复杂度和ziplist的内存使用量相关。
跳跃表 zSkiplist 跳跃表的性能可以保证在查找,删除,添加等操作的时候在对数期望时间内完成,这个性能是可以和平衡树来相比较的,而且在实现方面比平衡树要优雅,这是采用跳跃表的主要原因。跳跃表的复杂度是O(log(n))。
Set中的元素并不是有序的,但是Sorted Set中的每个元素和一个浮点数score相联系,有点像Hash和Set。
排序规则: (1)如果A.score is > B.score,那么 A>B (2)如果A.score is == B.score,那么字典序大的A会A>B
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 zadd <zset_name> score key zadd hackers 1940 "Alan Kay" zadd hackers 1912 "Alan Turing" 1969 "Linus Torvalds" zrange hackers 0 -1 zrange hackers 0 -1 withscores Alan Turing 1912 Claude Shannon 1916 Hedy Lamarr 1916 Alan Kay 1940 Sophie Wilson 1957 Linus Torvalds 1969 zrevrange hackers 0 -1 zrevrange hackers 0 -1 withscores Linus Torvalds 1969 Sophie Wilson 1957 Alan Kay 1940 Hedy Lamarr 1916 Claude Shannon 1916 Alan Turing 1912
范围查询 return all the elements with a score between negative infinity and 1950
1 2 3 4 5 6 > zrangebyscore hackers -inf 1950 1 ) "Alan Turing" 2 ) "Hedy Lamarr" 3 ) "Claude Shannon" 4 ) "Alan Kay" 5 ) "Anita Borg"
范围删除 1 2 zremrangebyscore hackers 1940 1960
获得zset中的元素排序 1 zrank hackers "Anita Borg"
字典排序 1 2 3 4 5 6 7 8 zadd hackers 0 "Alan Kay" 0 "Sophie Wilson" 0 "Richard Stallman" 0 "Anita Borg" 0 "Yukihiro Matsumoto" 0 "Hedy Lamarr" 0 "Claude Shannon" 0 "Linus Torvalds" 0 "Alan Turing" zrange hackers 0 -1 ZRANGEBYLEX key min max [LIMIT offset count]
zrangebylex的样例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 redis> ZADD myzset 0 a 0 b 0 c 0 d 0 e 0 f 0 g (integer ) 7 redis> ZRANGEBYLEX myzset - [c 1) "a" 2) "b" 3) "c" redis> ZRANGEBYLEX myzset - (c 1) "a" 2) "b" redis> ZRANGEBYLEX myzset [aaa (g 1) "b" 2) "c" 3) "d" 4) "e" 5) "f"
BITMAP
缓存穿透 击穿 雪崩 污染 穿透 穿透:redis没有数据,mysql也没有数据
(1)缓存空值 如一个不存在的userID,这个id在缓存和数据库中都不存在,则可以缓存一个空值,下次再查缓存直接返回空值;(防击穿)
(2)布隆过滤器 通过bloom filter算法来存储合法key,得益于算法超高的压缩效率,只需占用极小的空间就能存储大量key值。
击穿 击穿:redis没有数据,mysql有数据
现象 :数据key过期,导致多个对同一个key的查询压力给到服务器侧
解决方案
(1)接口限流与熔断,降级 重要的接口一定要做好限流策略,防止用户恶意刷接口,同时要降级准备,当接口中的某些 服务 不可用时候,进行熔断,失败快速返回机制。
(2)加互斥锁 雪崩 很多数据过期,导致查询压力大量给到服务器侧
(1)分散缓存时间 将缓存时间分散,比如在原有的实效时间上加一个随机数,例如不同key的过期时间,可以设置为10分1秒过期,10分23秒过期。
过期时间分散,对于热点数据,过期时间尽量设置得长一点,冷门数据过期时间可以短一点,这样留足够的时间给redis进行数据持久化和主从同步。
(2)使用缓存集群 使用缓存集群,避免单机宕机造成的缓存雪崩。
污染 指数据只被访问几次,但会长时间驻留在缓存中,消耗缓存空间 需要设置key淘汰策略
(1)分散缓存时间 将缓存时间分散,比如在原有的实效时间上加一个随机数,例如不同key的过期时间,可以设置为10分1秒过期,10分23秒过期。
过期时间分散,对于热点数据,过期时间尽量设置得长一点,冷门数据过期时间可以短一点,这样留足够的时间给redis进行数据持久化和主从同步。
(2)设置过期策略 缓存和数据库数据不一致 4种解决方案https://coolshell.cn/articles/17416.html
常用的是 Cache Aside Pattern
即先修改数据库,再删除缓存;在查询时,将对应的数据设置回redis。
参考 https://redis.io/docs/data-types/tutorial/