高级Java攻城狮面试通关宝典,用心看完这一篇就够了

高级Java攻城狮面试通关宝典

以十几家大厂、上市公司、C轮以上公司的面试经验呕心沥血之著作,希望能帮助大家顺利通过自己心仪公司的面试。

熟记内容可以让你的通过率直达70%。

废话不多说,开始圈重点了

1.1、 hashMap原理 (5星)

基本上是开门见山第一个问题,但是也有小几率不会问(也许是觉得我看上去肯定会的样子)

要点1:JDK1.8以前是数组+链表,JDK1.8以后是数组+链表+红黑树链表长度>=8 &&数组长度>=64,则转化为红黑树存储;

要点2:默认情况下hashMap的初始大小为16,达到75%则进行扩容,扩容量为2倍(16*2);

要点3:hashMap是允许存null键和null值的,当key是null时会调用putForNullKey方法,直接把值放在数组第一的位置;

要点4:put方法, 1.根据key的hash定位到对应的数组下标,下标如果是空则直接放入链头,如果下标不为空则循环遍历所有元素并equals元素的key,如果equals结果是true则直接进行新旧数据替换,如果全部是false则将当前数据放入链头.。2.进行扩容判断;

要点5:get方法,根据key的hash定位到数组下标,下标如果是空则直接返回null,如果有值则遍历equals,全部返回false则返回null,如果返回true则返回value;

要点6:jdk1.7中,在多线程环境下,扩容时会造成环形链或数据丢失(如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。在调整大小的过程中,存储在LinkedList中的元素的次序会反过来,因为移动到新的bucket位置的时候,HashMap并不会将元素放在LinkedList的尾部,而是放在头部,这是为了避免尾部遍历(tail traversing)。如果条件竞争发生了,那么就死循环了)。jdk1.8中,在多线程环境下,会发生数据覆盖的情况。线程是无法保证在当前分配到的时间片段下一次性能完成事件的,所以多线程的环境下先后去操作同一个逻辑(内存或数据库数据)会造成各种混乱,轻则数据先后覆盖,重则死循环;

1.2、ConcurrentHashMap(5星)

 hashMap三兄弟之一,都是套在一起提问,所以只要问到hashMap那么三兄弟肯定都会照顾到

 要点1:JDK1.8以前是数组+链表,JDK1.8以后是数组+链表+红黑树链表长度>=8 &&数组长度>=64,则转化为红黑树存储;

 要点2:默认情况下hashMap的初始大小为16,达到75%则进行扩容,扩容量为2倍(16*2);

 要点3:ConcurrentHashMap不允许存储null键和null值; 

 要点4:JDK1.8以前采用分段管理模式,对数组中的每个元素进行锁控制,而不是对数组本身上锁。JDK1.8以后采用CAS无锁     算法,这种乐观锁操作在完成前进行判断,符合预期的结果才给予执行,对并发操作提供了良好的优化;

 要点5:ConcurrentHashMap的工作原理,定位一个元素的过程需要进行两次Hash操作,第一次 Hash 定位到 分段,第二次 Hash 定位到元素所在的链表的头部,因此,这一种结构的带来的副作用是 Hash 的过程要比普通的 HashMap 要长;

1.3、hashTable(5星)

hashMap三兄弟之一,都是套在一起提问,所以只要问到hashMap那么三兄弟肯定都会照顾到

要点1:Hashtable继承的是Dictionary类,HashMap继承的是AbstractMap,但两者都实现了Map接口;

要点2:hashTable存储null键和null值编译可以通过,但是运行时会报错;

要点3:hashTable是线程安全的,在底层每个方法上都进行了synchronized,与同时线程安全的ConcurrentHashMap相比性能慢了N倍;

要点4:Hashtable支持Iterator和Enumeration两种遍历方式,HashMap仅支持Iterator的遍历方式;

要点5:默认情况下hashTable的初始大小为16,达到75%则进行扩容,扩容量为2倍加1(16*2+1);

要点6:Hashtable直接使用Object的hashCode(),hashCode是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值;

