这里是全站文章的归档入口,下面是按时间倒序排列的全部文章。若想按主题浏览,请从首页的专题分类进入。
《Java 服务端通信工程》7.2 熔断状态机
熔断不是布尔开关,而是滑动窗口、最小请求数、失败率边界与半开探针共同组成的并发状态机。本节用 AtomicReference 切状态、用一把锁保护窗口,给出完整 CircuitBreaker 与按下游实例分桶的接入代码,并说明迟到响应为什么必须用 generation 丢弃。
posts
这里是全站文章的归档入口,下面是按时间倒序排列的全部文章。若想按主题浏览,请从首页的专题分类进入。
熔断不是布尔开关,而是滑动窗口、最小请求数、失败率边界与半开探针共同组成的并发状态机。本节用 AtomicReference 切状态、用一把锁保护窗口,给出完整 CircuitBreaker 与按下游实例分桶的接入代码,并说明迟到响应为什么必须用 generation 丢弃。
从连接 drain 之后的下游抖动讲起,把重试拆成可重试码判定、指数退避与 ±20% 抖动、总 deadline 扣减和全局重试预算;给出 RetryPolicy、RetryBudget 与保留幂等键的 ClientCall 实现,并算清三层重试叠加时的放大倍数。
从「回声」共同好友查询在 1 万好友时耗时 12 秒的事故写起,拆解我关注谁、谁关注我、共同好友三类关系查询的代价,说明大 V 粉丝列表为什么不能全量拉,给出 Graph、Followers、Following 与 Common 的 Go 实现、去重排序测试和真实运行输出,并列出关系链存储与查询的常见错误。
发布时最怕新请求还在进、老请求被一刀切断。本节拆开 ManagedChannel 与 Server 的 shutdown 语义,用 DrainCoordinator 统计在途请求,给出 linkd-v3 从停止入口、健康降级到关闭 channel 的完整顺序和时间预算。
一条 channel 通常就够,但隔离、并发额度和故障半径会逼你建第二条。本节给出 linkd-v3 的池键设计、有界 channel 池的完整实现,以及池大小与 MAX_CONCURRENT_STREAMS 的换算,避免把连接池写成每请求一条连接。
一条 HTTP/2 连接能同时跑多少请求,取决于流上限、流控窗口和服务端并发配置。本节用 1.76.0 的实测默认值拆开 MAX_CONCURRENT_STREAMS 与 1 MiB 窗口,给出连接数估算表和 linkd-v3 的 9093 配置。
拿到地址列表只是开始,选哪一条、怎么判断它还能不能用才是负载均衡。本节对比 pick_first 与 round_robin 的子通道行为,用 HealthStatusManager 和 HealthGrpc 做出真实的 SERVING/NOT_SERVING 探活,并给出 linkd-v3 的探活周期与抖动控制。
forTarget 里的 scheme 决定谁来解析地址。本节实现 static-registry scheme 的 NameResolverProvider 与 Listener2,把 StaticRegistry 的端点转成 EquivalentAddressGroup,并用 round_robin 跑出真实的 resolver-reply=ok。
服务发现的第一步不是选组件,而是定义注册中心里到底存什么。本节用 linkd-v3 的 StaticRegistry 给出服务、端点、修订号和快照的数据模型,讨论租约、健康与失效,并把注册、解析、管理端三条消费路径接起来,附可编译实现与启动顺序。
消息从对象到字节要过 Marshaller、压缩和长度前缀三道关。本节拆开 gRPC 的 5 字节分帧、gzip 的协商位置,用本机探针读出 1.76.0 的 4 MiB 默认上限,并给出超限时 RESOURCE_EXHAUSTED 的真实输出。
请求 ID、租户、traceparent 不该散落在每个业务方法里。本节用 linkd-v3 的客户端与服务端拦截器,演示 Metadata 键的定义与校验、Context 的附着和清理、响应头回显,并给出拦截器顺序、异常与重试传播的边界。
Channel 管连接,Stub 管一次调用。本节用 linkd-v3 的 9093 端口拆开 ManagedChannel 的状态机、阻塞与异步 Stub 的不可变语义,给出预热、复用以及 shutdown、shutdownNow、awaitTermination 的完整代码,并用自包含探针验证 unary 调用。
区分 at-most-once、at-least-once 和 effectively-once,说明 x-idempotency-key 由谁生成、作用域怎么定、结果缓存多久,给出 20 ms 起、指数 2、±20% 抖动的退避实现,以及用 CompletableFuture 做并发去重的服务端代码。
从「回声」一次拉黑只在前端生效的事故写起:用户拉黑骚扰者后,换个客户端仍能看到对方内容。文章把拉黑、屏蔽与可见性拆成不同层次,给出 CanView 的判定顺序、可读原因、拉黑压过好友的实现、边界测试与真实输出,并说明为什么可见性必须在服务端最终响应处统一生效。
把 800 ms 总预算拆成每次尝试的可用时间,解释 grpc-timeout 为什么传相对时间、服务端为什么常看到 CANCELLED 而不是 DEADLINE_EXCEEDED,并给出 withDeadlineAfter、Context 剩余时间读取、setOnCancelHandler 清理的完整代码。
把 unary、server streaming、client streaming、bidi streaming 放进同一张分工表,说明每种模式的半关闭、流控和取消语义,给出 Library 四个方法的服务端实现,并用一段双向流客户端跑出 stream=echo:a / echo:b / stream-complete。
把兼容性拆成线上、源码、二进制、行为四个维度,给出新增、删除、改名、改类型、改枚举、动 oneof 的完整兼容矩阵,解释 int32 与 sint32 为什么不能互换,并用 Descriptors 的保留位检查写一条可在 CI 执行的契约回归测试。
把同一份 Book 数据分别写成 JSON 和 Protobuf,比较字节数、解析成本、演进能力和调试体验;说明 proto3 JSON 映射里 int64 变字符串、默认值省略、字段名转小驼峰的规则,并给出网关边界上用 JsonFormat 转换的代码。
从 tag、wire type 和 varint 三个部件拆开 Protobuf 的线格式,手算 Book 消息的十二个字节,解释字段号 1–15 为什么更省、负数为什么要用 sint32、proto3 默认值为什么不上线,并给出纯 JDK 的 varint 编解码代码。
契约不只是 .proto:字段号、错误原因码、metadata 键、超时预算和版本规则都算契约。本节给出 comm-api 的生成配置、兼容与破坏性改动清单、用 Descriptors 写契约基线和 JUnit 断言的方法,以及一次变更从提案到发布的流程。