每日十题八股-2025年1月24日

1.面试官:Kafka 百万消息积压如何处理?
2.面试官:最多一次、至少一次和正好一次有什么区别?
3.面试官:你项目是怎么存密码的?
4.面试官:如何设计一个分布式ID?
5.面试官:单点登录是怎么工作的?
6.面试官:如何设计安全的对外 API?
7.面试官:如果你的项目要支持百万用户,你会如何设计?
8.面试官:如果你的项目用户规模放大了 100 倍,怎么应对?
9.面试官:你的项目如何做到高可用、高吞吐、高扩展性?
10.面试官:CPU 100% 问题怎么排查?

1.面试官:Kafka 百万消息积压如何处理?

当 Kafka 出现百万级消息积压时,可以从以下几个方面处理:

定位问题:

先检查消费组的 Lag(消息积压量),确认是消费者处理能力不足,还是生产端消息量过大导致的。

提升消费能力:

增加消费者实例数: 增加消费者实例来分摊压力,但确保实例数不超过分区数。
优化消费逻辑: 使用批量拉取和异步处理,减少单条消息的处理时间。
跳过无关消息(如果业务允许): 临时将 offset 调整到最新位置,优先处理新消息。

优化 Kafka 配置:

调整消费端参数,比如增大 max.poll.records 和 fetch.max.bytes,提高拉取效率。
如果 Broker 性能不足,可以扩容集群或增加分区,将负载分散。

控制生产速度:

对生产端限流,避免消息积压进一步恶化。

清理积压消息(最后手段):

如果消息已经过期或无用,可以调整 offset 或删除积压消息。

总结: 处理积压关键在于快速提升消费能力,并结合优化生产消费的配置,确保系统及时恢复正常运行。

2.面试官:最多一次、至少一次和正好一次有什么区别?

“最多一次”、“至少一次”和“正好一次”是分布式系统中常见的消息投递语义,用来描述消息在网络中被传递的行为方式。
企业在设计分布式系统时,通常根据业务需求选择:
最多一次: 低成本,高吞吐,对可靠性要求低的场景。(投递一次,甚至不投递)
至少一次: 适合高可靠性需求,允许通过逻辑处理重复消息。(至少投递一次,甚至更多)
正好一次: 适用于对准确性要求极高的关键业务。(投且投递一次)
在这里插入图片描述

3.面试官:你项目是怎么存密码的?

采用 bcrypt/Argon2 哈希密码存储,结合随机盐值确保唯一性,并使用 HTTPS 加密传输。
在这里插入图片描述

4.面试官:如何设计一个分布式ID?

设计分布式 ID 时需要权衡:

	场景需求: 是否需要有序性、分布式部署、抗单点故障。
	性能要求: 每秒生成量是否满足高并发需求。

企业一般会根据具体场景选用合适的方案,如雪花算法解决高性能问题,号段模式减少数据库压力,Redis 保证灵活性。

一、为什么分布式 ID 是一个重要问题?

唯一性:
在分布式系统中,多个服务实例和数据库节点需要生成全局唯一的 ID,避免数据冲突。
例如,订单号、用户 ID 等不能重复。
高性能:
分布式 ID 的生成需要满足高并发场景,比如每秒生成百万级 ID。
有序性:
一些场景需要生成的 ID 具有顺序性(如时间递增),方便排序和索引优化。
可扩展性:
系统需要支持节点动态扩展或收缩,ID 生成机制不能成为瓶颈。

二、如何设计一个分布式 ID?

常见的分布式 ID 设计方案如下:
1. 数据库自增 ID
利用数据库的自增字段生成唯一 ID。
优点: 简单易用,ID 有序。
缺点: 性能瓶颈(高并发下会锁表),数据库故障导致不可用。
2. UUID(Universally Unique Identifier)
直接调用系统提供的 UUID 生成方法。
优点: 易实现,生成快,ID 唯一。
缺点: 长度较长(128 位),不适合索引,缺乏有序性。
3. 号段模式(Segment Model)
从数据库中预分配一批连续的 ID 号段(如[1-1000]),每个节点使用自己的号段。
优点: 高效、减少数据库压力。
缺点: 数据库依赖,批量失效可能浪费号段。
4. 雪花算法(Snowflake Algorithm)
Twitter 提出的分布式 ID 生成方案,将 ID 拆分成以下部分:
时间戳(41 位): 毫秒级时间,表示当前时间。
数据中心 ID(5 位)+ 机器 ID(5 位): 标识生成 ID 的节点。
序列号(12 位): 每毫秒内生成的序号,防止重复。
优点: 高性能、低延迟、时间有序、去中心化。
缺点: 实现复杂,需要全局时钟同步。
5. 基于 Redis 的分布式 ID
使用 Redis 的自增操作(INCR)生成 ID。
优点: 高性能,Redis 天生支持分布式。
缺点: Redis 故障会影响 ID 生成。
6. Zookeeper 分布式 ID
利用 Zookeeper 的顺序节点生成全局唯一的 ID。
优点: 可靠性高,ID 有序。
缺点: 性能一般(每次生成都需要写 Zookeeper)。

