聊一聊缓存之redis

起源

面试

  1. redis 有哪些数据类型?他们的应用场景你知道吗或者说你们在项目中怎么使用的?
  2. 有用过redis分布式锁吗?你们怎么用的?知道setnx是怎么实现的吗?setnx底层是有那几个命令组成的以及其中的细节?
  3. 你知道redis过期策略有哪些吗?假如让你实现redis的自动过期,你如何实现?
  4. 除了redis你还知道其他哪些缓存?他们之间的区别呢?

接下来将针对这几个问题,做一个简单的回答。即自身总结,也为同僚提供一些参考。

redis有哪些数据结构/类型,以及使用场景;

数据类型有5个:

String – Hash – List – Set – sortSet

  • String

数据结构是简单的key-value类型,value其实不仅是String,也可以是数字.
常用命令: set,get,decr,incr,mget 等。
应用场景: String是最常用的一种数据类型,普通的key/ value 存储都可以归为此类。
个人认为所有的数据如果不显麻烦都可以用String进行存储;如果你用过Memcached的话,其中所有的数据都是string形式进行存储的。


redis则相比与Memcached 数据结构更多,且提供了get、set、incr、decr 等操作外,Redis还提供了下面一些操作:

  • 获取字符串长度
  • 往字符串append内容
  • 设置和获取字符串的某一段内容
  • 设置及获取字符串的某一位(bit)
  • 批量设置一系列字符串的内容

  • Hash

常用命令: hget,hset,hgetall ,hincrby,hlen等。
应用场景: Hash,即可理解为常见的HashMap的操作。平日工作中较多用于存放用户的热点数据信息,例如:姓名,地址,一些业务经常使用的数据;采用HashMap结构可以做到最小更新的特点,而不需要把整个map信息取出来,再进行一次数据整体的覆盖。所有和这个类似的场景都可以采用Hash数据结构进行存储,个人觉得适合存储结构复杂不稳定的【大对象】


  • List

常用命令: lpush,rpush,lpop,rpop,lrange等。
应用场景: Redis list 的应用场景非常多,也是 Redis 最重要的数据结构之一。
比如 twitter 的关注列表,粉丝列表等都可以用 Redis 的 list 结构来实现,还可以做消息队,列息队列不仅被用于系统内部组件之间的通信,同时也被用于系统跟其它服务之间的交互。消息队列的使用可以增加系统的可扩展性、灵活性和用户体验。非基于消息队列的系统,其运行速度取决于系统中最慢的组件的速度(注:木桶效应)。而基于消息队列可以将系统中各组件解除耦合,这样系统就不再受最慢组件的束缚,各组件可以异步运行从而得以更快的速度完成各自的工作。
此外,当服务器处在高并发操作的时候,比如频繁地写入日志文件。可以利用消息队列实现异步处理。从而实现高性能的并发操作。


  • Set

常用命令: sadd,spop,smembers,sunion 等。
应用场景: Redis set 对外提供的功能与 list 类似是一个列表的功能,特殊之处在于 set 是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set 是一个很好的选择,并且 set 提供了判断某个成员是否在一个 set 集合内的重要接口,这个也是 list 所不能提供的。


  • Sorted set

常用命令: zadd,zrange,zrem,zcard等
使用场景: Redis sorted set 的使用场景与 set 类似,区别是 set 不是自动有序的,而 sorted set 可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择 sorted set 数据结构,比如你需要存储3个有关联事物时候,常见的用户,消息,消息等级;还可以利用zIncrBy,zRevRange,zAdd,zRevRank,zScore等接口做排行榜

问题1的参考资料
原文链接:https://blog.csdn.net/z15818264727/article/details/80166997

高端的数据类型


  • Bit 位图

应用场景

用户的签到记录,签了是1,没签是0,要记录365天。如果使用普通的key/value,每一个用户记录有365条,如果用户上亿,则需要的空间是非常吓人的。

