k8s中流量分离以及资源隔离实战

源宝导读:明源云客的终端用户越来越多,也涌现出线上流量活动的场景,大量的访问和接口请求导致服务器出现较高负载。本文将介绍云客团队为了缓解服务器压力,通过K8S进行分流与资源隔离的实践过程。

一、背景

    PaaS和B2C的主要客户云客的终端用户越来越多,也开始有流量活动的需求。

    近期云客需要开始一个流量活动,B2C配合对特定接口做了压测并且对系统容量进行了调整。当时的压测结果是200并发300ms完成基本符合云客的要求。可是活动开始后事情跟我们预想的是不一样的,压测只测试了注册接口,但是实际登陆接口也会有巨大的请求量。由于登陆接口有比较多的调用第三方所以在请求量大的是对服务器的CPU带来较高的负载。在这个情况下我们不断的对服务进行扩容。可是扩到190个核心服务服务依然是没法正常。

    由于当时部署的是整个服务组统一给所有用户提供服务,如下图:

    按照这个情况只要一个租户的流量特别大给集群带来压力就会导致整个服务异常,所有人都无法正常访问。出于将影响范围缩小的考虑,我们需要将活动的流量分流并保障即便活动的客户出现问题也只是影响活动租户不会影响到其他租户。

二、分流

    在思考如何分流时,第一个想到的是之前已经在云链和云空间落地的利用openresty识别url参数,header,cookie中的特征信息然后进行路由这个方案。但是由于paas和B2C部署是基于k8s这个方案就变的不那么好了。

    使用openresty就需要在集群之外架设将流量分配到两个集群,那么会遇到这些问题:

  1. 分流集群通常不是常驻有需要的时候才会部署,这样每次需要分流前都要去维护分流策略。

  2. 为了保障openresty的可用性,可能需要在集群外部部署多个openresty服务。那么流量的路径会变的很复杂且冗长,这会让排查问题变的困难,同时会影响访问速度。

  3. 需要时间完成分流策略的代码,并且要进行一定的压力测试才能够正式上线接管流量。会需要很比较多的时间。

    由于这些问题,考虑从k8s的ingress来进行分流。有了下图的设想:

    ingress-controller的选择

    我们使用的ingress-controller是nginx-ingress,nginx-ingress自带一个分流功能,定义上也十分符合k8s和helm的的管理方式。查阅官方文档后发现,目前nginx-ingress只支持header,cookie进行分流,可是现状是现有项目分流的特征信息在url的query才有。只能再去寻找其他ingress-controller。

    查找并对比了traefik,ambassador,haproxy,alibaba-ingress这几个ingress-controller。

  • traefik在功能上是满足的且有很多新的功能十分值得尝试,并且解决了nginx令人诟病的静态配置问题。但是不支持tcp协议路由,需要k8s版本高于1.14。由于一个网络插件升级的问题我们的k8s集群一直还在1.12版本,所以这次用不上了。

  • ambassador。如果严格遵循k8s的定义,ambassador其实不算一个ingress-controller。它并不是通过ingress去定义路由规则,而是直接在service上加上注解定义路由规则(更像一个api网关)。这样的话我们需要改动的点就比较多了。

  • haproxy的优势在负载均衡算法,在七层协议的路由能力不能满足需求。pass

  • alibaba-ingress,阿里云基于nginx-ingress进行了一些定制开发和优化的ingress-controller。基本是与我们现在用的nginx-ingress一致,在分流的规则定义上有一些差异。nginx的分流是分别在两个namespace定义两条ingress规则(注解有差异,通过注解匹配请求),alibaba的则是在同一个ingress规则定义2个后端服务再通过注解匹配请求。alibaba-ingress的分流规则支持基于query的匹配是符合我们需求的,但是两年没有更新版本并且官方不提供helm部署方式。

    基于符合需求且影响点最小化的思路,选用了alibaba-ingress来作为这次分流的ingress-controller。

