【工作经验分享】不会真有人觉得mybatis很难学吧

什么是自旋锁和互斥锁?

由于CLH锁是一种自旋锁,那么我们先来看看自旋锁是什么?

自旋锁说白了也是一种互斥锁,只不过没有抢到锁的线程会一直自旋等待锁的释放,处于busy-waiting的状态,此时等待锁的线程不会进入休眠状态,而是一直忙等待浪费CPU周期。因此自旋锁适用于锁占用时间短的场合。

这里谈到了自旋锁,那么我们也顺便说下互斥锁。这里的互斥锁说的是传统意义的互斥锁,就是多个线程并发竞争锁的时候,没有抢到锁的线程会进入休眠状态即sleep-waiting,当锁被释放的时候,处于休眠状态的一个线程会再次获取到锁。缺点就是这一些列过程需要线程切换,需要执行很多CPU指令,同样需要时间。如果CPU执行线程切换的时间比锁占用的时间还长,那么可能还不如使用自旋锁。因此互斥锁适用于锁占用时间长的场合。

1、为什么要使用消息队列?

分析:一个用消息队列的人,不知道为啥用,有点尴尬。没有复习这点,很容易被问蒙,然后就开始胡扯了。

回答:这个问题,咱只答三个最主要的应用场景(不可否认还有其他的,但是只答三个主要的),即以下六个字:解耦、异步、削峰

(1)解耦

传统模式:

传统模式的缺点:

  • 系统间耦合性太强,如上图所示,系统A在代码中直接调用系统B和系统C的代码,如果将来D系统接入,系统A还需要修改代码,过于麻烦!

中间件模式:

中间件模式的的优点:

  • 将消息写入消息队列,需要消息的系统自己从消息队列中订阅,从而系统A不需要做任何修改。

(2)异步

传统模式:

传统模式的缺点:

  • 一些非必要的业务逻辑以同步的方式运行,太耗费时间。

中间件模式:

中间件模式的的优点:

  • 将消息写入消息队列,非必要的业务逻辑以异步的方式运行,加快响应速度

(3)削峰

传统模式

传统模式的缺点:

  • 并发量大的时候,所有的请求直接怼到数据库,造成数据库连接异常

中间件模式:

中间件模式的的优点:

  • 系统A慢慢的按照数据库能处理的并发量,从消息队列中慢慢拉取消息。在生产中,这个短暂的高峰期积压是允许的。

2、使用了消息队列会有什么缺点?

分析:一个使用了MQ的项目,如果连这个问题都没有考虑过,就把MQ引进去了,那就给自己的项目带来了风险。

我们引入一个技术,要对这个技术的弊端有充分的认识,才能做好预防。要记住,不要给公司挖坑!

回答:回答也很容易,从以下两个个角度来答

  • 系统可用性降低:

    你想啊,本来其他系统只要运行好好的,那你的系统就是正常的。

    现在你非要加个消息队列进去,那消息队列挂了,你的系统不是呵呵了。因此,系统可用性降低

  • 系统复杂性增加:

    要多考虑很多方面的问题,比如一致性问题、如何保证消息不被重复消费,如何保证保证消息可靠传输。

    因此,需要考虑的东西更多,系统复杂性增大。

但是,我们该用还是要用的。

3、消息队列如何选型?

先说一下,博主只会ActiveMQ,RabbitMQ,RocketMQ,Kafka,对什么ZeroMQ等其他MQ没啥理解,因此只能基于这四种MQ给出回答。

分析:既然在项目中用了MQ,肯定事先要对业界流行的MQ进行调研,如果连每种MQ的优缺点都没了解清楚,就拍脑袋依据喜好,用了某种MQ,还是给项目挖坑。

如果面试官问:"你为什么用这种MQ?。"你直接回答"领导决定的。"这种回答就很LOW了。

还是那句话,不要给公司挖坑。

我们可以看出,RabbitMQ版本发布比ActiveMq频繁很多。至于RocketMQ和kafka就不带大家看了,总之也比ActiveMQ活跃的多。详情,可自行查阅。

再来一个性能对比表

综合上面的材料得出以下两点:

(1)中小型软件公司,建议选RabbitMQ.

一方面,erlang语言天生具备高并发的特性,而且他的管理界面用起来十分方便。

正所谓,成也萧何,败也萧何!他的弊端也在这里,虽然RabbitMQ是开源的,然而国内有几个能定制化开发erlang的程序员呢?

所幸,RabbitMQ的社区十分活跃,可以解决开发过程中遇到的bug,这点对于中小型公司来说十分重要。

