Java面试通关要点汇总集及参考答案(不吹不黑耿直福利)

以下是本人从某个视频中归纳出来的答案,感觉牛掰就总结了出来,你们可以到直播间去问管理要高清思维导图和一些实用的技术资料,他们会免费的发给你们,按照他们的说法是建立一个分享、交流、学习的平台,感觉他们太耿直了。

反模式设计

简单的来说,反模式是指在对经常面对的问题经常使用的低效,不良,或者有待优化的设计模式/方法。甚至,反模式也可以是一种错误的开发思想/理念。在这里我举一个最简单的例子:在面向对象设计/编程中,有一条很重要的原则, 单一责任原则(Single responsibility principle)。其中心思想就是对于一个模块,或者一个类来说,这个模块或者这个类应该只对系统/软件的一个功能负责,而且该责任应该被该类完全封装起来。当开发人员需要修改系统的某个功能,这个模块/类是最主要的修改地方。相对应的一个反模式就是上帝类(God Class),通常来说,这个类里面控制了很多其他的类,同时也依赖其他很多类。整个类不光负责自己的主要单一功能,而且还负责了其他很多功能,包括一些辅助功能。很多维护老程序的开发人员们可能都遇过这种类,一个类里有几千行的代码,有很多功能,但是责任不明确单一。单元测试程序也变复杂无比。维护/修改这个类的时间要远远超出其他类的时间。很多时候,形成这种情况并不是开发人员故意的。很多情况下主要是由于随着系统的年限,需求的变化,项目的资源压力,项目组人员流动,系统结构的变化而导致某些原先小型的,符合单一原则类慢慢的变的臃肿起来。最后当这个类变成了维护的噩梦(特别是原先熟悉的开发人员离职后),重构该类就变成了一个不容易的工程。

分库与分表设计

垂直分表在日常开发和设计中比较常见,通俗的说法叫做“大表拆小表”,拆分是基于关系型数据库中的“列”(字段)进行的。通常情况,某个表中的字段比较多,可以新建立一张“扩展表”,将不经常使用或者长度较大的字段拆分出去放到“扩展表”中。在字段很多的情况下,拆分开确实更便于开发和维护(笔者曾见过某个遗留系统中,一个大表中包含100多列的)。某种意义上也能避免“跨页”的问题(MySQL、MSSQL底层都是通过“数据页”来存储的,“跨页”问题可能会造成额外的性能开销,拆分字段的操作建议在数据库设计阶段就做好。如果是在发展过程中拆分,则需要改写以前的查询语句,会额外带来一定的成本和风险,建议谨慎。

垂直分库在“微服务”盛行的今天已经非常普及了。基本的思路就是按照业务模块来划分出不同的数据库,而不是像早期一样将所有的数据表都放到同一个数据库中。系统层面的“服务化”拆分操作,能够解决业务系统层面的耦合和性能瓶颈,有利于系统的扩展维护。而数据库层面的拆分,道理也是相通的。与服务的“治理”和“降级”机制类似,我们也能对不同业务类型的数据进行“分级”管理、维护、监控、扩展等。

众所周知,数据库往往最容易成为应用系统的瓶颈,而数据库本身属于“有状态”的,相对于Web和应用服务器来讲,是比较难实现“横向扩展”的。数据库的连接资源比较宝贵且单机处理能力也有限,在高并发场景下,垂直分库一定程度上能够突破IO、连接数及单机硬件资源的瓶颈,是大型分布式系统中优化数据库架构的重要手段。

然后,很多人并没有从根本上搞清楚为什么要拆分,也没有掌握拆分的原则和技巧,只是一味的模仿大厂的做法。导致拆分后遇到很多问题(例如:跨库join,分布式事务等)。

水平分表也称为横向分表,比较容易理解,就是将表中不同的数据行按照一定规律分布到不同的数据库表中(这些表保存在同一个数据库中),这样来降低单表数据量,优化查询性能。最常见的方式就是通过主键或者时间等字段进行Hash和取模后拆分。水平分表,能够降低单表的数据量,一定程度上可以缓解查询性能瓶颈。但本质上这些表还保存在同一个库中,所以库级别还是会有IO瓶颈。所以,一般不建议采用这种做法。

水平分库分表与上面讲到的水平分表的思想相同,唯一不同的就是将这些拆分出来的表保存在不同的数据中。这也是很多大型互联网公司所选择的做法。某种意义上来讲,有些系统中使用的“冷热数据分离”(将一些使用较少的历史数据迁移到其他的数据库中。而在业务功能上,通常默认只提供热点数据的查询),也是类似的实践。在高并发和海量数据的场景下,分库分表能够有效缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源的瓶颈。当然,投入的硬件成本也会更高。同时,这也会带来一些复杂的技术问题和挑战(例如:跨分片的复杂查询,跨分片事务等)。

分布式困境与应对之策

数据迁移与扩容问题

前面介绍到水平分表策略归纳总结为随机分表和连续分表两种情况。连续分表有可能存在数据热点的问题,有些表可能会被频繁地查询从而造成较大压力,热数据的表就成为了整个库的瓶颈,而有些表可能存的是历史数据,很少需要被查询到。连续分表的另外一个好处在于比较容易,不需要考虑迁移旧的数据,只需要添加分表就可以自动扩容。随机分表的数据相对比较均匀,不容易出现热点和并发访问的瓶颈。但是,分表扩展需要迁移旧的数据。

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析、双十一实战或者是面试难题的朋友可以加582505643里面的群主感觉蠢萌蠢萌的可以到她那骗资料,都是干货。

针对于水平分表的设计至关重要,需要评估中短期内业务的增长速度,对当前的数据量进行容量规划,综合成本因素,推算出大概需要多少分片。对于数据迁移的问题,一般做法是通过程序先读出数据,然后按照指定的分表策略再将数据写入到各个分表中。

表关联问题

在单库单表的情况下,联合查询是非常容易的。但是,随着分库与分表的演变,联合查询就遇到跨库关联和跨表关系问题。在设计之初就应该尽量避免联合查询,可以通过程序中进行拼装,或者通过反范式化设计进行规避。

分页与排序问题

一般情况下,列表分页时需要按照指定字段进行排序。在单库单表的情况下,分页和排序也是非常容易的。但是,随着分库与分表的演变,也会遇到跨库排序和跨表排序问题。为了最终结果的准确性,需要在不同的分表中将数据进行排序并返回,并将不同分表返回的结果集进行汇总和再次排序,最后再返回给用户。

分布式事务问题

随着分库与分表的演变,一定会遇到分布式事务问题,那么如何保证数据的一致性就成为一个必须面对的问题。目前,分布式事务并没有很好的解决方案,难以满足数据强一致性,一般情况下,使存储数据尽可能达到用户一致,保证系统经过一段较短的时间的自我恢复和修正,数据最终达到一致。

分布式全局唯一ID

在单库单表的情况下,直接使用数据库自增特性来生成主键ID,这样确实比较简单。在分库分表的环境中,数据分布在不同的分表上,不能再借助数据库自增长特性。需要使用全局唯一 ID,例如 UUID、GUID等。

MySQL 遇到的死锁问题

产生死锁的四个必要条件:

(1) 互斥条件:一个资源每次只能被一个进程使用。

(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

下列方法有助于最大限度地降低死锁:

(1)按同一顺序访问对象。

(2)避免事务中的用户交互。

(3)保持事务简短并在一个批处理中。

(4)使用低隔离级别。

(5)使用绑定连接。

数据库索引的原理

数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树。

聚集索引与非聚集索引的区别

1).聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个

2).聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物理存储并不连续

 3).聚集索引:物理存储按照索引排序;聚集索引是一种索引组织形式,索引的键值逻辑顺序决定了表数据行的物理存储顺序

 非聚集索引:物理存储不按照索引排序;非聚集索引则就是普通索引了,仅仅只是对数据列创建相应的索引,不影响整个表的物理存储顺序.

