欢迎访问

专注系统底层与高性能服务开发,持续记录 Go / Rust / C++ / 云原生的一线实践。

从源码细节到线上治理,尽量少空话,多代码。

Go 配置热更新:动态生效与安全边界

背景 很多服务希望不重启就能改配置,但并不是所有参数都适合热更新。 建议分类 可热更新:限流阈值、开关、采样率 谨慎热更新:连接池参数 不建议热更新:协议兼容、核心依赖地址 type RuntimeConfig struct { RateLimit int Sample float64 } var cfg atomic.Value 总结 热更新是能力,不是目标。先定义边界,再提供机制。 线上灵活性要建立在可控性之上。

2026年5月7日 · 1 分钟 · BvBeJ

Kafka Exactly-Once 的边界:事务语义与业务幂等如何配合

常见误解 启用 Kafka EOS 后,很多团队默认“不会重复消费”。实际上,数据库写入、HTTP 调用等外部副作用仍可能重复。 EOS 真正保证什么 Producer 端幂等写入(同一会话内去重)。 事务内“写输出 + 提交消费位点”原子性。 只在 Kafka 生态内部有效。 仍需业务补齐 下游写库使用幂等键(业务主键或事件 ID)。 外部调用提供去重令牌。 失败重试具备可重入语义。 处理流程建议 consume -> validate -> execute(idempotent) -> produce -> commit offsets 任何一步失败都可重试,且不会造成不可逆双写。 小结 EOS 不是银弹,而是基础设施层的“至少一次到一次”的收敛器。业务副作用一致性仍需你自己设计。

2026年5月7日 · 1 分钟 · BvBeJ

Rust unsafe 审计清单:把风险控制在可解释范围

背景 高性能或底层场景里,Rust 项目经常需要少量 unsafe。问题不在于有没有 unsafe,而在于是否可审计。 审计清单 每个 unsafe block 有明确不变量说明 边界输入做前置校验 单测覆盖成功与失败路径 关键模块做 fuzz 或 Miri 检查 // SAFETY: ptr 来自有效切片起始地址,len 已做边界校验。 unsafe { std::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), len); } 总结 unsafe 管理的核心是制度化约束,不是个人经验。 能解释安全前提的 unsafe,才是工程可接受的 unsafe。

2026年5月7日 · 1 分钟 · BvBeJ

C++ 服务内存碎片治理:从分配器选择到线上观测

症状识别 业务负载稳定,但 RSS 只涨不降。 堆分析看不到明显泄漏对象。 进程重启后内存瞬间回落。 为什么会碎片化 多线程下不同 size class 高频分配释放。 短命与长命对象混放。 大量临时 buffer 导致 arena 难回收。 治理路径 分离对象生命周期:短命池与长命池分开。 统一热点对象尺寸,减少跨 class 抖动。 评估 jemalloc/tcmalloc 与默认 allocator 差异。 线上指标建议 allocated_bytes active_bytes resident_bytes fragmentation_ratio = resident / active 风险点 只看进程总内存,不看分配器内部统计。 盲目手写内存池,忽略线程本地缓存竞争。 回收策略和 NUMA 绑定冲突。 小结 碎片治理是系统工程:对象模型、分配器、线程调度、NUMA 拓扑都要协同。先观测后改造,收益才稳定。

2026年5月6日 · 1 分钟 · BvBeJ

Kubernetes Gateway API 迁移:从 Ingress 到更细粒度治理

背景 Ingress 够简单,但在多团队协作、细粒度权限和高级路由策略上容易吃力。 迁移思路 先并行接入,不强切 从低风险路由开始迁移 明确 GatewayClass 与 Route 的职责边界 总结 迁移重点不在 YAML 语法,而在组织层面的边界和治理模型。 流量治理升级,技术和协作模型要一起升级。

2026年5月6日 · 1 分钟 · BvBeJ