1.3、Spring(5星)

要点1:Spring的两大特性为,IOC(控制反转)和AOP(切面)

要点2:

1、@Controller:用于标注控制器层组件

2、@Service:用于标注业务层组件

3、@Component : 用于标注这是一个受 Spring 管理的组件,组件引用名称是类名,第一个字母小写。可以使用@Component(“beanID”) 指定组件的名称

4、@Repository:用于标注数据访问组件,即DAO组件

5、@Bean:方法级别的注解,主要用在@Configuration和@Component注解的类里,@Bean注解的方法会产生一个Bean对象,该对象由Spring管理并放到IoC容器中。引用名称是方法名,也可以用@Bean(name = "beanID")指定组件名

6、@Scope("prototype"):将组件的范围设置为原型的(即多例)。保证每一个请求有一个单独的action来处理,避免action的线程问题。由于Spring默认是单例的,只会创建一个action对象,每次访问都是同一个对象,容易产生并发问题,数据不安全。

7、@Autowired:默认按类型进行自动装配。在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。

8、@Resource:默认按名称进行自动装配,当找不到与名称匹配的Bean时会按类型装配。


要点3:

原子性 (atomicity):强调事务的不可分割.
一致性 (consistency):事务的执行的前后数据的完整性保持一致.
隔离性 (isolation):一个事务执行的过程中,不应该受到其他事务的干扰
持久性(durability) :事务一旦结束,数据就持久到数据库

Spring四种隔离级别,比数据库事务隔离级别多一个default

1) DEFAULT (默认可重复度) 
这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应。

2) READ_UNCOMMITTED (读未提交) 
这是事务最低的隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。 

3) READ_COMMITTED (读已提交) 
保证一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。 

4) REPEATABLE_READ (可重复读) 
这种事务隔离级别可以防止脏读、不可重复读,但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读。

5) SERIALIZABLE(串行化) 
这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。除了防止脏读、不可重复读外,还避免了幻像读。

Spring事务七大传播属性

1) required(默认属性)
如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。 
被设置成这个级别时,会为每一个被调用的方法创建一个逻辑事务域。如果前面的方法已经创建了事务,那么后面的方法支持当前的事务,如果当前没有事务会重新建立事务。

2) Mandatory
支持当前事务,如果当前没有事务,就抛出异常。 

3) Never
以非事务方式执行,如果当前存在事务,则抛出异常。 

4) Not_supports
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 

5) requires_new
新建事务,如果当前存在事务,把当前事务挂起。 

6) Supports
支持当前事务,如果当前没有事务,就以非事务方式执行。 

7) Nested
支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。 
嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

1.4、SpringCloud(5星)

不管在大小任何一家公司,基本上是必问问题,区别在于问的深浅

要点1:Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、智能路由、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包

要点2:设计目标为协调各个微服务,简化分布式系统开发;

要点3:产出于Spring大家族,Spring在企业级开发框架中无人能敌,来头很大,可以保证后续的更新、完善,组件丰富,功能齐全。Spring Cloud 为微服务架构提供了非常完整的支持。例如、配置管理、服务发现、断路器、微服务网关等,pring Cloud 社区活跃度很高,教程很丰富,遇到问题很容易找到解决方案,服务拆分粒度更细,耦合度比较低,有利于资源重复利用,有利于提高开发效率,可以更精准的制定优化服务方案,提高系统的可维护性,减轻团队的成本,可以并行开发,不用关注其他人怎么开发,先关注自己的开发,微服务可以是跨平台的,可以用任何一种语言开发,适于互联网时代,产品迭代周期更短;

要点4:微服务过多,治理成本高,不利于维护系统,分布式系统开发的成本高(容错,分布式事务等)对团队挑战大

