分享
  1. 首页
  2. 文章

北京京东,看看难度

wangzhongyang007 · · 360 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

最近由于三大外卖平台"打仗",优惠券多到数不过来,一日三餐每个平台各点一单哈哈哈,正好最近[组织内部](https://mp.weixin.qq.com/s/OQD8MJakqkgMxdyvaYoX7w)还有朋友在**北京的京东**面试过,分享一下她的面经(Java岗): ### 1. Kafka消息不丢失问题,Kafka本身会去保证消息的不丢失,为什么还需要存一个本地消息表来保证消息的不丢失呢? Kafka 本身通过副本机制、生产者确认(acks)、消费者手动提交等设计理论上可以实现消息不丢失,但在实际分布式系统中,由于业务逻辑复杂性、中间件与业务操作的原子性难以保障,仍需要引入"本地消息表"等额外机制。以下是具体原因及解决方案的对比分析: **Kafka 消息不丢失的机制及其局限性** 1. **生产者端** - `acks=-1`:要求所有 ISR(同步副本)确认写入成功,否则重试。 - 重试机制:配置 `retries` 和 `retry.backoff.ms` 应对网络抖动。 2. **Broker 端** - 副本冗余:通过 `replication.factor≥3` + `min.insync.replicas≥2`,避免单点故障丢失数据。 - 持久化:消息先写入 PageCache 再异步刷盘(依赖服务器可靠性)。 3. **消费者端** - 手动提交 offset:关闭 `enable.auto.commit`,业务处理成功后再提交 offset,避免消息未处理就被标记消费。 **Kafka 机制的局限性** 1. **生产者与 Broker 的协同问题** - 若生产者发送成功但 Broker 未返回 ACK(如网络中断),重试可能导致消息重复,但无法避免中间状态丢失。 2. **业务操作与消息消费的原子性** - 消费者处理业务逻辑(如更新数据库)与提交 offset 不是原子操作。若业务成功但 offset 未提交,系统重启后消息会重复消费;若业务失败但 offset 已提交,则消息永久丢失。 3. **极端故障场景** - Broker 集群同时宕机且未持久化的 PageCache 丢失。 - ISR 副本全部失效时,`unclean.leader.election` 配置可能导致数据丢失。 **为什么需要本地消息表?解决哪些 Kafka 无法覆盖的问题** 本地消息表的核心是将业务操作与消息发送/消费绑定为原子操作,通过业务数据库事务保证一致性: 1. **生产者端:解决"发送后丢失"问题** - **场景**:消息发送到 Kafka 成功,但业务操作(如订单创建)失败,需回滚消息。 - **方案**: - 业务数据与消息记录同库事务写入本地表。 - 异步线程轮询本地表,将未发送的消息投递到 Kafka。 - 投递成功后删除本地记录。 2. **消费者端:解决"消费后丢失"问题** - **场景**:业务逻辑成功执行(如扣款),但提交 offset 前消费者崩溃,导致消息重复消费。 - **方案**: - 消费消息时,先查询本地消息表是否已处理(通过消息唯一 ID)。 - 若未处理,执行业务操作并记录结果到本地表,同事务提交。 - 成功后提交 offset。 3. **关键价值:弥补分布式事务缺口** - 业务与消息状态的强一致:本地消息表通过数据库事务,确保业务操作和消息状态变更的原子性,避免 Kafka 各环节可能出现的状态分裂。 - 幂等性保障:通过本地表去重,解决生产者重试或消费者重复消费导致的数据错乱。 > **生产建议**: > - 若使用本地消息表,建议配合异步核对机制(如比对 Kafka 与业务库消息状态),防止极端情况下的表状态异常。 > - 优先通过 `idempotent producer`(幂等生产者)减少重复发送,而非完全依赖本地表。 > > **总结:Kafka 与本地消息表的关系** > Kafka 的可靠性机制解决消息在管道内的传输问题,而本地消息表解决业务操作与消息状态的全局一致性问题。二者是互补而非替代关系: > - 在需要 100% 业务一致性的场景(如资金变动),本地消息表是必要的最终防线。 > - 在可容忍 At-Least-Once 语义的场景(如日志收集),仅 Kafka 原生机制即可满足。 --- ### 2. 用守护线程来保证任务执行状态和数据库状态的一致性,这里有个问题,如果 subjob 执行完了在状态翻转之前宕机了,怎么保证他的一致性呢?宕机导致数据丢失的问题? 在分布式系统中,通过守护线程监控任务状态并同步到数据库时,若任务执行完成但状态更新前发生宕机,需通过以下机制保证一致性。具体解决方案如下: 1. **核心问题:宕机导致状态丢失的风险** - **场景复现**:SubJob 执行完成 → 守护线程未完成状态更新(如数据库写入)→ 系统宕机 → 重启后状态未翻转,任务被视为"未完成",可能触发重复执行或数据不一致。 - **根本原因**:任务执行结果与状态更新操作非原子性,二者分离导致中间状态丢失。 2. **解决方案:原子性保障 + 故障恢复机制** - **本地事务绑定状态更新** - **设计要点**:将任务执行结果与状态更新置于同一数据库事务中。 - **优势**: - 若 `updateStatus` 失败,事务回滚,任务结果不会被确认。 - 宕机时事务未提交,数据库自动恢复至初始状态。 - **局限**:需任务执行本身支持事务(如数据库操作)。 - **预写日志(WAL) + 检查点(Checkpoint)** - **流程**: - SubJob 完成时,先持久化结果到预写日志(如 Kafka 或持久化队列)。 - 守护线程消费日志,更新状态。 - 周期性设置 Checkpoint,记录日志消费位点。 - **故障恢复**: - 宕机重启后,从最近 Checkpoint 恢复日志消费位点,重放未确认的状态更新。 - 通过日志唯一 ID 实现操作幂等性,避免重复更新。 - **异步核对 + 补偿机制** - **设计要点**: - 守护线程更新状态后,异步记录操作流水(如操作 ID + 时间戳)。 - 定时扫描任务表与状态表的差异,对"执行成功但状态未更新"的任务触发补偿更新。 - **关键点**: - 核对需覆盖极端场景(如守护线程更新状态后宕机)。 - 补偿操作需幂等(例如通过 `UPDATE status SET state='done' WHERE id=task_id AND state!='done'`)。 3. **总结:关键设计原则** - **原子操作优先**:通过事务或预写日志绑定任务执行与状态更新,减少中间态窗口。 - **幂等性必备**:状态更新操作需支持重复执行(如基于唯一任务 ID 的幂等更新)。 - **最终一致性兜底**:通过核对与补偿覆盖极端故障,实现数据闭环。 > **生产建议**: > - 若采用预写日志,建议搭配 Kafka 事务消息(`idempotent producer`)避免消息重复。 > - 核对频率需权衡时效性与系统负载(如每 5 分钟扫描一次)。 --- ### 3. Dubbo 执行的原理 Dubbo 是一个高性能 Java RPC 框架,其核心执行流程如下: 1. **服务暴露与注册**: - 服务提供者启动时,将服务接口、实现类及主机信息注册到注册中心(如 ZooKeeper)。 - 注册中心通知消费者服务列表变更。 2. **服务调用流程**: - **代理层**:消费者通过动态代理生成远程接口的代理对象,调用时转为 RPC 请求。 - **集群容错**:根据配置(如 Failover、Failfast)选择可用提供者,支持负载均衡(如随机、轮询)。 - **网络传输**:通过 Netty 或 Mina 进行网络通信,默认使用 Hessian2 序列化协议。 3. **核心分层设计**: - **Service 层**:业务逻辑接口与实现。 - **Config 层**:配置管理(如 `@Reference` 注解注入服务)。 - **Proxy 层**:生成服务代理。 - **Registry 层**:服务注册与发现。 - **Monitor 层**:调用统计与监控。 --- ### 4. 什么情况下会导致索引失效 MySQL 索引失效的常见场景包括: 1. **违反最左前缀原则**: - 复合索引 `(a,b,c)` 下,查询条件缺失 `a` 或未按顺序使用索引列(如 `WHERE b=1`)。 2. **对索引列运算或函数操作**: - 例如 `WHERE YEAR(create_time)=2023` 或 `WHERE amount*2>100`。 3. **隐式类型转换**: - 如字符串字段使用数字查询(`WHERE code=100`,实际 `code` 为 VARCHAR)。 4. **使用 `OR` 连接非索引列**: - `WHERE a=1 OR b=2`,若 `b` 无索引则全表扫描。 5. **`LIKE` 以通配符开头**: - `WHERE name LIKE '%abc'` 无法利用索引(`LIKE 'abc%'` 有效)。 6. **数据分布不均**: - 优化器判断全表扫描更快(如表中 90% 数据满足条件)。 --- ### 5. MySQL 的 MVCC 机制 MVCC(多版本并发控制)是 InnoDB 实现高并发的核心机制: 1. **核心组件**: - **隐藏字段**:每行数据包含 `DB_TRX_ID`(最近事务 ID)和 `DB_ROLL_PTR`(回滚指针)。 - **Undo Log**:存储数据的历史版本,用于回滚和一致性读。 - **Read View**:事务开启时生成,记录当前活跃事务 ID 列表,用于判断数据可见性。 2. **可见性规则**: - 数据行的 `DB_TRX_ID` 小于 Read View 中最小事务 ID → 可见(已提交)。 - `DB_TRX_ID` 大于 Read View 中最大事务 ID → 不可见(未提交)。 - `DB_TRX_ID` 在活跃事务列表中 → 不可见(未提交);否则可见。 3. **解决并发问题**: - **读已提交(RC)**:每次查询生成新 Read View,避免脏读。 - **可重复读(RR)**:事务内首次查询生成 Read View 并复用,避免不可重复读。 --- ### 6. 缓存穿透和缓存雪崩 1. **缓存穿透**: - **问题**:大量请求查询不存在的数据(如无效 ID),绕过缓存直击数据库。 - **解决方案**: - 布隆过滤器(Bloom Filter)拦截非法 Key。 - 缓存空值(`key:null`),并设置短过期时间。 2. **缓存雪崩**: - **问题**:大量缓存同时失效,请求集中访问数据库导致宕机。 - **解决方案**: - 过期时间添加随机值(如 `30min + rand(10min)`)。 - 热点数据永不过期,后台异步更新。 - 熔断降级:数据库压力过大时拒绝部分请求。 --- ### 7. Redis 如何保证高性能?Redis 数据结构 Redis 高性能的核心设计: 1. **内存操作**:数据全内存存储,读写速度比磁盘数据库快 105 倍。 2. **高效数据结构优化**: - **SDS(简单动态字符串)**:预分配空间减少扩容开销。 - **跳表(ZSET)**:O(logN) 复杂度实现范围查询。 - **渐进式 Rehash(Hash)**:避免一次性迁移大哈希表导致服务阻塞。 3. **单线程模型**(6.0 前核心命令处理): - 避免多线程锁竞争和上下文切换开销。 4. **I/O 多路复用**: - 基于 epoll/kqueue 监听大量连接,单线程处理网络 I/O。 5. **协议简单**:RESP 协议解析高效,减少 CPU 消耗。 > **Redis 6.0+ 优化**:网络 I/O 多线程化提升吞吐量,但命令执行仍保持单线程以保证原子性。 --- ### 8. Spring 和 Spring Boot 的区别 | **维度** | **Spring** | **Spring Boot** | |------------------|---------------------------------------|------------------------------------------| | **配置方式** | 需手动配置 XML/注解,依赖管理复杂。 | 自动配置(`@EnableAutoConfiguration`),简化依赖(Starter 包)。 | | **内嵌服务器** | 需外部部署(如 Tomcat)。 | 内置 Tomcat/Jetty,无需单独部署。 | | **监控与运维** | 需集成 Spring Actuator 等模块。 | 内置 Actuator,提供健康检查、指标收集等。 | | **开发效率** | 需大量样板代码。 | 约定优于配置,快速构建独立应用。 | --- ### 9. Spring Boot 自动装配的原理 自动装配通过以下流程实现: 1. **启动注解 `@SpringBootApplication`**: - 组合了 `@EnableAutoConfiguration`,触发自动配置加载。 2. **加载 `spring.factories`**: - 扫描 `META-INF/spring.factories` 文件,读取 `AutoConfiguration` 类列表。 3. **条件化装配**: - 通过 `@ConditionalOnClass`、`@ConditionalOnProperty` 等注解,按需实例化 Bean(如仅当存在 `DataSource.class` 时配置数据库连接)。 4. **Bean 注册**: - 符合条件的配置类中,`@Bean` 方法将对象注册到 IoC 容器。 --- ### 10. `@Autowired` 是如何把 Bean 注入进去的 `@Autowired` 注入流程分为四个阶段: 1. **注入触发阶段**: - `AutowiredAnnotationBeanPostProcessor` 扫描被 `@Component` 标记的类,识别带 `@Autowired` 的字段/方法。 - 收集依赖信息并封装为 `InjectionMetadata` 对象。 2. **依赖解析阶段**: - **按类型匹配**:查找容器中与目标类型匹配的 Bean(如 `UserService`)。 - **按名称兜底**:若同类型多个 Bean 存在,尝试匹配字段/参数名称(如 `userService`)。 - **`@Qualifier` 指定**:强制按名称注入(如 `@Qualifier("masterDB")`)。 3. **注入执行阶段**: - **字段注入**:反射直接修改字段值(无需 Setter)。 - **方法注入**:调用 Setter 方法传入依赖对象。 4. **特殊场景处理**: - **集合注入**:`List<Interface>` 注入所有实现类;`Map<String, Interface>` 的 Key 为 Bean 名称。 - **静态字段限制**:无法直接注入静态变量(需通过 `@PostConstruct` 中转)。 > **底层原理**:依赖解析由 `DefaultListableBeanFactory.doResolveDependency()` 完成,最终通过 `Field.set()` 或方法反射注入。 --- ### 11. ES 与 MySQL 的区别,几个数据节点,几个副本,副本数可以为 0? **一、核心差异** | **维度** | **Elasticsearch** | **MySQL** | |------------------|---------------------------------------|------------------------------------| | **数据模型** | 文档型(JSON),倒排索引支持全文搜索。 | 关系型(行列),B+树索引支持事务。 | | **分布式架构** | 原生分片,横向扩展至数千节点。 | 单机为主,分库分表需中间件。 | | **查询场景** | 多字段组合查询高效(如 `title:手机 AND price:[1000 TO 2000]`)。 | 事务操作(ACID)、关联查询(JOIN)高效。 | **二、节点与副本配置** 1. **节点数量**: - **ES**:至少 3 节点(防脑裂),主分片与副本分片跨节点分布。 - **MySQL**:主从架构至少需 2 节点(1 主 + 1 从)。 2. **副本数规则**: - **ES**: - 可配置为 0(`number_of_replicas: 0`),但宕机时数据可能丢失。 - 生产建议 ≥1(副本=1 容忍单节点故障)。 - **MySQL**:副本数不可为 0(单点部署即无副本),高可用方案需 ≥1 从节点。 --- ### 12. 设计模式,使用过哪些设计模式,详细介绍模板方法 **模板方法模式**: 1. **核心思想**: - 定义算法骨架(抽象类),子类重写特定步骤而不改变结构。 2. **实现示例**: ```java public abstract class DataProcessor { // 模板方法(final 防止篡改) public final void process() { connect(); // 固定步骤 transform(); // 抽象方法(子类实现) disconnect(); // 固定步骤 } private void connect() { /* 数据库连接逻辑 */ } protected abstract void transform(); // 由子类自定义 private void disconnect() { /* 断开连接 */ } } public class CSVProcessor extends DataProcessor { @Override protected void transform() { System.out.println("解析 CSV 数据..."); } } ``` 3. **应用场景**: - **框架扩展点**:如 Spring 的 `JdbcTemplate`,用户实现 `RowMapper` 处理结果集。 - **业务流程标准化**:如订单处理流程(校验 → 计算 → 持久化),子类定制计算逻辑。 4. **优势**: - 避免代码重复,确保核心流程稳定。 - 开放扩展点,提升灵活性。 ## 欢迎关注 ❤ 我们搞了一个**免费的面试真题共享群**,互通有无,一起刷题进步。 **没准能让你能刷到自己意向公司的最新面试题呢。** 感兴趣的朋友们可以加我微信:**wangzhongyang1993**,备注:面试群。

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
360 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