三、现在企业是如何解决分布式 ID 的问题?

互联网公司(高性能场景):
雪花算法(Snowflake): 常用于订单号、用户 ID 等。
例如:Twitter 原创,国内很多公司(如阿里、字节)都有改进版本。
号段模式: 数据库或缓存预分配号段,适合稳定、高并发场景。
金融领域(有序性要求高):
使用 Zookeeper 顺序节点或基于数据库主键生成。
对事务一致性和顺序要求高的场景。
大规模分布式系统:
利用 Redis 集群作为 ID 生成器,结合雪花算法或分片机制。

5.面试官:单点登录是怎么工作的?

单点登录(SSO) 通过一个统一的认证中心管理 用户登录状态,不同系统之间通过共享 Token 或凭证实现登录信息的同步。它提升了用户体验,同时简化了系统的认证流程。

在这里插入图片描述

6.面试官:如何设计安全的对外 API?

如果要设计一个安全的对外 API,我会从以下几个方面入手:

认证和授权:

使用 OAuth 2.0 或 JWT 来认证用户身份,确保调用者合法。
通过角色或权限控制(RBAC/ABAC),限制用户访问特定资源。

数据加密:

强制 HTTPS,确保传输中的数据被加密。
对敏感数据进行字段级加密,并对返回结果做数据脱敏。

防护机制:

使用时间戳和签名机制防止重放攻击。
针对敏感接口,比如登录,加验证码和失败次数限制,防止暴力破解。
实施限流策略,防止恶意刷 API,比如单 IP 每秒限制请求次数。

错误和暴露控制:

返回的错误信息只提供必要信息,避免暴露内部系统细节。
只开放必须的接口,隐藏无关的内部实现。

安全监控:

记录和审计所有 API 请求日志,实时监测异常流量,便于追溯和故障排查。

定期更新:

定期轮换密钥、修补依赖库漏洞,同时进行安全测试,确保系统长期安全。

通过以上方法,可以有效保证对外 API 的数据安全和系统稳定性,同时降低潜在风险。

7.面试官:如果你的项目要支持百万用户,你会如何设计?

和第八题类似,一起回答。
其实本质就是将单体项目逐渐改进到分体项目的过程。首先是把数据和应用分割到两个不同服务器,然后分别优化应用和数据形成各自的集群,引入主副,主从,各种微服务组件。

  1. 架构设计:分层解耦,支持高并发。我会采用分层架构和分布式设计,分解系统的功能模块,每层专注处理自己的职责。

    前端层(负载均衡 + CDN):
    部署CDN(内容分发网络),将静态资源如图片、CSS、JavaScript缓存到边缘节点,减少服务器压力,提升用户访问速度。
    使用负载均衡器(如 Nginx、HAProxy),将流量分发到多台后端服务器,支持水平扩展。
    应用层:
    应用服务会采用无状态设计,状态信息存储在缓存或数据库中,方便应用服务扩容。
    服务拆分为独立的微服务,按功能解耦(如用户服务、订单服务、支付服务),通过 API 网关(如 Kong)统一管理。
    数据层:
    使用分布式数据库(如 MySQL 分片、TiDB)支持海量数据存储和查询。
    利用读写分离,主库写数据,多个从库读数据,提高读性能。
    引入分布式缓存(如 Redis、Memcached)加速高频访问数据,如用户会话、热点数据等。
    
  2. 高并发:异步 + 分布式队列

     异步处理:
     对于耗时操作(如下单后发通知),使用消息队列(如 Kafka、RabbitMQ)异步处理,减少用户等待时间。
     异步任务处理还能平滑流量峰值。
     限流和降级:
     在接口层实现限流策略(如漏桶算法、令牌桶算法)来保护系统,防止流量暴增导致崩溃。
     非核心服务出现压力时,可以降级(如取消某些推荐功能)。
    
  3. 数据库设计:分区分库分表

     分区和分表:
     按用户 ID 或订单 ID 对表进行分区或分表,降低单表的数据量,提升查询效率。
     分库:
     数据按业务或地理位置拆分到不同的数据库节点,形成分布式数据库集群。
     事务处理:
     分布式事务可通过 **两阶段提交(2PC)或最终一致性(TCC 模式) ** 来保证。
    
  4. 高可用性:多副本 + 故障恢复

     服务高可用:
     通过服务注册与发现(如 Eureka、Consul),让服务实例自动接管流量,实现无缝扩容或切换。
     应用层部署多个实例,利用健康检查机制快速剔除故障实例。
     数据库高可用:
     数据库采用主从复制或多主架构,主节点故障后快速切换到从节点。
     灾备设计:
     跨数据中心部署,关键数据进行定时备份,保证在意外情况下的快速恢复。
    
  5. 可扩展性:按需扩容

     通过容器化和编排工具(如 Docker + Kubernetes)实现弹性扩容:
     根据流量动态调整实例数量,低谷时释放资源,高峰时自动扩展。
    
  6. 性能优化:监控和调优

     全链路监控:
     部署监控工具(如 Prometheus + Grafana)监测各模块性能,实时报警异常情况。
     代码和查询优化:
     数据库查询建立合理索引,避免全表扫描。
     服务接口按热点和冷门数据优化响应逻辑,提升吞吐量。
    

8.面试官:如果你的项目用户规模放大了 100 倍,怎么应对?

9.面试官:你的项目如何做到高可用、高吞吐、高扩展性?

高可用的意思就是保证服务尽可能保证处于正常状态,例如4个9,99.99%的时间内都是正常的。这一思路就是主从,集群之类的,保证一台服务器宕机立马会有其他副本服务器顶上。

高吞吐服务需要在一段时间内处理大量请求。常用的指标是 QPS(每秒查询次数)或 TPS(每秒事务次数)。为了实现高吞吐量,我们通常会在架构中添加缓存 ,以避免经过数据库或磁盘等较慢的 I/O 设备。我们还可以为计算密集型任务增加线程数量。 我们还可以在系统中使用异步处理,以有效地单独隔离耗时耗资源的组件。

高扩展性意味着系统可以快速、轻松地扩展,以容纳更多的容量**(横向可扩展性)** 或更多的功能(纵向可扩展性)。 要实现高度可扩展性,需要隔离每个服务的职责。为此,微服务被广泛采用 。我们还利用服务注册和负载平衡器 将请求路由到适当的实例。

10.面试官:CPU 100% 问题怎么排查?

基本思路就是先判断占用cpu资源最多的进程,如果是服务程序大致可以使用两种方式。
系统工具 + jstack: 适合手动分析,步骤清晰,适合初步排查。
Arthas: 提供更友好的交互界面和实时分析功能,适合快速深入定位问题。

top进程,然后找线程,最后找到对应代码块获得占用的核心步骤。

### 常见技术面试问题及答案 #### 1. Java 基础知识 **问题:解释Java中的多态性。** 答案:多态性是指允许不同类的对象对同一消息作出响应的能力。多态性主要通过方法重载(编译时多态)和方法重写(运行时多态)来实现。在运行时多态中,父类引用可以指向子类对象,调用方法时会根据实际对象类型来决定执行哪个方法。 ```java class Animal { void sound() { System.out.println("Animal makes a sound"); } } class Dog extends Animal { void sound() { System.out.println("Dog barks"); } } public class TestPolymorphism { public static void main(String[] args) { Animal myAnimal = new Dog(); // Upcasting myAnimal.sound(); // Outputs "Dog barks" } } ``` #### 2. 数据结构与算法 **问题:解释快速排序的基本思想。** 快速排序的基本思想是选择一个基准元素,通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比基准元素小,另一部分记录的关键字均比基准元素大,然后分别对这两部分记录继续进行排序,以达到整个序列有序的目的[^1]。 ```java public class QuickSort { public static void quickSort(int[] arr, int low, int high) { if (low < high) { int pi = partition(arr, low, high); quickSort(arr, low, pi - 1); quickSort(arr, pi + 1, high); } } private static int partition(int[] arr, int low, int high) { int pivot = arr[high]; int i = (low - 1); for (int j = low; j < high; j++) { if (arr[j] <= pivot) { i++; int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } int temp = arr[i + 1]; arr[i + 1] = arr[high]; arr[high] = temp; return i + 1; } public static void main(String[] args) { int[] arr = {10, 7, 8, 9, 1, 5}; quickSort(arr, 0, arr.length - 1); for (int num : arr) { System.out.print(num + " "); } } } ``` #### 3. 系统设计 **问题:如何设计一个高并发的Web应用?** 设计高并发的Web应用需要考虑多个方面,包括但不限于负载均衡、缓存机制、数据库优化、异步处理等。负载均衡可以通过Nginx或HAProxy来实现,将请求分发到多个服务器上。缓存机制可以使用Redis或Memcached来减少数据库的压力。数据库优化包括索引优化、读写分离等。异步处理可以通过消息队列如RabbitMQ或Kafka来解耦系统组件,提高系统的响应速度和吞吐量。 #### 4. 编程实践 **问题:解释Java中的垃圾回收机制。** Java的垃圾回收机制是自动管理内存的一种方式,它负责回收不再使用的对象所占用的内存空间。垃圾回收器会定期检查哪些对象是可达的(即仍然被引用的对象),哪些对象是不可达的(即不再被引用的对象)。不可达的对象会被标记为垃圾,并在后续的垃圾回收过程中被清除。Java提供了多种垃圾回收算法,如标记-清除算法、复制算法、标记-整理算法等,不同的垃圾回收器适用于不同的应用场景。 #### 5. 分布式系统 **问题:解释CAP定理。** CAP定理指出,在一个分布式系统中,一致性(Consistency)、可用性(Availability)和分区容忍性(Partition tolerance)这三个特性最多只能同时满足两个。一致性意味着所有节点在同一时间看到相同的数据;可用性意味着每个请求都能得到响应,但不保证是最新的数据;分区容忍性意味着即使网络分区存在,系统仍能继续运行。根据不同的业务需求,可以选择牺牲其中一个特性来实现其他两个特性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值