要点5:SpringCloud组件之一网关一般常用gateway或者zuul,两者均是web网关,处理的是http请求,gateway对比zuul多依赖了spring-webflux,在spring的支持下,功能更强大,内部实现了限流、负载均衡等,扩展性也更强,但同时也限制了仅适合于Spring Cloud套件,而zuul则可以扩展至其他微服务框架中,其内部没有实现限流、负载均衡等,gateway很好的支持异步,而zuul仅支持同步,那么理论上gateway则更适合于提高系统吞吐量(但不一定能有更好的性能),最终性能还需要通过严密的压测来决定,从框架设计的角度看,gateway具有更好的扩展性,并且其已经发布了2.0.0的RELESE版本,稳定性也是非常好的
编码上看,zuul更加简洁易懂,注释规范清晰,而gateway作为Spring家族的一份子,竟然几乎不注释,总的来说,在微服务架构,如果使用了Spring Cloud生态的基础组件,则Spring Cloud Gateway相比而言更加具备优势,单从流式编程+支持异步上就足以让开发者选择它了;

要点6:SpringCloud组件之一Eureka,服务注册中心,服务治理组件,包括服务端的注册中心和客户端的服务发现机制;

要点7:SpringCloud组件之一Ribbon,负载均衡的服务调用组件,具有多种负载均衡调用策略;

要点8:SpringCloud组件之一Hystrix,服务容错组件,实现了断路器模式,为依赖服务的出错和延迟提供了容错能力;

要点9:SpringCloud组件之一Feign,基于Ribbon和Hystrix的声明式服务调用组件,相较于REST的调用方式,Feign的调用方式更加简洁优雅;

要点10:SpringCloud组件之一Config是一个解决分布式系统的配置管理方案,俗称配置中心,生产环境需要做集群,不然如果配置中心出现问题将导致灾难性的后果

要点11:SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,

要点12:配置文件分为yml和properties两种方式

为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务

1.5、分布式(5星)

 SpringCloud的兄弟问题,前后关系或者直接套在一起问,都是属于必问问题

要点1:分布式CAP理论,任何一个分布式系统都无法同时满足Consistency(一致性)、Availability(可用性)、Partition  tolerance(分区容错性) 这三个基本需求。最多只能满足其中两项。而Partition tolerance(分区容错性) 是必须的,因此一般是  CP,或者AP;

要点2:BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语  的缩写。BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结, 是基于CAP定  理逐步演化而来的。BASE理论的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式  来使系统达到最终一致性;

要点3:2PC是分布式事物的一种解决方案(数据库层面解决数据库之间的分布式事务),它的主要原理是通过2阶段提交。1阶段为准备阶段,协调者进行事物询问,向所有  参与者发送事物预处理指令并等待响应,各个参与者节点执行本地事务操作,但在执行完成后并不会真正提交数据库本地事务,  而是先向协调者报告说:“我这边可以处理了/我这边不能处理”。2阶段为协调者收到的全部响应为yes则发送commit指令让参  与者提交事物,协调者如果收到的响应有1个NO或者响应超时则判定失败,给所有参与者发送回滚指令。2PC存在同步阻塞、单  点问题、脑裂等问题;

要点4:3PC是分布式事物的一种解决方案(数据库层面解决数据库之间的分布式事务),3PC是2PC的升级,核心是要解决协调者和参与者挂掉的问题。1阶段协调者向参与者发送CanCommit请求,询问是否可以执行事务提交操作。然后开始等待参与者的响应,参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态,否则反馈No。2阶段中如果所有的参与者都返回Yes的话,那么就会进入PreCommit阶段进行事务预提交。这里的PreCommit阶段跟上面的第一阶段是差不多的,只不过这里协调者和参与者都引入了超时机制 2PC中只有协调者可以超时,参与者没有超时机制。3阶段跟2PC的2阶段类似。3PC优点为避免了参与者在长时间无法与协调者节点通讯(协调者挂掉了)的情况下,无法释放资源的问题,因为参与者自身拥有超时机制会在超时后,自动进行本地commit从而进行释放资源。而这种机制也侧面降低了整个事务的阻塞时间和范围。缺点为因为网络问题万一超时了,会导致数据不一致;

要点5:TCC是分布式事物的一种解决方案(应用层面解决分布式系统中的分布式事务),1阶段负责资源的检查和预留,2阶段发送指令,执行真正的业务,3阶段是预留资源的取消。TCC与2PC提交机制类似,增加了补偿机制,当错误时进行一系列补偿机制操作。优点是解决了跨服务的业务操作原子性问题,例如组合支付,订单减库存等场景非常实用,把数据库的二阶段提交上升到微服务来实现,从而避免了数据库2阶段中锁冲突的长事务低性能风险,异步高性能,它采用了try先检查,然后异步实现confirm,真正提交的是在confirm方法中。缺点是对微服务的侵入性强,微服务的每个事务都必须实现try,confirm,cancel等3个方法,开发成本高,今后维护改造的成本也高,为了达到事务的一致性要求,try,confirm、cancel接口必须实现等幂性操作(定时器+重试),由于事务管理器要记录事务日志,必定会损耗一定的性能,并使得整个TCC事务时间拉长

要点6:基于消息的最终一致性方案,主要是基于MQ消息生产与订阅进行服务之间的通讯,流程为1消息生成者发送消息,2MQ收到消息,将消息进行持久化,在存储中新增一条记录,3返回ACK给消费者,4MQ push 消息给对应的消费者,然后等待消费者返回ACK,5如果消息消费者在指定时间内成功返回ack,那么MQ认为消息消费成功,在存储中删除消息,即执行第6步;如果MQ在指定时间内没有收到ACK,则认为消息消费失败,会尝试重新push消息,重复执行4、5、6步骤,6MQ删除消息。缺点是远程调用,结果最终可能为成功、失败、超时;而对于超时的情况,处理方最终的结果可能是成功,也可能是失败,调用方是无法知晓的;

要点7:分布式锁一般使用redis的setnx或者是zookeeper的临时节点来实现,zk的可靠性倍与redis,效率却低了点,如果并发量不是特别大,追求可靠性,首选zookeeper。为了效率,则首选redis实现

1.6、Redis(4.5星)

一般都会问到,但是有小几率不问,那么意味着要么有更头疼的问题在等你,要么要求很低

String(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)

要点1:redis的持久化方式有两种,AOF以独立日志记录写命令方式存储日志,重启时再重新执行日志中记录的数据即可完成恢复,缺点是占用存储空间大,恢复时候慢。RDB:将内存中的数据以快照的方式写进二进制文件中.优势是数据恢复快,方便备份,缺点是比较耗内存,可能会造成数据丢失;

要点2:缓存雪崩的原因是大部分的数据过期时间都设置为了相同的时间,在大部分数据过期时请求全部直接打击到数据库上,避免方法是过期时间都设置随机值;

要点3:缓存穿透的原因是查询一个一定不存在的数据时,缓存会不命中,如果从数据库中查询不到则不放入缓存,则每次请求实际都会进数据库进行查询。解决方法可以采取布隆过滤器或者是将查询到的null结果进行缓存,缓存时间设置短一些,最长不超过五分钟;

要点4:缓存击穿的原因是查询的数据存在但是在redis中过期了,就会直接去数据库里去查询,但是这个时候如果大量并发过来,这个时候大并发的请求可能会瞬间把后端DB压垮,就会造成缓存击穿。解决方法为先上锁然后再去数据库加载,加载完毕再释放锁,其他线程发现获取锁失败先wait一会;

要点5:redis的删除过期key的算法有两种,一、每100ms会定期去抽一批设置了过期时间的key去检查是否过期,二、是惰性删除不会去主动删除数据,而是在访问数据的时候,再检查当前键值是否过期,如果过期则执行删除并返回 null 给客户端,如果没有过期则返回正常信息给客户端。

要点6:redis高可用的方案有两种(单点和集群),一、主从复制则是负责让一个Redis服务器可以配备多个备份的服务器),主从节点复制数据有全量复制和部分复制之分,从服务器向主服务器发送psync(旧版本是sync)命令。二、哨兵可以管理多个Redis服务器,它提供了监控,提醒以及自动的故障转移的功能),edis使用一组哨兵(sentinel)节点来监控主从redis服务的可用性,一旦发现redis主节点失效,将选举出一个哨兵节点作为领导者(leader),哨兵领导者再从剩余的从redis节点中选出一个redis节点作为新的主redis节点对外服务

要点6:Redis 限流
一:基于Redis的setnx、zset

1、setnx

比如需要在10秒内限定20个请求,那么我们在setnx的时候可以设置过期时间10,当请求的setnx数量达到20时候即达到了限流效果。

缺点:

Redis中需要保持N个key
固定窗口统计
2、zset
类似滑动窗口,可以将请求组成一个zset数组,当每一次请求进来的时候,value保持唯一,可以用UUID生成,而score可以用当前时间戳表示,因为score我们可以用来计算当前时间戳之内有多少的请求数量。而zset数据结构也提供了range方法让我们可以很轻易的获取到2个时间戳内有多少请求,

缺点:

zset的数据结构会越来越大

1.7、Nginx(4星)

重点1:Nginx能做什么?反向代理负载均衡HTTP服务器(动静分离)正向代理

重点2:反向代理是Nginx做的最多的一件事,反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,简单来说就是真实的服务器不能直接被外部网络访问,所以需要一台代理服务器,而代理服务器能被外部网络访问的同时又跟真实服务器在同一个网络环境,当然也可能是同一台服务器,端口不同而已。

重点3:负载均衡是Nginx常用的一个功能,负载均衡其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。简单而言就是当有2台或以上服务器时,根据规则随机的将请求分发到指定的服务器上处理,负载均衡配置一般都需要同时配置反向代理,通过反向代理跳转到负载均衡。而Nginx目前支持自带3种负载均衡策略,还有2种常用的第三方策略。

              RR:每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。

              权重:指定轮询几率,用于后端服务器性能不均的情况。

              ip_hash:每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决登录信息存储在session中的问题。

               fair(第三方):按后端服务器的响应时间来分配请求,响应时间短的优先分配。

               url_hash(第三方):按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。

                

1.7、消息队列(4星)

一般来说会顺便问一下,但是不会深究,看面试官的心情

重点1:常用的几种MQ有activeMQ(万级)、rabbitMQ(万级)、rocketmq(十万级);

重点2:activeMQ的原理是把消息发送给activemq,Activemq 接收到消息, 然后查看有多少个消费者, 然后把消息转发给消费者, 此过程中生产者无需参与。 消费者接收到消息后做相应的处理和生产者没有任何关系。activeMQ有两种通讯方式:一、发布/订阅方式针对多个接受客户端,消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。 和点对点方式不同,发布到topic的消息会被所有订阅者消费, 当生产者发布消息,不管是否有消费者都不会保存消息。二、p2p(点对点)针对一对一的通讯,消息生产者生产消息发送到queue中,然后消息消费者从queue中取出并且消费消息,Queue支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费、其它的则不能消费此消息了

重点3:rabbitMQ的组成部分为以下

生产者(Producer):发送消息的应用。

消费者(Consumer):接收消息的应用。

队列(Queue):存储消息的缓存。

消息(Message):由生产者通过RabbitMQ发送给消费者的信息。

连接(Connection):连接RabbitMQ和应用服务器的TCP连接。

通道(Channel):连接里的一个虚拟通道。当你通过消息队列发送或者接收消息时,这个操作都是通过通道进行的。

交换机(Exchange):交换机负责从生产者那里接收消息,并根据交换类型分发到对应的消息列队里。要实现消息的接收,一个队列必须到绑定一个交换机。

绑定(Binding):绑定是队列和交换机的一个关联连接。

路由键(Routing Key):路由键是供交换机查看并根据键来决定如何分发消息到列队的一个键,路由键可以说是消息的目的地址。                     

rabbitMQ的交换机类型有四种

直连(Direct):直接交换机通过消息上的路由键直接对消息进行分发。

扇形(Fanout):一个扇出交换机会将消息发送到所有和它进行绑定的队列上。

主题(Topic):这个交换机会将路由键和绑定上的模式进行通配符匹配。

消息头(Headers):消息头交换机使用消息头的属性进行消息路由。

