侧边栏壁纸
博主头像
coydone博主等级

记录学习,分享生活的个人站点

  • 累计撰写 306 篇文章
  • 累计创建 51 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Redis设计原则和常见面试

coydone
2022-04-30 / 0 评论 / 0 点赞 / 369 阅读 / 3,996 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-04-27,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

Redis的键值设计原则

key键格式

我们之前都是使用简单的key存储,如存储string类型的name为zhangsan,此时普通的需求可以满足,然而在实际业务中,往往key键的存储会非常的复杂,比如我们现在有一个需求:

需求:根据基础数据系统中的数据字典类型查询对应的字典集合

这时,我们需要关注的业务就变得复杂了,就不能使用常规的key键存储方式,上面的需求大致可以拆分为:

系统:基础数据系统
模块:数据字典
方法:根据数据字典类型查询
参数:字典类型

为什么要这样拆分呢?为了可读性;也为了抽象出key存储规则;因为业务复杂情况下,我们定义的key键太多时就不便于管理,也不便于查找,以 系统-模块-方法-参数 这样的规则定义,我们可以很清晰的了解redis key存储的值是做了什么事情

common:sys:sex:1 男
common:sys:sex:0 女
common:page:title 欢迎使用XX管理系统
user:1  {id:1.name:小明}
user:2  {id:2.name:习大大}

这个在使用Redis Desktop Manager工具去查看的时候就可以看出层级关系。

value值格式

在Java常规开发中,我们需要有面向对象的思想,相对于对象来说,比较常用且能快速转换的格式就是 JSON 了;比较常用的Java处理JSON数据有三个比较流行的类库FastJSON、Gson和Jackson。

上面提到了JSON,这是因为在Redis的存储中,我们使用它来存储value值,为什么要这样做呢?主要是因为json格式有如下几种好处:

标准,主流数据交换格式
简单,结构清晰,相对于XML来说更加的轻量级,易于解析
语言无关,任何语言都能轻松搞它
类型安全,值是有类型的,比如整数、字符串、布尔等

代码中redis value在存储前我们对其做了一次转换,将对象Value转换为json对象后存储,也就是一个key对应一个json串。

Redis常见面试

Redis支持的数据类型

1、String(字符串)

String数据结构是简单的key-value类型,value其实不仅可以是String,也可以是数字。 常规key-value缓存应用; 常规计数:微博数,粉丝数等。

常用命令: set,get,incr,decr,mget 等
set key value #设置值
get key #获取值
incr key #加一
decr key #减一

2、hash(哈希)

Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值。

常用命令: set,get,decr,incr,mget 等
hset key field value #设置值
hget key field #获取值
hincrby key field num #设置增数量

3、list(列表)

Redis list 的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销。

Redis list 的应用场景非常多,也是Redis最重要的数据结构之一,比如微博的关注列表,粉丝列表,消息列表等功能都可以用Redis的 list 结构来实现。

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

常用命令: lpush,rpush,lpop,rpop,lrange等
lpush list a b c d #从list左边添加元素
rpush list 1 2 3 4 #从list右边添加元素
lrange list 0 -1 #从0 到 -1 元素查看:也就表示查看所有
lpop list #从list左边取,删除
rpop list #从list右边取,删除

4、set(集合)

Redis的Set是string类型的无序集合。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

常用命令: sadd,spop,smembers,sunion 等
sadd set1 a b c d d #向set1中添加元素,元素不重复
smembers set1 #查询元素
srem set1 a #删除元素
sorted set(zset,有序集合)

5、zset(排序集合)

和set相比,sorted set增加了一个权重参数score,使得集合中的元素能够按score进行有序排列。

例:在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息,适合使用 Redis 中的 Sorted Set 结构进行存储。

常用命令: zadd,zrange,zrem,zcard等
#添加元素 zadd key score member,这里添加元素a:1分、元素b:2分、元素c:3分
zadd zset1 1 a 2 b 3 c  
zrange zset1 0 -1 #查看zset1的所有元素,默认从小到大
zrange zset1 0 -1 withscores #查看zset1的所有元素,包括分数score
zrevrange zset1 0 -1 #查看zset1的所有元素,从大到小
zincrby zset1 5 a #对zset1的a元素增加5分

Redis持久化

概念

持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。(Redis 数据都放在内存中。如果机器挂掉,内存的数据就不存在。所以需要做持久化,将内存中的数据保存在磁盘,下一次启动的时候就可以恢复数据到内存中。)

方式

Redis 提供了两种持久化方式:RDB(默认) 和AOF 。

1、RDB (快照):Redis可以通过创建快照来 获得存储在内存里面的数据在某个时间点上的副本。Redis创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis主从结构,主要用来提高Redis性能),还可以将快照留在原地以便重启服务器的时候使用。

快照持久化是Redis默认采用的持久化方式,在redis.conf配置文件中默认有此下配置:

save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

2、AOF(只追加文件):与快照持久化相比,AOF持久化的实时性更好,因此已成为主流的持久化方案。默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:appendonly yes

开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof

在Redis的配置文件中存在三种不同的 AOF 持久化方式,它们分别是:

#每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync always

appendfsync everysec #每秒钟同步一次,显示地将多个写命令同步到硬盘
appendfsync no #让操作系统决定何时进行同步

为了兼顾数据和写入性能,用户可以考虑 appendfsync everysec选项 ,让Redis每秒同步一次AOF文件,Redis性能几乎没受到任何影响。而且这样即使出现系统崩溃,用户最多只会丢失一秒之内产生的数据。当硬盘忙于执行写入操作的时候,Redis还会优雅的放慢自己的速度以便适应硬盘的最大写入速度。

优缺点

RDB (快照):快照形式 ,定期将当前时刻的数据保存磁盘中。会产生一个dump.rdb文件,特点:性能较好,数据备份。但可能会存在数据丢失。

AOF(只追加文件) :append only file (所有对redis的操作命令记录在aof文件中),恢复数据,重新执行一遍即可。特点:每秒保存,数据比较完整。但耗费性能。

【注】如果两个都配了优先加载AOF。(同时开启两个持久化方案,则按照 AOF的持久化放案恢复数据。)

Redis的架构模式

主从模式(Redis2.8版本之前的模式)、哨兵sentinel模式(Redis2.8及之后的模式)、Redis Cluster集群模式(Redis3.0版本之后)。

缓存穿透/缓存雪崩

缓存穿透

一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

如何避免?

1、对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。

2、对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。

3、也可以使用流行的bloom filter布隆过滤器。

缓存雪崩

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力。导致系统崩溃。

如何避免?

1、在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

2、做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期。

3、不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

0

评论区