发布于: Jun 20, 2022
根据亚马逊云科技最佳实践,当推出新的 EC2 实例机型后,建议升级到最新的可用机型。原因有二:其一,新机型计算、存储和网络传输等性能提升;其二,单位时间实例使用成本降低。少量实例机型升级并不难,然而当实例数量较多、实例关系较复杂时,要规划可行、低成本的实例升级,手工操作的耗时和难度会显著增加。本文聚焦如何有效应对大规模实例机型升级。有效机型升级具体体现有三。成本优化:在新机型成本降低的基础上,充分考虑预留实例期限限制,最大化预留实例收益;兼顾实例关系:全面兼顾实例间复杂的关联与依赖关系,如主从数据库对,负载均衡器组等,把实例升级对系统整体运行的影响降至最低,使其平稳过渡;照顾现实约束:实际生产过程中实例有轻重缓急之别,升级过程中有各种限制,例如工作日节假日的安排,日处理或停机实例上限等等。上述要点无形中增加了规划实例机型升级的困难与复杂度,使得手工规划耗时费力。本文利用轻量的类结构化查询语言和亚马逊云科技无服务器解决方案,实现一套崭新和通用的规划实例机型升级架构,以达到两个目的。一是把手工需要数小时的规划操作大幅减少到数秒完成;二是根据预留期限和其他约束条件规划升级以尽量降低成本。
本文预期读者需要掌握以下技术的基础知识:
- 亚马逊云科技相关服务,包括 EC2 实例,S3, Lambda, DynamoDB 等;
- Javascript 语言及亚马逊云科技软件开发包第二版;
- 类结构化查询语言 PartiQL。
本文所述解决方案源代码开放并置于以下代码库:
亚马逊云科技实例机型总是不断更新换代,目前最新一代是第六代。从机型代码可以识别,例如通用类型 m6g.large。相应的前代机型为 m5.large, m4.large, m3.large 等。实例机型升级,通常意味着性价比提升。单一实例机型升级过程并不复杂,在完成相应驱动安装并打开增强网络支持后,借助相关命令可以轻松完成,例如:
aws ec2 modify-instance-attribute --instance-id $INSTANCE_ID --instance-type $NEW_TYPE Bash
当实例数量变庞大时,各种各样的考虑因素接踵而至。例如,各实例轻重缓急不同,复杂的实例间关联关系,预留实例到期期限不一等。综合上述各种因素,如何快速、有效、低成本的规划实例升级顺序是本文着重解决的问题。
问题定义为:给定一定数量的实例及其属性,实例间关联关系,以及规划约束条件,规划实例升级顺序。其中实例属性包括实例类别、机型、可用区、预留期限、所属应用等。本文抽象出两种实例间关联关系,主从数据库对关系和负载均衡器组关系。规划约束条件作为输入,包括开始日期,每日处理数量上限,按需实例排序依据,节假日以及处理星期等。
实例升级规划结果是以日为单位的实例升级顺序表。该表并不是最终结果。相反,用户可以该表为基础,根据实际情况,进一步微调和优化实例升级顺序。本文的工作旨在解决实例升级规划伊始最繁杂的部分。用户通过调整规划约束条件,亦可快速生成其他约束条件下的实例升级规划表,以便参考比较。
以日为最小单位规划批次。通常情况下,实例可以大致分为两个类别,即生产实例和非生产实例。生产实例处理起来需更加谨慎,例如放到非工作日处理。从降低成本的角度考虑,部分实例会购买预留实例。预留期限通常是一年。要节约开销,在预留到期日附近升级实例较好。此外从稳定性角度考虑,需要对关联实例做特殊处理。例如从库可以先升级,而负载均衡器不同组的实例要错开等。本文抽象了两种常见的关联关系。
- 主从数据库对:从库应该提前升级,因为不影响系统运行。平稳运行一段时间之后做一次主从数据库切换,然后对原来的主库升级。这样可以把对系统的影响降至最低。
- 负载均衡器组:负载均衡器分发实例按所在可用区分组。本文假定负载均衡器只有两个组。不同组实例应置于不同批次内,且前组实例全部升级完成后,再升级后组实例。亦即甲组的升级日期与乙组升级日期不相交,确保系统平稳过渡。具体来说,假设日期 A ⩽ B ⩽ C ⩽ D,甲组实例在首轮规划中升级日期在 A 与 C 之间,乙组在 B 与 D 之间,如下图所示。此时需要将乙组规划在 B 与 C 之间的实例推后到 C 之后升级,确保甲乙两组升级日期不重叠。
下表总结了通常情况下实例升级规划的约束条件。大部分条件都不言自明。其中按需实例规划策略有两种(预留实例基本上以预留期限排序):
- 按应用:把相同应用的实例排列在一起,减少单次升级涉及应用数量,便于安排和协调停机。
- 按机型:按实例机型贵贱排序,先升级昂贵机型,后升级便宜机型,可以有效减低成本。
变量 |
类型 |
默认值 |
开发实例可排星期 |
枚举
|
工作日,如 1, 2, 3, 4, 5 |
生产实例可排星期 |
周日,如 0 |
|
开发实例日处理上限 |
整数
|
10 |
生产实例日处理上限 |
50 |
|
开始日期 |
日期 |
无 |
节假日 |
日期数组 |
需要避开的日期组 |
按需实例排序策略 |
枚举 |
按应用/按机型 |
{ "startDate": "2021-03-01", "sortBy": "app/type", "holidays": [ "2021-04-03", "2021-04-04", "2021-04-05"], "devAllowedDays": [1, 2, 3, 4, 5], "prodAllowedDays": [0], "devDailyLimit": 10, "prodDailyLimit": 50 } JSON
class Instance { static mapType(type) { const subtype = type.substring(3); const result = /([0-9]+)xlarge/.exec(subtype); if (result != null) { return parseInt(result[1]) + 10; } switch (subtype) { case "nano": return 1; case "micro": return 2; case "small": return 3; case "medium": return 4; case "large": return 5; case "xlarge": return 6; case "metal": return 100; } } static compareType(a, b) { return Instance.mapType(a) - Instance.mapType(b); }} JavaScript
相关文章