应对这个问题,Redis 提供了位图数据结构。每天的签到记录只占用1个位,365天就是365位等于46字节(一个稍微长一点的字符串)

  • hyperloglog

应用场景

统计网页每天的UV数据,同一个用户一听之内的多次访问只能计数一次。如果你的网页访问量很大,如果采用set的集合来进行统计,非常浪费空间。如果需要统计的页面很多,那需要的空即是惊人的。针对UV 对于老板而言 103万 和 105万并没有多大区别。

hyperloglog 就是应对这种统计的。提供您不精确的去重计数方案,虽然不精确,但也不是非常离谱,标准误差是0.81%。这样用户统计上述UV非常合适

  • 布隆过滤器

应用场景

广泛应用于 内容推送场景下,只推送用户没有看过的内容。类似与B站APP中首页内容刷新机制,能很大程度上保证刷新出来的内容是用户没有看过的。
其基本原理 则通过 多个 hash函数,以确定某个值是否已经出现过。

通俗的理解则是:

在平常的人际交往中,一个人身上往往背负着 不同的标签、绰号、昵称、爱称、乳名等等(这里的这些称为则对应到 布隆过滤器中的hash 函数)。举例:
姓名:张XX; 绰号:阿三; 昵称:abc;乳名:张安安;等等…
只有所有的这些都相同的情况下则能确定你就是 咱们说的某某人; 当然其中很有可能出现 不准确的情况,恰好 某个人的特征和你的一样,这种情况则是没法避免的。这种情况也极其少见,所以能很好的适用与 内送刷新推送的场景当中去。
所以能否避免出现误判(出现重复的情况),则需要依赖与hash算法能否很好的避开这些重复的场景;暴力的就是增加hash 函数的数量、或者提取数据的特征值hash;




redis之分布式锁

口水话吐槽一下,可以完全跳过本段


本人在项目接触到的redis的操作,就是很普通的数据添加使用 和 一个自动过期。在一些场景中为了保证只有一个端或者线程执行某些操作,会使用到setnx的分布式相关的命令。
然而这很明显在面试的过程中,被 面试官 眼神diss和复杂表情的暗示。尽管这些redis的操作能满足大部分使用。但是只能说明一个问题,你对技术的渴望还没到达一种发疯的境界。只关心表面,就算是表面也应该要看全。而不是简单的数据存储,并没有往高级特性区学习和了解。

redis 分布式锁

基础用法,使用redis 自带的setnx命令
示例: setnx(key,value);

setnx当且仅当 key 不存在。若给定的 key 已经存在,则 setnx不做任何动作。setnx 是『set if not exists』(如果不存在,则 set)的简写,setnx 具有原子性。

解释一下,上面是什么意思:setnx本身是个原子操作。要么放入缓存成功,要么失败。
适用于场景简单,不涉及 高并发 和 锁竞争激烈的 情况。简单的适用这种特性来支持业务逻辑。


相对 高级 的用法,封装一下 setnx,使得setnx的数据可以自动过期。
示例:setnx(key,value,seconds);
执行逻辑,在setnx命令执行完之后,并设置key对应的过期时间。

long update =  redisClient.setnx("Key","Value");//1.setnx 将值放入
System.out.println("是否存储成功:"+update);
redisClient.expire("Key",30);  //30秒的过期时间;设置过期时间

在上边的这个执行过程当中,正常情况是不会出问题的。
倘若极端情况下,程序执行到setnx之后挂了。导致设置过期时间未执行。
在发生了这种不幸的情况时,程序重启之后。导致获取锁的逻辑进入一个全部获取失败,且永远如此。除非手动删除该key值。

ps:以上情况,出现在大量的高并发的获取锁的情况时。极易引发这种_极端情况_。为了避免这种情况的发生,便有了更加高级和安全的分布式锁

redis 分布式锁的正确用法

请仔细阅读,大牛们提供
正确用法示例1 正确用法示例2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值