不考虑rocketmq和kafka的原因是,一方面中小型软件公司不如互联网公司,数据量没那么大,选消息中间件,应首选功能比较完备的,所以kafka排除。

不考虑rocketmq的原因是,rocketmq是阿里出品,如果阿里放弃维护rocketmq,中小型公司一般抽不出人来进行rocketmq的定制化开发,因此不推荐。

(2)大型软件公司,根据具体使用在rocketMq和kafka之间二选一

一方面,大型软件公司,具备足够的资金搭建分布式环境,也具备足够大的数据量。

针对rocketMQ,大型软件公司也可以抽出人手对rocketMQ进行定制化开发,毕竟国内有能力改JAVA源码的人,还是相当多的。

至于kafka,根据业务场景选择,如果有日志采集功能,肯定是首选kafka了。具体该选哪个,看使用场景。

4、如何保证消息队列是高可用的?

分析:在第二点说过了,引入消息队列后,系统的可用性下降。在生产中,没人使用单机模式的消息队列。

因此,作为一个合格的程序员,应该对消息队列的高可用有很深刻的了解。

如果面试的时候,面试官问,你们的消息中间件如何保证高可用的?

如果你的回答只是表明自己只会订阅和发布消息,面试官就会怀疑你是不是只是自己搭着玩,压根没在生产用过。

因此,请做一个爱思考,会思考,懂思考的程序员。

回答:这问题,其实要对消息队列的集群模式要有深刻了解,才好回答。

以rcoketMQ为例,他的集群就有多master 模式、多master多slave异步复制模式、多 master多slave同步双写模式。

多master多slave模式部署架构图(网上找的,偷个懒,懒得画):

其实博主第一眼看到这个图,就觉得和kafka好像,只是NameServer集群,在kafka中是用zookeeper代替,都是用来保存和发现master和slave用的。

通信过程如下:

Producer 与 NameServer集群中的其中一个节点(随机选择)建立长连接,定期从 NameServer 获取 Topic 路由信息,并向提供 Topic 服务的 Broker Master 建立长连接,且定时向 Broker 发送心跳。

Producer 只能将消息发送到 Broker master,但是 Consumer 则不一样,它同时和提供 Topic 服务的 Master 和 Slave建立长连接,既可以从 Broker Master 订阅消息,也可以从 Broker Slave 订阅消息。

那么kafka呢,为了对比说明直接上kafka的拓补架构图(也是找的,懒得画)

如上图所示,一个典型的Kafka集群中包含若干Producer(可以是web前端产生的Page View,或者是服务器日志,系统CPU、Memory等),若干broker(Kafka支持水平扩展,一般broker数量越多,集群吞吐率越高),若干Consumer Group,以及一个Zookeeper集群。

Kafka通过Zookeeper管理集群配置,选举leader,以及在Consumer Group发生变化时进行rebalance。

Producer使用push模式将消息发布到broker,Consumer使用pull模式从broker订阅并消费消息。

至于rabbitMQ,也有普通集群和镜像集群模式,自行去了解,比较简单,两小时即懂。

要求,在回答高可用的问题时,应该能逻辑清晰的画出自己的MQ集群架构或清晰的叙述出来。

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

分析:这个问题其实换一种问法就是,如何保证消息队列的幂等性?

这个问题可以认为是消息队列领域的基本问题。换句话来说,是在考察你的设计能力,这个问题的回答可以根据具体的业务场景来答,没有固定的答案。

回答:先来说一下为什么会造成重复消费?

其实无论是那种消息队列,造成重复消费原因其实都是类似的。

正常情况下,消费者在消费消息时候,消费完毕后,会发送一个确认信息给消息队列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除。只是不同的消息队列发送的确认信息形式不同

例如RabbitMQ是发送一个ACK确认消息,RocketMQ是返回一个CONSUME_SUCCESS成功标志,kafka实际上有个offset的概念

简单说一下(如果还不懂,出门找一个kafka入门到精通教程),就是每一个消息都有一个offset,kafka消费过消息后,需要提交offset,让消息队列知道自己已经消费过了。

那造成重复消费的原因?

就是因为网络传输等等故障,确认信息没有传送到消息队列,导致消息队列不知道自己已经消费过该消息了,再次将该消息分发给其他的消费者。

如何解决?这个问题针对业务场景来答分以下几点

(1)比如,你拿到这个消息做数据库的insert操作。

那就容易了,给这个消息做一个唯一主键,那么就算出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。

