Update mengyastore

This commit is contained in:
2026-05-13 12:11:46 +08:00
parent ad54b1eb7e
commit 37983f3b60
156 changed files with 10064 additions and 5681 deletions

View File

@@ -0,0 +1,109 @@
# 字节后端面试模拟(萌芽小店情景 · 套八股式追问)
> **怎么用这份材料**:面试官通常**不会对着你的仓库逐行看**,而是听你说「我做了一个小店后端」之后,用**通用八股 + 业务情景**连续追问。下面 10 题按这种话术写:**先像真面试里的问法**,回答里把**原理(八股)**和**你会怎么落地到项目**揉在一起。
> **比重****Go、MySQL 为主****Redis、RabbitMQ 各挑典型一问为辅**(与当前仓库里可选组件对齐,不必假定对方读过源码)。
---
## 项目一句话(自我介绍用)
用 Go 写了小店后端Gin 提供 APIMySQL + GORM 存商品订单,结账有支付待确认状态,可选 MQ 异步发订单邮件、可选 Redis认证打外部账户中心。**细节不用背文件路径,按模块说即可。**
---
## 10 道面试题(主 Go / MySQL
### 1. 情景:下单要把「查库存、写订单」绑在一起 —— 为什么上事务?边界怎么收?
**问法**:你说下单用数据库事务包了一段逻辑。那**事务里放哪些、不放哪些**?如果要把事务缩到最短,你会拆成几步?和以前不用事务只扣库存相比,要解决什么并发问题?
**回答要点**:保证 **ACID 里的一致性**:读到的库存和写入的订单一致,避免并发下 **lost update / 超卖**。事务外适合做参数校验、调外部 HTTP事务内只做 **行锁下的读写**。缩短边界可降低锁持有时间、减死锁概率;但拆太散会失去原子性,要用 **TCC、本地消息表、幂等单号** 等补偿视业务接受度。InnoDB 里常用 **`SELECT … FOR UPDATE` 当前读**锁住商品行再扣减。
---
### 2. 情景:`SELECT … FOR UPDATE` 锁商品 —— 和乐观锁、直接 `UPDATE qty = qty - ?` 有啥区别?
**问法**:库存扣减你说是行锁读的,那**悲观锁和乐观锁**各适用什么场景?`UPDATE … WHERE qty >= ?` 用影响行数判断成败,和你先 `FOR UPDATE` 再改,**语义和性能**上差在哪?
**回答要点**:悲观锁(`FOR UPDATE`)适合**冲突概率高**、逻辑分支多的扣减;乐观锁用 **version 列** 或 CAS 式 `UPDATE`,适合读多写少、重试用业务可接受。**纯 UPDATE 条件扣减**一条 SQL 完成锁时间短但复杂流程预留卡密、多表仍常要事务配合。RR 下 `FOR UPDATE` 是当前读,和**普通快照读**不同,别混用。
---
### 3. 情景:同一商品只允许一笔「待支付」,不然支付回调不好认 —— 库里怎么表达?和隔离级别有关吗?
**问法**:如果业务上**同一 SKU 同时只能有一单 pending**,你除了应用层判断,**数据库层**还能怎么兜底MySQL 默认隔离级别下,只靠「先查有没有 pending 再插」会有什么问题?
**回答要点**:应用层在事务里 **FOR UPDATE 商品行 + 查 pending**串行化冲突。DB 层可 **唯一索引**(如 `(product_id, status)``pending` 状态——MySQL 里部分场景用**生成列 / 约束**不好表达,更常见是 **部分唯一索引** 8.0+ 或状态机 + 应用保证)。只靠快照读「先查后插」可能 **幻读 / 竞态**,要用当前读或约束。追问隔离级别:默认 **RR + 当前读/锁** 解决多数此类问题。
---
### 4. 情景:支付超时要把预留库存还回去 —— 除了定时扫表还有什么?索引注意啥?
**问法**:待支付订单过期要释放库存,你用定时任务扫「过期 pending」。**拖数据库**怎么优化延时队列、Redis TTL 通知这类方案你怎么权衡?
**回答要点**:扫表要有 **`status + payment_expires_at`** 等组合索引,避免全表扫。批量处理、限流、**幂等释放**`UPDATE … WHERE status='pending' AND expires_at < now()` 行数判断)。延时队列 / MQ 延迟消息:**精度与运维成本**更高Redis keyspace 通知不靠谱作唯一依据。核心是 **DB 仍为权威状态**,定时扫是简单稳妥的基线。
---
### 5. 情景Go 里起了后台 goroutine定时任务、MQ 消费)—— 进程要停时你怎么收尾?
**问法**`main` 外面 `go` 了长时间运行的循环,收到 **SIGTERM** 怎么办?`context.Cancel` 先取消谁?和 `server.Shutdown` 顺序?
**回答要点****根 Context** 可取消,`select` 里监听 `<-ctx.Done()` **退出循环**。优雅关停:先 **HTTP Shutdown** 停新流量,再 **cancel 后台任务**MQ **consumer ack 完再关 channel/connection**`defer` 释放要防 **Close 后再用**。生产用 **errgroup** 或包装 runnable 统一等待。
---
### 6. 情景HTTP Handler 里调外部认证、写数据库 —— 超时、错误怎么传?
**问法**:用户请求进来,你要调外部验 Token、再写库。`context` 是传 **`c.Request.Context()`** 还是自己 `WithTimeout`?超时到了 SQL 还会不会执行?
**回答要点**IO 应带 **可取消的 Context**HTTP 入口常用 **`c.Request.Context()`** 与用户断开联动,或包一层 **更短的业务超时**。GORM/MySQL driver 若支持 context**取消后会尝试中断**;未挂 context 的请求无法被动取消。错误:**包装 `fmt.Errorf("%w")`** 保留链;对外**脱敏**,日志里打 `request_id`
---
### 7. 情景:`database/sql` 连接池 —— 几个参数和 MySQL `wait_timeout` 关系?
**问法**`SetMaxOpenConns` / `SetMaxIdleConns` / `SetConnMaxLifetime` 各自干啥?`ConnMaxLifetime` 设得比服务端 **`wait_timeout` 长会怎样**
**回答要点****MaxOpen** 限并发连接数保护 DB**MaxIdle** 平衡复用与内存;**ConnMaxLifetime** 让连接定期重建,避免被 **MySQL 或中间层** 断开后的坏连接。经验上 **Lifetime 略小于 `wait_timeout`**(或云库推荐的 idle 时间),减少 `packets.go broken pipe` 类问题。**MaxIdle=0** 会导致高频建连。
---
### 8. 情景ORM + 迁移 —— 你怎么看待 `AutoMigrate` 上生产?
**问法**:项目启动时自动 Migrate大厂里也这么干吗**危险点**在哪?你更信哪种流程?
**回答要点**`AutoMigrate` 适合**开发/小项目**,生产常见 **显式迁移**goose / golang-migrate / Atlas**review、灰度、可回滚**。风险:**不能与复杂 DDL大表改列、索引等价**;线上锁表、双写切换需要 **人工方案**。面试答「小型服务可 AutoMigrate有 SLA 就上迁移工具 + CI」。
---
### 9. 【Redis · 辅】情景:浏览量或去重防刷 —— 单机内存和 Redis 差在哪?
**问法**:你说用过进程内 map 做访问去重,**多实例部署**会怎样?用 Redis 的话 **SET NX + EX**、**HyperLogLog** 分别在什么诉求下选?
**回答要点**:进程内 map **不跨实例**,计数会**偏高**或去重失效。Redis**SET key NX EX TTL** 做窗口内去重;**INCR** 做简单计数;**HLL** 只要大概 UV、省内存。**热 key** 要本地缓存、拆分 key 或读写分离;**持久化**与**缓存 DB 一致性**按业务容忍度设计(能接受最终一致即可)。
---
### 10. 【RabbitMQ · 辅】情景:订单邮件发 MQ —— 还会丢消息吗?你怎么补?
**问法**交换机、队列、durable、消息 persistent 都配了,**哪三段**仍可能丢?`at-least-once` 业务要做什么?
**回答要点**:经典三段:**Producer→Broker**(未 confirm、网络闪断、**Broker**(未刷盘、集群未完成同步——视配置)、**Consumer**(处理完未 ack 或先 ack 后崩)。**Publisher Confirm + 消费者手动 ack** 提高可靠性;语义多为 **至少一次**,消费端 **幂等**订单号去重、Unique 约束)。**重连重发**可能 duplicate要和幂等一起看。
---
## 题量分布(自检)
| 方向 | 题号 |
|------|------|
| Goruntime、context、goroutine、HTTP、错误 | 5、6 |
| MySQL事务、锁、隔离、索引、迁移、连接池 | 1、2、3、4、7、8 |
| Redis为辅 | 9 |
| RabbitMQ为辅 | 10 |
---
## 附:超短技术栈备忘(背 30 秒版)
Go 1.21 + Gin + GORMMySQL可选 RabbitMQ异步邮件、可选 Redis健康/扩展);外部 HTTP 验 Token。下单事务 + 行锁待支付超时回收支付回调匹配订单MQ 失败可降级发信。