JAVA高级工程师面试看这篇就够了--框架篇

1. MQ的应用场景

主要作用是:解耦、异步、削峰。
(1)解耦:
A 系统发送数据到 BCD 三个系统,通过接口调用发送。如果 E 系统也要这个数据呢?那如果 C 系统现在不需要了呢?A 系统负责人几乎崩溃…A 系统跟其它各种乱七八糟的系统严重耦合,A 系统产生一条比较关键的数据,很多系统都需要 A 系统将这个数据发送过来。如果使用 MQ,A 系统产生一条数据,发送到 MQ 里面去,哪个系统需要数据自己去 MQ 里面消费。如果新系统需要数据,直接从 MQ 里消费即可;如果某个系统不需要这条数据了,就取消对 MQ 消息的消费即可。这样下来,A 系统压根儿不需要去考虑要给谁发送数据,不需要维护这个代码,也不需要考虑人家是否调用成功、失败超时等情况。就是一个系统或者一个模块,调用了多个系统或者模块,互相之间的调用很复杂,维护起来很麻烦。

(2)异步:A 系统接收一个请求,需要在自己本地写库,还需要在 BCD 三个系统写库,自己本地写库要 3ms,BCD 三个系统分别写库要 300ms、450ms、200ms。最终请求总延时是 3 + 300 + 450 + 200 = 953ms,接近 1s,用户感觉搞个什么东西,慢死了慢死了。用户通过浏览器发起请求。如果使用 MQ,那么 A 系统连续发送 3 条消息到 MQ 队列中,假如耗时 5ms,A 系统从接受一个请求到返回响应给用户,总时长是 3 + 5 = 8ms。

(3)削峰:减少高峰时期对服务器压力。比如请求过来的后将数据推送到MQ中,由各个服务使用拉模式去定时拉取处理范围内的数据进行批量处理

2. MQ缺点

(1)系统可用性降低:系统引入的外部依赖越多,越容易挂掉。万一 MQ 挂了,MQ 一挂,整套系统崩溃,你不就完了?
(2)系统复杂度提高:硬生生加个 MQ 进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?问题一大堆。
(3)一致性问题:
A 系统处理完了直接返回成功了,人都以为你这个请求就成功了;
但是问题是,要是 BCD 三个系统那里,BD 两个系统写库成功了,结果 C 系统写库失败了,咋整?你这数据就不一致了。

3. Kafka、ActiveMQ、RabbitMQ、都有什么区别?

(1)对于吞吐量来说kafka支撑高吞吐,ActiveMQ和RabbitMQ比他们低一个数量级。对于延迟量来说RabbitMQ是最低的。
(2)ActiveMq 和RabbitMq 都支持持久化消息,持久化消息主要是指我们机器在不可抗力因素等情况下挂掉了,消息不会丢失的机制。
(3)综合技术实现
可靠性、灵活的路由、集群、事务、高可用的队列、消息排序、问题追踪、可视化管理工具、插件系统等等。RabbitMq / Kafka 最好,ActiveMq 次之
(4)高并发RabbitMQ 最高,原因是它的实现语言是天生具备高并发高可用的erlang 语言。

请求的到来,往往是没有规律的。
例如,某应用的处理能力是每秒 10 个请求。在某一秒,突然到来了 30 个请求,而接下来两秒,都没有请求到达。在这种情况下,如果直接拒绝 20 个请求,应用在接下来的两秒就会空闲。所以,需要把请求突刺均摊到一段时间内,让系统负载保持在请求处理水位之内,同时尽可能地处理更多请求,从而起到“削峰填谷”的效果。

4. MQ问题分析问答?

1、问:站点与服务,服务与服务上下游之间,一般如何通讯?
答:有两种常见的方式;一种是“直接调用”,通过RPC框架,上游直接调用下游:还有一种,在某些业务场景之下(具体哪些业务场景,见《到底什么时候该使用MQ?》),可以采用“MQ推送”,上游将消息发给MQ,MQ将消息推送给下游。
这两种都有问题:不管采用“直接调用”还是“MQ推送”,都有一个缺点,下游消息接收方无法控制到达自己的流量,如果调用方不限速,很有可能把下游压垮。

2、问:以上两种为什么会有流量冲击?
答:不管采用“直接调用”还是“MQ推送”,都有一个缺点,下游消息接收方无法控制到达自己的流量,如果调用方不限速,很有可能把下游压垮。
举个栗子,秒杀业务:
上游发起高并发的下单操作。
下游完成秒杀业务逻辑(库存检查,库存冻结,余额检查,余额冻结,订单生成,余额扣减,库存扣减,生成流水,余额解冻,库存解冻)。
上游下单业务简单,每秒发起了10000个请求,下游秒杀业务复杂,每秒只能处理2000个请求,很有可能上游不限速的下单,导致下游系统被压垮,引发雪崩。