4).索引是通过二叉树的数据结构来描述的,我们可以这么理解聚簇索引:索引的叶节点就是数据节点。而非聚簇索引的叶节点仍然是索引节点,只不过有一个指针指向对应的数据块。

Redis 持久化机制和如何实现

redis有两种持久化机制RDB与AOF。

RDB持久化方式会在一个特定的间隔保存那个时间点的一个数据快照。

AOF持久化方式则会记录每一个服务器收到的写操作。在服务启动时,这些记录的操作会逐条执行从而重建出原来的数据。写操作命令记录的格式跟Redis协议一致,以追加的方式进行保存。

Redis的持久化是可以禁用的,就是说你可以让数据的生命周期只存在于服务器的运行时间里。

两种方式的持久化是可以同时存在的,但是当Redis重启时,AOF文件会被优先用于重建数据。

缓存降级

页面降级:在大促或者某些特殊情况下,某些页面占用了一些稀缺服务资源,在紧急情况下可以对其整个降级,以达到丢卒保帅;

页面片段降级:比如商品详情页中的商家部分因为数据错误了,此时需要对其进行降级;

页面异步请求降级:比如商品详情页上有推荐信息/配送至等异步加载的请求,如果这些信息响应慢或者后端服务有问题,可以进行降级;

服务功能降级:比如渲染商品详情页时需要调用一些不太重要的服务:相关分类、热销榜等,而这些服务在异常情况下直接不获取,即降级即可;

读降级:比如多级缓存模式,如果后端服务有问题,可以降级为只读缓存,这种方式适用于对读一致性要求不高的场景;如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析、双十一实战或者是面试难题的朋友可以加582505643里面的群主感觉蠢萌蠢萌的可以到她那骗资料,都是干货。

写降级:比如秒杀抢购,我们可以只进行Cache的更新,然后异步同步扣减库存到DB,保证最终一致性即可,此时可以将DB降级为Cache。

爬虫降级:在大促活动时,可以将爬虫流量导向静态页或者返回空数据,从而保护后端稀缺资源。

自动开关降级

自动降级是根据系统负载、资源使用情况、SLA等指标进行降级。

超时降级

当访问的数据库/http服务/远程调用响应慢或者长时间响应慢,且该服务不是核心服务的话可以在超时后自动降级;比如商品详情页上有推荐内容/评价,但是推荐内容/评价暂时不展示对用户购物流程不会产生很大的影响;对于这种服务是可以超时降级的。如果是调用别人的远程服务,和对方定义一个服务响应最大时间,如果超时了则自动降级。

下面的截图为视频中的部分归纳思维图

你可能感兴趣的:(Java面试通关要点汇总集及参考答案(不吹不黑耿直福利))