头图

这篇文章是在一个粉丝分享的某大厂面经的基础上,进一步整理的后端面试题。文中涵盖了数据库、消息队列、分布式限流等问题以及解析,适合想要冲击大厂的朋友参考。

整体情况

适用范围:有一定后端开发经验,正在冲击大厂后端岗位的朋友。

笔者情况:经过多轮技术面的锤炼,积累了丰富的面试实战经验,并在技术面中收获了宝贵的成长。

笔者感言:后端面试侧重于系统架构、数据处理和分布式技术等方面的深度考查。大厂在后端领域对原理的理解和实践经验的要求极高,每一个问题都考验你的综合能力,下面就详细说说这些面试问题。

数据库相关

引擎选择与特性

数据库用什么引擎好,innodb 有何优势,rocksdb 是怎样的?

在众多数据库引擎中,InnoDB 是 MySQL 的默认事务引擎,具有很强的事务支持能力。它支持 ACID 属性,能保证数据的一致性和完整性。在并发处理方面表现出色,通过 MVCC(多版本并发控制) 实现了高效的读写并发操作,可有效减少锁冲突,提高系统性能。例如在高并发的电商订单处理场景中,InnoDB 能很好地应对大量的读写请求,确保数据准确无误。

RocksDB 则是一款基于 LSM-Tree(日志结构合并树)的高性能键值存储引擎。它具有出色的写性能,适合处理大量的写入操作,如日志记录、实时数据采集等场景。其架构设计使其能够在存储大规模数据时保持较好的性能,并且支持数据的快速随机读写。

分库分表策略

数据如何进行分库分表,容量又该怎么确定?

分库分表是应对大数据量和高并发的重要手段。常见的分库分表策略有垂直分库分表和水平分库分表。

垂直分库是按照业务模块将数据库拆分成不同的库。例如将电商系统中的用户库、订单库、商品库分开。这样可以降低单个库的复杂度,提高维护性和扩展性。垂直分表则是将一个表中字段较多且部分字段访问频率较低的情况,将常用字段和不常用字段拆分成不同的表,减少数据查询时的 I/O 开销。

水平分库分表是基于数据量或数据范围进行拆分。比如按照用户 ID 取模的方式将数据均匀分布到多个库或表中。确定容量时,需要综合考虑业务的增长趋势、硬件资源(如服务器的磁盘空间、内存、CPU 性能)以及当前系统的性能瓶颈等因素。可以通过对历史业务数据量的分析和预估未来的业务增长速度,来合理规划分库分表的规模,确保系统在未来一段时间内能够稳定运行。

索引优化要点

联合索引的创建原则是什么?

联合索引的创建要遵循最左前缀原则。在创建联合索引时,要考虑查询语句中经常使用的列组合,将选择性高(即列值重复率低)且经常一起出现在查询条件中的列放在索引的最左边。例如在一个员工表中,经常按照部门和职位进行查询,那么创建联合索引 (department, position) 会比单独创建索引更有效。这样在查询时,数据库可以利用索引快速定位到符合条件的数据范围,提高查询效率。

慢查询处理方案

数据库出现大量慢查询影响其他业务时该如何处理?

当出现大量慢查询时,首先要通过慢查询日志分析出导致慢查询的原因。可能是查询语句没有使用合适的索引、涉及大量的数据表连接或者是数据库服务器的资源不足(如 CPU、内存、磁盘 I/O 等)。

针对没有使用索引的情况,可以通过创建或优化索引来解决。对于复杂的查询语句,可以进行重写或分解成多个简单查询。如果是资源不足,考虑升级硬件设备或优化数据库配置参数,如调整内存分配、增加缓存大小等。同时,可以采用数据库连接池技术来限制同时执行的查询数量,避免过多的慢查询占用系统资源,确保其他业务的正常运行。

半同步机制剖析

半同步机制的原理及作用是什么?

半同步复制机制是数据库保证数据可靠性的一种方式。在半同步模式下,主库在提交事务时,会等待至少一个从库确认已经接收到并写入了该事务的日志后才返回客户端成功。

其作用在于在一定程度上保证了主从库数据的一致性。与异步复制相比,它降低了数据丢失的风险;与全同步复制相比,又减少了主库等待所有从库确认的时间开销,在保证数据可靠性的同时兼顾了系统性能。在金融交易、订单处理等对数据一致性要求较高的业务场景中应用广泛。

消息队列相关

灾备与数据安全

消息队列灾备时,如何避免数据丢失?

在消息队列灾备中,为避免数据丢失,首先要采用持久化存储机制。确保消息在发送到消息队列后,能够可靠地存储在磁盘等持久化介质中,即使在系统故障或断电情况下也不会丢失。

