当前互联网公司的后端架构都是微服务化的,服务彼此使用 RPC 通信,与业务无关的功能部分会从业务代码中抽离为框架。
框架提供了基础的 RPC 功能,同时需要对稳定性负责,一个微服务框架包含但不限于以下功能:
* 路由
* 限流
* 熔断
* 负载均衡
* 服务注册与发现
* tracing
* 链路加密
这些功能看起来也是通用且稳定,所以我们对一个框架的印象往往是成型了之后便很少再升级了。但是云原生时代将我们的假设击得粉碎。底层基础设施也开始迅速发生变化,例如:
* 物理机集群 -> k8s 集群,破坏了我们的服务实例 ip 不会变的假设
* 基础设施给服务的资源分配方式发生变化,超卖使以往未经审慎设计的代码在恶劣环境下更易崩溃
* 服务数量的爆炸式增长使每个内部的微服务都要面对 C10k
先来看一个 demo:
1 package main
2
3 import (
4 "fmt"
5 "net"
6 "os"
7 "runtime"
8 )
9
10 var rawFileList []*os.File
11
12 func main() {
13 l, err := net.Listen("tcp"
1.14 defer
正常处理流程
在 Go 1.14 中,增加了一种新的 defer 实现:open coded defer。当函数内 defer 不超过 8 个时,则会使用这种实现。
形如下面这样的代码:
defer f1(a)
if cond {
defer f2(b)
}
body...
会被翻译为:
deferBits
内网使用服务发现后,服务与其它服务的实例之间使用一条 TCP 长连接进行通信。这种情况下常见的做法是按照 registry 下发的 host:port
列表来直接建连。
简单来说就是下图这样:
每一个服务实例都需要和它依赖的服务的每一个实例都把连接给建上。如果各个服务的规模不大,这样没什么问题。
互联网公司的核心服务规模都比较大,几千/万台机器(或几千/万个实例)的单一服务并不少见,这时候 client 要和所有 server 实例建连,会导致
client 端的 conn pool 里有大量连接,当然,server
本文内容是 2013 年 Google 对 packetdrill 的论文翻译。
网络协议测试很麻烦,线上的网络问题往往都是偶发的,难以捕捉。
packetdrill 是一个跨平台的脚本工具,可以用来测试整个 TCP/UDP/IP 网络栈实现的正确性和性能,从系统调用一直到硬件网络接口,从 IPv4 到
IPv6。
该工具对 Google 工程师研发 Linux TCP 中的 Early Retransmit,Fast Open,Loss