当前位置:   article > 正文

Java高级阶段面试题库(Redis数据库、MQ消息队列、kafka、SpringBoot + SpringCloud、MySQL、JVM&JUC、其它)_java radis 和mq

java radis 和mq

文章目录

1. Redis数据库篇(忽略)

1.1 简单介绍一下redis

为什么不直接操作内存呢?

【答案解析】

(1)redis是一个key-value类型的非关系型数据库,基于内存也可持久化的数据库,相对于关系型数据库(数据主要存在硬盘中),性能高,因此我们一般用redis来做缓存使用;并且redis支持丰富的数据类型,比较容易解决各种问题

(2)Redis的Value支持5种数据类型,string、hash、list、set、zset(sorted set);

以下为5中类型比较经典的使用场景

类型使用场景
stringString类型是最简单的类型,一个key对应一个value,项目中我们主要利用单点登录中的token用string类型来存储;商品详情
hashHash类型中的key是string类型,value又是一个map(key-value),针对这种数据特性,比较适合存储对象,在我们项目中由于购物车是用redis来存储的,因此选择redis的散列(hash)来存储;
listList类型是按照插入顺序的字符串链表(双向链表),主要命令是LPOP和RPUSH,能够支持反向查找和遍历,如果使用的话主要存储商品评论列表,key是该商品的ID,value是商品评论信息列表;消息队列
setSet类型是用哈希表类型的字符串序列,没有顺序,集合成员是唯一的,没有重复数据,底层主要是由一个value永远为null的hashmap来实现的。可以基于 Set 玩儿交集、并集、差集的操作,比如交集吧,我们可以把两个人的好友列表整一个交集,看看俩人的共同好友是谁?
zsetzset(sorted set)类型和set类型基本是一致的,不同的是zset这种类型会给每个元素关联一个****double****类型的分数(score),这样就可以为成员排序,并且插入是有序的。这种数据类型如果使用的话主要用来统计商品的销售排行榜,比如:items:sellsort 10 1001 20 1002 这个代表编号是1001的商品销售数量为10,编号为1002的商品销售数量为20/附件的人

1.2 单线程的redis为什么读写速度快?

  1. 纯内存操作

  2. 单线程操作,避免了频繁的上下文切换

  3. 采用了非阻塞I/O多路复用机制

1.3 redis为什么是单线程的?

官方FAQ表示,因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了Redis利用队列技术将并发访问变为串行访问

1)绝大部分请求是纯粹的内存操作

2)采用单线程,避免了不必要的上下文切换和竞争条件

1.4 redis服务器的的内存是多大?

配置文件中设置redis内存的参数:maxmemory

该参数如果不设置或者设置为0,则redis默认的内存大小为:

32位下默认是3G

64位下不受限制

一般推荐Redis设置内存为最大物理内存的四分之三,也就是0.75

命令行设置config set maxmemory <内存大小,单位字节>,服务器重启失效

config get maxmemory获取当前内存大小

永久则需要设置maxmemory参数,maxmemory是bytes字节类型,注意转换

1.5 为什么Redis的操作是原子性的,怎么保证原子性的?

对于Redis而言,命令的原子性指的是:一个操作的不可以再分,操作要么执行,要么不执行。

Redis的操作之所以是原子性的,是因为Redis是单线程的。

Redis本身提供的所有API都是原子操作,Redis中的事务其实是要保证批量操作的原子性。

多个命令在并发中也是原子性的吗?

不一定, 将get和set改成单命令操作,incr 。使用Redis的事务,或者使用Redis+Lua==的方式实现.

1.6 你还用过其他的缓存吗?这些缓存有什么区别?都在什么场景下去用?

对于缓存了解过redis和memcache,redis我们在项目中用的比较多,memcache没用过,但是了解过一点;

Memcache和redis的区别:

比较项reidsmemcache
存储方式redis可以持久化其数据Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小
数据支持支持丰富的数据类型,提供list,set,zset,hash等数据结构的存储memcached所有的值均是简单的字符串
底层模型Redis直接自己构建了VM 机制
value值大小Redis 最大可以达到 512Mvalue 不能超过 1M 字节
速度Redis 采用单线程模式处理请求。这样做的原因有 2 个:一个是因为采用了非阻塞的异步事件处理机制;另一个是缓存数据都是内存操作 IO 时间不会太长,单线程可以避免线程上下文切换产生的代价MC 处理请求时使用多线程异步 IO 的方式,可以合理利用 CPU 多核的优势,性能非常优秀
数据备份Redis支持数据的备份,即master-slave模式的数据备份,能够提供高可用服务当容量存满时,会对缓存中的数据进行剔除,剔除时除了会对过期 key 进行清理,还会按 LRU 策略对数据进行剔除。
应用场景适用于对读写效率要求高、数据处理业务复杂、安全性要求较高的系统适合多读少写,大数据量的情况(一些官网的文章信息等)

1.7 Redis在你们项目中是怎么用的?

【答案解析】

(1)门户(首页)系统中的首页内容信息的展示。(商品类目、广告、热门商品等信息)门户系统的首页是用户访问量最大的,而且这些数据一般不会经常修改,因此为了提高用户的体验,我们选择将这些内容放在缓存中;

(2)单点登录系统中也用到了redis。因为我们是分布式系统,存在session之间的共享问题,因此在做单点登录的时候,我们利用redis来模拟了session的共享,来存储用户的信息,实现不同系统的session共享;

(3)我们项目中同时也将购物车的信息设计存储在redis中,购物车在数据库中没有对应的表,用户登录之后将商品添加到购物车后存储到redis中,key是用户id,value是购物车对象;

(4)因为针对评论这块,我们需要一个商品对应多个用户评论,并且按照时间顺序显示评论,为了提高查询效率,因此我们选择了redis的list类型将商品评论放在缓存中;

