Go 社区之父早期提到过 less is more [https://en.wikipedia.org/wiki/Less_is_more]
的哲学,可惜社区里有不少人被带偏了。
每次 Go 增加语法上的新特性、新功能,就会有原教旨主义者跳出来扔出一句 less is more(或者也可能是大道至简),扬长而去,留下风中凌乱的你。
即使到了官方已经确定要增加泛型功能的 2020 年,依然有人煞有介事地写文章说为什么 go doesn't need
当前互联网公司的后端架构都是微服务化的,服务彼此使用 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