作者 青鸟

最近在读istio的代码,正好借此来水一篇博客,顺便通过istio来学一点关于Service Mesh的相关知识

Service Mesh

什么是Service Mesh

用官方的话来说Service Mesh(服务网格)是一种用于处理服务之间通信的架构模式。在微服务架构中,应用程序通常被拆分成多个小型的、相互独立的服务,每个服务负责执行特定的功能。这些服务需要相互通信以完成整体业务逻辑。Service Mesh 提供了一种在服务之间进行通信的统一、可靠和可观察的方式。

说简单点Service Mesh就是处理微服务之间的通讯,它的主要实现形式就是在应用程序同主机上部署一个代理程序,所有的进出流量都被这个Side Car代理,于是我们便可以在这个代理程序中以最小的成本实现细粒度化的控制,包括服务的限流、熔断、降级等策略

在这种形式下,RPC 客户端将数据包先发送给,与自身同主机部署的 Sidecar,在 Sidecar 中经过服务发现、负载均衡、服务路由、流量控制之后,再将数据发往指定服务节点的 Sidecar,在服务节点的 Sidecar 中,经过记录访问日志、记录分布式追踪日志、限流之后,再将数据发送给 RPC 服务端。

还可以把业务代码和服务治理的策略隔离开,将服务治理策略下沉,让它成为独立的基础模块。这样一来,不仅可以实现跨语言,服务治理策略的复用,还能对这些 Sidecar 做统一的管理。

Service Mesh 的核心思想在于:将服务治理的细节,从客户端中拆分出来,形成一个代理层单独部署。这个代理层可以使用单一的语言实现,所有的流量都经过代理层,来使用其中的服务治理策略。这是一种 关注点分离 的实现方式。

Service Mesh的好处

微服务和容器化之后,异构语言使用的增加,服务的数量激增,容器的生命周期变短是导致服务网格出现的根本原因。

可能很多人会去思考一个问题,就是我们已经有很多成熟的微服务框架,比如spring cloud,go-zero等等,为什么还要Service Mesh来实现治理呢。首先是这些框架其实本质上还是注重于微服务的运行,而不是服务的治理。同时在现在的情况下,会有多种语言参与开发,Service Mesh就可以屏蔽掉技术栈上的差别,让我们以最小的成本来专注于服务的治理。

istio中的流量转发

istio就是当下最火的Service Mesh,主要说一下istio的流量代理

istio的流量代理

现在的istio代理主要是用iptables这个工具来实现(iptables其实只是一个简称,其真正代表的是netfilter/iptables这个IP数据包过滤系统。为了简便,本文也将整套系统用iptables简称。iptables是3.5版本的Linux内核集成的IP数据包过滤系统。当系统接入网络时,该系统有利于在Linux系统上更好地控制IP信息包和防火墙配置。此外,iptables还可以进行NAT规则的管理),在源代码中主要是有一个叫做 istio-iptables.sh 的脚本,这个脚本在 Sidecar 被初始化的时候执行,主要是设置一些 iptables 规则。从而无感知地引入 Sidecar 作为网络代理,也就是说,无论是数据流入还是数据流出时,都要将数据包重定向到 Sidecar 的端口上。

这里给出也原先代码中的摘要:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# 流出流量处理
iptables -t nat -N ISTIO_REDIRECT   # 增加 ISTIO_REDIRECT 链处理流出流量
iptables -t nat -A ISTIO_REDIRECT -p tcp -j REDIRECT --to-port "${PROXY_PORT}" # 重定向流量到 Sidecar 的端口上
iptables -t nat -N ISTIO_OUTPUT # 增加 ISTIO_OUTPUT 链处理流出流量
iptables -t nat -A OUTPUT -p tcp -j ISTIO_OUTPUT # 将 OUTPUT 链的流量重定向到 ISTIO_OUTPUT 链上
for uid in ${PROXY_UID}; do
	# Sidecar 本身的流量不转发
    iptables -t nat -A ISTIO_OUTPUT -m owner --uid-owner "${uid}" -j RETURN 
done
for gid in ${PROXY_GID}; do
	# Sidecar 本身的流量不转发
    iptables -t nat -A ISTIO_OUTPUT -m owner --gid-owner "${gid}" -j RETURN  
done
iptables -t nat -A ISTIO_OUTPUT -j ISTIO_REDIRECT # 将 ISTIO_OUTPUT 链的流量转发到 ISTIO_REDIRECT

# 流入流量处理
iptables -t nat -N ISTIO_IN_REDIRECT  # 增加 ISTIO_IN_REDIRECT 链处理流入流量
iptables -t nat -A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-port "${PROXY_PORT}" # 将流入流量重定向到 Sidecar 端口
iptables -t ${table} -N ISTIO_INBOUND # 增加 ISTIO_INBOUND 链处理流入流量
iptables -t ${table} -A PREROUTING -p tcp -j ISTIO_INBOUND # 将 PREROUTING 的流量重定向到 ISTIO_INBOUND 链
iptables -t nat -A ISTIO_INBOUND -p tcp --dport "${port}" -j ISTIO_IN_REDIRECT # 将 ISTIO_INBOUND 链上指定目的端口的流量重定向到 ISTIO_IN_REDIR

Iptables 方式的优势在于利用系统工具来实现流量转发, 对于业务完全透明,业务甚至不知道有 Sidecar 存在,这样会减少业务接入的时间。不过也相应带来些问题Istio 采用代理的方式去实现服务发现和治理,对业务的流量有侵入。它劫持了业务的流量,这就带来了业务流量上的性能损耗,proxy 也会增加 CPU 内存的消耗。这相当于是在每一个服务调用的过程中增加两个 proxy 转发,增加了架构的复杂度和运维的成本。

现在针对这个问题也是提出了很多的解决方案,包括轻量sdk,这里就不做赘述了

参考文章: