发帖服务 detail

我们项目实现了一个 xxxx

简历 preview

简历上 : 设计并实现了一个 文章 服务

  1. 考虑文章的业务属性, 创作者支持保存草稿和发布文章。 设计了 线上库 和 制作库 两个库表设计 。
  • 采用 ESR 原则,考虑会有 用户查看自己的文章,用户查看某篇文章详情,以及热榜查看对应时间的文章 。设定过了 _create,auth_id . 这两个索引
  1. 文章服务支持
  • 制作库 保存草稿, 设置隐私文章, 发布制作库内容, 按照 ID 查看文章,或许作者文章列表, 获取发布文章列表
  1. 支持 MongoDB 和 OSS 的扩展

  2. 设计合理的缓存服务

  3. 考虑并发场景

细节

数据库索引设计

主要涉及到的业务有 : 作者查看当前文章,和最近一周的热榜设计

对于作者查看当前文章预计查询是 select from where auth_id = '' and statuts = '' 因此设计了 auth_id 的索引

对于最近一周的热榜设计,因为热榜计算是一个频繁的操作,预计查询是 select from where _create >= now-7week 因此设计了 _create 的索引

数据库并发处理

隐私文章功能 :

需要同步改动 制作库和 线上库的 状态 。

系统设计的时候选择的是同库不同表的流程因此采用数据库事务进行一致性处理,对于更新失败的操作进行回滚 。从业务角度考虑,就算更新失败了也只是让用户多重试几次。

如果是不同库的情况,可以考虑在接口层面增加多次重试。

发布功能 :

对于发布功能, 线上库存在两个状态,线上没有文章需要create,线上有文章需要 update

防止数据库层面的同一篇文章多次竞态问题使用upsert进行操作。

缓存设计

对于列表接口 :

根据习惯习惯缓存第一页内容,大部分用户只会访问第一页的内容。 细节: 缓存之前需要清空文章的content 节省内存资源。

在更新,删除,隐私的接口增加对应的删除缓存的操作 。

对于查看detail接口 :

根据用户习惯,往往只会查看列表第一篇文章的内容。 因此考虑在拉取列表后,缓存第一篇文章的内容。 仅在 content < 1M 的时候进行缓存。 缓存设置了一个很短的过期时间,防止浪费。

对于发布接口 :

  1. 考虑作者发布文章后就会有人阅读,因此在发布的时候就设置缓存。

其他细节

MongoDB

尝试接入 MongoDB 进行存储文章数据。 接入 MongoDB 之后发现,MongoDB 返回的 ID 是 String 类型 。破坏了原先接口的定义。 因此引入了 雪花算法 进行对其接口

OSS

接入 OSS,在发布文章之后,对于线上库的文章内容进行优化。线上库不保存文章内容,文章内容全部存储在 OSS 中

对接阅读统计服务

使用 channel + ctxWithTimeout 进行批量发送阅读统计给 MQ。 供下游消费

作为 Golang 面试官,我按「2 年经验、能独立负责一个业务模块」的标准,对这份 发帖/文章服务 面试准备稿打分如下。


综合评分:68 / 100

维度 得分 说明
业务理解与架构设计 18/25 制作库/线上库分离思路正确,有业务驱动意识
数据库与索引 12/20 有索引意识,但 ESR 理解偏浅,热榜查询设计不完整
并发与一致性 13/20 提到事务、upsert、重试,但缺少边界与失败场景
缓存设计 14/20 第一页缓存、去 content、失效策略有亮点,缺 key 设计与一致性细节
工程化与 Golang 表达 6/15 几乎无 Go 实现细节,MQ 只一笔带过
面试表达与完整性 5/10 结构尚可,错别字多,placeholder 未填,缺 Q&A 演练

结论:作为 2 年经验候选人,项目经历是真实的、方向也对,但这份准备稿更像「项目笔记摘要」,还不足以支撑 45–60 分钟的深度技术面。能过初筛,若在索引、一致性、缓存、Go 并发等点被追问,容易失分。


优点

1. 业务建模有思考

「制作库 + 线上库」分离是内容类系统的常见做法,能解释:

  • 草稿编辑 vs 线上可读
  • 发布时从制作库同步到线上库

这比只会说「CRUD 增删改查」高一档。

2. 缓存策略贴近真实访问

  • 只缓存第一页 —— 符合大部分用户行为
  • 列表缓存去掉 content —— 说明考虑过内存成本
  • 写操作删缓存 —— 知道 Cache Aside 的基本思路
  • 详情预缓存第一条 + 短 TTL + < 1M 限制 —— 有「预测性缓存」意识

3. 并发场景有触点

  • 发布用 upsert 防竞态
  • 隐私状态双库同步用事务
  • 不同库场景考虑接口层重试

说明不是只写 happy path。

4. 扩展能力有落地

  • MongoDB 接入 + 雪花 ID 对齐 int64 接口
  • OSS 存正文、DB 存元数据
  • channel + ctxWithTimeout 批量发 MQ

有「存储分层 + 异步解耦」的工程感。


缺点

1. ESR 原则理解不准确(高风险扣分点)

文档写「采用 ESR 原则,设计了 _create 和 auth_id 两个索引」。