Vue3 前端可观测性:Web Vitals 与 RUM 采集

背景 前端性能优化如果只看本地 Lighthouse,经常和真实线上体验有偏差。 最小落地 采集 LCP/INP/CLS 上报到日志或指标平台 按页面和地区分桶观察 import { onLCP, onCLS, onINP } from 'web-vitals' onLCP(metric => report(metric)) onCLS(metric => report(metric)) onINP(metric => report(metric)) 总结 性能优化要闭环:采集真实数据 -> 定位问题 -> 验证回归。 没有真实用户数据,优化很容易变成自我感动。

2026年5月6日 · 1 分钟 · BvBeJ

C++ 协程生命周期陷阱:引用捕获与悬空对象

背景 C++ 协程常见 bug 之一是对象在挂起后已经销毁,但恢复时仍被访问。 典型风险 捕获局部引用并跨 suspend 使用 返回协程句柄后调用方提前释放上下文 Task<void> foo() { std::string buf = "hello"; co_await suspend_point(); use(buf); // 若生命周期判断错,这里会出问题 } 总结 协程代码要像异步状态机一样审生命周期,别按同步函数直觉来读。 控制流变了,生命周期审计方式也必须跟着变。

2026年5月5日 · 1 分钟 · BvBeJ

Monorepo Docker 构建缓存:减少无效重建

背景 Monorepo 常见痛点是:改了一个子目录,多个镜像都触发重建。 改进方向 精细化 .dockerignore 子项目独立 context 共享基础层分离 COPY services/api/go.mod services/api/go.sum ./ RUN go mod download COPY services/api/ ./ RUN go build -o app ./cmd/api 总结 缓存命中率是 CI 成本的核心变量,Monorepo 必须做分层构建设计。 构建系统的复杂度,迟早会和代码规模一起增长。

2026年5月5日 · 1 分钟 · BvBeJ

Rust Async 的 Cancellation Safety:避免半提交状态

关键事实 Future 在 .await 点可能被取消。若状态更新分布在多个 await 之间,就可能出现“写了一半”的业务状态。 设计原则 把副作用集中在单一提交点。 在可取消区间只做纯计算或幂等准备。 对外部系统写入使用幂等键。 反例与修正 // 反例:先扣库存再写订单,两个 await 中间可被取消 reserve_stock().await?; create_order().await?; // 修正:准备阶段无副作用,最后一次性提交 let plan = build_plan().await?; commit(plan).await?; 工程策略 为关键流程增加“中断注入测试”。 对每个 await 标注取消后的状态语义。 引入补偿任务清理孤儿状态。 小结 异步取消是默认行为,不是异常路径。把 cancellation safety 当作接口契约的一部分,才能避免线上出现“偶发且不可复现”的脏状态。

2026年5月5日 · 1 分钟 · BvBeJ

Go gRPC Streaming 的流控与内存治理

典型症状 单连接吞吐很高,但进程 RSS 持续上涨。 p99 抖动明显,GC 时间占比异常。 下游稍慢就触发级联超时。 流控设计要点 应用层窗口:限制每个 stream 的未确认消息数。 连接层隔离:大流量 stream 与普通 RPC 分离连接。 消费层背压:处理队列满时暂停读或降级。 服务端模式 type StreamState struct { inflight int64 limit int64 } func (s *StreamState) AllowRecv() bool { return atomic.LoadInt64(&s.inflight) < s.limit } 参数调优建议 MaxRecvMsgSize 不要无限放大,优先拆包。 对大对象优先走分块传输。 结合业务 ACK 做“应用级信用”控制。 观测面 每 stream inflight 数。 解码耗时与业务处理耗时拆分。 内存分配热点(pprof alloc_space)。 小结 Streaming 的本质是长期会话。想要稳,必须让发送速率服从消费能力,而不是盲目追求“尽快塞满管道”。

2026年5月4日 · 1 分钟 · BvBeJ