给博客做了一轮大改:多端、离线、服务端渲染和一堆小东西

周末 Claude 的额度有富余,就拿来收拾许久没更新的博客。结果先发现 robots.txt 一直在拒绝所有搜索引擎,索性从前端到后台整个翻修了一遍:去掉 Bootstrap 和 jQuery 重做多端适配,Markdown 改成服务端直出,加上离线阅读、即时搜索、草稿和标签管理。最后聊了聊这轮里 Claude 帮上…

一致性事务:从 2PC 到 Outbox pattern

如果你做过一点微服务开发,大概率都遇到过这种场景:用户下单 → 扣库存 → 扣余额 → 更新积分。这听上去很简单,按顺序写几行逻辑就好,但问题是——这些操作分散在不同的服务、不同的数据库里。于是问题来了:如果中间有一步失败了,整个流程该怎么办?订单创建了,但库存没扣?库存扣了,但支付失败?消息没发出去,用户看不到状态…

数据库分表实践:如何优雅地切换到分表架构

在我们的后端架构中,我们采用了以游戏为租户单位的多租户数据库设计。所有游戏共享同一套数据库 schema,每张表通过 game_id 字段进行逻辑隔离。这种设计在初期带来了显著的开发与维护效率,支持我们快速迭代、快速上线多个游戏项目。然而,随着接入的游戏数量增加、业务数据持续增长,这种“共享单表”的设计逐渐暴露出一些架…

“该省省,该花花”

春节假期,我终于完成了两件大事:见了未来的岳父岳母,还带奶奶游览了北京。忙里偷闲,我决定总结一下这几天的经历,顺便分享一些“花钱”与“省钱”的小感悟。

为什么你应该在代码中消除 "context deadline exceeded" 错误

在 Go 语言中,context 包提供了一种跨 API 和进程边界传递请求作用域值、取消信号以及超时信号的方式。使用 context 可以帮助我们更好地控制 goroutine,避免 goroutine 泄漏等问题。出现 "context deadline exceeded" 错误通常是因为在请求上下文中设置了超时时…

死锁日记:手写 GoLang 上报队列

我们团队负责的防沉迷上报服务突然在某一天遭遇了内存溢出(OOM)的情况。通过查看 Prometheus 监控数据,我们发现 Goroutines 的数量在中午十二点之后呈现出线性增长趋势,直至晚上十点 OOM 发生,Goroutines 数量骤降为零。

gorm 中 MySQL 错误码映射与主键冲突错误处理

在使用 gorm 处理数据库操作时,尤其是针对 MySQL,有时我们会遇到 golang 标准库errors.Is函数无法直接识别特定的 gorm 错误类型的情况,如主键冲突错误。尽管 gorm 提供了gorm.ErrDuplicatedKey来表示此类错误,但在原始错误返回中并不能直接通过errors.Is(err…

CloudFlare Tunnel 免费内网穿透的简明教程

Tunnel 可以做什么?将本地网络的服务暴露到公网,可以理解为内网穿透。将非常规端口服务转发到 80/443 常规端口。自动为你的域名提供 HTTPS 认证。为你的服务提供额外保护认证。跳过国内服务器备案域名。最重要的是——免费。

2023 年购物回忆录:值不值得买

2023年,对我来说是充满购物冒险的一年,我购买了很多东西,今天,我想回顾一下,分享哪些购买对我来说物超所值,哪些则是我冲动消费的产物,让我感到后悔。让我们开始这段回忆旅程吧~??️

API 设计中的多类型属性选择:OpenAPI 与 gRPC 的 oneof 与强类型对比

在谈论 API 设计和开发时,有时,一个属性可以是多种类型中的一个,但不能同时是多种类型。比如支付接口的回调处理,常常为了兼容不同平台的参数,会使用以下方式中的一种来进行接收,在程序开发中,我们往往会采用主流的 HTTP 协议和 gRPC 协议进行通信,两种技术都为开发者提供了强大的工具来描述、验证和生成 API,但它…