本文做者: 柴克斌 (网易传媒技术团队)web
网易传媒作为国内最先的内容资讯平台,随着业务体量的增长,业务迭代的速度加快,基础架构也面临着不少挑战,为了能提供快速、稳定、安全的基础架构及基础服务,传媒在2019年初进行了一次基础架构的容器化升级,本文就传媒基础架构在容器化升级方面所作的工做、面临的问题、提出的解决方案及将来的规划都作一些详细描述,但愿能给也在容器化升级的读者有所借鉴算法
随着传媒业务的不断增长,基础架构也面临着不少挑战,主要包括如下几类问题sql
资源利用率:传媒基础架构在容器化以前,资源使用率在20%左右,存在着波峰波谷,波谷时期总体利用率得不到有效的利用数据库
流程繁琐,人工操做较多:业务在申请资源的时候,须要通过流程审批,耗时比较长,在遇到流量高峰的时候,扩容资源比较耗时,流量高峰后,运维还须要手动将资源下线api
频繁的数据爬取:传媒一些核心接口,一直存在被外网爬取的状况,致使了服务的不稳定及流量突增安全
手动扩容、缩容,耗费人力:业务比较难设置合理的资源使用量,当出现业务高峰时,就须要扩容,高峰事后,又须要手动缩容restful
服务依赖拓扑不清晰:当服务要作迁移或下线时,服务提供方须要经过各类人工方式找到全部的服务依赖方,并作下线通知,人工方式常常会找不全全部依赖方,致使服务提供方下线后,消费方出现了故障markdown
为了应对上述的挑战,传媒决定对基础架构作一次总体的升级,但愿达到以下目标网络
提高资源总体利用率:传媒但愿总体资源利用率提高至50%~60%,而且将波谷资源充分利用起来,可以优化成本架构
提升效率:传媒计划取消一些繁琐的流程,业务方随时从资源池中获取资源,咱们会监控用户对资源的使用状况,对于资源使用率低的业务进行资源优化
加固安全:传媒须要搭建网关服务,为用户提供统一的流量入口,在网关上增长熔断降级、安全、审计等方面的能力
保障稳定:资源出现故障后业务能快速迁移,流量突增后能快速扩容,流量恢复后也能自动缩容
快速定位业务依赖:传媒但愿可以快速、准确的定位到业务的依赖,可以看到总体的业务依赖拓扑图,可以看到核心接口的URL调用拓扑图
传媒的架构演进主要经历了四个阶段
物理机阶段:最先传媒业务都在物理机上进行部署
虚拟化阶段:为了节约成本,传媒总体业务都迁移到了专属云
容器化阶段:为了进一步节约成本、提升效率、保障稳定、加固安全,传媒总体业务都迁移到了容器云,资源作到了池化,业务随用随取
容器云升级阶段:迁移到容器云后,基础资源管理更为方便,为弹性、精细化资源管理提供了强大的基础
本文主要介绍传媒容器化阶段所作的工做
在对业务架构和需求了解后,咱们规划了三个资源池
容器资源池:全部无状态业务都容器化,运行在容器资源池内
云主机资源池:有些使用了rsync、IP绑定、IP哈希、有状态的服务,暂时没有时间进行架构改造,就使用云主机资源池
物理机资源池:有些使用资源很大的应用(推荐、算法等)没有必要进行容器化改造和云主机迁移的应用,仍是保留物理机
容器资源池和云主机资源池在一个大的VPC内,物理机在VPC外,之间的通讯使用DGW网关和NLB进行
容器资源池,咱们划分为如下7类
APP:这个资源池部署全部的业务应用
Redis:Redis属于敏感性业务,单独划分资源池,对这个资源池的使用作独立的配置
PUSH:PUSH业务白天的时候会占用70%以上的资源,但夜晚的资源使用率很低,独立一个资源池,防止PUSH在白天高峰的时候对其余业务产生影响
Rec:推荐资源池,推荐业务要求独立资源池,不想与其余业务共同使用资源池
Kafka:Kafka Operator资源池,部署全部Kafka服务
ES:ES Operator资源池,部署全部ES服务
GW:网关资源池,部署全部容器网关
咱们规划了容器资源池、虚拟机资源池和物理机资源池,但容器内外的服务如何互相调用,通过讨论和设计,咱们采用以下的方式进行容器内外的调用
容器外调用容器外服务:咱们使用传媒本身的服务框架NDSF作为服务调用的框架,使用Consul作为服务注册中心
容器内调用容器内服务:容器内咱们直接使用ServiceName进行调用
容器内调用容器外服务:容器内调用容器外服务,咱们也使用NDSF服务框架,使用Consul作为服务注册中心
容器外调用容器内服务:容器外服务调用统一通过入口网关
为了彻底隔离生产环境和测试环境,咱们独立建立了Beta环境,Beta环境与生产环境网络设备,机柜和机器彻底隔离,Beta环境有独立的VPC资源池,也有独立的容器云资源池和云主机资源池
默认状况下,Beta环境是不能访问生产环境的,但有些业务方有Beta环境访问生产环境的需求,为此,咱们设置了白名单安全组,若是有须要访问生产环境的业务需求,将IP列表加入白名单便可访问生产环境
咱们建立了容器资源池和云主机资源池,容器资源池的网络使用了OVS,在整个VPC环境内和虚机都是网络平行的,咱们划分了一个大的网段,并在这个大网段中划分了若干子网
容器公网网段:这个网段容许访问公网
容器内网网段:这个网段不容许访问公网,大部分容器实例都在这个网段
云机公网网段:这个网段容许访问公网
云机内网网段:这个网段不容许访问公网,大部分虚机实例都在这个网段
网关网段:容器网关所使用的子网
Redis网段:Redis所使用的子网
Kafka网段:Kafka所使用的子网
ES网段:ES所使用的子网
管控网段:Kubernetes管控组件所使用的子网
7**.技术选型**
专属云环境咱们选择了网易杭研提供的云1.0,云1.0基于OpenStack扩展,提供了虚拟机、RDS、NCR、LB等基础资源和公共中间件,网络使用OVS,云1.0是咱们一直使用的云环境,比较稳定,可靠,运维团队对这个环境也很是的熟悉
容器云环境咱们使用了网易杭研提供的轻舟平台,轻舟平台是在社区Kubernetes的基础上推出的PAAS平台,轻舟自己基于社区,但在社区提供的能力基础上,稳定性和可用性方面都作了很大的提高,符合生产环境的使用要求,咱们使用了轻舟的如下组件
NCS:容器服务,提供基础、可靠的容器实例服务
NSF:容器ServiceMesh,使用Envoy和Istio,并在社区开源的基础上支持了Dubbo、Thrift协议,支持了热升级、懒加载、服务治理能力等。咱们在使用NSF时,只启动了调用端拦截
混部:离线/在线业务混部平台,用于总体提升CPU的使用率
容器网关:容器池外访问容器内服务的惟一入口,用于安全,审计,熔断/降级,监控等能力
Redis Operator:容器Redis PAAS服务
Kafka Operator:容器Kafka PAAS服务
HPA:Kubernetes默认支持的能力,使用HPA实现弹性扩缩容,支持了CPU负载,QPS,任务积压量等指标的弹性扩缩容
通过1年左右的努力,传媒已经创建起来了容器资源池、云机资源池和物理机资源池,容器资源池运行了上万个POD,上千个Service,核心业务都已经迁移到了容器环境,80%的物理机资源都进入了容器资源池
服务调度和治理框架作为微服务的基础框架,起到了很是重要的做用,市面上有不少可用的开源框架,好比:Dubbo、Spring Cloud等,传媒容器化以前有本身的一套服务调用与治理框架,咱们命名为NDSF。
NDSF的功能架构图以下所示:
NDSF框架主要包括三大块内容
SDK:提供了数据库、中间件的Client SDK,这些SDK封装了用户密码,访问地址等敏感信息,同时也提供了核心指标的调用统计能力
Framework:提供了微服务启动的基础能力,包括:服务上线/下线、服务状态查看、服务拓扑上报、服务健康状态监控等基础能力
服务调用:服务框架调用、服务注册、服务发现、负载均衡、服务治理能力的提供
NDSF作为传媒的基础框架,基本全部服务都在使用,在服务调用和服务治理层面,NDSF框架使用Consul作为服务注册中心,基于HTTP2.0C的服务调用框架,服务的调用实现了Jar包调用和Proxy调用两种能力
Jar包方式调用:适用于Java语言的微服务,经过在工程里引入NDSF Jar包实现服务的调用、注册和治理
Proxy方式调用:适用于非Java语言的微服务,经过在每台机器上部署一个Proxy实现服务的调用、注册和治理
NDSF目前已经覆盖了传媒80%以上的业务,在业务方接入完成,使用过程当中,也出现了不少问题,主要的问题以下
框架的升级须要业务方的感知,业务方须要配合升级Jar包,从新发布应用,这种方式对升级形成了很大的阻碍
业务在接入或升级过程当中,比较容易引发Jar包冲突,致使业务方进行修复,增长了业务方接入成本和时间
业务方接入NDSF时须要修改服务调用代码,对接入也形成了不少困难
为了作到让业务无感知,也不须要作任何改动,咱们决定使用ServiceMesh作为整个服务治理的框架,经过ServiceMesh,咱们想达到如下几个目的
业务无感知:对业务代码无需修改,业务代码无需引入Jar包
语言无关:业务方所使用的语言都能支持
多协议支持:支持常见的Dubbo、Thrift、HTTP、gRPC协议
动态生效:服务治理、服务发现、服务注册都可以动态生效,版本升级也对业务无感知
完善的服务治理能力:可以支持超时重试、熔断降级、黑/白名单、限流等服务治理能力
在ServiceMesh方案选型方面,咱们使用了NSF作为ServiceMesh的底层支撑,NSF是基于Istio和Envoy作了加强,不只支持了Dubbo和Thrift,也在动态升级、动态拦截、服务兜底策略方面作了比较大的升级
因为传媒有部分服务使用的Dubbo,ServiceMesh须要对Dubbo协议作一些支持,NSF在Istio和Envoy的基础上,增长了对Dubbo的支持,主要的架构以下:
业务方使用Dubbo直接调用目标IP的方式
经过 iptable ⽅式对指定端⼝(⽬前10000端⼝)的流量进⾏拦截,重定向到 envoy
保留 zk 注册中⼼,扩展 galley 组件从 zk 拉取 dubbo 服务的注册信息及服务依赖
galley 组件经过 mcp 上报 service entry 资源给 pilot,扩展字段⾥包含了 dubbo 服务的依赖关系
pilot 在同步 xds 配置的时候根据 service entry 上的依赖关系,按需下发所需的配置
VirtualService协议上面扩展了Dubbo
ServiceMesh目前支持的能力以下表所示
传媒容器化的主要一个目标之一就是可以提升总体CPU的利用率,节省资源。目前传媒总体资源利用率在20%左右,波谷的资源得不到有效的利用,咱们但愿总体资源利用率可以达到50%~60%,而且不能影响总体服务的稳定性,通过分析后,将资源的使用状况分为如下三类
资源利用率很低,在3%~5%左右,这类应用业务比较敏感,不能有延迟,比较典型的就是Redis集群
存在明显的波峰波谷,在线资源在波谷的状况下,会空闲出大量的计算资源
在线资源的使用率不是很低,通常在15%~20%左右,这些业务不是很敏感,比较典型的就是无状态服务
咱们对目前的资源使用状况和业务进行了分析,将总体业务区分为在线业务和离线业务两种类型,这两种业务的主要特色以下:
咱们对离线业务/在线业务混部作了以下限制:
离线业务不能影响在线业务
优先在线服务可用的资源保证
在线服务资源使用率低的状况下,离线服务使用资源,保证总体资源使用率在必定水位
容器资源池,按照在线/离线维度,划分为三类资源池
在线资源池:只能调度在线业务上来
离线资源池:只能调度离线业务上来
混部资源池:能够混合调度在线、离线业务上来业务类型
容器内部署的业务类型,划分为四类业务类型
Job:离线任务,会调度到离线资源池
Serivce:在线任务,会调度到在线资源池
Colocation-job:容许混部的Job,会调度到混部资源池
Colocation-service:容许混部的service,会调度到混部资源池
咱们使用了轻舟团队提供的Zeus混部系统作为传媒混部的基础平台,Zeus能保证在线业务稳定的前提下,最大化利用CPU资源,而且支持灵活的混部策略和弹性扩缩容
Zeus主要架构以下图所示:
混部系统主要包括六个组件,管控面有四个组件:
zeus-webhook-server:基于kubernetes dynamic admission control开发的准入控制插件。拦截用户请求,进行默认值的设置和字段的合法性检查
zeus-manager:基于kubernetes的 operator 模式开发的控制器。实现CRD资源的生命周期管理、离线任务重调度等
zeus-scheduler-extender:基于kubernetes的 scheduler http extender机制 开发的用来实现离线业务动态调度的扩展调度器
zeus-exporter: 相似于kube-state-metrics组件,统计汇总各类资源数据,推送到prometheus
数据面有两个组件:
zeus-monitor-agent:采集节点监控数据的agent,运行在混部资源池的每一个节点上。monitor组件将节点的负载状况按期更新到NodeProfile(custom resource)资源中,而且提供本地restful api,提供给zeus-isolation-agent查询
zeus-isolation-agent:是一个负责实如今/离线业务资源隔离的组件,运行在混部资源池的每一个节点上。访问 zeus-monitor-agent 获取监控数据,按期执行隔离规则。
咱们依据业务使用资源的特性,将整个容器混部资源池划分为三类
APP:在线应用资源使用率较高,有可能存在突增现象
NCR:在线应用资源使用率很低,但比较敏感,离线不能占用太多资源,防止抖动
PUSH:在线应用有明显的波峰波谷,波谷资源利用率须要提升
在合理估算离线任务可以使用的CPU的方面,若是在线业务负载较高,节点资源利用率高,那么分配给离线业务的资源就会少或者该节点就彻底不须要混部离线业务;若是在线业务负载较低,节点资源利用率低,那么分配给离线业务的资源就能够变多,基于以上的分析,咱们定义了以下公式
Capacity = MAX(节点可分配资源总量 * 节点目标利用率 - 在线业务使用量, 最低资源保证核数)
复制代码
节点目标利用率是咱们根据每一个资源池的敏感状况动态设置的
好比一个混部节点的cpu capacity为56核,allocatable为55核,该节点上的在线业务实际使用了10核,而且该节点的CPU目标利用率配置为50%,最低资源保证为2核,则该混部节点的可用CPU核数为:
Capacity = Max( 55*50% - 10 , 2 ) = 12.5 核
复制代码
通过在线/离线混部,目前资源总体利用率获得了很大提高,节省了30%左右的资源
咱们对预约义的混部资源池进行监控,总体资源使用趋势以下:
必须对业务进行容量评估
须要对进入容器的业务提早进行容量的评估,以防止容器集群总体压力增大而致使的故障,评估的主要内容包括:网络带宽、PPS、QPS、CPU算力、内存大小、磁盘IO、业务特性、LB带宽、网关带宽等关键项和指标,以确保新业务进入容器集群后,容器集群也可以支持这个流量
节点标签不宜打太多
K8S可用经过在节点上打不一样的Tag,业务在部署的时候能够选择不一样的资源池进行部署,若是资源池的Tag打的过多,则会带来很大的管理难度,对于资源的合理应用也会形成很大的阻碍,建议业务部署选择的资源池按业务特性进行选择,传媒目前主要的资源池包括:APP、网关、Redis、Kafka、PUSH、推荐、ES,这些资源池都有独立的特性,不能互相影响
合理建立Service
若是服务须要用到Service资源,再去建立。Service资源建立后,当业务发布、扩容、缩容、更新后,都会致使Endpoint发生变化,IPTables会全量刷新,若是Service下的POD不少,全量刷新会很慢,对整个网络也会形成没必要要的影响
容器IP不宜粒度太细
用户在访问Mysql数据库的时候,为了数据安全,都会对要访问的库增长IP白名单限制,在使用云机和物理的时候,IP都能固定住,但在容器的场景下,IP地址是在一个大网段随机分配的,若是要细粒度管理IP资源,就须要用到IPPool,为每个集群建立本身的IPPool,这样对于管理复杂度有很大的增长,并且对于IP资源也有很大的浪费,由于对每个集群,都须要预留必定数量的IP作为备份,建议在容器集群下,就不要限制Mysql数据库白名单,或者限定容器集群的一个大段,在管理上会方便不少
目前,传媒的核心业务都已经进入了容器,对基础资源的管理作到了下沉,后续,在K8S的基础上主要作如下几件事
资源精细化管理:咱们分析目前容器集群的使用状况,发现业务申请资源和实际使用的资源差距很大,致使业务占用了不少资源,但其余业务没法从资源池中获取须要的资源,接下来,咱们将会细化每一个集群的资源申请量和实际使用量之间的差距,争取缩小二者的差距
资源使用自动推荐:依据集群历史实际资源的使用状况,可以给应用一个合理的资源量,让业务能有个参考
资源弹性:为了应对流量的徒增能快速扩容,须要增长容器的弹性,目前已经在使用HPA解决资源的弹性,也在尝试VPA方面解决资源的弹性问题
推广ServiceMesh:服务治理能力下沉,让业务方更关注于业务自己,目前咱们已经支持了ServiceMesh的能力,接下来会给业务推广这样的能力
容量管理:容器集群内的总体容量监控,包括:网络、计算、内存、磁盘等资源的总体容量监控,为新业务进入容器作到准确的评估