首页系统综合问题在 K8S 大规模场景下 Service 性能如何优化?

在 K8S 大规模场景下 Service 性能如何优化?

时间2022-12-09 07:25:07发布分享专员分类系统综合问题浏览190

今天小编给各位分享service的知识,文中也会对其通过在 K8S 大规模场景下 Service 性能如何优化?和如何在Kubernetes中部署一个高可用的PostgreSQL集群环境等多篇文章进行知识讲解,如果文章内容对您有帮助,别忘了关注本站,现在进入正文!

内容导航:

  • 在 K8S 大规模场景下 Service 性能如何优化?
  • 如何在Kubernetes中部署一个高可用的PostgreSQL集群环境
  • k8s service ipvs性能
  • k8s 对外服务之ingress
  • 一、在 K8S 大规模场景下 Service 性能如何优化?

    【摘要】 Kubernetes 原生的 Service 负载均衡基于 Iptables 实现,其规则链会随 Service 的数量呈线性增长,在大规模场景下对 Service 性能影响严重。本文分享了华为云在 Kubernetes service 性能优化方面的探索与实践。

    在大促过程中,不同业务领域的流量高峰通常都是在不同时间段来临,而应对这些不同时间到来的业务流量往往都需要大量的额外网络资源做保障。今天给大家带来我们在 Kubernetes Service 上的一些优化实践,这是一个网络相关的话题。首先,介绍Kubernetes的Service机制。现在 Kubernetes 中 Service 的三种模式,包括原来的 Userspace 和 Iptables,以及后来我们贡献的 IPVS;第二部分会介绍原来社区是如何使用 Iptables 来实现 Service 负载平衡的;第三部分主要是 Iptables 实现中存在的一些问题;接下来是如何使用 IPVS 来做 Service 的负载实现的;最后是一个对比。

    Kubernetes的Service机制

    先看一下 Kubernetes 里面的 Service。在用 Kubernetes 之前,当我们有了容器网络之后,访问一个应用最直接的做法,就是客户端直接去访问一个 Backend Container。这种做法最直观和容易,同时问题也是显而易见的。当应用有多个后端容器的时候,怎么做负载均衡,会话保持怎么做,某个容器迁了之后 IP 跟着变怎么办,还有对应的健康检查怎么配,如果想用域名来做访问入口要怎么处理……这些其实就是 Kubernetes 的 Service 引入所要解决的问题。

    01 Kubernetes Service 与 Endpoints

    这张图表现了 Service 与其它几个对象的对应关系。首先是 Service,它保存的是服务的访问入口信息(如 IP、端口),可以简单理解为 Kubernetes 内置的一个 LoadBalancer,它的作用就是给多个 Pod 提供负载均衡。

    图中是一个 Replication Controller 部署出来 2 个 pod 所对应的 Service。我们知道 RC 和 pod 的关系是通过 label-selector 来关联的,service 也是一样,通过 Selector 来匹配它所要做负载均衡的 Pod。实际上这中间还有一个对象,叫做 Endpoint,为什么要有这个对象呢?因为在实际应用中,一个 pod 被创建,并不代表它马上就能对外提供服务,而这个 pod 如果将被删除,或处于其他不良状态,我们都希望客户端的请求不被分发到这个无法提供服务的 pod 上。Endpoint 的引入,就是用来映射那些能对外提供服务的 pod。每个 Endpoints 对象的 IP 对应一个 Kubernetes 的内部域名,可以通过这个域名直接访问到具体的 pod。

    再看 Service 和 Endpoint 的定义。这里注意 Service 有一个 ClusterIP 的属性字段,可以简单理解为是虚 IP。Service 的域名解析通常得到的就是这个 ClusterIP。另外值得注意的是 Service 支持端口映射,即 Service 暴露的端口不必和容器端口一致。

    02 Service 内部逻辑

    刚才介绍了 Service、Pods 跟 Endpoint 三者的关系,再来看 Service 的内部逻辑。这里主要看下 Endpoint Controller,它会 watch Service 对象、还有 pod 的变化情况,维护对应的 Endpoint 信息。然后在每一个节点上,KubeProxy 根据 Service 和 Endpoint 来维护本地的路由规则。

    实际上,每当一个 Endpoint 发生变化(即 Service 以及它关联的 Pod 状态发生变化),Kubeproxy 都会在每个节点上做对应的规则刷新,所以这个其实更像是一个靠近客户端的负载均衡——一个 Pod 访问其他服务的 Pod 时,请求在出节点之前,就已经通过本地的路由规则选好了它的目的 Pod。

    Iptables实现负载均衡

    好,我们来看一下 Iptables 模式是怎么实现的。

    Iptables 主要分两部分,一个是它的命令行工具,在用户态;然后它也有内核模块,但本质上还是通过 Netfilter 这个内核模块来封装实现的,Iptables 的特点是支持的操作比较多。

    这是 IPtables 处理网络包的一个流程图,可以看到,每个包进来都会按顺序经过几个点。首先是 PREROUTING,它会判断接收到的这个请求包,是访问本地进程还是其他机器的,如果是访问其他机器的,就要走 FORWARD 这个 chain,然后再会做一次 Routing desicion,确定它要 FORWARD 到哪里,最后经 POSTROUTING 出去。如果是访问本地,就会进来到 INPUT 这条线,找到对应要访问哪个本地请求,然后就在本地处理了。处理完之后,其实会生成一个新的数据包,这个时候又会走 OUTPUT,然后经 POSTROUTING 出去。

    01 Iptables 实现流量转发与负载均衡

    我们知道,Iptables 做防火墙是专业的,那么它是如何做流量转发、负载均衡甚至会话保持的呢?如下图所示:

    02 Iptables 在 Kubernetes 的应用举例

    那么,在 Kubernetes 里面是怎么用 Iptables 来实现负载均衡呢?来看一个实际的例子。在 Kubernetes 中,从VIP到RIP,中间经过的Iptables链路包括:PREROUTING/OUTPUT(取决于流量是从本机还是外机过来的)-> KUBE-SERVICES(所有 Kubernetes 自定义链的入口)->KUBE-SVC-XXX(后面那串 hash 值由 Service 的虚 IP 生成)->KUBE-SEP->XXX(后面那串 hash 值由后端 Pod 实际 IP 生成)。

    当前Iptables实现存在的问题

    01 Iptables 做负载均衡的问题

    那么 Iptables 做负载均衡主要有什么缺陷呢?起初我们只是分析了原理,后来在大规模场景下实测,发现问题其实非常明显

    • 首先是时延,匹配时延和规则更新时延。我们从刚刚的例子就能看出,每个 Kubernetes Service 的虚 IP 都会在 kube-services 下对应一条链。Iptables 的规则匹配是线性的,匹配的时间复杂度是 O(N)。规则更新是非增量式的,哪怕增加/删除一条规则,也是整体修改 Netfilter 规则表。

    • 其次是可扩展性。我们知道当系统中的 Iptables 数量很大时,更新会非常慢。同时因为全量提交的过程中做了保护,所以会出现 kernel lock,这时只能等待。

    • 最后是可用性。服务扩容/缩容时,Iptables 规则的刷新会导致连接断开,服务不可用。

    02 Iptables 规则匹配时延

    上图说明了 Service 访问时延随着规则数的增加而增长。但其实也还能接受,因为时延最高也就 8000us(8ms),这说明真正的性能瓶颈并不在这里。

    03 Iptables 规则更新时延

    那么 Iptables 的规则更新,究竟慢在哪里呢

    首先,Iptables 的规则更新是全量更新,即使 --no--flush 也不行(--no--flush 只保证 iptables-restore 时不删除旧的规则链)。

    再者,kube-proxy 会周期性的刷新 Iptables 状态:先 iptables-save 拷贝系统 Iptables 状态,然后再更新部分规则,最后再通过 iptables-restore 写入到内核。当规则数到达一定程度时,这个过程就会变得非常缓慢。

    出现如此高时延的原因有很多,在不同的内核版本下也有一定的差异。另外,时延还和系统当前内存使用量密切相关。因为 Iptables 会整体更新 Netfilter 的规则表,而一下子分配较大的内核内存(>128MB)就会出现较大的时延。

    04 Iptables 周期性刷新导致 TPS 抖动

    上图就说明了在高并发的 loadrunner 压力测试下,kube-proxy 周期性刷新 Iptables 导致后端服务连接断开,TPS 的周期性波动。

    K8S Scalability

    所以这个就给 Kubernetes 的数据面的性能带来一个非常大的限制,我们知道社区管理面的规模,其实在去年就已经支持到了 5000 节点,而数据面由于缺乏一个权威的定义,没有给出规格。

    我们在多个场景下评估发现 Service 个数其实很容易达到成千上万,所以优化还是很有必要的。当时先到的优化方案主要有两个:

    • 用树形结构来组织 Iptables 的规则,让匹配和规则更新过程变成树的操作,从而优化两个时延。

    • 使用 IPVS,后面会讲它的好处。

    使用树形结构组织 Iptables 规则的一个例子如下所示:

    在这个例子中,树根是 16 位地址,根的两个子节点是 24 位地址,虚 IP 作为叶子节点,根据不同的网段,分别挂在不同的树节点下。这样,规则匹配的时延就从 O(N) 降低到 O(N 的 M 次方根),M 即树的高度。但这么做带来的代价是 Iptables 规则变得更加复杂。

    IPVS实现Service负载均衡

    01 什么是 IPVS

    • 传输层 Load Balancer,LVS 负载均衡器的实现;

    • 同样基于 Netfilter,但使用的是 hash 表;

    • 支持 TCP, UDP,SCTP 协议,IPV4,IPV6;

    • 支持多种负载均衡策略,如 rr, wrr, lc, wlc, sh,dh, lblc…

    • 支持会话保持, persistent connection 调度算法。

    02 IPVS 的三种转发模式

    IPVS 有三种转发模式,分别是:DR,隧道和 NAT。

    • DR 模式工作在 L2,使用的 MAC 地址,速度最快。请求报文经过 IPVS director,转发给后端服务器,响应报文直接回给客户端。缺点是不支持端口映射,于是这种模式就很可惜地 PASS 掉了。

    • 隧道模式,使用 IP 包封装 IP 包。后端服务器接收到隧道包后,首先会拆掉封装的 IP 地址头,然后响应报文也会直接回给客户端。IP 模式同样不支持端口映射,于是这种模式也被 PASS 掉了。

    • NAT 模式支持端口映射,与前面两种模式不同的是,NAT 模式要求回程报文经过 IPVS 的 director。内核原生版本 IPVS 只做 DNAT,不做 SNAT。

    03 使用 IPVS 实现流量转发

    使用 IPVS 做流量转发只需经过以下几个简单的步骤。

    • 绑定 VIP

    由于 IPVS 的 DNAT 钩子挂在 INPUT 链上,因此必须要让内核识别 VIP 是本机的 IP。绑定 VIP 至少有三种方式:

    1.创建一块 dummy 网卡,然后绑定,如下所示。

    # ip link add dev dummy0 type dummy # ip addr add 192.168.2.2/32 dev dummy0

    2.直接在本地路由表中加上 VIP 这个 IP 地址。

    # ip route add to local 192.168.2.2/32 dev eth0proto kernel

    3.在本地网卡上增加一个网卡别名。

    # ifconfig eth0:1 192.168.2.2netmask255.255.255.255 up

    • 为这个虚 IP 创建一个 IPVS 的 virtual server

    # ipvsadm -A -t 192.168.60.200:80 -s rr -p 600

    这上面的例子中,IPVS virtual server 的虚 IP 是 192.168.60.200:80,会话保持时间 600s。

    • 为这个 IPVS service 创建相应的 real server

    # ipvsadm -a -t 192.168.60.200:80 -r 172.17.1.2:80–m

    # ipvsadm -a -t 192.168.60.200:80 -r 172.17.2.3:80–m

    这上面的例子中,为 192.168.60.200:80 这个 IPVS 的 virtual server 创建了两个 real server:172.17.1.2:80 和 172.17.2.3:80。

    Iptables vs. IPVS

    01 Iptables vs. IPVS 规则增加时延

    通过观察上图很容易发现:

    • 增加 Iptables 规则的时延,随着规则数的增加呈“指数”级上升;

    • 当集群中的 Service 达到 2 万个时,新增规则的时延从 50us 变成了 5 小时;

    • 而增加 IPVS 规则的时延始终保持在 100us 以内,几乎不受规则基数影响。这中间的微小差异甚至可以认为是系统误差。

    02 Iptables vs. IPVS 网络带宽

    这是我们用 iperf 实测得到两种模式下的网络带宽。可以看到 Iptables 模式下第一个 Service 和最后一个 Service 的带宽有差异。最后一个 Service 带宽明显小于第一个,而且随着 Service 基数的上升,差异越来越明显。

    而 IPVS 模式下,整体带宽表现高于 Iptables。当集群中的 Service 数量达到 2.5 万时,Iptables 模式下的带宽已基本为零,而 IPVS 模式的服务依然能够保持在先前一半左右的水平,提供正常访问。

    03 Iptables vs. IPVS CPU/内存消耗

    很明显,IPVS 在 CPU/内存两个维度的指标都要远远低于 Iptables。

    特性社区状态

    这个特性从 1.8 版本引入 Alpha,到 1.9 版本发布 Beta,修复了大部分的问题,目前已经比较稳定,强烈推荐大家使用。另外这个特性目前主要是我们华为云 K8S 开源团队在维护,大家在使用中如果发现问题,欢迎反映到社区,或者我们这边。

    云原生时代已经到来,华为云通过 Kubernetes 迈出了云原生基础设施建设的第一步。虽然当前在实践中仍然有许多挑战在等着我们去应对,但相信随着我们在技术上持续的投入,这些问题会一一得到解决。

    一、如何在Kubernetes中部署一个高可用的PostgreSQL集群环境

    虽然 kubernetes 社区一直在努力使得有状态应用成为一等公民,也推出了 statefulset 控制器支持 pod 的顺序部署,稳定的域名访问和存储访问。但鉴于 MySQL 部署运维的多样性和复杂性,在 kubernetes 上部署 MySQL 仍然要面临众多挑战。
    1、业务流量入口的配置方式
    传统虚拟机环境下,我们通过虚IP的方式,让业务应用都配置事先定义的一个虚IP为链接数据库的地址,然后由高可用服务保证虚IP始终能被路由到master数据库。在kubernetes中,出现了一层网络插件屏蔽了底层网络拓扑,高可用服务管理虚IP的方式需要随之适应调整,比如通过service结合标签完成虚IP的漂移,但service本身是kubernetes提供的一项功能,其可靠性和性能都取决于kubernetes服务的稳定。以性能来说,service是kubeproxy组件通过配置iptables实现的,当iptables规则较多时不可避免的会产生时延,需要我们针对性的解决。
    2、容器隔离带来的监控视野问题
    在 kubernetes 中,如果将 MySQL 制作为 container 运行在一个 pod 中,container 会将 MySQL 进程和运行环境隔离在一个单独的 namespace 中。监控组件在获取 MySQL 的一些 metirc 时,可能不得不进入与 MySQL 同一个 namespace 中,在部署和设计监控组件时需要考虑到这些限制。
    3、存储在 kubernetes 中,支持配置各种不同的存储。
    如果使用本地存储 local persistent volume,则需要绑定 MySQL 在一个固定的节点,这就完全浪费了 kubernetes 灵活调度的天然优势;而如果使用远程共享存储,确实是将 MySQL 进程与其存储完全解耦,使得 MySQL 进程可以在任意节点调度,然而考虑到高 I/O 吞吐量的情况,就不是那么美好了。设计时需要考量远程存储是否能够满足 MySQL 的带宽要求。
    4、高可用/备份恢复
    kubernetes 提供的 statefulset 控制器只能提供最基本的部署,删除功能,无法实现完善的 MySQL 集群高可用/备份恢复操作。对于有状态应用的部署,仍需要定制开发,所以多数公司提供了定制的 operator 来完成应用容器的管理。比如 etcd operator,MySQL operator,后文将为大家详述我测试使用 MySQL operator 的一些记录。

    二、k8s service ipvs性能

    ipvs 算是主流调度模式, 性能经过验证的,没问题,而且支持多种调度算法,

    三、k8s 对外服务之ingress

    负载均衡(LB)在微服务架构演进中具有非常重要的意义,可以说的内容有很多, 这里仅仅讨论四层和七层负载均衡的一些要点和区别 ,以便于对 ingress 的理解。所谓四层和七层负载均衡是按照网络层次OSI来划分的负载均衡类型(也可以按照其他的规则来分类,比如:应用的地理结构),简单来说: 四层负载均衡 表示负载均衡器用ip+port接收请求,再直接转发到后端对应的服务上,工作在传输层( transport layer ); 七层负载均衡 表示负载均衡器根据虚拟的url或主机名来接收请求,经过处理后再转向相应的后端服务上,工作在应用层( application layer )。

    下图表示了4层和7层负载均衡在建立TCP连接上的区别,从图中可以看出,四层负载均衡需要建立的TCP连接其实之有一个,它只做一次转发,client直接和server连接;而7层负载均衡则需要建立两次TCP连接,client到LB,LB根据消息中的内容( 比如URL或者cookie中的信息 )来做出负载均衡的决定,接着建立LB到server的连接。

    7层负载均衡有什么好处呢?

    举个例子:
    正向代理 :在使用VPS访问 的时候,通常会使用一个本地的代理服务器,浏览器的网络包会先经过本地的代理服务器,代理服务器会通过远在异国它乡的电脑来访问 并返回消息;这就好比去附近的咖啡店要先问一下手机咖啡店在哪里一样,手机就是一个正向代理服务器。
    反向代理 :当访问的请求到达 时, 那边也设置了一个代理服务器,它通过查看请求的URL,发现是想查找视频内容,于时把消息转给了视频搜索服务器(过程是我乱说的),这就好比你去朋友家做客,开门的却是个管家,问你找谁?这时候管家就是一个反向代理了。
    关于反向代理的好处这里就不多介绍,感兴趣可以看 这里

    k8s 对外 暴露服务(service)主要有两种方式: NotePort , LoadBalance , 此外 externalIPs 也可以使各类service对外提供服务,但是当集群服务很多的时候,NodePort方式最大的缺点是会占用很多集群机器的端口;LB方式最大的缺点则是每个service一个LB又有点浪费和麻烦,并且需要k8s之外的支持; 而ingress则只需要一个NodePort或者一个LB就可以满足所有 service 对外服务的需求。工作机制大致可以用下图表示:

    实际上, ingress 相当于一个7层的负载均衡器,是k8s对反向代理的一个抽象。大概的工作原理也确实类似于Nginx,可以理解成在 Ingress 里建立一个个映射规则 , ingress Controller 通过监听 Ingress 这个api对象里的配置规则并转化成 Nginx 的配置(kubernetes声明式API和控制循环) , 然后对外部提供服务。ingress包括: ingress controller ingress resources

    ingress controller :核心是一个deployment,实现方式有很多,比如nginx, Contour, Haproxy, trafik, Istio,需要编写的yaml有:Deployment, Service, ConfigMap, ServiceAccount(Auth),其中service的类型可以是NodePort或者LoadBalancer。

    ingress resources :这个就是一个类型为 Ingress 的k8s api对象了,这部分则是面向开发人员。

    假设已经有两个服务部署在了k8s集群内部:

    配置 Ingress resources,即可实现多个service对外暴露服务:
    方式一:

    接着在hosts文件中添加一条解析规则: ${ingress_IP} foo.bar.com ,这时通过 在浏览器 中访问: foo.bar.com/coffee 或者 foo.bar.com/tea 即可访问对应的后端service了。

    方式二:

    这时在hosts文件添加两条解析规则就可以在浏览器中访问了。此外,还可以配置TLS证书实现HTTPS访问,这里不再详述。

    关于service的问题,通过《k8s service ipvs性能》、《k8s 对外服务之ingress》等文章的解答希望已经帮助到您了!如您想了解更多关于service的相关信息,请到本站进行查找!

    爱资源吧版权声明:以上文中内容来自网络,如有侵权请联系删除,谢谢。

    service
    怎么一键批量无损去水印下载抖音、快手、微博、B站等短视频 忘记了自己加密的压缩包密码,该怎么办?