阿里面试面试题
文章目录
- 阿里一面
-
- 问题1:为什么要用 Redis?有预估 QPS 的提升幅度吗?
- 问题2:Redis 内存不够用怎么办?
- 问题3:是否定义、设计过业务模型?
- 问题4:百万级用户规模服务上线的话需要做什么?
- 问题5:JVM 怎么创建一个对象?
- 问题6:有哪些场景会触发类的加载?
- 阿里二面
-
- 如果不使用双亲委派会有什么问题?
- 线程中包含哪些状态?
- 线程池执行任务的过程?
- 线程同步有哪些策略和类?有没有实测过关键字的性能?
- SpringBoot 搭建的 Web 服务处理过程?
- 有没有看过开源框架的源码,举一个例子讲讲?
-
- Spring Boot 请求执行源码
- Spring Cloud LoadBalancer 负载均衡
- 小结
阿里一面
问题1:为什么要用 Redis?有预估 QPS 的提升幅度吗?
答案解析思路: 为什么用 Redis?回答 Redis 的优势即可。 QPS(Queries Per Second,每秒钟查询次数)的问题可以使用 Redis 性能测试报告中的数据即可。 Redis 优势有以下几个:
- 基于内存: Redis 是一种基于内存的数据存储系统,所有的数据都存储在内存中。相比传统的磁盘存储系统,内存访问速度更快,这使得 Redis 能够在毫秒级别快速地读取和写入数据。
- 单线程模型: Redis 使用单线程模型来处理客户端请求。这可能听起来似乎效率不高,但实际上,这种设计有助于避免多线程的竞争条件和锁开销。Redis 通过非阻塞的方式处理多个客户端请求,每个请求的执行时间很短,因此在单线程下,Redis 能够处理大量的并发请求。
- 高效数据结构: Redis 提供了多种高效的数据结构,如哈希表、有序集合等。这些数据结构的实现都经过了优化,使得 Redis 在处理这些数据结构的操作时非常高效。
- 非阻塞 I/O: Redis 使用了非阻塞 I/O 模型,这意味着当进行磁盘读写或者网络通信时, Redis 不会等待数据的返回,而是继续处理其他请求。这样可以充分利用 CPU 的时间,提高整体的吞吐量。
Redis 官方性能测试报告地址:https://redis.io/docs/management/optimization/benchmarks/
window答案加分项: 除了官方的性能测试数据之后,还可以使用 Redis 自带的性能测试工具 redis-benchmark l来对当前环境下的 Redis 做性能测试和预测,但也需要注意,网络带宽和网络延迟可能是 Redis 操作最大的性能瓶颈。
问题2:Redis 内存不够用怎么办?
答案解析思路: Redis 内存不够用时,会触发 Redis 内存淘汰策略。 早期版本的 Redis 有以下 6 种淘汰机制(也叫做内存淘汰策略):
- noeviction:不淘汰任何数据,当内存不足时,新增操作会报错,Redis 默认内存淘汰策略;
- allkeys-lru:淘汰整个键值中最久未使用的键值;
- allkeys-random:随机淘汰任意键值;
- volatile-lru:淘汰所有设置了过期时间的键值中最久未使用的键值;
- volatile-random:随机淘汰设置了过期时间的任意键值;
- volatile-ttl:优先淘汰更早过期的键值。
在 Redis 4.0 版本中又新增了 2 种淘汰机制:
- volatile-lfu:淘汰所有设置了过期时间的键值中,最少使用的键值;
- allkeys-lfu:淘汰整个键值中最少使用的键值。
其中 allkeys-xxx 表示从所有的键值中淘汰数据,而 volatile-xxx 表示从设置了过期键的键值中淘汰数据。 所以,现在 Redis 的版本中有 8 种内存淘汰策略。
答案扩展: 当然你还可以通过设置 Redis 的最大运行内存来尽量避免这个问题,它的设置步骤
- 打开 Redis 的配置文件:在 Redis 的安装目录下找到 redis.conf 文件,使用文本编辑器打开该文件。
- 找到并修改 maxmemory 参数:在配置文件中,搜索并找到名为"maxmemory"的参数,该参数控制 Redis 的最大内存限制。默认情况下,该参数被注释掉,即 Redis 不会限制内存使用。
- 设置 maxmemory 的值:取消注释 “maxmemory” 参数,并将其值设置为期望的运行内存大小。值可以使用单位 K、M、G 来表示,如"1G"表示 1GB 内存。确保设置的内存大小合理,不要超过可用物理内存的限制。
- 配置内存淘汰策略:在 Redis 超过设置的最大内存限制时,需要根据配置的策略来决定如何清理数据。找到并修改"maxmemory-policy"参数,可以选择使用的内存逐出策略,如 volatile-lru、allkeys-lru、volatile-random 等。
- 保存配置文件:保存对 redis.conf 文件的修改。
- 重启 Redis 服务:重新启动 Redis 服务,使新的配置生效。
问题3:是否定义、设计过业务模型?
答案解析思路: 这个问题看似“高大上”,但其实非常简单。所谓的业务模型就是将需求转换成程序之后,设计的数据库和数据表,所以在开发中你一定定义过或设计过业务模型。
在软件开发过程中,业务模型是一种抽象表示,用于描述系统中涉及的业务实体、其属性和关系,以及业务流程。
定义和设计业务模型的过程涉及以下几个方面:
- 理解业务需求:首先,需要与业务团队密切合作,深入了解业务需求。这包括了解业务流程、业务规则以及业务参与者之间的关系。
- 分析业务实体:根据业务需求,将业务实体抽象成模型中的类或对象。这些实体可能包括产品、用户、订单等,每个实体都有相应的属性和行为。
- 建立关系和依赖:在业务模型中,不同实体之间可能存在关系和依赖,如一对一、一对多、多对多等关系。需要根据业务需求,确定和定义这些关系。
- 设计业务逻辑:根据业务需求,确定业务模型中的行为和业务逻辑。这些逻辑可以通过方法、规则或者流程来表示,以实现业务的各种操作和处理。
- 持久化与数据模型:将业务模型映射到数据模型,用于在持久化介质(如数据库)中存储和检索数据。这涉及选择合适的数据结构和数据库设计,以及确保业务模型与数据模型的一致性。
在设计数据库的整个过程中,要遵循数据库的“三范式”。
数据库的三范式是指关系型数据库设计中的三个规范化级别,用于优化数据存储和查询的效率,提高数据的一致性和可维护性。这三个范式分别是:
- 第一范式(1NF):第一范式要求关系表中的每个属性(列)都是原子的,不可再分的。每个属性都应该包含单一的值,不允许存在重复的属性或属性中包含多个值。这样可以避免数据冗余和数据的不一致性。
- 第二范式(2NF):第二范式在满足第一范式的基础上,进一步要求表中的非主键属性完全依赖于主键属性。也就是说,表中不存在非主键属性对部分主键属性进行冗余的情况。通过将数据分解为更小的表和使用关联关系,可以减少数据冗余,并确保数据的一致性。
- 第三范式(3NF):第三范式在满足第二范式的基础上,进一步要求表中的非主键属性之间互不依赖。也就是说,表中的每个非主键属性只依赖于主键或其他非主键属性,不会存在传递依赖的情况。通过进一步的数据分解和建立外键关系,可以消除冗余数据和数据的多次更新。
遵循三范式的设计原则能够提高数据库的数据结构和查询效率,并减少数据冗余和依赖问题,从而提高数据库的性能和可维护性。但需要注意,在实际设计中需要根据具体的业务需求和查询需求进行灵活的取舍和权衡,不一定要求严格遵守三范式。
问题4:百万级用户规模服务上线的话需要做什么?
答案解析思路: 百万级用户规模在上线的时候,主要考虑的是高可用和容错的处理。因为你的业务更新不能影响用户的正常使用,并且要做好上线前测试、以及灰度发布、备份及回滚等准备工作。
百万级用户规模需要考虑的主要内容有以下几方面:
- 架构设计与扩展性规划:确保服务具备良好的扩展性和可伸缩性,以应对大量用户的访问请求。这涉及到合理的系统架构设计、使用水平扩展和垂直扩展等技术手段。
- 性能测试和优化:进行全面的性能测试,模拟高并发、大数据量等场景,发现和解决系统瓶颈和性能问题。通过优化数据库查询、缓存使用、代码逻辑等方面,提高系统的响应速度和稳定性。
- 高可用和容错处理:确保服务在面对故障或意外情况时也能保持高可用性,不影响用户体验,所以尽量选择用户使用频率最低的时间段来更新,比如凌晨 3 点到 5 点之间。采用负载均衡、故障转移、备份恢复等机制,对关键系统组件进行容错处理。
- 安全性保障:加强系统的安全性,保护用户数据和隐私。进行安全性评估和漏洞扫描,采用合适的身份认证、访问控制、数据加密等技术手段,预防和防范潜在的安全威胁。
- 监控和日志记录:建立全面的系统监控和日志记录机制,及时发现和解决系统故障和异常。监控系统的性能指标、错误日志、访问日志等,保持对系统运行状态的实时了解,为及时处理问题提供依据。
- 客户支持和用户反馈:建立用户支持渠道,及时处理用户反馈和问题。通过建立客户服务团队、在线帮助文档、用户反馈收集等方式,积极跟进用户需求和问题,不断优化产品和服务。
问题5:JVM 怎么创建一个对象?
答案解析思路: JVM 创建对象的过程,其实就是 JVM 类加载的过程。JVM 类加载可以分为以下几个阶段:
-
加载
-
链接
- 验证
- 准备
- 解析
-
初始化
具体内容如下。
① 加载
加载(Loading)阶段是整个“类加载”(Class Loading)过程中的一个阶段,它和类加载 Class Loading 是不同的,一个是加载 Loading 另一个是类加载 Class Loading,所以不要把二者搞混了。 在加载 Lo