ESR(Equality / Sort / Range)说的是 复合索引字段顺序,不是两个单列索引。面试官很可能追问:

  • 作者查文章:auth_id = ? AND status = ? → 更合理的是 (auth_id, status) 或 (auth_id, status, ctime DESC)
  • 热榜:ctime >= now-7d 且可能要 status = published → 单列 _create 往往不够,还要考虑排序字段(阅读量、score)

若被问到「为什么不用复合索引」,目前文档撑不住。

2. 热榜设计过于粗糙

  • now-7week 应为 7 天(笔误会减印象分)
  • 没说明热榜指标(UV、阅读量、点赞、时间衰减)
  • 没说明是实时算还是定时任务 + 缓存
  • 频繁计算却只提 _create 索引,逻辑链不完整

3. 一致性问题讲不深

隐私文章「制作库 + 线上库同步」只说了事务和重试,缺:

  • 同库不同表 vs 跨库:最终一致性怎么做
  • 事务失败后用户看到什么状态
  • OSS 与 DB 不一致怎么办(DB 更新了,OSS 上传失败)
  • 是否需要 Saga / 补偿 / 幂等键

2 年经验不要求精通分布式事务,但要能讲清 自己的方案边界。

4. 几乎没有 Golang 相关内容

这是 Golang 面试准备,但全文没有:

  • context 怎么用、超时怎么传
  • goroutine 泄漏怎么防
  • errgroup / worker pool 怎么做批量 MQ
  • 接口设计、依赖注入、分层(handler/service/repo)
  • 单元测试、压测数据

channel + ctxWithTimeout 只一句,深度不够。

5. 表达与细节问题

  • statuts、auth_id/author_id 混用、_create 命名不规范
  • 「习惯习惯」重复
  • description 仍是 xxxx
  • 相比同系列的 register_login tidy,这篇 没有 Q&A 脱稿演练,面试时容易散

6. 缺少可量化的结果

没有 QPS、P99 延迟、缓存命中率、发布失败率等,「设计合理」缺少说服力。


改进建议

一、把每个技术点补成「STAR + 追问应答」

建议每个模块固定四句话:

  1. 背景:为什么这么做
  2. 方案:具体怎么实现
  3. 取舍:为什么不用别的方案
  4. 结果:数据或线上表现

示例(索引):

作者列表查询是 author_id + status + 按创建时间倒序分页。我用复合索引 (author_id, status, ctime DESC),遵循 ESR:等值条件在前,排序字段在中间。热榜是近 7 天已发布文章按 score 排序,定时任务每 5 分钟算一次,结果放 Redis ZSet,读路径不走 DB。

二、重点补强 5 个高频追问

追问 建议准备内容
为什么制作库/线上库要分开? 读写隔离、草稿不影响线上、发布可审核
发布接口如何保证幂等? 幂等键、upsert 条件、版本号 / status 机
缓存一致性怎么保证? key 设计、先更 DB 再删缓存、延迟双删要不要
为什么用 MongoDB?MySQL 行不行? 文档结构、字段变化、大正文;MySQL 可以但 OSS 后 MySQL 更合适
MQ 批量发送失败怎么办? batch 大小、重试、dead letter、ctx 超时

三、补 Golang 实现细节(至少 3 点)

  1. 发布流程:ctx 超时、errgroup 并行写 DB + 上传 OSS
  2. 阅读统计:带 buffer 的 worker,select + ctx.Done() 优雅退出
  3. 接口层:统一错误码、middleware 鉴权、作者只能改自己的文章

能画一张流程图或贴 20 行核心代码,比纯文字强很多。

四、OSS + DB 一致性单独成段

建议明确:

  • 先发 OSS 还是先写 DB?
  • 发布失败如何回滚 / 清理孤儿文件?
  • 读路径:DB 存 content_url,CDN /cache 怎么处理?

五、参考 register_login tidy 的结构改版

那篇有「脱讲稿 + 问题列表 + 标准答法」,这篇建议对齐:

1
2
3
4
5
6
## 30 秒 elevator pitch
## 架构图(制作库/线上库/OSS/缓存/MQ)
## 核心接口(Publish / SaveDraft / SetPrivate / List / Detail)
## 5 个技术亮点(每个 1 分钟)
## 10 个高频面试题 + 参考答案
## 踩坑(MongoDB ObjectId、缓存大对象、双库不一致)

六、修正文档硬伤

  • 统一术语:author_id、status、ctime
  • 修正「7 week」→「7 day」
  • 填满 front matter 的 description
  • 通读去掉错别字

面试官视角的一句话评价

「候选人做过真实的文章发布模块,有制作库/线上库、缓存、OSS、MQ 等完整链路意识;但对索引、一致性、Go 并发和面试表达深度不足。若能在 ESR、发布幂等、缓存 key 设计、双库一致性边界上准备充分,可从『大概做过』提升到『能独立负责』,分数有望到 80+。」


如果你愿意,我可以按面试官口吻,直接把这篇 tidy 文档改成「可背诵版」(含 10 道追问 + 参考答案),或对照 register_login tidy 的结构帮你重写一版。

使用 Golang 构建