(2)再比如,你拿到这个消息做redis的set的操作

那就容易了,不用解决。因为你无论set几次结果都是一样的,set操作本来就算幂等操作。

(3)如果上面两种情况还不行,上大招。

准备一个第三方介质,来做消费记录。以redis为例,给消息分配一个全局id,只要消费过该消息,将以K-V形式写入redis。那消费者开始消费前,先去redis中查询有没消费记录即可。

6、如何保证消费的可靠性传输?

分析:我们在使用消息队列的过程中,应该做到消息不能多消费,也不能少消费。如果无法做到可靠性传输,可能给公司带来千万级别的财产损失。

同样的,如果可靠性传输在使用过程中,没有考虑到,这不是给公司挖坑么,你可以拍拍屁股走了,公司损失的钱,谁承担。

还是那句话,认真对待每一个项目,不要给公司挖坑

回答:其实这个可靠性传输,每种MQ都要从三个角度来分析:生产者弄丢数据、消息队列弄丢数据、消费者弄丢数据

RabbitMQ

(1)生产者丢数据

从生产者弄丢数据这个角度来看,RabbitMQ提供transaction和confirm模式来确保生产者不丢消息。

transaction机制就是说,发送消息前,开启事物(channel.txSelect()),然后发送消息,如果发送过程中出现什么异常,事物就会回滚(channel.txRollback()),如果发送成功则提交事物(channel.txCommit())。

然而缺点就是吞吐量下降了。因此,按照博主的经验,生产上用confirm模式的居多。

一旦channel进入confirm模式,所有在该信道上面发布的消息都将会被指派一个唯一的ID(从1开始)

一旦消息被投递到所有匹配的队列之后,rabbitMQ就会发送一个Ack给生产者(包含消息的唯一ID)

这就使得生产者知道消息已经正确到达目的队列了.如果rabiitMQ没能处理该消息,则会发送一个Nack消息给你,你可以进行重试操作。

处理Ack和Nack的代码如下所示(说好不上代码的,偷偷上了):

channel.addConfirmListener(new ConfirmListener() {@Overridepublic void handleNack(long deliveryTag, boolean multiple) throws IOException {System.out.println("nack: deliveryTag = "+deliveryTag+" multiple: "+multiple);}@Overridepublic void handleAck(long deliveryTag, boolean multiple) throws IOException {System.out.println("ack: deliveryTag = "+deliveryTag+" multiple: "+multiple);}
});

(2)消息队列丢数据

处理消息队列丢数据的情况,一般是开启持久化磁盘的配置。

这个持久化配置可以和confirm机制配合使用,你可以在消息持久化磁盘后,再给生产者发送一个Ack信号。

这样,如果消息持久化磁盘之前,rabbitMQ阵亡了,那么生产者收不到Ack信号,生产者会自动重发。

那么如何持久化呢,这里顺便说一下吧,其实也很容易,就下面两步

1、将queue的持久化标识durable设置为true,则代表是一个持久的队列

2、发送消息的时候将deliveryMode=2

这样设置以后,rabbitMQ就算挂了,重启后也能恢复数据

(3)消费者丢数据

消费者丢数据一般是因为采用了自动确认消息模式。

这种模式下,消费者会自动确认收到信息。这时rahbitMQ会立即将消息删除,这种情况下如果消费者出现异常而没能处理该消息,就会丢失该消息。

至于解决方案,采用手动确认消息即可。

kafka

Producer在发布消息到某个Partition时,先通过ZooKeeper找到该Partition的Leader

然后无论该Topic的Replication Factor为多少(也即该Partition有多少个Replica),Producer只将该消息发送到该Partition的Leader。

Leader会将该消息写入其本地Log。每个Follower都从Leader中pull数据。
针对上述情况,得出如下分析

(1)生产者丢数据

在kafka生产中,基本都有一个leader和多个follwer。follwer会去同步leader的信息。

因此,为了避免生产者丢数据,做如下两点配置

  1. 第一个配置要在producer端设置acks=all。这个配置保证了,follwer同步完成后,才认为消息发送成功。

  2. 在producer端设置retries=MAX,一旦写入失败,这无限重试

(2)消息队列丢数据

针对消息队列丢数据的情况,无外乎就是,数据还没同步,leader就挂了,这时zookpeer会将其他的follwer切换为leader,那数据就丢失了。

针对这种情况,应该做两个配置。

  1. replication.factor参数,这个值必须大于1,即要求每个partition必须有至少2个副本

  2. min.insync.replicas参数,这个值必须大于1,这个是要求一个leader至少感知到有至少一个follower还跟自己保持联系

这两个配置加上上面生产者的配置联合起来用,基本可确保kafka不丢数据

(3)消费者丢数据

这种情况一般是自动提交了offset,然后你处理程序过程中挂了。kafka以为你处理好了。

再强调一次offset是干嘛的

offset:指的是kafka的topic中的每个消费组消费的下标。

简单的来说就是一条消息对应一个offset下标,每次消费数据的时候如果提交offset,那么下次消费就会从提交的offset加一那里开始消费。

比如一个topic中有100条数据,我消费了50条并且提交了,那么此时的kafka服务端记录提交的offset就是49(offset从0开始),那么下次消费的时候offset就从50开始消费。

解决方案也很简单,改成手动提交即可。

ActiveMQ和RocketMQ

大家自行查阅吧

7、如何保证消息的顺序性?

分析:其实并非所有的公司都有这种业务需求,但是还是对这个问题要有所复习。

回答:针对这个问题,通过某种算法,将需要保持先后顺序的消息放到同一个消息队列中(kafka中就是partition,rabbitMq中就是queue)。然后只用一个消费者去消费该队列。

有的人会问:那如果为了吞吐量,有多个消费者去消费怎么办?

这个问题,没有固定回答的套路。比如我们有一个微博的操作,发微博、写评论、删除微博,这三个异步操作。如果是这样一个业务场景,那只要重试就行。

比如你一个消费者先执行了写评论的操作,但是这时候,微博都还没发,写评论一定是失败的,等一段时间。等另一个消费者,先执行写评论的操作后,再执行,就可以成功。

总之,针对这个问题,我的观点是保证入队有序就行,出队以后的顺序交给消费者自己去保证,没有固定套路。

最后

小编利用空余时间整理了一份《MySQL性能调优手册》,初衷也很简单,就是希望能够帮助到大家,减轻大家的负担和节省时间。

关于这个,给大家看一份学习大纲(PDF)文件,每一个分支里面会有详细的介绍。

image

这里都是以图片形式展示介绍,如要下载原文件以及更多的性能调优笔记(MySQL+Tomcat+JVM)可以直接【点击 “性能调优”】免费下载!

就可以成功。

总之,针对这个问题,我的观点是保证入队有序就行,出队以后的顺序交给消费者自己去保证,没有固定套路。

最后

小编利用空余时间整理了一份《MySQL性能调优手册》,初衷也很简单,就是希望能够帮助到大家,减轻大家的负担和节省时间。

关于这个,给大家看一份学习大纲(PDF)文件,每一个分支里面会有详细的介绍。

[外链图片转存中…(img-4JyE6rxr-1623850686005)]

这里都是以图片形式展示介绍,如要下载原文件以及更多的性能调优笔记(MySQL+Tomcat+JVM)可以直接【点击 “性能调优”】免费下载!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/386061.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【工作经验分享】这些新技术你们都知道吗

前言 近年来,微服务架构(Microservices Architecture)已经成为一种主流的软件开发方法论,所谓微服务( Microservices ),就是一些具有足够小的粒度、能够相互协作且自治的服务体系。 微服务架构基于分布式系统,同时借助了面向服务架构和企业服…

【微信小程序】使用Hystrix的插件机制

前言 在本篇文章开始前,我想想来回答一个问题:我为什么要写这一篇关于面试的文章? 原因有三:第一,我想为每一个为梦想时刻准备着的”有心人“尽一份自己的力量,提供一份高度精华的Java面试清单&#xff1…

【微信小程序】目前最全的《Java面试题及解析》

开头 在找工作的过程中,对于 Redis 技术知识的掌握已经成为必须的技能。美团面试常常就会被问到Redis相关知识,而这次我就差点倒在了美团3面,面试官连问我以下几个Redis的问题,然后就卡壳了… redis了解吗?你说说怎么…

大话数据结构——算法

算法:算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。 为什么把数据结构和算法一起说? 想想罗密欧与朱丽叶,梁山伯和祝英台,少了一个你总会觉得奇怪…

java线上培训班学费一般多少,成长路线图

