Redis常见问题

news/2024/11/14 13:12:10/

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


http://www.ppmy.cn/news/936.html

相关文章

【Java难点攻克】「Guava RateLimiter」针对于限流器的入门到实战和源码原理分析

限流器的思路和算法 如果让你来造一个限流器&#xff0c;有啥想法&#xff1f; 漏桶算法 用一个固定大小的队列。比如设置限流为5qps&#xff0c;1s可以接受5个请求&#xff1b;那我们就造一个大小为5的队列&#xff0c;如果队列为满了&#xff0c;就拒绝请求&#xff1b;如…

第十三章 DFS与BFS(保姆级教学!!超级详细的图示!!)

第十三章 DFS与BFS一、深度优先搜索1、什么是DFS&#xff1f;2、DFS代码模板&#xff08;1&#xff09;问题&#xff1a;&#xff08;2&#xff09;分析&#xff1a;&#xff08;3&#xff09;模板&#xff1a;3、DFS代码分析二、广度优先搜索1、什么是BFS&#xff1f;2、BFS代…

远程办公:通过cpolar内网穿透,远程桌面控制家里公司内网电脑

疫情反反复复的当下&#xff0c;有时候会遇到需要居家办公的情况&#xff0c;但在办公室的电脑上仍有很多重要资料需要存取&#xff0c;且办公室所在的局域网中也有很多相关资源需要被访问&#xff08;如文件共享服务器、OA系统等&#xff09;。如何能在家通过远程处理好办公事…

vue.js父组件访问子组件

父组件访问子组件 有时候我们需要父组件直接访问子组件&#xff0c;子组件直接访问父组件&#xff0c;或者是子组件访问跟组件。 父组件访问子组件&#xff1a;使用$children或refs子组件访问父组件&#xff1a;使用$parent 代码 <!DOCTYPE html> <html><he…

[附源码]计算机毕业设计仓库管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

关于PCB布局布线,这篇文章说透了

关于PCB布局布线的问题&#xff0c;今天我们不讲信号完整性分析&#xff08;SI&#xff09;、电磁兼容性分析&#xff08;EMC&#xff09;、电源完整性分析&#xff08;PI&#xff09;。 只讲可制造性分析&#xff08;DFM) &#xff0c;可制造性设计不合理同样会导致产品设计失…

基础生态学名词解释

生态学(ecology)&#xff1a;是研究有机体及其周围环境-包括非生物环境和生物环境相互关系的科学。 生态学的研究方法&#xff1a;野外的、实验的、理论的 环境&#xff08;environment&#xff09;&#xff1a;是指某一特定生物体或生物群体 生活空间的外界自然条件的总和。…

[LeetCode 1769]移动所有球到每个盒子所需的最小操作数

题目描述 题目链接&#xff1a;[LeetCode 1769]移动所有球到每个盒子所需的最小操作数 有 n 个盒子。给你一个长度为 n 的二进制字符串 boxes &#xff0c;其中 boxes[i] 的值为 ‘0’ 表示第 i 个盒子是 空 的&#xff0c;而 boxes[i] 的值为 ‘1’ 表示盒子里有 一个 小球。…