面试背景:两年工作经验 电商直播供应链背景 部门内推
面试总结:面试过程交谈愉快,总体耗时1h,一面寄
面试官反馈: 经验稍浅,技术深度需再沉淀
可取点:整体业务流程和技术架构能表述完整清晰,成功引导话题向CDC这一项目亮点并展开
需改进点:在解释技术选型和细节不够流畅,交谈时过于偏向于日常案例分析而忽略了方法论的总结;聊的太开废话多没有侧重点,所以会给人逻辑不够清晰的印象;在一些问题上没有更深入地聊下去。
Q:
1.自我介绍
2.项目中使用了mongoDB数据库,是为了解决什么问题?有对比过其他noSql吗,为什么选择了mongo?
3.聊聊Mysql怎么合理地创建索引
4.项目中使用了CDC,聊聊架构和数据同步流程
5.CDC从mongoDB同步到ES,怎么保证两端数据的一致性?
6.CDC框架中最终使用了Kafka做消息中间件,出于什么考虑,对比RocketMQ有什么优势吗?
7.JVM内存模型
8.线程池工作流程,平时怎么设置线程池参数
9.Spring事务传播机制,声明式事务和编程式事务区别
10.排查故障的流程
11.CodeReview工作怎么开展
12.反问
A:
2.项目中使用了mongoDB数据库,是为了解决什么问题?有对比过其他noSql吗,为什么选择了mongo?
多业务部门使用的业务字段不一且时常变动,因此使用MongoDB替换Mysql来存储客户信息,利用其“模式自由”的特性,方便业务自定义增加和设置属性,减少技术人员的开发成本。
3.聊聊Mysql怎么合理地创建索引
- 选择唯一性索引
- 为经常需要排序、分组和联合操作的字段建立索引
- 为常作为查询条件的字段建立索引
- 限制索引的数目
- 尽量使用数据量少的索引
- 数据量小的表最好不要使用索引
- 尽量使用前缀来索引
- 删除不再使用或者很少使用的索引
- 代码先行,索引后上
- where 与 Order by 冲突时优先 where
- 基于慢查询做优化
4.项目中使用了CDC,聊聊架构和数据同步流程
CDC架构原本采用canal+RocketMQ,后使用Debezium + Kafka。
原因:canal只支持Mysql存储引擎,canal全量同步默认使用offset分页,会出现慢sql问题,社区不活跃,很多问题需要重新开发解决。
Debezium支持多种存储引擎,并且框架自带KafkaConnect,保证高可用和高吞吐。
同步流程:
- source端提交connector任务到KafkaConnect集群
- 创建debezium connector,读取数据库相关权限配置
- 连接默认进行全量快照模式,获取指定库的scheme,记录当前binlog的offset,采集已有全量数据
- 采集完成后,启动binlogReader,从上一步的offset开始读取binlog记录,开始增量同步
- debezium本地采用生产者消费者模式,先将binlog消息加入队列再批量发送到broker
- sink端创建KafkaConnect任务,开始消费topic中的数据完成同步
5.CDC从mongoDB同步到ES,怎么保证两端数据的一致性
分成几个问题讨论
保证Kafka集群的高可用
常规的内存、CPU、异常监控+告警,对于Kafka集群,我们是部署在k8s上,通过statefulset 技术来做到集群的高可用。
保证变更日志消息不会丢失
消息写入都是通过batch操作,并且会等待ack完成才更新offset的topic数据,做到消息的最终落库;使用Avro统一消息数据格式,减小带宽的占用减小延迟,kafka集群每个节点会绑定一个PVC,来做到数据的持久化落盘;消费端异常重复消费+幂等处理。
保证消息的顺序消费
更改kafka消息路由策略,使用db主键作为路由键,保证对于db同一条记录的变更消息会落到topic的同一个partition中,单个partition顺序消费。
消费端异常如何发现问题
sink端重启任务,紧急时重建connector重新消费消息来快速恢复。
通过Kafka lag监控发现消息堆积问题,如果延迟过大可适当增加任务来提高消费速度。
最后,可能存在网络抖动导致的少量消息丢失,这种情况Kafka不能发觉,因此只能等待业务方反馈后手动对db记录进行编辑后重新触发日志消息并消费,并且定期的进行全量同步来达到最终一致性。
6.CDC框架中最终使用了Kafka做消息中间件,出于什么考虑,对比RocketMQ有什么优势吗?
最主要的原因还是Debezium框架中自带KafkaConnect,不用额外编码。
同时Kafka的单机性能强于RocketMQ。
7.JVM内存模型
1. 堆空间
存储对象实体和数组
2. 栈
栈帧存放内部变量、运行时常量引用、方法返回地址
3. 本地方法栈
存储内容同栈,供Native方法使用
4. 程序计数器
CPU时间片切换后,记录线程的运行到的位置
5. 方法区
存储类文件、常量、静态变量、编译后代码
8.线程池工作流程,平时怎么设置线程池参数
流程略
CPU密集型 最大线程数= CPU核心数+1;
IO密集型 最大线程数 = CPU核心数*2;
对于混合型任务,可以通过继承线程池并重写线程池的 beforeExecute,afterExecute 和 terminated 方法来监控任务的平均执行时间,最大执行时间和最小执行时间等,并根据数据动态调整线程池参数。