点击 "阅读原文" 可以获得更好的阅读体验。
前言
Envoy Proxy 在大多数情况下都是作为 Sidecar
与应用部署在同一网络环境中,每个应用只需要与 Envoy(localhost
)交互,不需要知道其他服务的地址。然而这并不是 Envoy 仅有的使用场景,它本身就是一个七层代理,通过模块化结构实现了流量治理、信息监控等核心功能,比如流量治理功能就包括自动重连、熔断、全局限速、流量镜像和异常检测等多种高级功能,因此 Envoy 也常常被用于边缘代理,比如 Istio 的 Ingress Gateway
、基于 Envoy 实现的 Ingress Controller(Contour、Ambassador[1]、Gloo[2] 等)。
我的博客也是部署在轻量级 Kubernetes
集群上的(其实是 k3s
啦),一开始使用 Contour
作为 Ingress Controller
,暴露集群内的博客、评论等服务。但好景不长,由于我在集群内部署了各种奇奇怪怪的东西,有些个性化配置 Contour
无法满足我的需求,毕竟大家都知道,每抽象一层就会丢失很多细节。换一个 Controller 保不齐以后还会遇到这种问题,索性就直接裸用 Envoy
作为边缘代理,大不了手撸 YAML
呗。
当然也不全是手撸,虽然没有所谓的控制平面,但仪式感还是要有的,我可以基于文件来动态更新配置啊,具体的方法参考 Envoy 基础教程:基于文件系统动态更新配置。
1. UDS 介绍
说了那么多废话,下面进入正题。为了提高博客的性能,我选择将博客与 Envoy
部署在同一个节点上,并且全部使用 HostNetwork
模式,Envoy
通过 localhost 与博客所在的 Pod(Nginx
) 通信。为了进一步提高性能,我盯上了 Unix Domain Socket(UDS,Unix 域套接字)[3],它还有另一个名字叫 IPC
(inter-process communication,进程间通信)。为了理解 UDS
,我们先来建立一个简单的模型。
现实世界中两个人进行信息交流的整个过程被称作一次通信(Communication
),通信的双方被称为端点(Endpoint
)。工具通讯环境的不同,端点之间可以选择不同的工具进行通信,距离近可以直接对话,距离远可以选择打电话、微信聊天。这些工具就被称为 Socket
。
同理,在计算机中也有类似的概念:
- 在
Unix
中,一次通信由两个端点组成,例如HTTP
服务端和HTTP
客户端。 - 端点之间想要通信,必须借助某些工具,Unix 中端点之间使用
Socket
来进行通信。
Socket
原本是为网络通信而设计的,但后来在 Socket
的框架上发展出一种 IPC
机制,就是 UDS
。使用 UDS 的好处显而易见:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC 机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。
UDS
与网络 Socket 最明显的区别在于,网络 Socket 地址是 IP 地址加端口号,而 UDS
的地址是一个 Socket 类型的文件在文件系统中的路径,一般名字以 .sock
结尾。这个 So