重点4:rocketmq的组成部分为以下

NameServer:相当于集群管理服务。

Broker:相当于单个节点负责数据的读写的,而Producer就是负责生产消息后写入Broker的,Consumer则是从Broker来消费消息。

Producer:发送消息的应用。

Consumer:接收消息的应用。

从Producer分析:如何确保消息正确的发送到了Broker?

默认情况下,可以通过同步的方式阻塞式的发送,check SendStatus,状态是OK,表示消息一定成功的投递到了Broker,状态超时或者失败,则会触发默认的2次重试。此方法的发送结果,可能Broker存储成功了,也可能没成功

采取事务消息的投递方式,并不能保证消息100%投递成功到了Broker,但是如果消息发送Ack失败的话,此消息会存储在CommitLog当中,但是对ConsumerQueue是不可见的。可以在日志中查看到这条异常的消息,严格意义上来讲,也并没有完全丢失

RocketMQ支持 日志的索引,如果一条消息发送之后超时,也可以通过查询日志的API,来check是否在Broker存储成功

从Broker分析:如果确保接收到的消息不会丢失?

消息支持持久化到Commitlog里面,即使宕机后重启,未消费的消息也是可以加载出来的
Broker自身支持同步刷盘、异步刷盘的策略,可以保证接收到的消息一定存储在本地的内存中
Broker集群支持 1主N从的策略,支持同步复制和异步复制的方式,同步复制可以保证即使Master 磁盘崩溃,消息仍然不会丢失

 

从Cunmser分析:如何确保拉取到的消息被成功消费?

消费者可以根据自身的策略批量Pull消息
Consumer自身维护一个持久化的offset(对应MessageQueue里面的min offset),标记已经成功消费或者已经成功发回到broker的消息下标
如果Consumer消费失败,那么它会把这个消息发回给Broker,发回成功后,再更新自己的offset
如果Consumer消费失败,发回给broker时,broker挂掉了,那么Consumer会定时重试这个操作
如果Consumer和broker一起挂了,消息也不会丢失,因为consumer 里面的offset是定时持久化的,重启之后,继续拉取offset之前的消息到本地

 

重点5:保证MQ高可用可以使用集群,例如rabbitMQ话推荐使用镜像集群,把需要的队列做成镜像队列,存在于多个节点,属于RabbitMQ的HA方案;

重点6:保证消费不重复以rabbitMQ为例,它没有提供防止消息被重复消费的功能,只能在业务逻辑中去处理,处理方法为运用redis把msgid和消息状态存储起来,每次消费前先查看一下本次消费的消息状态,如果已经被消费过了,就可以不用消费.如果尚未消费,就可以进行消费,消费完把对应的状态改为已消费即可;

重点7:保证消费有序以rabbitMQ为例,消息1和消息2需要按顺序消费,必须先消费消息1,后消费消息2,我们可以将消息放顺序到不同的queue里,然后由worker来消费;

重点8:解决消息失效的方法为消息重导,自己写程序把失效的数据查出来然后重新导入队里中;

重点9:解决消息队列满了或者是消息过度挤压的方法为在设计上尽量避免出现这种问题,如果确实已经碰到了,可以采取服务降级策略,同时临时增加一些消费能力更强劲的消费者,以X倍速率消费队列中积压的消息;

重点10:解决消息丢失问题可以使用rabbitmq提供的confirm机制.confirm机制是异步的,在消费者收到生产者发送的消息后会回调ack,如果消费者接收失败会回调nack接口

重点11:解决activeMQ消息丢失:修改session配置,启动事务,启动事务后,commit()方法会负责任的等待服务器的返回;

1.8、kafka(3星)

这里把kafka单独摘出来说是因为它有别与MQ,主要用于处理活跃的流式数据,大数据量的数据处理,在金融和安防行业经常使用

