当前位置: 首页 > news >正文

Redis常见问题

1 为什么使用Redis

Redis是No-SQL(Not Only SQL)的一种,目前最火的一种非关系型数据库

基于内存存储,支持多种数据类型,键值对存储,Java开发主要面向服务端,就需要抗并发量,性能

Java程序中,使用Redis.

主流NO-SQL对比:对比选择了Redis

小知识:

数据库的分类:

1.Old-SQL

泛指关系型数据库,典型代表:Mysql、Sql Server、Oracle、PostgreSql、H2、Sqllite

2.No-SQL

泛指非关系型,性能,典型代表:Redis(内存 键值对存储)、MongoDB(文档)、Hbase(列)

3.New-SQL

泛指新型数据库,主打海量数据,高并发,典型代表:TiDb、云平台(自主数据)

2 Redis为什么快

1.基于C语言开发,可以直接操作硬件

2.基于内存存储,性能高

3.多路复用:单线程干多线程的事

4.RESP协议-实现数据传输

5.底层存储结构的优化

6.快速实现集群

3 Redis数据类型

Redis的数据类型,针对Redis中键值对(Key-Value)的值而言

1.String类型

值是字符串类型

2.List类型

值是List集合,特点:存储多个元素,可以重复,保证添加顺序

3.Set类型

值是Set集合,特点:存储多个元素,不重复,不保证添加顺序

4.SortSet(Zset)类型

值是Map<Object,Double>,一种特殊Set集合,特点:存储多个元素,每个元素有:元素的值(任意类型)和分数(Score,只能Double),其中元素的值不能重复,分数是可以重复,而且还能根据分数排序

5.Hash类型

值是Map<Field(Object),Value(Object),>,特点:存储多个元素,每个元素有字段(Field)和值(Value),Field唯一,Value可以重复

6.Bitmap类型

值是一个byte数组,特点:byte数组,值只能是0或1,默认0

小身材大容量,应用场景:2种状态,海量数据,比如1亿用户,今日登录的人数、今日的签到人数、今日的抽奖人数

1Byte=8byte

1GB=1024MB=1024 * 1024KB=1024 * 1024 * 1024 B=1024 * 1024 * 1024 * 8b

7.Geo类型

值是一个地理位置数组,特点:元素是地理位置信息(经度、纬度、地点名称),可以进行计算距离,半径搜索

8.Hyperloglog类型

值是基数,特点:类似函数,计算集合中的基数

4 Redis底层结构之SDS

SDS(simple dynamic string)简单动态字符串,Redis是基于C语言,但是字符串类型,重构了SDS

SDS就是String的底层,内部有三个属性

  1. len : 保存的字符串长度。获取字符串的长度就是O(1)
  2. free:剩余可用存储字符串的长度
  3. buf:保存字符串

SDS的优点:

当用户修改字符串时sds api会先检查空间是否满足需求,如果满足,直接执行修改操作,如果不满足,将空间修改至满足需求的大小,然后再执行修改操作 空间预分配 如果修改后的sds的字符串小于1MB时(也就是len的长度小于1MB),那么程序会分配与len属性相同大小的未使用空间(就是再给未使用空间free也分配与len相同的空间) 例:字符串大小为600k,那么会分配600k给这个字符串使用,再分配600k的free空间在那。 惰性空间释放,当缩短sds的存储内容时,并不会立即使用内存重分配来回收字符串缩短后的空间,而是通过free将空闲的空间记录起来,等待将来使用。真正需要释放内存的时候,通过调用api来释放内存 通过空间预分配操作,redis有效的减少了执行字符串增长所需要的内存分配次数 如果修改后sds大于1MB时(也就是len的长度大于等于1MB),那么程序会分配1MB的未使用空间 例:字符串大小为3MB,那么会分配3MB给这个字符串使用,再分配1MB的free空间在那。

5 Redis底层结构之Hash

Hash表数据结构,其实hash表本身就是一个数组,将key通过hash算法计算得出hash值对数组长度取模,用得到的值作为数组下标,然后把value保存在数组下标的位置。由于存储结构是数组,所以hash表的读复杂度是O(1)。

应用场景

1.Redis键值对(Hash类型)的底层实现。

2.当一个哈希键包含的键值对比较多,又或者键值对总的元素都是比较长的字符串时,Redis会使用hash表作为哈希键的底层实现。

3.集合键的底层实现之一

哈希冲突问题

当hash表的负载因子过大时,会频繁出现hash冲突的问题,不同的key经过hash计算和取模得到相同的数组下标。redis使用链表法,将数组下标相同的key使用链表串联起来,以解决哈希冲突的问题。但是当哈希冲突过多,链表长度过长时(需遍历链表,查找key完全匹配的数据),那么它的查询效率也将会降低到O(n),这个时候就要考虑增大数组的长度,执行rehash操作。

渐进式rehash

