首页 > 技术文章 > Redis入门学习:几种数据类型、缓存淘汰策略

scorpio-cat 2020-04-26 09:40 原文

Redis是一种key-value的格式存储数据的NO-SQL非关系型数据库。其中value有五种数据类型:String字符类型、Hash散列类型、List列表类型、Set集合类型、SortedSet或者叫zset有序集合类型。

  • 常用redis命令

key是不忽略大小写的,命令是忽略大小写的。

  • String类型

一个键最大能存储512MB。redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。

赋值 SET key value ,取值 get key ,删除key del key  

将储存的值加上1 incr key ,加上整数amount incrby key amout 

将储存的值减去1 decr key ,减去整数amount decrby key amout 

将值追加到key当前储存值的末尾 append key v 

获取下标start到end的字符串 getrange key start end 

  • Hash类型

格式: hmset name  key1 value1 key2 value2

是一个field和value的映射表,hash特别适合用于存储对象。

为多个key设置值 hmset hkey key v… , 获取多个值hmget hkey key ,删除多个值并返回 hdel hkey key 

检查key是否存在在散列中 hexists hkey key 

获取散列中所有key hkeys hkey 

  • List类型

是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

将一个或多个加入列表左端 lpush key [v…] 

将一个或多个加入列表右端 rpush key [v…] 

移除并返回最右端的元素 rpop key 

移除并返回列表最左端的元素 lpop key 

返回下标(偏移量)为size的元素 lindex key size 

返回从start 到end的元素 包含start和end lrange key start end 

只保留从start 到end的元素 包含start和end ltrim key start end 

  • Set类型

是无序集合,不允许重复的元素。

添加多个,返回新添加的个数(已存在的不算) sadd key item … 

检查元素item是否在集合中 sismember key item 

随机的移除一个元素 并返回已删除的元素 spop key 

  • SortedSet类型

每个元素都会关联一个double类型的分数,分数(score)却可以重复,成员是唯一的,通过分数来为集合中的成员进行从小到大的排序。

添加多个 zadd key score member … 

移除多个 zerm key memer… 

返回所有成员 zcard key 

返回member的分值 zscore key member 

  • 通用命令

查看满足规则的所有key keys pattern 如,keys mylist*

删除key DEL key 

确认一个key是否存在 exists key 

设置key的生存时间 EXPIRE key seconds 

查看key剩余的生存时间 TTL key 

清除生存时间 PERSIST key 

生存时间设置单位为毫秒 PEXPIRE key milliseconds 

  • 缓存淘汰策略

LRU原理:最近最少使用,LRU算法根据数据的历史访问记录来进行淘汰数据,其核心思想是如果数据最近被访问过,则将来被访问的几率也更高。

如使用一个链表保存数据,需满足规则:新插入的数据都插入到头部,最新查询数据都移动到头部,当链表满了就把尾部的数据丢弃。

  在redis.conf中有一行配置

  maxmemory-policy volatile-lru 

Redis提供了6种数据淘汰策略

(1)volatile-lru:从已设置过期时间的数据集中选最近最少使用的数据淘汰。

(2)volatile-ttl:从已设置过期时间的数据集中选要过期的数据淘汰。

(3)volatile-random:从已设置过期时间的数据集中任意选择数据淘汰。

(4)allkeys-lru:从数据集中挑选最近最少使用的数据淘汰。

(5)allkeys-random:从数据集中任意选择数据淘汰。

(6)no-enviction:禁止驱逐数据。

缓存穿透

一般,都是按key去缓存查询,如果没查到,就去数据库查找。如果遇到大量请求查询永远不存在的key,就会都是数据库访问,这就会对数据库产生很大的压力,这种情况就是缓存穿透。

我们可以通过以下方式来防止:

(1)把所有可能会查询的key,放在一个bitmap中,查询前先校验bitmap中是否存在,避免查询本来不存在的数据请求。

(2)对查询结果为空的情况也进行缓存,有效时间设置短一点,在该key被插入后清除缓存,这样可以避免每次不存在的key都会访问数据库。

(3)将可能查到的key在布隆过滤器中存储,规则是,查询存储key,就是查/存的key的hash值,缓存中对存在的key是存1,对不存在的key存0。

缓存雪崩

缓存重启或大量缓存同时段失效,需要都从数据库查,导致的系统崩溃,就是缓存雪崩。

我们可以通过下面方式尽量避免缓存雪崩:

(1)给不同的key,设置不同的过期时间,尽量合理,让缓存失效的时间点均匀分布。

(2)做两级缓存,第一级设置为短期缓存,第二级设置为长期缓存;保证一级缓存失效,可以去二级缓存查找,都找不到,则去数据库查找。

(3)对数据库访问做处理,就是在缓存失效后,通过一定手段控制从数据库查找数据并写入缓存的线程数据,如对查数据库,写入缓存这两部分加锁。

缓存击穿

和缓存雪崩不同之处是,单个缓存有效期到了,而同一时间点有大量请求进行查这个key,导致都访问到数据库了。

我们可以通过下面方式尽量避免缓存击穿:

(1)使用redis的setnx互斥锁。获取到锁,则查询缓存/数据库,否则就处于等待状态中,保证不会大并发操作数据库。

怎么保证缓存中的数据和数据库中的数据库的一致性?

延时双删策略:就是先删除缓存key,再更新数据库数据;等待不会后,再尝试删除一下缓存key,防止整个过程中,出现还没更新完成,其他线程查询了改key并缓存了旧值的情况。

  •  Redis消息模式

(1)使用List类型的lpush和rpop实现消息队列。

rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试,但是在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。

(2)如果要实现生产一次消费多次,需要使用pub/sub发布订阅者模式,可以实现1:N的消息队列;要先订阅后发布消息,不然前期发布的数据接收不到。

订阅消息 subscibe my-channel 

发布消息 publish my-channel "我是发布者,发布了一个消息,请查收" 

推荐阅读