redis整理心得

1、数据类型:

1.1、String(查看具体操作命令使用 help @String)

String使用场景:

//单值缓存:

SET KEY  VALUE

GET KEY 

//对象缓存

SET user:1  value(json格式数据)

MSET user:1:name  xifeng  user:1:age 18

MGET user:1:name user:1:age

//分布式锁

SETNX product:1000 true   //返回1,加锁成功

SETNX product:1000 true   //再次加锁返回0,加锁失败

DEL product:1000  //释放锁

SET product:10001 true ex 10 nx //防止程序意外终止导致死锁

//计数器

INCR article:readcount:{文章ID}  //订阅数加1

GET article:readcount:{文章ID}   //获取订阅数
//web集群session共享

spring session+redis  //redis实现session共享

//分布式系统获取序列号(比如订单ID)

 INCRBY ORDERID 1000  //一次性获取1000序列号
View Code

1.2、List(查看具体操作命令使用help  @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,一直阻塞等待

使用场景:

//生成数据结构
LPUSH+LPOP //STACK栈 
LPUSH+RPOP //QUEUE队列
LPUSH+BRPOP//BLOCKING MQ阻塞队列
//微博和微信公号消息流
//1、诸葛老师关注了Mactalk,备胎说车等
//2、MacTalk发微博,消息ID为10018
LPUSH MSG:{诸葛老师ID} 10018
//3、备胎说车发微博,消息ID为10086
LPUSH MSG:{诸葛老师ID} 10086
//4、查看最新消息
LRANGE MSG:{诸葛老师ID} 
LREVRANGE MSG:51668 0 4

1.3、Hash(查看具体操作命令使用help @hash)

优点:1、同类数据归类整合存储,方便数据管理2、相比string操作消耗内存和cpu更小3、相比string储存更节省空间。

缺点:过期功能不能使用在field上,只能用在key上2、redis集群架构下不适合大规模使用

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使用场景

//存储对象
HMSET  user {userid}:name  xifeng  {userid}:age  18
HMSET user 1000:name xifeng 1000:age 18
HMGET user 1000:name  1000:age  

//购物车增加商品
//以用户id为key,用户商品为field,商品数量为value
//添加商品
HSET cart:1000 10088 1

//商品增加数量
hincrby cart:1000 10088 2

//购物车商品总数
 hlen cart:1000

//删除商品
 hdel cart:1000 10088

//获取购物车所有商品
hgetall cart:1000
View Code

1.4、Set(查看具体操作命令使用help @set)

//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、zhuge关注的人
zhugeSet-> {guojia, xushu}
//2、yangguo关注的人
 yangguoSet--> {zhuge, baiqi, guojia, xushu}
//3、guojia关注的人
guojiaSet-> {zhuge, yangguo, baiqi, xushu, xunyu)
//4、zhuge关注的人也关注他(yangguo): 
SISMEMBER guojiaSet yangguo//判断yangguo在guojiaSet是否存在
SISMEMBER xushuSet  yangguo
//5、zhuge和yangguo老师共同关注: 
SINTER zhugeSet yangguoSet
//6、如我进入到yangguo老师的页面,推荐zhuge可能认识的人
SDIFF yangguoSet zhugeSet

SADD  brand:huawei  P40
SADD  brand:xiaomi  mi-10
SADD  brand:iPhone iphone12
SADD os:android  P40  mi-10
SADD cpu:brand:intel  P40  mi-10
SADD ram:8G  P40  mi-10  iphone12
//筛选最终符合条件的手机
SINTER  os:android  cpu:brand:intel  ram:8G   {P40,mi-10}

1.5、zSet(查看具体操作命令使用help @sorted_set)

//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 …]      //交集计算

应用场景:

//新闻访问次数
ZINCRBY  hotNews:20190819  1  守护香港
//展示当日排行前十,并且带点击量
ZREVRANGE  hotNews:20190819  0  9  WITHSCORES 
//七日搜索榜单计算
ZUNIONSTORE  hotNews:20190813-20190819  7  hotNews:20190813  hotNews:20190814... hotNews:20190819
//展示七日排行前十
ZREVRANGE hotNews:20190813-20190819  0  9  WITHSCORES

1.6、geo

1.7、HyperLogLog(并不是一种新的数据类型(实际还是String类型),而是一种技术算法,通过极小的内存空间完成总数的统计,存储的数据是不会重复的)

//用于向 HyperLogLog 添加元素,如果添加成功返回1
pfadd key element [element …]
pfadd 08-15:u:id "u1" "u2" "u3" "u4"
//用于计算一个或多个 HyperLogLog 的独立总数
pfcount key [key …]
//返回结果4
pfcount 08-15:u:id 
//此时向08-15:u:id插入 u1、u2、u3、u90
pfadd 08-15:u:id "u1" "u2" "u3" "u90"
//此时结果是5
pfcount 08-15:u:id
//可以求出多个 HyperLogLog 的并集并赋值给 destkey
pfmerge destkey sourcekey [sourcekey ... ]

使用场景:

1、网站每个网页每天的 UV(同一个用户一天只能算一次) 数据

1.8、bitmaps

  使用场景:实现布隆过滤器(当然判断存在的时候有误差,判断数据不存在那么就一定不存在),使用布隆过滤器实现40亿qq账号数据去重(预先把40亿的账号数据放入到bitmaps中,再使用布隆过滤器筛选哪些数据可能在布隆过滤器中,单独做标记)。

1.9、管道(pipline)和lua(脚本)

  脚本会将多个命令和操作当成一个命令在redis中执行,也就是该脚本在执行过程中,不会被其他命令或脚本插入、打扰,因此具备原子性,更适合处理事务。

  管道也会一次性将多个命令传输到redis服务端,但在服务端执行的时候仍然是多个命令,因此有可能会被其他命令插入、打扰,因此管道并不具有原子性。

2、高并发方案

2.1、穿透:查询数据库和缓 中都不存在的数据(解决方案:1、根据访问的键值缓存空对象,实现简单,效果不好。2、布隆过滤器:代码复杂 ,效果好。)

2.2、击穿:热点数据访问,刚好缓存过期或失效,导致大量并发访问到达数据库,对于数据库是致命的(使用分布式锁,在分布式锁的前面和后面分别加上缓存,保证缓存失效时,并发访问只能到达数据库一次)

2.3、雪崩:redis挂了或大批量数据过期

解决方案:

1、redis搭建高可用集群

2、大批数据,分批错开设置过期时间,或考虑过期时间用时间戳

3、使用redisson分布式锁

4、限流

2.4、微服务读写并发情况下,数据库和缓存不一致的问题(一般为数据一致未被使用或者缓存数据刚好失效,这时候有读的操作进来,因为读和更新缓存这两个操作不具备原子性,然后在读操作更新缓存之前,写操作刚好把数据和缓存都更新了,此时读操作再把缓存更新,就会存在不一致问题)。解决方案:使用redisson的分布式读写锁机制解决。

3、分布式锁实现

原理:使用setnx()获取锁,获取失败的话等待获取(循环获取,每次休眠500ms),获取锁成功之后,先给锁设置过期时间,再执行业务,最后再设置删除锁

4、数据库和缓存不一致解决方案(具体使用哪种方案,看业务对于数据库和缓存不一致的忍受情况而定):

a、使用redisson分布式读写锁(此方案可以完全杜绝不一致问题,但是会有并发读写性能问题)

b、使用延时双删方案(当更新数据时,先删除缓存,再更新数据,延时x秒(根据业务逻辑和写入缓存时间判断延时时间),再次删除缓存),此方案可以提高并发吞吐量,但是可能还是会存在数据库和缓存不一致的情况。

c、使用阿里的canal框架解决缓存更新问题(此框架监听mysql binlog日志变化,根据binlog更新缓存数据),因为监听binlog变化也会存在网络延时,此方案也会出现数据库和缓存不一致的情况。

 

posted @ 2021-03-26 23:52  西风51668  阅读(37)  评论(0编辑  收藏  举报