3、问:MQ怎么改能缓冲流量?
答:由MQ-server推模式,升级为MQ-client拉模式。
MQ-client根据自己的处理能力,每隔一定时间,或者每次拉取若干条消息,实施流控,达到保护自身的效果。并且这是MQ提供的通用功能,无需上下游修改代码。

4、问:如果上游发送流量过大,MQ提供拉模式确实可以起到下游自我保护的作用,会不会导致消息在MQ中堆积?
答:下游MQ-client拉取消息,消息接收方能够批量获取消息,需要下游消息接收方进行优化,方能够提升整体吞吐量,例如:批量写。
结论:

1)MQ-client提供拉模式,定时或者批量拉取,可以起到削平流量,下游自我保护的作用(MQ需要做的)
2)要想提升整体吞吐量,需要下游优化,例如批量处理等方式(消息接收方需要做的)

5. 如果发生丢消息的时候怎么解决?

采用持久化订阅的方式,防止消息的丢失,PTP模式,持久化是不会丢失消息的。
同时还可以采用mq手动签到的方式,client真的接收到了消息,才签到,否则就不能签到,直接接收再签到。

6. 怎么保证MQ不会重复发送消息?

采用的是一张表来记录消息处理的状态,在处理MQ发送的消息的时候,我先查看一下这张表,是不是处理过相同的消息,如果发送过,就不在发送。

7. MQ重复消费的问题

  1. 首先产生mq重复消费的问题的原因
    1.1 首先假如生产者生产数据,生产的数据都有一个offset标号,代表这个数据消费的顺序的序号
    1.2 例如生产者生产了三条消息152,153,154,这时发送到mq,
    1.3 mq按照顺序将数据提交到消费者
    1.4 消费者是定时将消费的数据记录提交到zookeeper zk中记录了现在消费到第几条数据,告诉mq
    1.5 如果此时消费了152,153消费者重启了,那么记录没提交到zk,此时mq以为消费者才消费到151,还会重新提交152,153
    1.6 此时数据就出现了重复的问题,数据库就出现了脏数据

  2. 如何解决mq的重复消费问题
    2.1 重复消费的问题会导致数据库出现脏数据,我们一般通过保证幂等性来解决这个问题
    2.2 幂等性是什么。一次和多次请求某一个资源对于资源本身应该具有同样的结果。如何保证生产者重复消费数据保证幂等性
    2.3 有多种方式实现。最简单的在插入数据库的数据加个唯一健,这样你插入相同的数据的时候只会保错,不会出现脏数据
    2.4 在redis中存个id,每次操作数据之前查下id是否存在。存在的话就不做处理,不存在的话,我们就操作数据库。这样解决幂等性问题

8. mq消息的顺序是怎么进行保证的?

消息被发送的时候保持顺序
消息被存储的时候保持和发送的顺序的一致
消息被消费的时候保持和存储的消息顺序一致

9. 引入消息队列之后如何保证其高可用性?

(1)RabbitMQ的高可用性
RabbitMQ是比较有代表性的,因为是基于主从做高可用性的,我们就以他为例子讲解第一种MQ的高可用性怎么实现。rabbitmq有三种模式:单机模式,普通集群模式,镜像集群模式
(1.1) 单机模式:
就是demo级别的,一般就是你本地启动了玩玩儿的,没人生产用单机模式
(1.2)普通集群模式:
意思就是在多台机器上启动多个rabbitmq实例,每个机器启动一个。但是你创建的queue,只会放在一个rabbtimq实例上,但是每个实例都同步queue的元数据。完了你消费的时候,实际上如果连接到了另外一个实例,那么那个实例会从queue所在实例上拉取数据过来。
这种方式确实很麻烦,也不怎么好,没做到所谓的分布式,就是个普通集群。因为这导致你要么消费者每次随机连接一个实例然后拉取数据,要么固定连接那个queue所在实例消费数据,前者有数据拉取的开销,后者导致单实例性能瓶颈。
而且如果那个放queue的实例宕机了,会导致接下来其他实例就无法从那个实例拉取,如果你开启了消息持久化,让rabbitmq落地存储消息的话,消息不一定会丢,得等这个实例恢复了,然后才可以继续从这个queue拉取数据。
所以这个事儿就比较尴尬了,这就没有什么所谓的高可用性可言了,这方案主要是提高吞吐量的,就是说让集群中多个节点来服务某个queue的读写操作。