(5)在统计模块中,我们有个功能是做商品销售的排行榜,因此选择redis的zset结构来实现;

还有一些其他的应用场景,主要就是用来作为缓存使用。

1.8 对redis的持久化了解不?

Redis是内存型数据库,同时它也可以持久化到硬盘中,redis的持久化方式有两种:

(1)RDB(半持久化方式):

按照配置不定期的通过异步的方式、快照的形式直接把内存中的数据持久化到磁盘的一个dump.rdb文件(二进制文件)中;

这种方式是redis默认的持久化方式,它在配置文件(redis.conf)中的格式是:save N M,表示的是在N秒之内发生M次修改,则redis抓快照到磁盘中;

原理:当redis需要持久化的时候,redis会fork一个子进程,这个子进程会将数据写到一个临时文件中;当子进程完成写临时文件后,会将原来的.rdb文件替换掉,这样的好处是写时拷贝技术(copy-on-write),可以参考下面的流程图;

在这里插入图片描述

优点:只包含一个文件,对于文件备份、灾难恢复而言,比较实用。因为我们可以轻松的将一个单独的文件转移到其他存储媒介上;性能最大化,因为对于这种半持久化方式,使用的是写时拷贝技术,可以极大的避免服务进程执行IO操作;相对于AOF来说,如果数据集很大,RDB的启动效率就会很高

缺点:如果想保证数据的高可用(最大限度的包装数据丢失),那么RDB这种半持久化方式不是一个很好的选择,因为系统一旦在持久化策略之前出现宕机现象,此前没有来得及持久化的数据将会产生丢失;rdb是通过fork进程来协助完成持久化的,因此当数据集较大的时候,我们就需要等待服务器停止几百毫秒甚至一秒;

(2)AOF(全持久化的方式)

把每一次数据变化都通过write()函数将你所执行的命令追加到一个appendonly.aof文件里面;

Redis默认是不支持这种全持久化方式的,需要将no改成yes在这里插入图片描述

实现文件刷新的三种方式:

在这里插入图片描述

no:不会自动同步到磁盘上,需要依靠OS(操作系统)进行刷新,效率快,但是安全性就比较差;

always:每提交一个命令都调用fsync刷新到aof文件,非常慢,但是安全;

everysec:每秒钟都调用fsync刷新到aof文件中,很快,但是可能丢失一秒内的数据,推荐使用,兼顾了速度和安全;

原理:redis需要持久化的时候,fork出一个子进程,子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令;父进程会继续处理客户端的请求,除了把写命令写到原来的aof中,同时把收到的写命令缓存起来,这样包装如果子进程重写失败的话不会出问题;当子进程把快照内容以命令方式写入临时文件中后,子进程会发送信号给父进程,父进程会把缓存的写命令写入到临时文件中;接下来父进程可以使用临时的aof文件替换原来的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中追加。下面的图为最简单的方式,其实也是利用写时复制原则。

在这里插入图片描述

优点:

数据安全性高

该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机问题,也不会破坏日志文件中已经存在的内容;

缺点:

对于数量相同的数据集来说,aof文件通常要比rdb文件大,因此rdb在恢复大数据集时的速度大于AOF;

根据同步策略的不同,AOF在运行效率上往往慢于RDB,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效;

针对以上两种不同的持久化方式,如果缓存数据安全性要求比较高的话,用aof这种持久化方式(比如项目中的购物车);如果对于大数据集要求效率高的话,就可以使用默认的。而且这两种持久化方式可以同时使用。

1.9 redis的过期策略以及内存淘汰机制有了解过吗

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

为什么不用定时删除策略?

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

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

定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。

于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。

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

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

在redis.conf中有一行配置

maxmemory-policy volatile-lru

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

volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

no-enviction(驱逐):禁止驱逐数据,新写入操作会报错

ps:如果没有设置 expire 的key, 不满足先决条件(prerequisites); 那么 volatile-lru, volatile-random 和 volatile-ttl 策略的行为, 和 noeviction(不删除) 基本上一致。

1.10 做过redis的集群吗?你们做集群的时候搭建了几台,都是怎么搭建的?

针对这类问题,我们首先考虑的是为什么要搭建集群?(这个需要针对我们的项目来说)

Redis的数据是存放在内存中的,这就意味着redis不适合存储大数据,大数据存储一般公司常用hadoop中的Hbase或者MogoDB。因此redis主要用来处理高并发的,用我们的项目来说,电商项目如果并发大的话,一台单独的redis是不能足够支持我们的并发,这就需要我们扩展多台设备协同合作,即用到集群。

Redis搭建集群的方式有多种,例如:客户端分片、Twemproxy、Codis等,但是redis3.0之后就支持redis-cluster集群,这种方式采用的是无中心结构,每个节点保存数据和整个集群的状态,每个节点都和其他所有节点连接。如果使用的话就用redis-cluster集群。

集群这块直接说是公司运维搭建的,小公司的话也有可能由我们自己搭建,开发环境我们也可以直接用单机版的。但是可以了解一下redis的集群版。搭建redis集群的时候,对于用到多少台服务器,每家公司都不一样,大家针对自己项目的大小去衡量。举个简单的例子:

我们项目中redis集群主要搭建了6台,3主(为了保证redis的投票机制)3从(

【扩展】高可用),每个主服务器都有一个从服务器,作为备份机。

1、架构图如下:

在这里插入图片描述

(1)所有的节点都通过PING-PONG机制彼此互相连接;

(2)每个节点的fail是通过集群中超过半数的节点检测失效时才生效;

(3)客户端与redis集群连接,只需要连接集群中的任何一个节点即可;

(4)Redis-cluster把所有的物理节点映射到【0-16383】slot上,负责维护

2、容错机制(投票机制)

(1)选举过程是集群中的所有master都参与,如果半数以上master节点与故障节点连接超过时间,则认为该节点故障,自动会触发故障转移操作;