rehash操作需要创建一个新的长度*2的数组,将所有的key进行hash计算并对新的数组长度取模,然后把数据放在新的数组下标中,这样可以大幅度减少哈希冲突的比例,防止查询效率的退化。但是在生产系统中的数据量是很大的,如果一下子对所有的key进行rehash计算并迁移,那么会导致cpu负载过重,响应正常的对外提供服务。redis采用了渐进式的rehash方式,分批次的将所有key完成rehash,然后将指针引用到新的数组地址。

6 Redis底层结构之ZipList

ZipList:压缩表,列表键(List)和哈希键(Hash类型和SortSet)底层实现,Redis会在列表键包含少量列表项且短字符串,使用压缩表作为底层结构。为了节约内存而开发

7 Redis底层结构之SkipList

SkipList跳表,有序的链表,构建索引,提高查询效率,空间换时间,查找方式从上链表的顶层往下查找

时间复杂度是O(logn)

8 Redis集群策略

3种策略

第一种:主从复制

可以实现一主多从,一台主库(Master),多台从库(Slaver)

优点:避免单点故障,主从的数据一模一样

缺点:1.Redis存储上限没有解决 2.一旦主库崩了,就无法写入

第二种:哨兵机制+主从复制

Redis提供了哨兵机制,监听主库运行,一旦主库连接不上,在从库中自动选举一台从库作为主库

优点:避免单点故障,解决了主库宕机的意外情况

缺点:1.Redis存储上限没有解决

第三种:Redis-Cluster+Redis哨兵+主从复制

利用Redis的插件Redis-cluster实现去中心化的Redis集群搭建,实现多主多从

优点:避免单点故障,解决了主库宕机的意外情况,解决了Redis存储上限

缺点:费钱、复杂度

9 Redis穿透

穿透:海量请求,访问一些Redis不存在的数据,最终请求全部落到数据库中,引起了数据库的宕机或卡顿

解决方案:

1.布隆过滤器,直接使用RedissonClient(看门狗)的BloomFilter,底层原理:hash算法+Bitmap类型

10 Redis击穿

击穿:海量请求,同时访问一个热点key,结果访问的一瞬间,key失效了,导致请求落到了数据库

解决方案:

1.热点key不设置有效期

2.key失效了,加个锁再去访问数据库,然后更新数据

3.避免热点key

11 Redis雪崩

雪崩:海量请求,同时访问很多个key,结果访问的一瞬间,这些key失效了,导致请求落到了数据库

解决方案:

1.这些key不要在同一时间失效,追加随机时间戳

12 Redis倾斜

倾斜:集群中,海量请求,访问key结果都分配到了某一个服务器上,导致这台服务器压力过大

解决方案:

1.从设计的角度解决热点key的问题

13 Redis过期策略

Redis中,可以为key设置有效期,key过去的时候,就需要触发过期策略

1.定期删除:Redis每隔指定时间,随机检查指定数量key,如果key失效就删除。

2.惰性删除:Redis在查询的时候,会对进行校验,校验是否过期,如果过期删除。

Redis就是采用这2种方式解决过期的key删除

14 Redis淘汰机制

Redis中有淘汰机制,解决存储空间不足的问题

在redis.conf文件中,设置触发的条件,内存使用率达到多少就触发哪种淘汰机制

在Redis内存已经满的时候,添加了一个新的数据,执行淘汰机制。

volatile-lru:在内存不足时,Redis会在设置过了生存时间的key中干掉一个最近最少使用的key。

allkeys-lru:在内存不足时,Redis会在全部的key中干掉一个最近最少使用的key。

volatile-lfu:在内存不足时,Redis会在设置过了生存时间的key中干掉一个最近最少频次使用的key。

allkeys-lfu:在内存不足时,Redis会再全部的key中干掉一个最近最少频次使用的key。

volatile-random:在内存不足时,Redis会再设置过了生存时间的key中随机干掉一个。

allkeys-random:在内存不足时,Redis会再全部的key中随机干掉一个。

volatile-ttl:在内存不足时,Redis会在设置过了生存时间的key中干掉一个剩余生存时间最少的key。

noeviction:(默认)在内存不足时,直接报错。

指定淘汰机制的方式:maxmemory-policy 具体策略,设置Redis的最大内存:maxmemory 字节大小

15 基于Redis的分布式锁

锁:保证任一时间,只能有一个线程访问,解决线程安全

分布式锁:集群下,解决线程安全,就需要使用分布式锁

分布式锁的实现方案:

1.基于Redis实现分布式锁:性能高,稳定性一般

2.基于zookeeper(分布式目录存储)实现分布式锁:性能一般,稳定性高

Redis实现分布式锁:RedLock(红锁) 直接设置key(锁的名称)再设置一个超时时间

**1.互斥:**任何时刻只能有一个client获取锁

**2.释放死锁:**即使锁定资源的服务崩溃或者分区,仍然能释放锁

**3.容错性:**只要多数redis节点(一半以上)在使用,client就可以获取和释放锁

RedLock的底层实现原理:

