涉及分布式锁、中间件、数据库、分布式缓存、系统高可用等多个技术领域,旨在考查候选人的技术深度、架构设计能力与解决实际问题的能力。
1. 以 Redis 是否可以作为分布式锁为例:
-
用 Redis 实现分布式锁会存在哪些问题?
- 死锁:如果锁持有者崩溃,锁不会被释放。解决方法:设置锁的过期时间。
- 竞争条件:多个进程同时获取锁。解决方法:使用
SETNX
或Redisson
等客户端支持的加锁机制。 - 释放锁失败:由于锁的释放通常需要持有者来释放,其他进程无法主动释放锁。解决方法:锁的释放必须由持有者原子操作完成,且使用
Lua 脚本
来避免竞争。
-
Redis 如何实现多节点之间的数据一致性?
- 复制和持久化:通过主从复制和 AOF(Append Only File)来实现数据同步和持久化。
- 哨兵机制:通过 Redis Sentinel 实现自动故障转移和监控,保证高可用性。
- 集群模式:Redis 集群通过分片实现数据的分布式存储,各个节点通过一致性哈希来分配和同步数据。
2. 中间件相关:
-
如何回答实现一个 RPC 框架?
- 服务注册与发现:使用 ZooKeeper 或 Consul 进行服务的注册与发现。
- 请求路由:客户端根据服务名称从注册中心获取服务地址,路由到具体的服务节点。
- 网络通信:使用高效的序列化协议(如 Protobuf、Thrift)和网络协议(如 HTTP/2、gRPC)进行数据传输。
- 负载均衡:支持多种负载均衡策略(如轮询、加权随机、哈希等)来分发请求。
- 容错机制:支持超时、重试、断路器等机制来保证服务的可靠性。
-
MQ 如何实现消息的不丢失、不重复消费以及积压等问题?
- 不丢失:使用持久化存储(如 Kafka 的日志存储)和消息确认机制(ACK)来保证消息不丢失。
- 不重复消费:通过消息的去重标识(如唯一 ID)来避免重复消费,或者通过幂等性设计。
- 积压问题:可以通过消费端的并发消费、消息队列的分区机制、以及合理的消费速率来解决积压问题。使用死信队列(DLQ)处理无法消费的消息。
3. 分布式缓存相关:
- 在高并发场景下,分布式缓存的解决方案是什么?
- 缓存穿透:使用 Bloom Filter 预过滤非法请求。
- 缓存雪崩:设置缓存的过期时间为随机值,避免同一时刻大量缓存失效。
- 缓存击穿:使用互斥锁或分布式锁来保证同一时间只有一个请求去加载数据。
- 一致性哈希:通过一致性哈希算法来保证缓存数据均匀分布,减少缓存重建的成本。
- 缓存降级:当缓存不可用时,可以使用本地存储或者通过异步加载机制进行降级处理。
4. 互联网高性能高可用设计相关:
- 如何判断你的系统是高可用的?
- 容错能力:系统可以容忍单点故障,并且能够自动恢复。使用冗余、主备模式、健康检查等机制。
- 自动扩展:系统可以根据负载自动扩展或收缩,保证高并发时的性能。
- 负载均衡:多个节点之间通过负载均衡算法均匀分配流量,避免单点瓶颈。
- 故障转移:采用集群部署、分布式数据库和缓存,具备自动故障转移能力(如 Redis Sentinel、Zookeeper)。
- 监控与报警:实时监控系统各项指标,如响应时间、CPU 使用率、内存使用情况,及时报警并快速定位问题。
- 架构设计认知
- 面试重要性:面试中架构设计问题回答得好,易获面试官认可,可掩盖个别技术问题回答的不足。
- 回答思路:应立足于点、连接成线、扩散成面。以交易系统拆分为例,从订单、促销、报价系统层面及复杂度评估层面,全面阐述拆分逻辑,体现对系统设计的思考和理解。
- 底层逻辑:架构拆分目的是系统解耦,使系统职责单一、功能内聚,提高研发团队响应业务需求速度和开发效率,是管理在技术上提效的手段。
- 分析问题认知
- 系统设计与战略定位关系:技术人员做系统设计需与公司或部门战略定位对齐,满足业务方和管理者不同诉求,系统设计原则应针对系统现阶段业务发展主要矛盾提出。
- 实例分析:老系统架构改造时,业务发展使主要矛盾变为研发效率无法匹配业务需求,此时架构核心原则应围绕提升研发效率,合理拆分系统边界。
- 面试要点:面试回答系统设计问题时,要依据系统所处阶段主要矛盾,避免只强调高性能、高可用,展现解决业务领域主要问题的技术认知。
- 能力边界认知
- 高级研发工程师与架构师区别:高级研发工程师对系统的驾驭边界在模块或子系统层面,架构师至少在全系统层面,高级架构师在某一领域层面,架构师需掌握多系统层面的复杂度和解决问题的思考逻辑。
- 成长建议:研发工程师应养成归纳总结习惯,形成知识体系和方法论,跳出舒适区,争取扩展能驾驭系统边界的机会。
如何用架构师视角进行技术面试
以电商点评系统改造为例:
-
架构师视角面试要点
- 技术面试回答系统设计问题时,避免陷入技术细节,应从架构师全局技术视角阐述设计过程,展现解决问题的思维。
- 以电商点评系统初期同步RPC调用接口为例,业务发展后出现性能低、可用性受影响、需求迭代慢等问题,可引入MQ异步解耦并拆分业务逻辑。
-
系统复杂度分析方法
- 分析系统复杂度能明确设计原则,避免架构设计偏离方向,防止出现设计与实际需求不匹配的情况。
- 互联网软件复杂度包括功能性和非功能性复杂度。功能性方面,业务发展导致系统耦合、协作效率低;非功能性方面,通过计算点评系统消息处理量,可知其复杂度不在高性能,而在高可用性,如消息队列故障会影响业务。
-
点评系统架构方案设计
- 明确点评系统改造复杂度来源后,确定方案设计目标,即解决功能性复杂度带来的系统耦合和开发效率问题,以及保证非功能性复杂度中的高可用性。
- 提出多种架构方案,如采用开源MQ(如Kafka、RocketMQ等)、基于Redis实现消息队列、内存队列加MySQL等,并分析各方案技术可行性和优缺点。
-
架构方案评估标准
- 架构师常用设计原则(如系统无单点、可降级、可监控等)控制项目技术风险,这些原则是评估架构方案的重要手段。
- 针对点评系统,从功能性复杂度考虑团队能力、IT成本等与方案的匹配度;从非功能性复杂度依据系统无单点、可水平扩展、可降级原则评估方案。
-
技术实现与面试总结
- 确定架构方案后,需说明技术落地实现方式和深层原理,如基于Redis实现消息队列的多种方式及其优缺点。
- 总结系统改造面试四部回答法:谈复杂来源(结合业务场景和阶段)、谈解决方案(基于复杂度来源,区分主次问题)、谈评估标准(从功能性和非功能性角度)、说技术实现(讲出实现原理)。架构师视角是全局视角,涵盖空间和时间全局。
分布式技术
-
分布式面试与CP理论重要性:在互联网技术面试里,分布式技术是必考内容,尤其在一线互联网公司对候选人的要求中,分布式系统设计是关键考察点。
-
CP理论原理剖析
- 基本概念:CP理论中的C代表数据一致性,A代表服务可用性,P代表分区容错性,在分布式系统中,P必须保留,所以要在C和A之间进行选择,保证一致性选CP模型,保证可用性选AP模型。
- 原理示例:以分布式系统及其副本在正常和网络分区情况下的数据同步与读取为例,解释CP原理。在正常情况下,系统数据能正常同步,节点数据一致且都可用;但网络分区时,数据同步受阻,需在一致性和可用性间权衡。
- 实际权衡:实际中网络分区虽常见,但多数时间不存在。不同分布式系统要依据业务场景和需求在CP间权衡,由此产生了新模型,如PAC PLC模型。该模型规定,网络分区时在A和C间取舍,无网络分区时在L(延迟)和C间取舍。
-
BASE理论及实践应用
-
理论引入:BASE理论是CP理论的延伸,由Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)组成,作用是保证系统可用性,通过最终一致性代替强一致性,是分布式系统重要的经验总结。
-
实践案例:在电商网站双11场景中,通过关闭次要功能(服务降级)、延后预售商品支付时间(流量消峰)、使用延时队列处理抢购请求等方式实现基本可用性;用户下单时先在前台计数,后台异步批量处理库存扣减,体现软状态和最终一致性,这种数据处理方式在互联网设计中很常见。
-
-
-
不同层次面试要点
- 初中级研发工程师:回答问题时要充分理解CP理论原理,不能仅停留在概念层面,要有自己的思考,并将理论与实际结合,展示处理问题的思考逻辑。
- 高级研发工程师及架构师:除掌握CP理论外,还要展示知识体系和技术判断力。以Redis能否作为分布式锁为例,先指出实际问题,再依据CP理论分析其技术选型错误,进而扩展到分布式存储系统知识体系,从多维度分析问题,形成自己的知识体系和技术判断力,面试中要展现造轮子的能力(实际不推荐造轮子)。
-
面试答题思路总结:遇到理论性知识考察,可从三个层面回答:
- 展示理论深度:阐述知识点的工作原理、优劣势、适用场景等。
- 结合落地经验:将理论与落地方案的技术实现相结合,体现技术闭环思维。
- 展示知识体系:这是程序员向上发展的基础能力,知识体系和技术判断力体现架构师的能力边界。
-
分布式系统面试核心要点
- 面试常以业务场景设问,如设计海量商品存储架构,考察分布式系统中数据的存储、分布复制及相关协议算法。
- 核心考察点包括数据分配(如哈希分片、范围分片)、数据复制(主从模式保证高可用)和数据一致性(通过一致性协议解决)。
-
数据分片策略
-
哈希分片:以商品id为例,通过哈希函数计算并取模确定分片。优点是数据分布均匀、实现简单;缺点是节点变动时需重新计算哈希值,导致大规模数据迁移 。
-
一致性哈希:将存储节点和数据映射到哈希环上,按顺时针查找存储节点。常采用带虚拟节点的方式,能提升稳定性,减少节点变动时的数据迁移,但仍存在无法避免单一热点问题等局限。
-
例如当增加节点E时,商品100和1001需要迁移到节点E
-
范围分片:结合业务逻辑,如按商品类目分片,可使数据更均衡。通过分配元数据节点调度数据,客户端需请求分配元数据服务获取实际节点地址。该方式灵活性高、易扩展,但增加了系统复杂性。
-
-
数据一致性与相关算法
- etcd与raft协议:为保证分配元数据服务的可用性和数据一致性,可使用etcd集群。etcd基于raft协议实现数据共识,相比Paxos算法,raft算法更适用于工业界。Paxos算法虽能解决一致性前提下提高系统可用性的问题,但时间复杂度高,很少被直接采用。
- 最终一致性算法(Gossip协议):在一些对可用性要求高的场景,raft算法不适用,可选择基于Gossip协议的实现方式。它通过谣言传播机制实现最终一致性,适合动态变化的分布式系统。共识算法的选择与数据副本数量相关,副本少、节点少适合广播方式的协议,副本多、节点多适合最终一致性协议。
- 谣言传播
- 面试应对策略
- 回答时要基于常见的分库分表解决方案,如哈希取模、一致性哈希等,展示解决架构设计问题的思路,权衡系统可用性与一致性。
- 若涉及算法原理考察,需掌握basic Paxos、multi Paxos、raft等分布式系统中数据一致性共识算法。
分布式系统事务一致性
-
分布式事务问题引入:系统拆分后,一次写操作需协调多个子系统,引出分布式事务问题,即多个分布在不同服务器的小操作组成大操作,需保证同时成功或失败。以京都旅行系统下单场景为例,订单、商品、促销系统协同操作,体现其典型性。同时指出面试中候选者常选两阶段提交(2PC)方案,但实际多基于消息队列(MQ)实现分布式一致性。
-
面试答题套路:建议先介绍主流分布式事务一致性方案,再阐述可实现方案及知识点。可提及2PC或TCC与面试官交流,但要明确其在工业界落地代价大,仅适用于部分业务场景,如金融支付领域。
-
基于两阶段提交的解决方案:2PC是数据库领域解决分布式事务的典型协议,处理过程分准备和提交两个阶段,由协调者和参与者共同完成。涉及分布式事务规范。以具体系统为例,讲述其运行方式,包括事务管理器和资源管理器的作用。同时介绍了2PC存在的问题,如准备阶段加锁导致死锁、性能低下,提交阶段故障会使数据库阻塞,还可能出现数据不一致情况。
-
基于MQ的方案:在高并发场景下,通过放弃强一致性选择最终一致性提高系统可用性。以订单系统下单为例,将扣减优惠券事件放入MQ,由优惠券系统执行,实现业务解耦和流量消费。
- 但MQ存在自动应答机制导致消息丢失的问题,需手动发送应答解决。
- 大促时消息积压,订单系统无法感知下游操作,可通过让订单系统知道消费响应,利用定时任务扫描未完成消息重新投递进行补偿。
- 实现方式是订单系统先将消息持久化到本地数据库,设置状态为待发送,投递消息后,若收到优惠券系统消费成功的通知消息,再将本地消息状态设为已完成。如此,即使 MQ 出现消息丢失,也能从订单系统本地数据库扫描未完成消息重新投递,确保订单系统和优惠券系统最终操作的一致性。
- 基于MQ方案的考核点在于可落地性,实现生产者和消费者双向确认即可,且具有业务解耦和流量削峰优势。
- 实际工作中的考量:实际工作中并非所有业务都对事务一致性要求很高,更高要求意味着更多成本,这也是架构复杂度来源之一。回答分布式事务问题时,应站在业务实际场景考虑 。
分布式锁
- 分布式锁面试问题引入
- 概念:分布式锁用于协调分布式系统同步访问共享资源,系统获取访问权限后才能写入数据,其他系统需等待锁释放。
- 面试考察要点:面试官常问分布式锁问题并深挖细节,如控制并发访问、解决资源冲突等,在下单、优惠券等场景均有考察。
- 常见面试问题:包括如何实现分布式锁,如基于关系型数据库或分布式缓存实现;还会追问服务器挂掉时防止死锁的方法,以及不借助第三方组件设计分布式锁等问题。
- 分布式锁需解决的核心问题
- 核心问题:设计分布式锁需解决可用性、死锁、脑裂三个核心问题。可用性确保锁服务始终可用;死锁问题指客户端能获取锁,即使锁资源的客户端崩溃或网络不可达;脑裂问题是集群同步时数据不一致,导致多个进程同时拿到同一把锁。
- 问题解决的重要性:只有解决这些核心问题,才能评估分布式锁的优劣,回答面试提问时应从解决这些问题出发。
- 基于关系数据库实现分布式锁
- 实现方法:先查询数据库是否存在记录,借助数据库行锁(如MySQL的select for update)锁住数据,将查询和插入操作放在同一事务中提交。
- 存在问题:基于MySQL行锁可能出现交叉死锁,高并发场景下性能存在缺陷。
- 相关延伸问题:涉及数据库事务隔离级别,隔离级别影响并发处理能力,级别越高,系统并发性能越差;还可基于乐观锁(如版本号机制)实现分布式锁。
- 基于分布式缓存实现分布式锁
- 以Redis为例的实现方式:加锁时为键设置值并设置过期时间(避免死锁),解锁时通过Lua脚本保证删除操作的原子性,并确保执行客户端是加锁客户端。
- 优缺点:优点是性能高效、实现方便,跨集群部署可避免单点故障;缺点是低版本Redis存在死锁风险,超时时间设置不合理会导致分布式锁不可靠。
- 超时时间设置难题:可通过续约方式设置超时时间,但实现较复杂,需结合业务场景。
- Redis集群高可用问题及解决方案:Redis集群数据同步异步,可能导致多个应用服务器同时获取锁。Redis官方的RedLock算法可解决此问题,客户端向多个独立Redis实例依次申请加锁,若能和半数以上实例成功加锁且总耗时未超锁有效时间,则加锁成功。
- 分布式锁设计原则
- 互斥性:在分布式系统环境下,对于共享资源,同一时间只能有一个线程或进程进行操作,保证数据一致性和正确性。
- 高可用:锁服务无单点风险,集群环境下部分机器故障不影响锁服务。
- 锁释放具备失效机制:防止死锁,进程崩溃或解锁失败时能被动解锁。
- 可重入:获取锁的节点可再次获取锁资源。
- 基于Zookeeper实现分布式锁
- 利用临时顺序节点实现互斥性:Zookeeper 中,客户端在特定目录下创建临时顺序节点。由于顺序节点编号唯一且递增,创建编号最小节点的客户端获得锁。其他客户端创建节点后,通过监听编号前一个节点来等待锁释放,保证同一时刻只有一个客户端能获取锁进行资源操作 。
- 保障高可用性:Zookeeper 采用集群模式,多个节点保存相同数据副本。某节点故障时,其他节点可继续提供服务,客户端能重新连接到可用节点,避免单点故障,确保分布式锁服务稳定。
- 具备锁失效机制防止死锁:创建的临时节点与客户端会话绑定,客户端崩溃或网络故障导致会话超时,临时节点自动删除,即锁自动释放,后续等待客户端可获取锁,避免死锁。
- 支持可重入性:客户端可通过维护本地锁持有记录,每次请求操作前检查是否已持有锁。若已持有,直接执行操作;若未持有,按获取锁流程获取。Zookeeper 可根据客户端 ID 等标识判断节点是否由同一客户端创建,实现可重入功能。
RPC技术在面试中的考察
-
RPC技术面试考察点概述
- RPC是微服务架构基础,开发常需使用相关框架,面试常考察此技术。
- 候选人对RPC面试问题存在误区,认为仅考察常见基础问题,这些问题易找到答案,难以区分技术能力。
- 面试官多从实践操作和原理掌握两个角度递进考察候选人。
-
RPC超时问题与实践能力考察
- 以电商app商品详情页场景为例,面试官会问RPC调用链路超时时间设置及考虑问题,不能简单认为app调用网关超时时间大于网关调用后端服务超时时间之和。
- RPC超时设置涉及超时重试机制、调用链平均响应时间、依赖服务耗时、重传次数、服务降级等技术问题。
- 回答超时时间设置和重传次数问题,需综合考虑微服务的tp99请求耗时和业务场景,讲清网关调用下游服务的串并行方式、服务依赖关系,区分核心与非核心服务及相应处理策略,做到理论与实践结合。
-
RPC原理性知识考察
- 以电商app高并发场景为例,考察如何设计RPC框架承载大量请求,可从优化网络多元性能(选择高性能网络编程IO模型)和选择合适序列化方式(提升封包和解包性能)两个角度分析。
- RPC调用涉及网络通信,默认用TCP保证数据传输可靠性,因传输数据需为二进制,所以有序列化和反序列化过程,同时要约定RPC协议解决网络传输中的连包和半包问题。
-
RPC调用流程与序列化问题
-
RPC通信流程核心组成部分包括协议、序列化和反序列化以及网络通信。一次完整调用包括调用方序列化请求参数、通过TCP传输,服务提供方接收、分割、反序列化数据,调用方法,再序列化结果并回传,调用方接收后反序列化应答对象。
-
常见序列化方式有JSON(易用、应用广泛但空间开销大)、Hessian(性能和体积表现好)、Protobuf(序列化后体积小、兼容性好)。回答序列化方式选型问题,要综合考虑时间和空间开销、兼容性等因素。
-
-
RPC网络通信性能与IO模型
-
提升RPC网络通信性能关键在于选择高性能网络编程IO模型,需掌握网络编程中的五种IO模型(同步阻塞IO、同步非阻塞IO、IO多路复用、信号驱动以及异步IO),实际开发中常用BIO和NIO。
-
BIO网络模型中每个socket对应一个独立线程,存在socket连接数量受限、不适用于高并发场景、有两处阻塞(等待客户端连接和等待客户端发送数据)的问题。
-
NIO网络模型用一个线程处理多个连接,提高了工作线程利用率,减少了所需线程数量,通过selector选择器实现socket连接和数据读写分离,是目前主流RPC框架广泛使用的IO多路复用模型的基础。
-
-
RPC技术扩展考核点及总结
- 对于高级研发工程师,还会考察Reactor模型及其三种编程模型(单线程、多线程以及主从Reactor线程模型),以及Java中的高性能网络编程框架Netty。
- 程序员应具备造轮子的能力,建议阅读成熟RPC框架(如阿里Dubbo、谷歌gRPC)的源代码。
- 还具备连接管理、负载均衡、请求路由、熔断降级、优雅关闭等高级功能,了解这些功能在面试中可作为加分项。
[ 本章完 ]