10. Mysql优化相关

  1. MYSQL优化主要分为以下四大方面:
    设计:存储引擎,字段类型,范式与逆范式
    功能:索引,缓存,分区分表。
    架构:主从复制,读写分离,负载均衡。
    合理SQL:测试,经验。
  2. MYSQL如何使用索引
    MySQL每次查询只使用一个索引。与其说是“数据库查询只能用到一个索引”,倒不如说,和全表扫描比起来,去分析两个索引B+树更加耗费时间。所以where A=a and B=b这种查询使用(A,B)的组合索引最佳,B+树根据(A,B)来排序。
    (1)主键,unique字段;
    (2)和其他表做连接的字段需要加索引;
    (3)在where里使用>,≥,=,<,≤,is null和between等字段;
    (4)使用不以通配符开始的like,where A like ‘China%’;
    (5)聚集函数MIN(),MAX()中的字段;
    (6)order by和group by字段;
  3. MYSQL什么情况下索引会失效
    (1)组合索引未使用最左前缀,例如组合索引(A,B),where B=b不会使用索引;
    (2)like未使用最左前缀,where A like ‘%China’;
    (3)搜索一个索引而在另一个索引上做order by,where A=a order by B,只使用A上的索引,因为查询只使用一个索引 ;
    (4)or会使索引失效。如果查询字段相同,也可以使用索引。例如where A=a1 or A=a2(生效),where A=a or B=b(失效)
    (5)如果列类型是字符串,要使用引号。例如where A=‘China’,否则索引失效(会进行类型转换);
    (6)在索引列上的操作,函数(upper()等)、or、!=(<>)、not in等;
  4. 使用explain语句分析SQL语句
    (1)通过EXPLAIN,我们可以分析出以下结果:
    表的读取顺序
    数据读取操作的操作类型
    哪些索引可以使用
    哪些索引被实际使用
    表之间的引用
    每张表有多少行被优化器查询
    (1)列解释:
    table:显示这一行的数据是关于哪张表的

11. Mysql优化相关方法内部,如何实现更好的异步?

答:我们知道异步其实就是让另一个线程去跑,那么如何创建线程? 第一种直接new Thread ,第二种new 一个实现Runnable接口的实现类。 第三种,通过线程池来管理创建等 ,这里说到更好的实现异步,那就是说我们在方法内部避免频繁的new 线程,就可以考虑线程池了。 那么线程池如何创建? 这里可以new 一个线程池,但是需要考虑单例,或者在程序初始启东时,就创建一个线程池,让他跑着,然后在具体方法的时候,通过线程池来创建线程,实现异步

12. 项目中为何要用缓存?如何理解nginx + tomcat + redis 集群缓存?

答1:最直接的表现就是减轻数据库的压力。避免因为数据读取频繁或过大而影响数据库性能,降低程序宕机的可能性

答2:nginx常用做静态内容服务和代理服务器,直面外来请求转发给后面的应用服务。nginx本身也能做缓存,比如静态页面的缓存什么的。而tomcat是应用服务器,处理JAVA WEB程序功能等等 。你也可以这么理解,假设把用户的请求当做是一条河流,那么nginx就相当于一个水利工程,tomcat相当于一条条分流的支流,而redis 相当于支流旁边的一个个水库。 当你洪水来了,nginx根据你每条支流的承受力度分发不同的水流量,在确保程序正常运行的情况下,分发给每条支流(tomcat)不同的水流量。而redis相当于一个个支流的水库,存储水源,降低压力,让后面的水量平稳。

13. 日常项目中,如果你接手,你准备从哪些方面调优?

答:这个呢首先是了解哪些需要优化,需要优化肯定是项目性能遭遇瓶颈或者猜测即将遭遇了,我们才会去考虑优化。那么怎么优化?

a、扩容 ,扩容的理解,就是扩充服务器并行处理的能力,简单来说就是加服务器,增加处理请求的能力,例如增加nginx 、tomcat等应用服务器的个数,或者物理服务器的个数,还有加大服务器带宽等等,这里考虑的是硬件方面

b、调优 ,调优,包括系统调优和代码调优 。 系统调优就是说加快处理速度,比如我们所提到的CDN、ehcache、redis等缓存技术,消息队列等等,加快服务间的响应速度,增加系统吞吐量,避免并发,至于代码调优,这些就需要多积累了,比如重构、工厂等, 数据库调优的话这个我不是很懂,只知道索引和存储过程,具体参考:Mysql数据库调优21个最佳实践 ,其他数据库调优方面就各位自己找找吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值