三、部署

    在选定了分流的方案之后,如何高效稳定的部署两组服务成为第二个需要解决的问题。

    目前我们的部署方式:将一组服务打包成一个产品进行部署。

    如何部署分流的服务组,有两个方案:

  1. 将分流的服务一个个加入产品里面进行部署。

  2. 将现有产品在其他namespace再部署一份。

  • 方案1:所有服务都在一个namespace中ingress规则很好配(ingress规则不能路由到不同namespace的service),但是会让服务管理变的十分复杂,并且需要修改应用配置。放弃。

  • 方案2:两组服务分别 部署在两个namespace需要解决跨namespace配置ingress规则的问题,但是管理上简单,也不需要对应用做任何改动。

    改变部署存在的影响点太多,时间紧迫必须选择影响点最少的办法。所以方案2是首选。

    如何让ingress规则跨namespace

    既然ingress的规则不能跨namespace路由,那就想办法把其他namespace的service弄到当前namespace。在k8s中有一种ExternalName类型的service,提供了映射外部服务的能力(其实就是一个类似cname解析的功能)。

    部署示意:

    分两个命名空间部署两组一模一样的服务,在常驻服务的命名空间中用ExternalName类型的service将分流服务命名空间内的服务映射过来。ingress在同一个命名空间下进行流量分配。

四、资源隔离

    在分流和部署的方案都确定以后,需要考虑最后一个问题。如何保障正常用户不被活动的用户影响。根据我们的现状,之所以正常用户会被影响的主要原因就是资源被活动用户消耗殆尽导致整个系统的崩溃,基于这个情况为了保护正常用户的访问只需要将正常用户和活动用户使用的资源进行隔离即可。

    K8S提供了几种管理容器调度到节点的功能:

  1. 节点选择器(nodeSelector),非常简单的方法来将 pod 约束到具有特定标签的节点上

  2. 节点亲和(nodeAffinity),节点亲和分为硬和软两种,“硬”类似节点选择器只是可以用更复杂的约束规则,“软”则是尽可能运行到符合条件的节点上。

  3. 节点瑕疵和容忍度(Taint和Toleration),为特定节点打上瑕疵标签,只有能够容忍该瑕疵的pod才能运行到这类节点上。

    实现隔离

    利用1和3的功能,就能够实现我们期望的效果。

  1. 为活动的租户新增一批节点,给这些节点打上瑕疵标签。保持正常业务的容器无法被调度到这些节点。

  2. 按照之前部署中介绍的方案,为活动租户新部署一套服务。

  3. 新增的一组服务,配置节点选择器约束到特定节点,配置节点容忍新增节点的瑕疵标签。

    经过上述步骤就能够将两组服务的资源很好的隔离开。

五、快速配置

    完成了功能性的诉求,最后就是需要在使用上变得便利。因为之前选择方案都会考虑配置和部署的便利性,所以最终只需要对现有的chart(部署模版)进行一些小小的调整就能实现快速配置分流以及隔离。

    新增节点

    通过阿里云新增节点,之后通过下面命令对节点打标签和瑕疵

kubectl label node cn-hangzhou.i-bp1faickzmmuat2f09dr b2c=canary
kubectl taint node cn-hangzhou.i-bp1faickzmmuat2f09dr b2c=canary:NoSchedule

    部署分流服务

    我们使用helm部署,只需要复制常驻服务的values文件新增几个字段并关闭ingress配置然后用helm部署到新的namespace即可。
    以一个服务的values举例,复制内容如下:

b2c-nginx-proxy:replicaCount: 5image:tag: "20190920"env:enabled: true ingress:enabled: trueannotations: kubernetes.io/ingress.class: nginxhosts:- example.mypaas.com.cntls: - secretName: example.com.cnhosts:- example.mypaas.com.cn

修改后内容如下:

b2c-nginx-proxy:replicaCount: 5image:tag: "20190920"env:enabled: true ingress:enabled: falseannotations: kubernetes.io/ingress.class: nginxhosts:- example.mypaas.com.cntls: - secretName: example.com.cnhosts:- example.mypaas.com.cntolerations:- key: b2coperator: "Equal"value: "canary"effect: "NoSchedule" nodeSelector:b2c: canary

    常驻服务开启分流配置

    常驻服务的values文件新增几行即可实现分流以一个服务的values举例:

b2c-nginx-proxy:replicaCount: 3image:tag: "20190920"env:enabled: true ingress:enabled: truecanary:enable: true       #开启分流annotations: kubernetes.io/ingress.class: nginxnginx.ingress.kubernetes.io/service-match: |   #分流规则配置b2c-nginx-proxy-canary: query("tenant_code", /.*zhaosadmin.*/) hosts:- example.mypaas.com.cntls: - secretName: example.com.cnhosts:- example.mypaas.com.cn

    简单的三步即可完成租户分流并且隔离。

六、应用

    当所有验证ok后,立马将这套方案在生产上线,将当时活动的租户分流并隔离。同时开始缩减集群规模把为正常租户提供服务的服务组节点数量恢复成常驻节点数量,保留四个节点继续为活动租户提供服务。
    到目前为止正常租户的服务没有受到过影响。

七、云擎的灰度策略

    灰度发布的技术本质跟这个分流并没有太大的区别。只是使用场景上的差异,所以这套方案可以放到云擎直接实现灰度发布。简单介绍一下,将来各团队接入使用时也能提前准备。

    支持的路由规则

    云擎支持的ingress-controller只会是nginx-ingress,因为alibaba-ingress几年没有更新,不敢在生产环节长期使用。
所以云擎只能支持根据header和cookie进行路由。如果各团队希望能够灰度发布需要在请求头中加入特定标识。

    数据库的灰度

  1. 没有租户库的团队,需要保持灰度的两个版本在数据结构上是兼容的

  2. 有租户库的团队,选择租户的范围进行数据升级

    产品内部的服务调用

    需要使用灰度发布必须保持各个服务间的调用都要走内网调用。不能通过公网域名调用,这样会导致调用关系混乱。

    支持的特性

    由于是利用nginx-ingress实现的,所以还是会遵循一些nginx本身的限制。

  • 只能创建一条灰度规则

  • 一条规则内可以同时定义header,cookie,权重。优先级关系:header -> cookie -> 权重。

  • header支持自定义值并且值可以用正则匹配,cookie只支持固定值:always或never

  • 分流规则所有配置遵循原有的所有配置,如:最大传输大小,是否强制https,超时时间等

八、未来

    现阶段利用nginx-ingress云擎能够以极低的成本提供灰度发布的能力,但是nginx-ingress整体来看功能还是有欠缺。不过在这次事件中为了找方案,了解了其他优秀的ingress-controller。后续应该会把所有的ingress-controller替换成traefik来实现更多功能。

------ END ------

作者简介

尹同学: 运维负责人,目前在云技术创新中心负责技术运维工作。

也许您还想看

天眼系统对应用页面首次有效渲染的数据采集

云客大数据管理保障体系

浅谈Readiness和Liveness在云客的应用

基于Go的微服务运行情况监控实践

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/310426.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

怎样实现WPF Prism Module的国际化和本地化?

English | 简体中文上一篇有简单介绍主工程的国际化,使用的资源字典(XAML)实现的。这几天我添加了几个Prism模块(Module),发现子模块使用资源字典的方式实现国际化和本地化不好做,没有找到比较好的参考文章,所以换了一种方式&…

dotNET Core 3.X 使用 Jwt 实现接口认证

在前后端分离的架构中,前端需要通过 API 接口的方式获取数据,但 API 是无状态的,没有办法知道每次请求的身份,也就没有办法做权限的控制。如果不做控制,API 就对任何人敞开了大门,只要拿到了接口地址就可以…

数据结构与算法--代码鲁棒性案例分析

代码鲁棒性 鲁棒是robust的音译,就是健壮性。指程序能够判断输入是否符合规范,对不合要求的输入能够给出合理的结果。容错性是鲁棒的一个重要体现。不鲁棒的代码发生异常的时候,会出现不可预测的异常,或者程序奔溃。由于鲁棒性非…

【半译】两个gRPC的C#库:grpc-dotnet vs Grpc.Core

grpc-dotnet 是在2019年随着 .NET Core 3.0 一起发布的一个gPRC官方库。在ASP.NET Core 的 gRPC项目模板里面就使用了这个库。.NET Core 3.0之前难道不可以使用gRPC吗?目前,gRPC 在.NET上有两种官方实现:Grpc.Core:这个是原来的gR…