前言 众所皆知的,Linux的核心原型是1991年由托瓦兹(Linus Torvalds)写出来的,但是托瓦兹为何可以写出Linux这个操作系统?为什么它要选择386的计算机来开发?为什么Linux的发展可以这么迅速?又为什么Linux是免费的?以及目前为何有这么多的 Linux版本(…

java线程池使用实战,太牛了!

前言 今天这篇文章中简单介绍一下一个 Java 程序员必知的 Linux 的一些概念以及常见命令。 如果文章有任何需要改善和完善的地方,欢迎在评论区指出,共同进步!笔芯! 正式开始 Linux 之前,简单花一点点篇幅科普一下操作…

大数据基础技术和应用

大数据概述 数据的表现形式: 线下数据信息化:数据库、文字记录、照片……互联网-移动互联网:网页数据、用户行为记录、数字图像……传感器:设备监控、智能家居、摄像头…… 大数据的4V特征: 大量化(Vol…

java线程池参数面试题,附赠复习资料

前言 作为同时具备高性能、高可靠和高可扩展性的典型键值数据库,Redis不仅功能强大,而且稳定,理所当然地成为了大型互联网公司的首选。 众多大厂在招聘的时候,不仅会要求面试者能简单地使用Redis,还要能深入地理解底…

java线程池有几种,讲的太透彻了

前言 该文档在Github上收获40Kstar的Java面试神技(这赞数,质量多高就不用我多说了吧)非常全面,包涵Java基础、Java集合、JavaWeb、Java异常、OOP、IO与NIO、反射、注解、多线程、JVM、MySQL、MongoDB、Spring全家桶、计算机网络、…

HIVE入门

Hive概述 什么是 Hive? * Hive 是建立在 Hadoop HDFS 上的数据库仓库基础建构 * Hive 可以用来进行数据库提取转化加载(ETL) * Hive 定义了简单的类似 SQL 查询语言,称为 HQL,它允许熟悉 SQL 的用户查询数据 * Hi…

java线程面试题博客园,超详细

简介 HikariCP 是用于创建和管理连接,利用“池”的方式复用连接减少资源开销,和其他数据源一样,也具有连接数控制、连接可靠性测试、连接泄露控制、缓存语句等功能,另外,和 druid 一样,HikariCP 也支持监控…

java编写斐波那契数列,实战案例

前言 提到插件,相信大家都知道,插件的存在主要是用来改变或者增强原有的功能,MyBatis中也一样。然而如果我们对MyBatis的工作原理不是很清楚的话,最好不要轻易使用插件,否则的话如果因为使用插件导致了底层工作逻辑被…

java编程代写有哪些平台,学习路线+知识点梳理

前言 今天刚好有空,跟大家聊聊如何学好算法进大厂。 前两天一个读者和我说,他坚持刷算法题2个月,薪资翻番去了他梦寐以求的大厂,期间面字节跳动还遇到了原题…其实据我所知目前国内的大厂和一些独角兽,已经越来越效仿…

【工作感悟】java编程规范pdf下载

前言 要相信,你现在所有的努力和付出都会在将来的某一天回报给你! 首先阿里巴巴作为国内互联网行业的领头羊,培养了一代又一代的IT技术人才,很多想进阿里这些互联网大厂的程序员看中的不仅仅是高薪丰厚的福利待遇,同样…

【工作感悟】全网最经典26道Spring面试题总结

开头 学习如逆水行舟,尤其是IT行业有着日新月异的节奏。 而且现在这个浮躁而又拜金的社会,我相信很多人做技术并非出于热爱,只是被互联网的高薪吸引,毕竟技术岗位非常枯燥,不仅要面对奇奇怪怪的需求,还要…

大话数据结构——树

一、树的定义 树(Tree)是n(n>0)个结点的有限集。 n0又称为空树。在任意一课非空的树中:(1)有且仅有一个特定的称为跟(Root)的结点;(2&#xf…

大话数据结构——图

图(Graph)是由定点的又穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。 一、各种图的定义 …

【工作感悟】达内java大数据课程

前言 其实前几篇文章已经写了好多有关于Spring源码的文章,事实上,很多同学虽然一直在跟着阅读、学习这些Spring的源码教程,但是一直都很迷茫,这些Spring的源码学习,似乎只是为了面试吹逼用,我大概问过一些…

大话数据结构——查找

查找(Searching)是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。 一、顺序表查找 顺序查找又叫线性查找,是最基本的查找技术,它的查找过程是:从表中…

【工作经验分享】java图片转文字

前言 又到一年金九银十之际。 Java作为目前用户最多,使用范围最广的软件开发技术之一。 Java的技术体系主要由支撑Java程序运行的虚拟机,提供各开发领域接口支持的Java,Java编程语言及许多第三方Jvav框架构成。 其中,以Java的虚拟器为今天的着…