1.string

这是最基本的类型了,就是普通的set和get,做简单的kv缓存。

2.hash

这个是类似map的一种结构,这个一般就是可以将结构化的数据,比如一个对象(前提是这个对象没嵌套其他的对象)给缓存在redis里,然后每次读写缓存的时候,可以就操作hash里的某个字段。

key=150	
	
value={	
  “id”: 150,	
  “name”: “zhangsan”,	
  “age”: 20	
}

hash类的数据结构,主要是用来存放一些对象,把一些简单的对象给缓存起来,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值

value={	
  “id”: 150,	
  “name”: “zhangsan”,	
  “age”: 21	
}

3.list

有序列表,这个是可以做很多不同操作的
比如:微博,某个大v的粉丝,就可以以list的格式放在redis里去缓存

key=某大v	
value=[zhangsan, lisi, wangwu]

比如:可以通过list存储一些列表型的数据结构,类似粉丝列表了、文章的评论列表了之类的东西

比如:可以通过lrange命令,就是从某个元素开始读取多少个元素,可以基于list实现分页查询,这个很棒的一个功能,基于redis实现简单的高性能分页,可以做类似微博那种下拉不断分页的东西,性能高,就一页一页走

比如:可以搞个简单的消息队列,从list头怼进去,从list尾巴那里弄出来


4.set

无序集合,自动去重

直接基于set将系统里需要去重的数据扔进去,自动就给去重了,如果你需要对一些数据进行快速的全局去重,你当然也可以基于jvm内存里的HashSet进行去重,但是如果你的某个系统部署在多台机器上呢?

得基于redis进行全局的set去重

可以基于set玩儿交集、并集、差集的操作,比如交集吧,可以把两个人的粉丝列表整一个交集,看看俩人的共同好友是谁?对吧

把两个大v的粉丝都放在两个set中,对两个set做交集


5.sorted set

排序的set,去重但是可以排序,写进去的时候给一个分数,自动根据分数排序,这个可以玩儿很多的花样,最大的特点是有个分数可以自定义排序规则

比如说你要是想根据时间对数据排序,那么可以写入进去的时候用某个时间作为分数,人家自动给你按照时间排序了

排行榜:将每个用户以及其对应的什么分数写入进去,zadd board score username,接着zrevrange board 0 99,就可以获取排名前100的用户;zrank board username,可以看到用户在排行榜里的排名

zadd board 85 zhangsan	
zadd board 72 wangwu	
zadd board 96 lisi	
zadd board 62 zhaoliu	
96 lisi	
85 zhangsan	
72 wangwu	
62 zhaoliu	
zrevrange board 0 3	
获取排名前3的用户	
96 lisi	
85 zhangsan	
72 wangwu	
zrank board zhaoliu	
4

6. 数据为什么会过期?

首先,要明白redis是用来做数据缓存的,不是用来做数据存储的(当然也可以当数据库用),所以数据时候过期的,过期的数据就不见了,过期主要有两种情况,
①在设置缓存数据时制定了过期时间,这样到了过期时间数据就不见了。
②redis的数据是存放在内存中的,而内存是有限的,是不可能放过多数据的,比如只有10G的内存,想要向里面放入20G的数据,那么就注定会有10G的数据会丢失。


7. redis的过期策略是什么样的?

redis采用了 “定期删除+惰性删除”  的过期策略。
①定期删除  
原理定期删除指的是redis默认每隔100ms就随机抽取一些设置了过期时间的key,检测这些key是否过期,如果过期了就将其删掉。
为什么会选择一部分,而不是全部因为如果这是redis里面有大量的key都设置了过期时间,那么如果全部去检测一遍,CPU负载就会很高,会浪费大量的时间在检测上面,甚至直接导致redis挂掉。所有只会抽取一部分而不会全部检查。
出现问题这样的话就会出现大量的已经过期的key并没有被删除,这就是 为什么有时候大量的key明明已经过了失效时间,但是redis的内存还是被大量占用的原因 ,为了解决这个问题,就需要 惰性删除 这个策略了。

②惰性删除  
原理惰性删除不在是redis去主动删除,而是在你要获取某个key 的时候,redis会先去检测一下这个key是否已经过期,如果没有过期则返回给你,如果已经过期了,那么redis会删除这个key,不会返回给你。
这样两种策略就保证了 过期的key最终一定会被删除掉 ,但是这只是保证了最终一定会被删除,要是定时删除漏掉了大量过期的key,而且我们也没有及时的去访问这些key,那么这些key不就不会被删除了吗?不就会一直占着我们的内存吗?这样不还是会导致redis内存耗尽吗?
由于存在这样的问题,所以redis引入了 内存淘汰机制 来解决。


8.内存淘汰机制

内存淘汰机制就保证了在redis的内存占用过多的时候,去进行内存淘汰,也就是删除一部分key,保证redis的内存占用率不会过高,那么它会删除那些key呢?
redis提供了6中内存淘汰策略,我们可以去进行选择,六中策略如下:
①noeviction当内存不足以容纳新写入数据时,新写入操作会报错,无法写入新数据,一般不采用。
②allkeys-lru当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key,这个是最常用的。
③allkeys-random当内存不足以容纳新写入的数据时,在键空间中,随机移除key,一般也不使用。
④volatile-lruvolatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key(这个一般不太合适)  。
⑤volatile-random当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key  。
⑥volatile-ttl当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。


9.手写一个LRU算法

//基于JavaLinkedHashMap实现	
public class LRUCache<K,V> extends LinkedHashMap<K,V>{	
private final int CACHE_SIZE;	
      	
//保存传递进来的最大数据量	
public LRUCache(int cacheSize){	
//设置hashmap的初始大小,同时最后一个true指的是让linkedhashmap按照访问顺序来进行排序,	
//最近访问的放在头,最老访问的放在尾	
super((int)Math.ceil(cacheSize/0.75)+1,0.75f,true);	
          CACHE_SIZE = CacheSize;	
      }	
	
@Override	
protected boolean removeEldestEntry(Map.Entry eldest){	
//当map中的数据量大于指定的缓存个数的时候,就自动删除最老的数据。	
return size() > CACHE_SIZE;	
      }	
}

— THE END —

关于Redis的几件小事 | Redis的数据类型/过期策略/内存淘汰_大数据技术


推荐阅读


《关于MQ面试的几件小事 | 消息队列的用途、优缺点、技术选型》       

《关于MQ面试的几件小事 | 如何保证消息队列高可用和幂等》

《关于MQ面试的几件小事 | 如何保证消息不丢失》

《关于MQ面试的几件小事 | 如何保证消息按顺序执行》

《关于MQ面试的几件小事 | 消息积压在消息队列里怎么办》