(2)集群不可用?

a:如果集群任意master挂掉,并且当前的master没有slave,集群就会fail;

b:如果集群超过半数以上master挂掉,无论是否有slave,整个集群都会fail;

1.11 说说Redis哈希槽的概念?

Redis集群没有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384个哈希槽,每个key通 过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。

1.12 redis有事务吗?

Redis是有事务的,redis中的事务是一组命令的集合,这组命令要么都执行,要不都不执行,redis事务的实现,需要用到MULTI(事务的开始)和EXEC(事务的结束)命令 ;

在这里插入图片描述

当输入MULTI命令后,服务器返回OK表示事务开始成功,然后依次输入需要在本次事务中执行的所有命令,每次输入一个命令服务器并不会马上执行,而是返回”QUEUED”,这表示命令已经被服务器接受并且暂时保存起来,最后输入EXEC命令后,本次事务中的所有命令才会被依次执行,可以看到最后服务器一次性返回了两个OK,这里返回的结果与发送的命令是按顺序一一对应的,这说明这次事务中的命令全都执行成功了。

Redis的事务除了保证所有命令要不全部执行,要不全部不执行外,还能保证一个事务中的命令依次执行而不被其他命令插入。同时,redis的事务是不支持回滚操作的。

【扩展】

Redis的事务中存在一个问题,如果一个事务中的B命令依赖上一个命令A怎么办?

这会涉及到redis中的WATCH命令:可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令(事务中的命令是在EXEC之后才执行的,EXEC命令执行完之后被监控的键会自动被UNWATCH)。

应用场景:待定

1.13 是否了解过redis的安全机制?

1、redis的安全机制(你们公司redis的安全这方面怎么考虑的?)

漏洞介绍:redis默认情况下,会绑定在bind 0.0.0.0:6379,这样就会将redis的服务暴露到公网上,如果在没有开启认证的情况下,可以导致任意用户在访问目标服务器的情况下未授权访问redis以及读取redis的数据,攻击者就可以在未授权访问redis的情况下可以利用redis的相关方法,成功在redis服务器上写入公钥,进而可以直接使用私钥进行直接登录目标主机;

比如:可以使用FLUSHALL方法,整个redis数据库将被清空

解决方案:

(1)禁止一些高危命令。修改redis.conf文件,用来禁止远程修改DB文件地址,比如 rename-command FLUSHALL “” 、rename-command CONFIG"" 、rename-command EVAL “”等;

(2)以低权限运行redis服务。为redis服务创建单独的用户和根目录,并且配置禁止登录;

(3)为redis添加密码验证。修改redis.conf文件,添加

requirepass mypassword;

(4)禁止外网访问redis。修改redis.conf文件,添加或修改 bind 127.0.0.1,使得redis服务只在当前主机使用;

(5)做log监控,及时发现攻击;

(6)服务器不安装

1.14 你对redis的哨兵机制了解多少?

哨兵机制:

监控:监控主数据库和从数据库是否正常运行;

提醒:当被监控的某个redis出现问题的时候,哨兵可以通过API向管理员或者其他应用程序发送通知;

自动故障迁移:主数据库出现故障时,可以自动将从数据库转化为主数据库,实现自动切换;

具体的配置步骤面试中可以说参考的网上的文档。要注意的是,如果master主服务器设置了密码,记得在哨兵的配置文件(sentinel.conf)里面配置访问密码

1.15 redis缓存与mysql数据库之间的数据一致性问题?

不管先保存到MySQL,还是先保存到Redis都面临着一个保存成功而另外一个保存失败的情况。

不管是先写MySQL数据库,再删除Redis缓存;还是先删除缓存,再写库,都有可能出现数据不一致的情况。举一个例子:

1.如果删除了缓存Redis,还没有来得及写库MySQL,另一个线程就来读取,发现缓存为空,则去数据库中读取数据写入缓存,此时缓存中为脏数据。

2.如果先写了库,在删除缓存前,写库的线程宕机了,没有删除掉缓存,则也会出现数据不一致情况。

因为写和读是并发的,没法保证顺序,就会出现缓存和数据库的数据不一致的问题。

解决:

基于mysql的binlog日志(canal)
消息队列(双删)

1.16 什么是redis的缓存穿透?如何防止穿透?

缓存穿透是指查询一个不存在的数据,由于缓存无法命中,将去查询数据库,但是数据库也无此记录,并且出于容错考虑,我们没有将这次查询的null写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。

解决:空结果也进行缓存,但它的过期时间会很短,最长不超过五分钟。

1.17 什么是redis的缓存雪崩?如何防止?

缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。

解决:原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

1.18 什么是redis的缓存击穿?如何防止?

缓存击穿是指对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:如果这个key在大量请求同时进来之前正好失效,那么所有对这个key的数据查询都落到db,我们称为缓存击穿。

与缓存雪崩的区别:

  1. 击穿是一个热点key失效

  2. 雪崩是很多key集体失效

解决:锁

在这里插入图片描述

1.19 redis中对于生存时间的应用

Redis中可以使用expire命令设置一个键的生存时间,到时间后redis会自动删除;

应用场景:

(1)设置限制的优惠活动的信息;

(2)一些及时需要更新的数据,积分排行榜;

(3)手机验证码的时间;

(4)限制网站访客访问频率;

2. MQ消息队列(忽略!!!)

2.1 为什么使用rabbitmq?

削峰填谷、异步、解耦合

消息类型较多:五种(simple、work、fanout、direct、topic)

对比只允许基于JAVA实现的消息平台的之间进行通信的JMS,AMQP(rabbitmq)允许多种消息协议进行通信)

2.2 如何保证消息的可靠性传输/如何处理消息丢失问题?