Producer:Producer即生产者,消息的产生者,是消息的入口。
kafka cluster:
Broker:Broker是kafka实例,每个服务器上有一个或多个kafka的实例,我们姑且认为每个broker对应一台服务器。每个kafka集群内的broker都有一个不重复的编号,如图中的broker-0、broker-1等……
Topic:消息的主题,可以理解为消息的分类,kafka的数据就保存在topic。在每个broker上都可以创建多个topic。
Partition:Topic的分区,每个topic可以有多个分区,分区的作用是做负载,提高kafka的吞吐量。同一个topic在不同的分区的数据是不重复的,partition的表现形式就是一个一个的文件夹!
Replication:每一个分区都有多个副本,副本的作用是做备胎。当主分区(Leader)故障的时候会选择一个备胎(Follower)上位,成为Leader。在kafka中默认副本的最大数量是10个,且副本的数量不能大于Broker的数量,follower和leader绝对是在不同的机器,同一机器对同一个分区也只可能存放一个副本(包括自己)。
Message:每一条发送的消息主体。
Consumer:消费者,即消息的消费方,是消息的出口。
Consumer Group:我们可以将多个消费者组成一个消费者组,在kafka的设计中同一个分区的数据只能被消费者组中的某一个消费者消费。同一个消费者组的消费者可以消费同一个topic的不同分区的数据,这也是为了提高kafka的吞吐量!
Zookeeper:kafka集群依赖zookeeper来保存集群的的元信息,来保证系统的可用性

重点1:Kafka是分布式发布-订阅消息系统,是一款分布式流处理框架,用于实时构建流处理应用。它有一个核心的功能广为人知,即作为企业级的消息引擎被广泛使用

重点2:消费群组是Kafka 提供的可扩展且具有容错性的消费者机制,在 Kafka 中,消费者组是一个由多个消费者实例 构成的组。多个实例共同订阅若干个主题,实现共同消费。同一个组下的每个实例都配置有 相同的组 ID,被分配不同的订阅分区。当某个实例挂掉的时候,其他实例会自动地承担起 它负责消费的分区

重点3:目前,Kafka 使用 ZooKeeper 存放集群元数据、成员管理、Controller 选举,以及其他一些管理类任务。之后,等 KIP-500 提案完成后,Kafka 将完全不再依赖 于 ZooKeeper。

重点4:在 Kafka 中,每个主题分区下的每条消息都被赋予了一个唯一的 ID 数值,用于标识它在分区中的位置。这个 ID 数值,就被称为位移,或者叫偏移量。一旦消息被写入到分区日志,它的位移值将不能 被修改。

重点5:kafka2.4以前Kafka 副本当前分为领导者副本和追随者副本。只有 Leader 副本才能 对外提供读写服务,响应 Clients 端的请求。Follower 副本只是采用拉(PULL)的方式,被动地同步 Leader 副本中的数据,并且在 Leader 副本所在的 Broker 宕机后,随时准备应聘 Leader 副本。2.4以后允许 Follower 副本有限度地提供读服务

重点6:设置kafka接受文件的大小需要同时设置 Broker 端参数和 Consumer 端参数以及Follower 副本能够接收的最大消 息的大小,否则副本同步就会失败

重点7:kafka不支持读写分离的原因是因为读写分离适用于那种读负载很大,而写操作相对不频繁的场景,可 Kafka 不属于这样的场景。Kafka 采用 PULL 方式实现 Follower 的同步,因此,Follower 与 Leader 存 在不一致性窗口。如果允许读 Follower 副本,就势必要处理消息滞后(Lagging)的问题。不过在2.4版本后支持有限的读写分离,也就是Follower 副本能够对外提供读服务;

kafka读数据重复问题:手动提交offset;

kafka分区数量不均匀问题:不要用固定的几个key,最好是随机不重复的,例如订单号;

1.8、mysql(4星)

重点1:mysql主从原理,就是主服务将自己的动作二进制日志文件给到从服务,从服务从日志中将动作同步过来即可实现。

重点2:mysql主从配置步骤,一、打开主服务器的mysql配置文件:my.conf,在# vi /etc/my.cnf下加入log-bin=mysql-bin  //将mysql二进制日志取名为mysql-bin,binlog_format=mixed //二进制日志的格式,server-id=101 //为服务器设置一个独一无二的id便于区分