[Java基础]String对象的特点(易错点)

String对象的特点: 1.通过new创建的字符串对象,每一次new都会申请一个内存空间,虽然内容相同,但是地址值不同。 2.以""方式给出的字符串,只要字符串相同(顺序和大小写),无论在程序代码中出现几次&#xff0…

数据结构与算法--解决问题的方法- 二叉树的的镜像

解决问题的思路 工作中遇到的问题可能用到的数据结构由很多,并且各种数据结构都不简单,我们不可能光凭借想象就能得到问题的解法,因此画图是在家具问题过程中用来帮助自己分析,推理的常用手段。很多问题比较抽象,不容…

使用dnSpy调试asp.net core源码

环境:window 10vs2019 16.5.1dnspy v6.1.4.netcore3.1参考:.Net反编译技术详解及4个反编译工具介绍一、关于dnSpydnSpy是近几年的新秀,功能远比ILSpy强大,甩.net Reflector几条街,被汉化、破解、逆向方面的人才奉为神器…

数据结构与算法--解决问题的方法-顺时针打印矩阵

顺时针打印矩阵 题目输入一个矩阵,按照从外向里顺时针的顺序依次打印每一个数字。例如下案例: 如上图矩阵,顺时针打印:1,2,3,4,8,12,16,15,14,13,9,5,6,7,1,10 以上问题看起来比较复杂,但是又没有涉及到复杂的数据结…

.NET与鲲鹏共展翅,昇腾九万里(二)

在上一篇文章 .NET与鲲鹏共展翅,昇腾九万里(一)中,我们通过在鲲鹏架构的Euler系统上跑Docker的方式把dotnet core 跑起来了,有读者反馈说“还是走docker喽,你这个标题应该改成鲲鹏和docker两条鲸鱼的故事”…

[Java基础]final和static修饰符

final: final修饰局部变量时: static: static访问特点:

优化委托的 DynamicInvoke

优化委托的 DynamicInvokeIntro委托方法里有一个 DynamicInvoke 的方法,可以在不清楚委托实际类型的情况下执行委托方法,但是用 DynamicInvoke 去执行的话会比直接用 Invoke 的方法会慢上很多,差了两个数量级,所以在知道委托类型的…

数据结构与算法-- 广度优先打印二叉树

广度优先打印二叉树 题目:从上往下打印出二叉树的每一个节点,同一层节点按照从左到右顺序打印,例如下图中二叉树,依次打印出是8,6,10,5,7,9,11 如上题中二叉树的节点定义我们用之前文章 二叉树实现原理中定义的节点结构。此处提议…

实现一个基于动态代理的 AOP

实现一个基于动态代理的 AOPIntro上次看基于动态代理的 AOP 框架实现,立了一个 Flag, 自己写一个简单的 AOP 实现示例,今天过来填坑了目前的实现是基于 Emit 来做的,后面有时间再写一个基于 Roslyn 来实现的示例效果演示演示代码&…

数据结构与算法-- 二叉树后续遍历序列校验

二叉树后续遍历序列校验 题目:输入一个整数数组,判断改数组是否是某个二叉搜索树的后续遍历结果,如果是返回true否则false,假设输入数组的任意两个数字不相同。 例如输入{5,7,6,9,11,10,8}则返回true,因为这个整数序列…

程序员过关斩将-- 工作好多年可能还未真正了解接口和抽象类

点击上方“蓝字”关注我们菜菜哥,我偷偷出去面试了,然后面试官让我回来等消息那你可能挂了呀,有什么问题没回答上来吗确实有一个问题回答的不太好哎,就是接口和抽象类这个确实是面试官比较爱问的题目之一那能不能说说接口和抽象类…

数据结构与索引-- mysql InnoDB存储引擎索引

索引与算法 索引是我们在应用开发过程中程序数据可开发的一个重要助力。也是一个重要的研究方向,索引太多,应用的性能可能受到影响,如果索引太少,对查询性能又会有制约。我们需要找到一个合适的平衡点,这个对性能至关…