考虑维度分析
生产者原因:网络中断解决1:可以使用rabbitmq提供的事务功能 就是生产者发送数据之前开启rabbitmq事务(channel.txSelect),然后发送消息,如果消息没有成功被rabbitmq接收到,那么生产者会收到异常报错,此时就可以回滚事务(channel.txRollback),然后重试发送消息;如果收到了消息,那么可以提交事务(channel.txCommit)此方法会严重降低系统的吞吐量,性能消耗太大解决2:生产者开发confirm模式之后 你每次写的消息都会分配一个唯一的id,然后如果写入了rabbitmq中,rabbitmq会给你回传一个ack消息,告诉你说这个消息ok了。如果rabbitmq没能处理这个消息,会回调你一个nack接口,告诉你这个消息接收失败,你可以重试。而且你可以结合这个机制自己在内存里维护每个消息id的状态,如果超过一定时间还没接收到这个消息的回调,那么你可以重发。
rabbitMQ本身原因:MQ宕机解决:开启rabbitmq的持久化 就是消息写入之后会持久化到磁盘,哪怕是rabbitmq自己挂了, 恢复之后会自动读取之前存储的数据,一般数据不会丢。除非极其罕见的是,rabbitmq还没持久化,自己就挂了,可能导致少量数据会丢失的,但是这个概率较小。设置持久化有两个步骤,第一个是创建queue的时候将其设置为持久化的,这样就可以保证rabbitmq持久化queue的元数据,但是不会持久化queue里的数据;第二个是发送消息的时候将消息的deliveryMode设置为2,就是将消息设置为持久化的,此时rabbitmq就会将消息持久化到磁盘上去。必须要同时设置这两个持久化才行,rabbitmq哪怕是挂了,再次重启,也会从磁盘上重启恢复queue,恢复这个queue里的数据。而且持久化可以跟生产者那边的confirm机制配合起来,只有消息被持久化到磁盘之后,才会通知生产者ack了,所以哪怕是在持久化到磁盘之前,rabbitmq挂了,数据丢了,生产者收不到ack,你也是可以自己重发的。
消费者原因:刚消费到,还没处理,结果进程就挂了解决: 用rabbitmq提供的ack机制,简单来说,就是你关闭rabbitmq自动ack,可以通过一个api来调用就行,然后每次你自己代码里确保处理完的时候,再程序里ack一把。这样的话,如果你还没处理完,不就没有ack?那rabbitmq就认为你还没处理完,这个时候rabbitmq会把这个消费分配给别的consumer去处理,消息是不会丢的。

2.3 如何保证消息不被重复消费?

这个很常见的一个问题,2.1和2.2两个问题基本可以连起来问。

既然是消费消息,那肯定要考虑考虑会不会重复消费?能不能避免重复消费?或者重复消费了也别造成系统异常可以吗?这个是MQ领域的基本问题,其实本质上还是问你使用消息队列如何保证幂等性,这个是你架构里要考虑的一个问题。

一般情况下,任何一种消息队列中间件都会出现消息的重复消费问题,因为这个问题不是mq能够保证的,需要程序员结合实际业务场景来控制的,所以回答这个问题最好是结合实际业务场景阐述

在这里插入图片描述

(1)数据要写库操作,最好先根据主键查一下,如果这数据都有了,就不再执行insert操作,可以update

(2)写入redis,redis的set操作天然幂等性

(3)你需要让生产者发送每条数据的时候,里面加一个全局唯一的id,类似订单id之类的东西,然后你这里消费到了之后,先根据这个id去比如redis里查一下,之前消费过吗?如果没有消费过,你就处理,然后这个id写redis。如果消费过了,那你就别处理了,保证别重复处理相同的消息即可。(防止订单重复提交)

2.4 消息积压问题

如何解决消息队列的延时以及过期失效问题?消息队列满了之后该如何处理?有几百万的消息持续积压几小时,说说如何解决?

方案分析

该问题,其本质针对的场景,都是说,可能你的消费端出了问题,不消费了,或者消费的极其极其慢。另外还有可能你的消息队列集群的磁盘都快写满了,都没人消费,这个时候怎么办?或者是整个这就积压了几个小时,你这个时候怎么办?或者是你积压的时间太长了,导致比如rabbitmq设置了消息过期时间后就没了怎么办?

所以这种问题线上常见的,一般不出,一出就是大问题,一般常见于,举个例子,消费端每次消费之后要写mysql,结果mysql挂了,消费端挂掉了。导致消费速度极其慢。

分析1+话术

这个是我们真实遇到过的一个场景,确实是线上故障了,这个时候要不然就是修复consumer的问题,让他恢复消费速度,然后傻傻的等待几个小时消费完毕。(可行,但是不建议 在面试的时候说)

一个消费者一秒是1000条,一秒3个消费者是3000条,一分钟是18万条,1000多万条

所以如果你积压了几百万到上千万的数据,即使消费者恢复了,也需要大概1小时的时间才能恢复过来

一般这个时候,只能操作临时紧急扩容了,具体操作步骤和思路如下:

1)先修复consumer的问题,确保其恢复消费速度,然后将现有cnosumer都停掉

2)新建一个topic,partition是原来的10倍,临时建立好原先10倍或者20倍的queue数量

3)然后写一个临时的分发数据的consumer程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的10倍数量的queue

4)接着临时征用10倍的机器来部署consumer,每一批consumer消费一个临时queue的数据

5)这种做法相当于是临时将queue资源和consumer资源扩大10倍,以正常的10倍速度来消费数据

6)等快速消费完积压数据之后,得恢复原先部署架构,重新用原先的consumer机器来消费消息

分析2+话术

rabbitmq是可以设置过期时间的,就是TTL,如果消息在queue中积压超过一定的时间就会被rabbitmq给清理掉,这个数据就没了。那这就是第二个坑了。这就不是说数据会大量积压在mq里,而是大量的数据会直接搞丢。