同时可以采用多副本技术,将消息在多个节点上进行冗余存储。例如在 Kafka 中,通过配置多个副本因子,当一个节点出现故障时,其他副本可以继续提供服务,保证消息的可用性。设置合理的消息确认机制也很关键,如生产者在收到消息队列的确认应答后才认为消息发送成功,消费者在成功处理消息后向消息队列发送确认,确保消息在整个处理流程中的可靠性。

幂等性实现策略

消息队列的幂等性是如何实现的?

实现消息队列的幂等性可以通过多种方式。一种常见的方法是在消息中添加唯一标识,如消息 ID。消费者在处理消息时,先根据消息 ID 检查该消息是否已经被处理过,如果已经处理则直接丢弃,避免重复消费。

在数据库操作层面,也可以利用数据库的唯一约束来保证幂等性。例如在处理订单消息时,如果订单号在数据库中已经存在,则不再执行插入或更新操作。此外,还可以通过分布式锁来确保同一时间只有一个消费者实例对同一消息进行处理,防止因并发导致的重复消费问题。

RocketMQ 事务消息应用

rocketmq 的事务消息是如何使用的?

在 RocketMQ 中使用事务消息,首先生产者发送半事务消息到消息队列,此时消息处于不可见状态。然后生产者执行本地事务,并根据本地事务的执行结果向消息队列发送提交或回滚指令。

如果是提交指令,消息队列会将半事务消息标记为可消费状态,消费者可以正常消费;如果是回滚指令,消息队列会删除半事务消息。在整个过程中,消息队列会通过定时回查机制来检查未确定状态的半事务消息,确保事务的最终一致性。例如在电商系统的库存扣减和订单创建场景中,利用 RocketMQ 的事务消息可以保证库存和订单操作的原子性和一致性。

消息队列切换场景

在什么情况下会出现 rocketmq 不可用,需要切换到 kafka?

当 RocketMQ 出现严重的性能瓶颈,如在高并发场景下无法满足系统的吞吐量需求,或者发生频繁的系统故障且难以快速恢复时,可能需要考虑切换到 Kafka

例如在大规模的日志采集与分析系统中,如果 RocketMQ 无法及时处理海量的日志数据流入,导致消息积压严重,影响系统的实时性和稳定性,此时 Kafka 的高吞吐量和良好的扩展性可能更适合这种场景。另外,如果遇到 RocketMQ 与现有系统的某些组件兼容性问题,且无法通过简单的配置或升级解决时,也可能成为切换到 Kafka 的原因之一。

Kafka 消费有序保障

kafka 怎么保证消费有序?

Kafka 保证消费有序主要通过分区(Partition)机制。一个主题(Topic)可以分为多个分区,每个分区内的消息是按照顺序存储和消费的。

生产者在发送消息时,可以根据消息的关键属性(如订单 ID、时间戳等)选择合适的分区进行发送,确保具有相同关键属性的消息进入同一个分区。消费者在消费时,按照分区顺序依次拉取消息进行处理,从而保证了在分区内的消费有序性。对于需要全局有序的场景,可以通过设置只有一个分区来实现,但这会牺牲一定的吞吐量和扩展性。

分布式限流相关

第三方接口限流方案

调用第三方接口需要限流时,怎么做分布式限流?

在调用第三方接口时进行分布式限流,可以采用令牌桶算法或漏桶算法的分布式实现。例如基于 Redis 等分布式缓存来实现令牌桶算法,在 Redis 中设置一个计数器作为令牌桶,按照一定的速率向桶中添加令牌。

当需要调用第三方接口时,先从 Redis 中获取令牌,如果获取成功则允许调用,否则进行限流等待或拒绝调用。同时,可以结合分布式配置中心来统一管理限流规则,方便在集群环境中动态调整限流参数,确保各个节点的限流行为一致,避免因某个节点的过度调用导致第三方接口服务不可用。

分布式令牌桶原理

分布式令牌桶的具体实现原理是什么?

分布式令牌桶的原理是基于一个固定容量的桶来存放令牌,令牌以固定的速率生成并放入桶中。当有请求到来时,需要从桶中获取一个令牌才能继续执行后续操作,如果桶中没有令牌,则表示当前请求超过了限制速率,需要进行限流处理。

在分布式环境中,通常借助分布式存储(如 Redis)来实现令牌桶的共享和一致性。例如,通过 Redis 的原子操作来实现令牌的生成、获取和桶容量的控制。定时任务负责按照设定的速率向 Redis 中的令牌桶添加令牌,每次请求在进入业务逻辑前先尝试从 Redis 中获取令牌,根据获取结果决定是否允许请求通过,从而实现分布式系统中的限流功能,有效保护后端服务免受高并发请求的冲击。

希望这篇文章能为你的面试和学习之路提供帮助,后续还会有更多技术干货分享,敬请期待!

早日上岸!

我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。

没准能让你能刷到自己意向公司的最新面试题呢。

感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:sf面试群。


王中阳讲编程
805 声望297 粉丝