近几年,OPPO 构建并不断完善基于 kubernetes 的混合云平台,统一了之前公有云、自有机房裸机部署的方式,积极推动业务迁移上云,使得在简化运维、降低成本等方面取得了一定的成果。但是初尝喜悦之后,我们发现不(ke)合(you)理(hua)的地方:
从平台的角度看,要做的就是一件事:“把资源盘活、盘好、盘细”,我们内部把他们分成不同的方向在探索,比如统一算力、智能调度,而我们这里要谈的就是弹性伸缩,希望通过它做到的是节省空余资源,提高分时利用率。
我们从不同的维度,挖掘了OPPO云实际业务的一些配对特征(下图所示):
按实时性分:
在线业务,实时要求高,不可重试,不太能接受被抢占;
离线业务,可以接受排队,被抢占重试任务即可;
按职能分:
基础设施,包括云上的一些paas产品,或者保护平台基本运作的设施;
对外服务,主要是对外业务的服务;
按部署形态分:
单集群部署,不具备跨集群部署能力的业务;
可用区部署,跨集群业务,但这里想表达的是包括但不限于serverless化;
按状态分:
有状态业务:各种rds、中间件、甚至大数据处理的集群等;
无状态业务:一些高并发服务;
按实现方式分:
传统方式实现:传统技术实现的服务直接上云;
其实有很多是具备“逻辑可弹”的属性(即逻辑上可以设置多副本,组成集群或者组的概念),比如“持续部署”是一个 PAAS 产品,他里面的“分组”就是用来管理业务节点副本的,同时又包装了诸多比如rds授权、服务发现、对接监控等能力,我们把持续部署打造为一款弹性资源,那只要接入了持续部署的所有业务,就变成了弹性资源的实例化对象。我们这里希望做的不仅仅是通过“弹性伸缩”解决典型的场景问题,更想要统一的管理和挖掘弹性资源,输出标准。
综上所述,我们打算做个统一管理弹性资源的平台,提供弹性伸缩能力。
▎2.1 原则
在上述背景下,对于弹性平台的设计,我们设立了一些基本原则:
丰富:提供丰富的弹性策略,支持多种触发能力;
安全:伸缩执行时要有严格的兜底管控能力;同时具备详细的观测、审计能力可以追溯;
统一:设定资源弹性化标准,需要弹性化的资源方只需做一些对接,即可自动化接入;
复用:公司内部已经有非常完备的监控、告警、调用链等系统,我们的弹性产品希望能够做良好的集成,把整个产品链起来;
▎2.2 选型
基于 kubernetes 的弹性开源方案并不太多,像原生的 HPA 或者 keda,本质都是利用了 hpa controller 对各种metrics server做轮询。
而又鉴于以下几点,我们觉得 kubernetes 已有的方案并不适合我们:
我们决定自己去实现一款弹性平台,吸收了现有方案的优势,择善而从,在包含了 hpa 能力的同时又增加了一些实用的功能,项目代号为“burrfish”。
本节主要介绍在平台开发中的一些设计理念和架构组件。
▎3.1 理念设计
对于弹性平台的设计:
首先得具备丰富的弹性功能,这是本职工作;
对于弹性资源的设计:
前文提到可以设置多副本、多worker、多成员的对象,其实都具备逻辑可弹性,一般实现来说,即使没有用 kubernetes 里原生的工作负载比如 deployment、statefulset,也会去构造“组”的概念,对组设置副本。而我们则做了个取(chou)巧(xiang),设计了弹性资源的概念,这样我在控制面上不需要关心你用什么去承载多副本,你在我这就是注册的一种弹性资源。
梳理完思路后,我们提出了一个分层构想:
▎3.2 架构设计
如下图所示,我们架构包括5个组件,guarder、trigger、scaler、hooker、tracer。其中:
guarder:守卫模块,职能包括:
保存弹性策略完整的伸缩配置;
根据触发器的不同类型,决定是否要到指标源进行必要注册;
trigger:触发器模块,他是一类可以扩展的组件。只要实现了逻辑语义“拿到一个指标,格式化发给后续组件”都可以认为是触发器,即使有业务逻辑比较重的触发规则,也可以归类到扩展层中。它的分类如下:
定时触发:基本需求;
k8s metrics server:主要就是一些开源的指标采集方式,可以无缝支持,但实际对我们来说不是很用得上;
云监控告警:绝大部分策略采用的触发方式。我们有完备的监控体系,他集成了系统负载(cpu/memory等)、消息中间件、rds、log日志、自定义业务指标等监控,它同时支持轮询(分钟级)、流式(秒级)告警,所以我们并不需要造太多的触发器轮子;
支持原生的 hpa controller 能力;
hooker:hooker设计的目的如下:
形成统一的方式扩缩容。因为不同的弹性资源,实现方式不同,副本设置逻辑也有差异,比如:
k8s scale resource:原生方式,面向一些比较新的云原生弹性资源;
http scale resource:调用弹性标准接口扩缩容,他主要面向了两类弹性资源:
传统服务包装成弹性资源,不方便改造为云原生方式;
做业务侧的扩缩容决策,不希望直接提交给原生的controller;
可以增加其他逻辑比如前后钩子等;
tracer:追踪器,是为了可观测、可审计单独设置的一个模块。我们在框架的几个关键部位进行埋点,就可以实现:
输出完整的副本变化指标;
输出关键的event事件;
这里说的是指整个集群的稳定性,因为在没有弹性伸缩的时候,业务一般都是维持了一个固定的副本数在运行,当用上弹性之后,副本是在动态变化的,这里面其实暴露了一些问题,比如:
资源不足:尤其是一些规格大的、规格比例不太友好的业务,缩了之后扩不出来;
对于这些,我们总的规划是“用不同的专项去解决,弹性伸缩专注在实现副本扩缩容”,这里列举以下几个主要方面和我们的应对措施,些许笔墨道不清其中逻辑,可以等待后续专题:
资源问题:智能调度;
本文为上篇,主要描述怎么实现一个弹性框架,因为我们的希望始终都是“功能上通用、设计上解耦”。在“下篇-运用实践”中,我们会通过不同场景的案例来描述弹性平台如何在 OPPO 内运用的。
Jia Zhu
OPPO高级后端工程师
负责OPPO云弹性伸缩的整体架构、云原生化的设计与开发。