Redis基本数据类型、数据持久化、过期策略及淘汰机制

一点技术、技术乐享!!!

如果有人问你:Redis这么快,他的“多线程模式”你了解吗?

请回答他:您是想问Redis这么快,为什么还是单线程模式吗?

redis是什么

简单来说redis是C语言开发的一个开源的(遵从BSD协议)高性能键值对(key-value)的内存数据库,可以用作数据库、缓存、消息中间件等。

  • 性能优秀,数据在内存中,读写速度非常快,支持并发10W QPS。

  • 单进程单线程,是线程安全的,采用Io多路复用机制。

  • 丰富的数据类型,支持字符串(string)、散列(hash)、列表(list)、集合(set)、有序集合(sorted set)。

  • 支持数据持久化(RDB、AOF),可以将内存中的数据保存到磁盘中,重启时加载。

  • 主从复制、哨兵、高可用。

  • 可以用作分布式锁。

  • 可以作为消息中间件使用,支持发布订阅。


redis的五种数据类型

  1. String 这个其实没啥好说的,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。

  2. hash 这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。博主在做单点登录的时候,就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似session的效果。

  3. list 使用List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。

  4. set 因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去重,再起一个公共服务,太麻烦了。 另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。

  5. sorted set

    sorted set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。另外,参照另一篇《分布式之延时任务方案解析》,该文指出了sorted set可以用来做延时任务。最后一个应用就是可以做范围查找。


redis数据持久化

  1. RDB(快照)

    在默认情况下,Redis将内存数据库快照保存到dump.rdb的二进制文件中。 可以对Redis进行设置,让它在“N秒内数据集至少有N个改动”, 这一条件被满足时,自动保存一次数据集。比如说:让Redis满足“60秒内至少有1000个键被改动”这一个条件时,自动保存一次数据集。

    1 save 60 1000

    除了在配置文件中使用save关键字设置RDB快照,还可以在命令行中手动执行命令生成RDB快照,进入redis客户端执行命令save或bgsave可以生成dump.rdb文件。 每次执行命令都会将所有redis内存快照保存到一个rdb文件里,并覆盖原有的rdb快照文件。 save是同步命令,bgsave是异步命令,bgsave会从redis主进程fork出一个子进程专门用来生成rdb二进制文件。

  2. AOF(append only file)

    在对数据完整性要求比较高的情况下,快照模式就不能满足我们的需求,这是就需要aof持久化。

    修改配置文件开启aof功能:

    appendonly yes

    打开aof功能,每当redis执行一个改变数据集的命令时,这个命令就会追加到aof文件的末尾。这样的话,当redis重新启动时,程序就会通过执行aof文件中的命令来达到重建数据集的目的。 我么还可以配置redis多久才将命令持久化到磁盘一次。

    appendfsync always:每次有新命令追加到aof文件时就执行一个持久化,非常慢但是安全appendfsync everysec:每秒执行一次持久化,足够快(和使用rdb持久化差不多)并且在故障时只会丢失1秒钟的数据appendfsync no:从不持久化,将数据交给操作系统来处理。redis处理命令速度加快但是不安全。

  1. RDB和AOF的对比

    命令RDBAOF
    启动优先级
    体积
    回复速度
    数据安全性数据容易丢失根据策略决定

redis的过期策略以及内存淘汰机制

这个问题其实相当重要,到底redis有没用到家,这个问题就可以看出来。比如你redis只能存5G数据,可是你写了10G,那会删5G的数据。怎么删的,这个问题思考过么?还有,你的数据已经设置了过期时间,但是时间到了,内存占用率还是比较高,有思考过原因么?

1. redis采用的是定期删除+惰性删除策略

   为什么不用定时删除策略? 定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略.

2. 定期删除+惰性删除是如何工作的呢?

   定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。 于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。

3. 采用定期删除+惰性删除就没其他问题了么?

   不是的,如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制。 在redis.conf中有一行配置

# maxmemory-policy volatile-lru

  该配置就是配内存淘汰策略的(什么,你没配过?好好反省一下自己)

  1)noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。应该没人用吧。

  2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。推荐使用,目前项目在用这种。

  3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。应该也没人用吧,你不删最少使用Key,去随机删。

  4)volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。这种情况一般是把redis既当缓存,又做持久化存储的时候才用。不推荐。

  5)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。依然不推荐。

  6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。不推荐 ps:如果没有设置 expire 的key, 不满足先决条件(prerequisites); 那么 volatile-lru, volatile-random 和 volatile-ttl 策略的行为, 和 noeviction(不删除) 基本上一致。

相关推荐