重点3:MySQL目前主要有的索引类型为,普通索引、唯一索引、主键索引、组合索引、全文索引。

1.9、涉及核心逻辑如充值、提现、支付等宕机时候补偿机制问题(3星)

一般是不会问,问了你面试完出门可以买个刮刮乐,福利彩票什么的就不要想了

解决方案1:可以将相关信息在执行前存放在redis里,并标记录上状态为未执行,逻辑执行中将该记录取出来并将状态更改为进行中,然后逻辑执行完毕后删除掉,这里不考虑支付宝、微信、银联请求递交后出事故的处理问题,因为它们都有良好的回调机制;

解决方案2:可以将解决方案1中的方法照搬,但是不存放在redis里,而是直接存放在本地磁盘上,这样只要不是服务器爆炸,应该都可以恢复;

我个人是不推荐更改redis的存储模式的,那样就违背的设计和应用初衷;

2.0、缓存热点数据问题(3星)

一般是不会问,问了说明这家公司要求很高,并且业务铺的很开

热点数据分析:1.凭借业务经验,进行预估哪些是热key。2.redis自带命令monitor。3.执行redis-cli时加上–hotkeys选项即可

解决方案:具体思路为不让并发热点key直接走一个redis,可以做二级缓存,可以将热点key备份在多个redis里;

2.1、大数据去重(2星)

基本上不会问,除非公司有这方面业务

解决方案1:数据量不是特别大(上亿)软硬件环境不紧凑或者实时性不强,单纯使用hashMap或者hashSet就可以了;

解决方案2:条件与方案一要求相反的话,采用数据分割,1亿数据分成十份一份就1千万,不行就继续分,然后用使用hashMap或者hashSet去去重,但是会遇见无法完全去重的问题,解决方法是有可利用的元素例如时间、关键字等可以以这些条件进行数据分组后再去重,如果是无规则数据则随机进行数据分组,记录高频率重复数据,最后再去对各个数据组进行相应处理;

2.2、大数据入库(2星)

基本上不会问,除非公司有这方面业务

解决方案1:数据量不是特别大(上亿)软硬件环境不紧凑或者实时性不强,单纯使用批量录入就可以了;

解决方案2:条件与方案一要求相反的话,根据数据量具体大小进行分表,然后分表批量录入,要是数据量超级超级大的话,可能还需要配合上分库;

2.3、oom+cpu持续飙高导致系统卡顿问题

临时解决方案:线上服务重启

彻底排查及解决方案:top命令查看最耗CPU的进程,top -Hp 17038查看该进程中最耗CPU的线程,将线程号转为16进制,同时查看这些线程当前正在干什么(在此以17045线程为例),jstack 17038 | grep '0x4295' -C10 --color 查看线程情况,用Jmap命令查看当前堆的使用情况,jstat -gcutil 17038 5000查看gc频率的命令(其中O代表老年代占用率,FGC是FullGC次数,FGCT是fullGC时间;可以看出在频繁FullGC但是老年代有资源一直释放不掉),至此定位到问题根源是内存溢出导致。

  • 将JVM内存文件dump文件导出到本地,用Eclipse Memary Analysis(MAT官网下载地址) 进行分析,然后就可以找到是哪个类占用大了。

最后、JVM调优(5星)

重点中的重点,甭管什么公司基本上都会问,虽然你就算入职也不会让你做这方面,但是一定会问。

尽可能把堆内存的空间设置大一些,以减少垃圾回收的次数。假设服务器上的可用内存还有12GB,那么先指定堆所分配内存的最大值和初始值为8GB。一般情况下,年轻代内存大小需在整个堆大小的1/2到1/4之间,那么就指定年轻代内存大小为3GB。再把Eden区和一个Survivor区的空间大小的比率设置为4。元空间第一次触发垃圾回收的内存大小的阈值设置为256MB,一般情况下足够用。元空间所分配内存的最大值设置为512MB,为了避免极端情况下占用大量内存。另外,还需要明确指定JVM以server模式启动。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值