知其然,知其所以然
gRPC 2026-10-12

与 HTTP/1.1 JSON 的对比:同一接口的延迟和字节数

本机实测同一个 Item 用 gRPC 和 HTTP/1.1 JSON:小消息线上字节是 gRPC 的 2.06 倍、64 KiB 是 1.33 倍;小消息延迟几乎没差、64 KiB 的 p50 慢 1.66 倍;64 并发下 HTTP/1.1 一条连接只有 16484 请求/秒,要 64 条连接才追平;新连接上 gRPC 更慢。

gRPC HTTP/1.1 JSON 对比 延迟 字节数 多路复用 Go 真实验证 动画演示
gRPC 2026-10-12

连接池:多少个 ClientConn 合适

本机实测 gRPC 的连接池:MaxConcurrentStreams 为 100 时吞吐接近“连接数 × 100 ÷ 处理时间”直到 CPU 瓶颈;选在途最少的连接让吞吐高约 25% 但 p50 更差;本机上预热看不出收益;服务端每条空闲连接约 48 KiB、3 个 goroutine。

gRPC 连接池 ClientConn MaxConcurrentStreams 选连接策略 冷启动 Go 真实验证 动画演示
gRPC 2026-10-12

通道状态:IDLE、CONNECTING、READY、TRANSIENT_FAILURE

实测 gRPC 通道状态机:断开后是 IDLE 而不是 TRANSIENT_FAILURE;服务端回来后要等当前退避结束才 READY;握手超时按 MinConnectTimeout 进入 TRANSIENT_FAILURE;拒绝连接时一直 TRANSIENT_FAILURE;Close 后是 SHUTDOWN;多地址时 READY 表示至少一个子连接可用。

gRPC 连接状态 IDLE CONNECTING READY TRANSIENT_FAILURE SHUTDOWN 退避 Go 真实验证 动画演示
gRPC 2026-10-12

服务端 max_connection_age:主动断开长连接的好处

实测服务端 MaxConnectionAge:到期发 GOAWAY(最后流 2147483647,附加数据 max_age);±10% 抖动(2 秒设置下 1.87~2.21 秒);宽限默认无限时长流不受影响、宽限 1 秒时长流被打断;持续负载下换连接没有失败调用;与 MaxConnectionIdle 的区别。

gRPC MaxConnectionAge MaxConnectionIdle GOAWAY 连接更替 抖动 Go 真实验证 动画演示
gRPC 2026-10-12

错误传播:服务 A 调 B 时状态码怎么翻译

实测服务 A 调服务 B 时的错误传播:原样透传会把 B 的 InvalidArgument、Unauthenticated 等错误当成客户端的错;message 会泄漏库表名和内网地址;两层各重试 3 次 B 收到 9 次;下游超时翻译成 Unavailable 还是 DeadlineExceeded 会改变重试行为。

gRPC 错误传播 状态码翻译 重试放大 信息泄漏 微服务 Go 真实验证 动画演示
gRPC 2026-10-12

grpc-go 的日志与调试环境变量

实测 grpc-go 的日志与调试:默认连不上服务也没有任何输出,要 GRPC_GO_LOG_SEVERITY_LEVEL=warning 才看到连接失败;info 级别 42 条、verbosity=2 为 50 条;JSON 格式;grpclog.SetLoggerV2 接入自己的日志;channelz 里 RPC 层失败与流层成功的区别。

gRPC 日志 GRPC_GO_LOG_SEVERITY_LEVEL grpclog channelz 调试 Go 真实验证 动画演示
Kubernetes 2026-10-11

CoreDNS 与 ndots:一次解析为什么发了五次查询

在 kind 集群里给 CoreDNS 加 log 插件,逐条看 DNS 请求:ndots:5 时解析 example.com 先依次查 example.com.k64.svc.cluster.local、example.com.svc.cluster.local、example.com.cluster.local 三个 NXDOMAIN,最后才查 example.com,A 和 AAAA 共 8 条请求;名字末尾加点只要 2 条;ndots:1 让外部名字变成 2 条,但集群内 s1.k64 变慢;Service 不同写法的请求数从 2 到 8+ 不等。

Kubernetes CoreDNS ndots DNS search 域 真实验证 动画演示
Kubernetes 2026-10-11

kube-proxy iptables 模式:Service 对应的链

在 kind 节点上读 iptables-save:一个 Service 在 nat 表里是 KUBE-SERVICES → KUBE-SVC → KUBE-SEP 三层链,后端靠 statistic random 概率(3 个副本 1/3、1/2、无条件)抽签后 DNAT 到 Pod;300 个新连接分到 99/105/96;scale 到 4 个后 1.5 秒规则更新;没有后端时 filter 表写 REJECT,访问立即 Connection refused;NodePort 经 KUBE-NODEPORTS,连接映射由 conntrack 记住。

Kubernetes kube-proxy iptables Service DNAT conntrack 真实验证 动画演示
Kubernetes 2026-10-11

kube-proxy 的 ipvs 与 nftables 模式

分别用 networking.kubeProxyMode 起 ipvs 和 nftables 的 kind 集群读内核:ipvs 里 Service 是 /proc/net/ip_vs 的虚拟服务器,rr 轮询把 300 个连接分成 100/100/100,ClusterIP 挂在 dummy 网卡 kube-ipvs0 上;nftables 里是 kube-proxy 表的 map 加 numgen random;再建 300 个 Service,iptables 模式多出 4500 行规则,ipvs 的 iptables 不变,三种模式 m299 都在 14~15 秒后可访问。

Kubernetes kube-proxy ipvs nftables iptables Service 真实验证 动画演示
Kubernetes 2026-10-11

Service 会话保持:ClientIP 的超时

在 kind 集群里实测 Service 会话保持:sessionAffinity: ClientIP 让同一个客户端 IP 的 30 个连接全落在一个后端,不同客户端各自固定;iptables 里是 -m recent --rcheck/--set 加每个后端一张内核 recent 表;timeoutSeconds=3 时 1 秒间隔的访问 12/12 粘住、4 秒间隔 8/12 换了后端,每次访问刷新计时器;固定的后端被删后客户端被重新分配并重新固定。

Kubernetes Service sessionAffinity ClientIP iptables recent 真实验证 动画演示
Kubernetes 2026-10-11

externalTrafficPolicy:源 IP 保留与跨节点跳转

在 kind 集群里实测 externalTrafficPolicy:Cluster 下集群外的客户端(172.18.0.3)到 NodePort,后端看到的是 10.244.1.1 或 172.18.0.4 而不是真实 IP,没有后端的节点会转发一跳;Local 下后端看到真实 IP,但没有本地后端的节点把包 DROP,curl 3.1 秒超时;LoadBalancer + Local 分配 healthCheckNodePort,有后端的节点返回 200、没有的返回 503。

Kubernetes Service externalTrafficPolicy NodePort 源 IP healthCheckNodePort 真实验证 动画演示
Kubernetes 2026-10-11

NetworkPolicy:默认拒绝和选择器语义

在 kind 集群(kindnet)里实测 NetworkPolicy:没有策略时全通;default-deny ingress 约 1.1 秒生效且被拒的连接是超时而不是拒绝;podSelector 单独只匹配本命名空间,同一个 from 条目里 namespaceSelector 加 podSelector 是“且”,拆成两个条目是“或”;多条策略取并集;egress default-deny 会把 DNS 一起拦掉,必须单独放行 kube-system 的 53 端口。

Kubernetes NetworkPolicy default-deny namespaceSelector podSelector 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号