redis五大类型
redis 的key 都是string类型的,
所谓的五大类型 string set zset list hash 其实都是value的类型
在这些类型的底层还有更加底层的数据结构,所以redis的存储速度非常快
redis会根据你的value选择最合适的数据结构存储value
例如 set daicheng 666 和set daicheng1 66a
type daicheng 结果 string
type daicheng1 结果 string
incr daicheng 结果 667
incr daicheng1 结果报错
可以看出 daicheng 和 daicheng1都是选择redis五大类型中的 string类型存储
但在底层redis对于 daicheng 的value 先强转为int 发现可以转换 直接使用int整形存储
而daicheng1 先强转为int类型发现无法转换 则是使用简单字符类型embstr存储
所以daicheng 进行自增操作 结果是667 而daicheng1进行自增操作报错
字符串常用操作
SET key value //存入字符串键值对
MSET key value [key value...] //批量存储字符串键值对
SETNX key value //存入一个不存在的字符串键值对
GET key //获取一个字符串键值
MGET key [key...] //批量获取字符串键值
DEL key [key...] //删除一个键
EXPIRE key seconds //设置一个键的过期时间(秒)
原子加减
INCR key //将key中储存的数字值加1
DECR key //将key中储存的数字值减1
INCRBY key increment //将key所储存的值加上increment
DECRBY key decrement //将key所储存的值减去decrement
string 用法场景
1计数器 比如统计 文章的阅读次数 incr 文章id 每次文章被点击自增1次
2分布式系统全局序列号 一次连接生成加一次太浪费性能
直接一次加100 然后把这个数放到系统缓存中,系统缓存从0开始消耗一直到一百,
用完再去redis获取新的
例 : 进入redis incrby id 100 结果100 ,然后拿到系统缓存中,缓存从0开始使用,
每一次加一,直至加到100,然后再到redis中获取一次 redis incrby id 100 结果200,
再次给系统缓存,依次循环,可以在分布式环境下,生成全局使用的自增id
Hash常用操作 key value value里又是key-value
HSET key field value //存储一个哈希表key的键值
HSETNX key field value //存储一个不存在的哈希表key的键值
HMSET key field value [field value...] //在一一个哈希表key中存储多个键值对
HGET key field //获取哈希表key对应的field键值
HMGET key field [field...] //批量获取哈希表key中多个field键值
HDEL key field [field...] //删除哈希表key中的field键值
HLEN key //返回哈希表key中field的数量
HGETALL key //返回哈希表key中所有的键值
HINCRBY key field increment //为哈希表key中field键的值加上增量increment
hash 使用场景
可以灵活的改变对象中的属性
例 一个user对象 属性 id=1 name=dc age=18
存一个 hset key value[key value]
hset user 1:name dc
hset user 1:age 18
存多个
hmset user id:name id:age
hmset user 1:name dc 1:age 18
取一个
hget user 1:name 得到结果 dc
hget user 1:age 得到结果 18
取多个
hmget user 1:name 1:age 得到结果 dc 18
单独对年龄自增
hincrby key 1:age 100 得到结果 118
List常用操作
LPUSH key value [value...] //将一个或多个值value插入到key列表的表头(最左边)
RPUSH key value [value...] //将一个或多个值value插入到key列表的表尾(最右边)
LPOP key //移除并返回key列表的头元素
RPOP key //移除并返回key列表的尾元素
LRANGE key start stop //返回列表key中指定区间内的元素,区间以偏移量start和stop指定
BLPOP key [key...] timeout //从key列表表头弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,一直阻塞等待
BRPOP key [key...] timeout //从key列表表尾弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,一直阻塞等待
常用数据结构(分布式环境下)
Stack(栈) = LPUSH + LPOP = FILO(first in last out 先进后出)
Queue(队列) = LPUSH + RPOP = FIFO(first in first out 先进先出)
Blocking MQ(阻塞队列) = LPUSH + BRPOP 去取元素时队列里没有元素 会一直阻塞着,直到元素被放入队列 (相当于监听)
lpush 左边插入 lpop 左边取出
rpush 右边插入 rpop 右边取出
取出所有元素 lrange key 0 -1
pipline 管道 一次性可以执行N条命令 建议不超过1000条
Set常用操作
SADD key member [member...] //往集合key中存入元素,元素存在则忽略,若key不存在则新建
SREM key member [member...] //从集合key中删除元素
SMEMBERS key //获取集合key中所有元素
SCARD key //获取集合key的元素个数
SISMEMBER key member //判断member元素是否存在于集合key中
SRANDMEMBER key [count] //从集合key中选出count个元素,元素不从key中删除
SPOP key [count] //从集合key中选出count个元素,元素从key中删除
Set运算操作
SINTER key [key...] //交集运算
SINTERSTORE destination key [key...] //将交集结果存入新集合destination中
SUNION key [key...] //并集运算
SUNIONSTORE destination key [key...] //将并集结果存入新集合destination中
SDIFF key [key...] //差集运算
SDIFFSTORE destination key [key...] //将差集结果存入新集合destination中
使用场景
微信抽奖小程序
1)点击参与抽奖加入集合
SADD key {userlD}
2)查看参与抽奖所有用户
SMEMBERS key
3)抽取count名 中奖者
SRANDMEMBER key [count] 不从key中删除
或者 SPOP key [count] 从key中删除
微信微博点赞,收藏,标签
1)点赞
SADD like:{消息ID} {用户ID} 把id加入集合中
2)取消点赞
SREM like:{消息ID} {用户ID} 把id从集合中删除
3)检查用户是否点过赞
SISMEMBER like:{消息ID} {用户ID} 点赞的红心是否高亮
4)获取点赞的用户列表
SMEMBERS like:{消息ID}
5)获取点赞用户数
SCARD like:{消息ID}
集合操作实现微博微信关注模型
1)诸葛老师关注的人:
zhugeSet-> {zhuangzhou, xushu}
2)楼兰老师关注的人:
loulanSet--> {zhuge, baiqi, zhuangzhou, xushu}
3)庄周老师关注的人:
zhuangzhouSet-> {zhuge, loulan, baiqi, xushu, xunyu)
4)我和楼兰老师共同关注:
SINTER zhugeSet loulanSet--> {zhuangzhou, xushu}
5)我关注的人也关注他(楼兰老师):
SISMEMBER zhuangzhouSet loulan
SISMEMBER xushuSet loulan
6)我可能认识的人:
SDIFF loulanSet zhugeSet- > (zhuge, baiqij
ZSet常用操作
ZADD key score member [score member...] //往有序集合key中加入 带分值元素
ZREM key member [member...] //从有序集合key中删除元素
ZSCORE key member //返回有序集合key中元素member的分值
ZINCRBY key increment member //为有序集合key中元素member的分值加上increment
ZCARD key //返回有序集合key中元素个数
ZRANGE key start stop [WITHSCORES] //正序获取有序集合key从start下标到stop下标的元素
ZREVRANGE key start stop [WITHSCORES] //倒序获取有序集合key从start下标到stop下标的元素
Zset集合操作
ZUNIONSTORE destkey numkeys key [key...] //并集计算
ZINTERSTORE destkey numkeys key [key...] //交集计算
Zset集合操作实现排行榜
1)点击新闻
ZINCRBY hotNews:20200819 1总理记者会
2)展示当日排行前十
ZREVRANGE hotNews:20200819 0 9 WITHSCORES
3)七日搜索榜单计算
ZUNIONSTORE hotNews:202008 13 - 20200819 7
hotNews:20200813 hotNews:202008 14... hotNews:20200819
4)展示七日排行前十
ZREVRANGE hotNews:20200813- 20200819 0 9 WITHSCORES
压缩列表 跳表 哈希表
其他问题
缓存击穿 查询的数据在缓存中不存在 直接去数据库查询 问题 导致数据库服务器压力变大 解决方法 先判断有没有缓存 没有则查询数据库 然后重新设置缓存 并添加过期时间
缓存穿透 查询的数据在缓存与数据库中都不存在 问题 并发过大时数据库服务器可能会宕机 解决方法 为不存在的数据创建空值 并添加过期时间
缓存冷门数据热点重建,原因,原本冷门的数据突然出现高并发访问 问题 并发过大时数据库服务器可能会宕机 解决方法 双重检测锁机制 先检查一遍缓存 缓存中没有 再用jvm锁或redis分布式锁 把查询数据库的代码锁起来(不能让高并发的请求同时穿透到数据库),在同步代码块中再查询一遍缓存,如果缓存中存在则直接返回数据(锁会影响效率,越快结束越好),如果缓存中还是没有才去查询数据库,然后把数据添加到缓存 并添加过期时间 一定要try catch finally 无论情况如何 最终必须解锁
缓存数据库双写不一致问题 修改数据的代码用锁 注意控制粒度 并发大效率低 可以用下边的读写锁优化
分布式锁优化方案 分场景 1读多写少 基于读写锁优化 读写互斥 写写互斥 读读不互斥 redis 的 readwriteLock 读写锁 readLock和writeLock锁同一个id 但读读不会互斥 可以优化
当redis的访问量过大,此时需要使用JVM级别的二级缓存,但jvm级别的缓存又必须要解决数据同步问题