这个情况下,就不是说要增加consumer消费积压的消息,因为实际上没啥积压,而是丢了大量的消息。我们可以采取一个方案,就是批量重导,这个我们之前线上也有类似的场景干过。就是大量积压的时候,我们当时就直接丢弃数据了,然后等过了高峰期以后,比如大家一起喝咖啡熬夜到晚上12点以后,用户都睡觉了。

这个时候我们就开始写程序,将丢失的那批数据,写个临时程序,一点一点的查出来,然后重新灌入mq里面去,把白天丢的数据给他补回来。也只能是这样了。

假设1万个订单积压在mq里面,没有处理,其中1000个订单都丢了,你只能手动写程序把那1000个订单给查出来,手动发到mq里去再补一次

分析3+话术

如果走的方式是消息积压在mq里,那么如果你很长时间都没处理掉,此时导致mq都快写满了,咋办?这个还有别的办法吗?没有,谁让你第一个方案执行的太慢了,你临时写程序,接入数据来消费,消费一个丢弃一个,都不要了,快速消费掉所有的消息。然后走第二个方案,到了晚上再补数据吧。

2.5 消息在什么时候会变成Dead Letter(死信)?

声明队列的时候,指定一个Dead Letter Exchange,来实现Dead Letter的转发。

队列中的消息出现以下情况会变成DL:

1.消息被拒绝并且没有设置重新入队:(NACK || Reject)&&requeue == false

2.消息过期(消息或者队列的TTL设置)

3.消息堆积,并且队列达到最大长度,先入队的消息会变成DL。

rabbitmq消息队列的长度或者大小配置:
可以通过为队列声明参数 x-max-length 提供一个非负整数值来设置最大消息数。
可以通过为队列声明参数 x-max-length-bytes 提供一个非负整数值,设置最大字节长度。
如果设置了两个参数,那么两个参数都将适用;无论先达到哪个限制,都将强制执行。
  • 1
  • 2
  • 3
  • 4

2.6 RabbitMQ如何实现延时队列?

利用TTL(队列的消息存活时间或消息的存活时间),加上死信交换机。

队列中的消息过期时会被丢到绑定的死信队列。

3. kafka

3.1 消息队列的作用

异步处理
用户注册后,需要发注册邮件和注册短信。传统的串行方式会等所有业务执行完成后再返回结果。并行方式将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信,可以加快响应速度。

应用解耦
利用消息队列存储消息,需要消费消息的系统只需要订阅消息队列即可,有新的业务加入时无需修改原本的代码。

流量削锋
高并发请求同时对数据库执行写操作,可能会导致数据库卡死导致宕机。将请求消息保存到消息队列,系统可以按照自己的能力来消费消息。

3.2 Kafka的主要组件

  • Broker:Kafka集群中的单个服务器节点,负责数据存储和处理。

  • Topic:消息发布的类别或者主题。

  • Partition:每个Topic被划分为多个不同的分区,分区内的数据有序。

  • Producer:生产者,负责向Kafka的Topic发送消息。

  • Consumer:消费者,负责从Kafka的Topic接收和处理消息。

  • Consumer Group:一组消费者的集合,用于实现消费者的负载均衡和故障转移。

  • ZooKeeper:Kafka使用ZooKeeper来进行集群管理、协调和元数据存储。

3.3 Kafka如何保证消息可靠性(消息不丢失)

  • 持久化:Kafka将消息持久化到磁盘上,以保证即使在发生故障时也不会丢失。

  • 复制:Kafka允许将消息分布到多个Broker上的副本。当一个Broker故障或不可用时,其他副本仍然可以使用。

  • 批量发送:Kafka允许消息在一批中发送,在网络传输中可以降低开销,提高效率。

  • 确认机制:Kafka通过Producer的确认机制保证消息的可靠传递。Producer可以选择等待Broker的确认,以确保消息成功写入。

3.4 Kafka为什么要分区,都有哪些分区策略?

分区为了提供负载均衡的能力,实现系统的高伸缩性。分区策略是决定生产者将消息发送到哪个分区的算法,避免造成数据“倾斜”

Kafka提供了默认的分区策略,同时也支持自定义的分区策略

  • 默认分区策略:如果指定了 Key,那么默认实现按消息键保序策略;如果没有指定 Key,则使用轮询策略。

  • 自定义分区策略(限制配置生产者端的参数 partitioner.class,编写一个具体的类实现org.apache.Kafka.clients.producer.Partitioner接口):

    轮询策略(Round-robin)

    随机策略(Randomness)

    按消息键保序策略(Key-ordering):保证同一个 Key 的所有消息都进入到相同的分区里

3.5 Kafka消费者的幂等性如何保证

幂等简单点讲,就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会产生任何副作用。

在一些特殊情况下(如网络不稳定),生产者可能重复发送消息,消费者也可能会重复消费消息。

解决方案:

  • 生产者发送消息时添加唯一标识符
  • 消费者获取消息时通过消息唯一标识符判断是否消费过消息(可利用redis缓存)

3.6 Kafka如何保证消息有序性

生产有序性

Kafka 最多只保证单分区内的消息是有序的,所以如果要保证业务全局严格有序,就要设置 Topic 为单分区。通过指定key将消息发送到同一个分区。
kafka默认开启幂等性,服务端会缓存producer发来的最近5个request的元数据,故无论如何,都可以保证最近5个request的数据都是有序的。

消费有序性

不要使用多线程消费,它会破坏有序性

消费者手动同步提交ACK,确保消息一条一条的被消费

3.7 Kafka如何避免消息堆积

  • 增加消费者数量及分区数量:两者数量相等。

  • 消费者中使用多线程消费。

  • 增加批量接收消息的大小, 减少网络IO次数。

  • 消费者选择自动提交,但是可能会导致消息丢失。

  • 提升物理硬件性能。