多节点redis实现的分布式锁算法(RedLock):有效防止单点故障

假设有5个完全独立的redis主服务器

1.获取当前时间戳

2.client尝试按照顺序使用相同的key,value获取所有redis服务的锁,在获取锁的过程中的获取时间比锁过期时间短很多,这是为了不要过长时间等待已经关闭的redis服务。并且试着获取下一个redis实例。

比如:TTL为5s,设置获取锁最多用1s,所以如果一秒内无法获取锁,就放弃获取这个锁,从而尝试获取下个锁

3.client通过获取所有能获取的锁后的时间减去第一步的时间,这个时间差要小于TTL时间并且至少有3个redis实例成功获取锁,才算真正的获取锁成功

4.如果成功获取锁,则锁的真正有效时间是 TTL减去第三步的时间差 的时间;比如:TTL 是5s,获取所有锁用了2s,则真正锁有效时间为3s(其实应该再减去时钟漂移);

5.如果客户端由于某些原因获取锁失败,便会开始解锁所有redis实例;因为可能已经获取了小于3个锁,必须释放,否则影响其他client获取锁

16 Redis应用

项目中使用Redis的时候:1.为什么用Redis 2.Redis的哪种数据类型 3.Redis存储什么数据 4.Redis是否设置有效期 5.怎么保证数据同步

1.缓存

很多次的访问都是访问相同的数据,可以考虑做缓存

比如首页、商品详情页、动态列表页、排行榜、多版本号兼容等

难点:保证数据一致性

2.有效期数据

短时间的有效期的数据,可以考虑使用Redis

比如:验证码、令牌、订单超时等

3.分布式锁

实现分布式锁,共享锁的状态

4.共享数据

利用Redis实现微服务(或集群)中的多个服务间的数据共享

比如:分布式Session

5.性能

利用Redis的高性能,可以早海量并发量下,以Redis为主库

比如:秒杀的下单、订单削峰填谷等

17 数据同步一致性

数据同步一致性的问题:比如Redis->Mysql Mysq->Es

1.直接操作

更改数据源的时候直接更改对应缓存数据

2.延迟同步(延时双删)

更改数据源(主库),基于Mq的延迟实现延迟同步操作

3.定时同步

任务调度框架实现定时数据同步

4.第三方软件,实现数据迁移(定时)

淘宝Cancel

相关文章:

  • 【毕业设计】1-基于单片机的城市轨道交通列车超速防护系统_里程表设计(原理图+PCB+源码+仿真工程+答辩论文)
  • 【数据结构】堆和优先级队列
  • 关于如何找环形链表的入环点
  • 下班路上捡了一部手机,我用8年开发知识主动找到了失主
  • 【Linux系统】第三篇:Linux中软件包管理器yum的使用
  • Bootstrap学习(十一)
  • 学生HTML个人网页作业作品:基于HTML实现教育培训机构网站模板毕业源码(8页)
  • 作为前端你还不懂MutationObserver?那Out了
  • 2021 年河南省中等职业教育技能大赛“网络安全”项目比赛任务书解析教程
  • 【目标检测】Faster R-CNN论文代码复现过程解读(含源代码)
  • rpm包常用命令指南
  • 15.前端笔记-CSS-PS切图
  • 网站变灰代码如何让网页变灰
  • 实用调试技巧
  • Python图像处理【3】Python图像处理库应用
  • hexo+github搭建个人博客
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • CentOS7 安装JDK
  • es6(二):字符串的扩展
  • exports和module.exports
  • gf框架之分页模块(五) - 自定义分页
  • log4j2输出到kafka
  • MQ框架的比较
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • 对象引论
  • 缓存与缓冲
  • 基于阿里云移动推送的移动应用推送模式最佳实践
  • 记一次和乔布斯合作最难忘的经历
  • 区块链将重新定义世界
  • 思维导图—你不知道的JavaScript中卷
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 我的业余项目总结
  • 协程
  • 正则表达式
  • 如何在招聘中考核.NET架构师
  • #NOIP 2014#Day.2 T3 解方程
  • #宝哥教你#查看jquery绑定的事件函数
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (附源码)ssm考试题库管理系统 毕业设计 069043
  • (六)Hibernate的二级缓存
  • (四)模仿学习-完成后台管理页面查询
  • .mat 文件的加载与创建 矩阵变图像? ∈ Matlab 使用笔记
  • .NET Core WebAPI中使用swagger版本控制,添加注释
  • .NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)
  • .sh文件怎么运行_创建优化的Go镜像文件以及踩过的坑
  • @Bean有哪些属性
  • @requestBody写与不写的情况
  • @我的前任是个极品 微博分析
  • [ C++ ] STL_list 使用及其模拟实现
  • [ C++ ] template 模板进阶 (特化,分离编译)
  • []我的函数库
  • [2669]2-2 Time类的定义
  • [Avalon] Avalon中的Conditional Formatting.
  • [BPU部署教程] 教你搞定YOLOV5部署 (版本: 6.2)