BlogX项目数据库读写分离AI面试题
下面是一组围绕“项目中的数据库读写分离”设计的面试题,先给出提问,再给出面试官心中的理想回答示例。题目难度从基础到进阶递进,既考察对现有代码的理解,也延伸到常见的线上实战问题。
──────────────────────
一、基础理解
Q1 :项目用的读写分离技术栈是什么?核心代码在哪几行?
A1 :用的是 GORM 官方提供的 dbresolver
插件;核心代码在 core/init_db.go
第 25–34 行,通过
db.Use(dbresolver.Register(dbresolver.Config{ ... }))
把 db1
注册为 Sources
(写库),把 db
注册为 Replicas
(读库)。
Q2 :为什么先用读库 DSN 调用 gorm.Open
,而不是写库?
A2 :优先连读库可以保证“只配了一套库”时程序依旧可用;如果 YAML 里没有 db1:
,Empty()
返回 true,代码就不会启用读写分离,项目自动退化为单库模式。
Q3 :Sources
和 Replicas
在 GORM 中各自负责什么?
A3 :Sources
处理所有 写 操作(Create、Update、Delete、事务等);Replicas
处理所有 读 操作(First、Find、Scan、Raw 查询)。
──────────────────────
二、配置与回退
Q4 :DB.Empty()
的作用是什么?它为什么只判断用户名、密码、Host、Port?
A4 :Empty()
用来判断写库配置是否留空,如果完全为空就不启用读写分离。字段只要四项同时为空基本能认定用户没写配置;这样避免因为缺少单个字段导致 YAML 解析成功、但连接失败。
Q5 :如果线上写库宕机,读操作还能继续吗?为什么?
A5 :能。因为读只走 Replicas
(读池),而写库故障不会影响已经存在的从库连接池。但写操作会失败,需要业务侧兜底或者运维尽快切主。
──────────────────────
三、运行时行为
Q6 :dbresolver.RandomPolicy{}
具体做了什么?还有哪些可选策略?
A6 :随机策略会在可用的 Replicas
里随机选择一个连接池执行查询。GORM 还内置 RoundRobinPolicy{}
轮询策略;也支持自定义实现 dbresolver.Policy
接口,比如按权重、按延迟选库。
Q7 :当代码执行 db.Transaction(func(tx *gorm.DB){ ... })
时,读操作会不会跑到从库?
A7 :不会。dbresolver
在事务上下文里会强制把 tx
的 ConnPool 固定在 Sources
,确保在同一个主库连接里完成读写,保证事务一致性。
Q8 :连接池参数(MaxIdle、MaxOpen 等)对写库生效吗?
A8 :sqlDB.SetXXX()
只作用于初始化时创建的那一个 *sql.DB
(读库池)。写库的连接池由 dbresolver
内部创建,使用默认参数;如果要调整,需要通过
dbresolver.Register(dbresolver.Config{}).SetConnMaxIdleTime(...)
或在 Use()
之后再取到写库池进行设置。
──────────────────────
四、拓展与优化
Q9 :如果从库出现主从延迟,如何避免读取到旧数据?
A9 :常见做法:① 对关键业务用事务包裹(强制走主库);② 在写后立即读的场景用 db.Clauses(dbresolver.Write).First(&x)
强制指定写库;③ 监控主从延迟并动态调整流量比例。
Q10 :如何实现多写库 + 多读库的场景?
A10 :可以把多套写库 DSN 放进 Sources: []gorm.Dialector{…}
,读库放进 Replicas: []gorm.Dialector{…}
,再自定义一个按业务分库的 Policy
;或者注册多个 dbresolver.Config
并用 db.Use
多次绑定到不同的表/模型。
──────────────────────
五、潜在坑位
Q11 :为什么要在发生配置错误时调用 logrus.Fatalf
而不是 logrus.Error
?
A11 :读写分离配置错误意味着连接串无效或权限不足,此时程序继续启动也无法正常访问数据库;Fatalf
会写日志后 os.Exit(1)
,防止应用带着半残配置上线。
Q12 :DB.Debug
字段在读写分离场景下有什么用?
A12 :如果为 true,可在 InitDB()
里调用 db = db.Debug()
,让 GORM 打印所有 SQL,帮助定位跨库路由是否正确(比如读操作是否真的落到从库)。
──────────────────────
总结
这些题目覆盖了:
• 核心实现:dbresolver
的注册与路由
• 可靠性:配置回退、主从故障应对、事务一致性
• 运维调优:连接池参数、负载均衡策略、监控延迟
面试者能回答到 80% 以上,就说明既熟悉项目代码,也理解读写分离的底层机制与生产实践。