3.8 为什么使用Kafka

  • 分区机制:消息会被发送到不同分区中,由不同消费者组进行消费。

  • 顺序写

  • 批量发送

  • 批量接收

  • 消息压缩:提高消息吞吐量

4. SpringBoot+SpringCloud

4.1 为什么要用 Spring Boot?

Spring Boot的优点

独立运行

Spring Boot而且内嵌了各种servlet容器,Tomcat、Jetty等,现在不再需要打成war包部署到容器中,Spring Boot只要打成一个可执行的jar包就能独立运行,所有的依赖包都在一个jar包内。

简化配置

spring-boot-starter-web启动器自动依赖其他组件,简少了maven的配置。除此之外,还提供了各种启动器,开发者能快速上手。

自动配置

Spring Boot能根据当前类路径下的类、jar包来自动配置bean,如添加一个spring-boot-starter-web启动器就能拥有web的功能,无需其他配置。

无代码生成和XML配置

Spring Boot配置过程中无代码生成,也无需XML配置文件就能完成所有配置工作,这一切都是借助于条件注解完成的,这也是Spring4.x的核心功能之一。

应用监控

Spring Boot提供一系列端点可以监控服务及应用,做健康检测。

4.2 Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?

启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:

@SpringBootConfiguration:

组合了 @Configuration 注解,实现配置文件的功能。

@EnableAutoConfiguration:

打开自动配置的功能,也可以关闭某个自动配置的选项

如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })

@ComponentScan:

Spring组件扫描。

4.3 Spring Boot 自动配置原理是什么?

启动类上的注解@SpringBootApplication是一个组合注解,组成它的@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个注解比较重要

@EnableAutoConfiguration注解

开启自动配置,对jar包下的spring.factories文件进行扫描,这个文件中包含了可以进行自动配置的类,当满足@Condition注解指定的条件时,便在依赖的支持下进行实例化,注册到Spring容器中。

4.4 你如何理解 Spring Boot 中的 Starters?

Starters可以理解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成 Spring 及其他技术,而不需要到处找示例代码和依赖包。如你想使用 Spring JPA 访问数据库,只要加入 spring-boot-starter-data-jpa 启动器,相关依赖就可以引入到项目中了。

4.5 Spring Boot、Spring 和Spring Cloud什么关系

SpringBoot底层就是Spring,简化使用Spring的方式而已,多加了好多的自动配置

Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务

Spring Cloud是一个基于Spring Boot实现的开发工具;

Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;

Spring Boot使用了默认大于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置

Spring Cloud很大的一部分是基于Spring Boot来实现,必须基于Spring Boot开发。

4.6 Ribbon和Feign的区别?

Ribbon

Ribbon 是 Netflix开源的基于HTTP和TCP等协议负载均衡组件
Ribbon 可以用来做客户端负载均衡,调用注册中心的服务
Ribbon的使用需要代码里手动调用目标服务
  • 1
  • 2
  • 3

Feign

Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端。
Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。
Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。
Feign本身不支持Spring MVC的注解,它有一套自己的注解。
  • 1
  • 2
  • 3
  • 4

OpenFeign

OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解,如@RequesMapping等等。
OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
  • 1
  • 2

4.7 LoadBalancer/Ribbon负载均衡能干嘛?

LB(负载均衡LB,即负载均衡(Load Balance),在微服务或分布式集群中经常用的一种应用。负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA。

Ribbon/LoadBalancer属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。

4.8 你所知道的微服务技术栈有哪些?请列举一二

服务注册与发现:Eureka、Nacos、Consul、Zookeeper等

服务调用:Rest(Openfeign)、RPC、gRPC

服务熔断器: Hystrix、Sentinel、Envoy等

负载均衡:Ribbon、Openfeign、Nginx等

消息队列:Kafka、RabbitMQ、ActiveMQ等

服务配置中心管理:SpringCloudConfig、Nacos、Apollo等

服务路由(API网关):Gateway、Zuul等

分布式链路追踪:zipkin+Sleuth 、skywalking等

4.7 Nacos

4.7.1 什么是Nacos,主要用来作什么?

Nacos是一个开源的分布式服务注册和配置中心。它提供了服务注册、发现、配置和管理的能力,可以帮助开发者构建和管理微服务架构。

主要功能包括:

  1. 服务注册与发现:Nacos充当了服务注册中心的角色,服务提供者通过向Nacos注册自己的服务,使得服务消费者能够方便地发现和调用服务。

  2. 动态配置管理:Nacos提供了统一的配置管理功能,可以集中管理应用程序的配置信息。它支持动态刷新配置,可以在运行时动态修改应用程序的配置,而无需重启应用。

  3. 服务路由与负载均衡:Nacos可以根据服务的健康状况和负载情况,动态地进行服务路由和负载均衡,以提供更好的服务质量和可用性。

  4. 服务共享与版本管理:Nacos支持多租户的服务共享,不同的租户可以共享同一个服务。同时,Nacos还提供了版本管理功能,可以管理不同版本的服务。

  5. 服务监控与治理:Nacos提供了服务的健康检查和监控功能,可以实时监控服务的状态和性能指标。此外,Nacos还提供了服务熔断、限流等治理能力,以提高系统的稳定性和可靠性。

4.7.2 Nacos是AP的还是CP的?

Nacos是一个AP(可用性和分区容忍性)的系统。在分布式系统中,CAP定理指出,一个系统无法同时满足一致性(Consistency)、可用性(Availability)和分区容忍性(Partition tolerance)这三个特性。Nacos选择了AP模型,即在面对网络分区时,为了保证系统的可用性和分区容忍性,它牺牲了一致性。这意味着在网络分区的情况下,Nacos可能会出现数据的不一致性,但它能够保证服务的可用性和高效性。对于服务注册发现、配置管理等功能,Nacos提供了强大的可用性和灵活性,使得开发者能够便捷地构建和管理分布式系统。然而,在某些特定情况下,如果一致性是系统中最重要的特性,那么可能需要考虑选择其他CP模型的系统。

4.8 Spring Cloud Alibaba断路器Sentinel的作用是什么?

Spring Cloud Alibaba 中的断路器组件 Sentinel 主要用于保护和控制微服务的稳定性和可靠性。下面是 Sentinel 的主要作用:

  1. 流量控制:Sentinel 可以通过流量控制功能限制微服务的请求量,防止系统因过高的请求负载而崩溃或响应变慢。它通过实时监控和统计请求的 QPS(每秒钟的请求数量)、线程数、响应时间等指标,根据预先设置的规则,对请求进行限流,保证服务在承受范围内的正常运行。

  2. 熔断降级:当微服务出现故障或不可用时,Sentinel 可以自动地将请求快速熔断,避免故障的传播,从而减少对其他服务的影响。通过设置熔断规则,当服务调用失败或超时达到一定阈值时,Sentinel 可以自动触发熔断,进入预设的降级逻辑,比如返回默认值或执行备选逻辑,以保证系统的可用性。

  3. 服务监控:Sentinel 提供实时的监控和统计功能,可以对微服务的请求流量、各项指标进行实时监控和报警。通过控制台或仪表盘,开发者可以实时查看和分析系统的运行状况,了解请求的分布、成功率、响应时间等关键指标,帮助定位问题,进行性能优化和故障排查。

通过流量控制、熔断降级和服务监控,Sentinel 能够帮助开发者保护和控制微服务的稳定性和可靠性。它可以有效地防止潜在的请求过载、服务雪崩等问题,提高系统的容错能力和稳定性,同时也为开发者提供了实时监控和报警的能力,帮助快速定位和解决问题,保障微服务架构的可用性和性能。

4.9 什么是服务熔断?什么是服务降级?

在复杂的分布式系统中,微服务之间的相互呼叫可能会导致服务堵塞的各种原因。在高并发场景下,服务堵塞意味着线程堵塞,导致当前线程不可用,服务器线程全部堵塞,导致服务器崩溃。由于服务之间的呼叫关系是同步的,它将导致整个微服务系统的服务雪崩。为了解决微服务的调用响应时间过长或不可用,占用越来越多的系统资源,导致雪崩效应,需要进行服务熔断和服务降级。

所谓服务熔断,是指某个服务故障或异常在一起,类似于显示世界“保险丝”当异常情况被触发时,整个服务将被直接熔断,而不是等到服务加班。

服务熔断相当于我们电闸的保险丝,一旦发生服务雪崩,整个服务将被熔断。通过维护自己的线程池,当线程达到阈值时,将启动服务降级。如果其他请求继续访问,则直接返回fallback的默认值。

5. Mysql

5.1 MySQL多表连接有哪些方式?怎么用的?这些连接都有什么区别?

连接方式:左连接、右连接、内连接

使用方法:

左连接:select * from A LEFT JOIN B on A.id=B.id;

右连接:select * from A RIGHT JOIN B on A.id=B.id;

内连接:select * from A inner join B on a.xx=b.xx;(其中inner可以省略)

区别:

Inner join 内连接,在两张表进行连接查询时,只保留两张表中完全匹配的结果集

left join 在两张表进行连接查询时,会返回左表所有的行,即使在右表中没有匹配的记录。

right join 在两张表进行连接查询时,会返回右表所有的行,即使在左表中没有匹配的记录。

5.2 说一下索引的优势和劣势?

优势:

唯一索引可以保证数据库表中每一行数据的唯一性索引可以加快数据查询速度,减少查询时间

劣势:

创建索引和维护索引要耗费时间索引需要占物理空间,除了数据表占用数据空间之外,每一个索引还要占用一定的物理空间给表中的数据进行增、删、改的时候,索引也要动态的维护。

5.3 MySQL聚簇和非聚簇索引的区别

都是B+树的数据结构

**聚簇索引:**将数据存储与索引放到了一块、并且是按照一定的顺序组织的,找到索引也就找到了数 据,数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是 相邻地存放在磁盘上的。

**非聚簇索引:**叶子节点不存储数据、存储的是数据行地址,也就是说根据索引查找到数据行的位置 再去磁盘查找数据,这个就有点类似一本树的目录,比如我们要找第三章第一节,那我们先在这个目录里面找,找到对应的页码后再去对应的页码看文章。

  • 优势:

    ​ 1、查询通过聚簇索引可以直接获取数据,相比非聚簇索引需要第二次查询(非覆盖索引的情况下)效率要高

    ​ 2、聚簇索引对于范围查询的效率很高,因为其数据是按照大小排列的。

    ​ 3、聚簇索引适合用在排序的场合,非聚簇索引不适合。

  • 劣势:

    ​ 1、维护索引很昂贵,特别是插入新行或者主键被更新导至要分页(page split)的时候。建议在大量插入新行后,选在负载较低的时间段,通过OPTIMIZE TABLE优化表,因为必须被移动的行数据可能造成碎片。使用独享表空间可以弱化碎片。

    ​ 2、表因为使用UUId(随机ID)作为主键,使数据存储稀疏,这就会出现聚簇索引有可能有比全表扫面更慢,所以建议使用int的auto_increment作为主键

    ​ 3、如果主键比较大的话,那辅助索引将会变的更大,因为辅助索引的叶子存储的是主键值;过长的主键值,会导致非叶子节点占用占用更多的物理空间。

InnoDB中一定有主键,主键一定是聚簇索引,不手动设置、则会使用unique索引,没有unique索引,则会使用数据库内部的一个行的隐藏id来当作主键索引。在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找,非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引,辅助索引叶子节点存储的不再是行的物理位置,而是主键值.

MyISAM使用的是非聚簇索引,没有聚簇索引,非聚簇索引的两棵B+树看上去没什么不同,节点的结构完全一致只是存储的内容不同而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。

如果涉及到大数据量的排序、全表扫描、count之类的操作的话,还是MyISAM占优势些,因为索引所占空间小,这些操作是需要在内存中完成的。

5.4 MySQL中B+树和B树的区别

1、非叶子节点数据不同:

​ B+树的非叶子节点的数据都在叶子节点中出现过,也就是叶子节点中的数据都在非叶子节点冗余一份。B树中非叶子节点中元素不会冗余。

​ B+树非叶子节点只存放指针,不存放数据,B树所有节点(叶子节点)都存放数据。

2、叶子节点数据不同:

​ B+树叶子节点存放数据,B树所有节点(非叶子节)点存放数据。数据遍布整个树结构。

3、时间复杂度不同:

​ 由于B+树的数据都存在叶子节点,因此B+树的时间复杂度固定为o(log n),而B树的数据分布在每个节点中,因此时间复杂度不固定,最好为o(1).

4、叶子节点连接不同:

​ B+树的叶子节点通过有序的双向链表相连,B树叶子节点不相连。

5、区间查询效率不同:

​ 因为第4点的原因,所以B+树去范围查询效率更快,而B树范围查询比较慢。

因此,存在大量范围查询的场景,适合使用B+树

而对大量单个key查询的场景,可以考虑B树

5.5 Mysql有哪些锁?

1、基于锁的属性分类:

共享锁、排他锁。

共享锁(Share Lock):

共享锁又称读锁,简称S锁;当一个事务为数据加上读锁之后,其他事务只能对该数据加读锁,而不能对数据加写锁,直到所有的读锁释放之后其他事务才能对其进行加持写锁。共享锁的特性主要是为了支持并发的读取数据,读取数据的时候不支持修改,避免出现重复读的问题。

排他锁(Exclusive Lock):

排他锁又称写锁,简称X锁;当一个事务为数据加上写锁时,其他请求将不能再为数据加任何锁,直到该锁释放之后,其他事务才能对数据进行加锁。排他锁的目的是在数据修改时候,不允许其他人同时修改,也不允许其他人读取。避免了出现脏数据和脏读的问题.

2、基于锁的粒度分类:

行级锁(INNODB)、表级锁(INNODB、MYISAM)、页级锁(BDB引擎 )、记录锁、间隙锁、临键锁。

表锁:

表锁是指上锁的时候锁住的是整个表,当下一个事务访问该表的时候,必须等前一个事务释放了锁才能进行对表进行访问; 特点: 粒度大,加锁简单,容易冲突

行锁:

行锁是指上锁的时候锁住的是表的某一行或多行记录,其他事务访问同一张表时,只有被锁住的记录不能访问,其他的记录可正常访问; 特点:粒度小,加锁比表锁麻烦,不容易冲突,相比表锁支持的并发要高。

记录锁(Record Lock)

记录锁也属于行锁中的一种,只不过记录锁的范围只是表中的某一条记录,记录锁是说事务在加锁后锁住的只是表的某一条记录。 精准条件命中,并且命中的条件字段是唯一索引 加了记录锁之后数据可以避免数据在查询的时候被修改的重复读问题,也避免了在修改的事务未提交前被其他事务读取的脏读问题。

页锁:

页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。 特点:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

间隙锁(Gap Lock)

属于行锁中的一种,间隙锁是在事务加锁后其锁住的是表记录的某一个区间,当表的相邻ID之间出现空隙则会形成一个区间,遵循左开右闭原则。 间隙锁只会出现在REPEATABLE_READ(可重复读)的事务级别中。 触发条件:防止幻读问题,事务并发的时候,如果没有间隙锁,就会发生如下图的问题,在同一个事务里,A事务的两次查询出的结果会不一样。 比如表里面的数据ID 为 1,4,5,7,10 ,那么会形成以下几个间隙区间,-n-1区间,1-4区间,5-7区间,7-10区间,10-n区间 (-n代表负无穷大,n代表正无穷大)。

临建锁(Next-Key Lock):

也属于行锁的一种,并且它是INNODB的行锁默认算法,总结来说它就是记录锁和间隙锁的组合,临键锁会把查询出来的记录锁住,同时也会把该范围查询内的所有间隙空间也会锁住。 触发条件:范围查询并命中,查询命中了索引。 结合记录锁和间隙锁的特性,临键锁避免了在范围查询时出现脏读、重复读、幻读问题。加了临键锁之后,在范围区间内数据不允许被修改和插入。

5.6 关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?

在业务系统中,除了使用主键进行的查询,其他的都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们。

慢查询的优化首先要搞明白慢的原因是什么?

​ 1、是查询条件没有命中索引?

​ 2、是load了不需要的数据列?

​ 3、还是数据量太大?

所以优化也是针对这三个方向来的:

​ 1、首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。

​ 2、分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引。

​ 3、如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。

5.7 MySQL事务的基本特性和隔离级别

事务基本特性ACID分别是:

  • **原子性:**指的是一个事务中的操作要么全部成功,要么全部失败。

  • **一致性:**指的是数据库总是从一个一致性的状态转换到另外一个一致性的状态。比如A转账给B100块钱,假设A只有90块,支付之前我们数据库里的数据都是符合约束的,但是如果事务执行成功了,我们的数据库数据就破坏约束了,因此事务不能成功,这里我们说事务提供了一致性的保证。

  • **隔离性:**指的是一个事务的修改在最终提交前,对其他事务是不可见的。

  • **持久性:**指的是一旦事务提交,所做的修改就会永久保存到数据库中。

事务并发问题:

  • **脏读(Drity Read):**某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。

  • **不可重复读(Non-repeatable read)

    声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/499849
推荐阅读
相关标签