• 如何使用DuckDB进行降本增效

    在前一篇公众号文章 《DuckDB 是什么及适用场景》中,原文链接为:https://mp.weixin.qq.com/s/v7yJhoJkZVKcho4PjoQEhw,我们介绍了 DuckDB 是什么及其适用场景,接下来就以一个实际的例子进行演示,验证一下 DuckDB 是不是真的很香。

    今天要探讨的这个例子就是如何使用 DuckDB 对云上的资源进行降本增效。既然要进行降本增效,那么我们就要用一定的方法论来指导我们的工作。

    01我们的方法论

    评估和优化云资源使用

    • 分析现有云资源的使用情况,包括实例类型、存储使用量、网络带宽等
    • 根据业务需求,评估并优化云资源的使用效率,避免资源浪费
    • 定期进行云资源审计,确保资源的合理分配和使用

    选择合适的云服务商和定价模型

    • 对比不同云服务商的性能、价格、服务质量等因素
    • 根据业务需求选择合适的定价模型,如按需付费、预留实例、节省计划等
    • 密切关注云服务商的优惠活动,合理利用优惠政策降低成本

    实施自动化和智能化管理

    • 使用自动化工具和技术,如自动化部署、监控和告警等,提高云资源管理的效率
    • 利用 AI 和机器学习技术,实现云资源的智能调度和优化
    • 自动化处理云资源的生命周期,包括创建、扩缩容、终止等

    精简应用架构和减少资源依赖

    • 评估现有应用架构的合理性,精简不必要的组件和服务
    • 减少对外部资源和服务的依赖,降低潜在的成本和风险
    • 优化应用性能,提高资源利用率

    推广云原生技术和容器化部署

    • 引入云原生技术和容器化部署方案,提高应用的可移植性和弹性
    • 利用容器编排工具,实现资源的自动分配和调度
    • 简化应用部署和运维流程,降低维护成本

    加强安全防护和风险管理

    • 建立健全的安全防护体系,保障云资源的安全性和稳定性
    • 定期进行安全漏洞扫描和风险评估,及时修复潜在的安全隐患
    • 加强员工的安全意识和培训,降低人为风险

    建立成本效益评估机制

    • 定期对云资源使用的成本效益进行评估
    • 分析成本结构,找出成本控制的关键点
    • 根据评估结果调整云资源管理策略,实现持续优化

    02以往是怎么做的

    接下来我们介绍一下之前是怎么做的。不写文字了,放一个思维导图吧:

    03现在是怎么做的

    接下来就以一种全新的方法来处理,思维导图如下:

    准备数据

    从 Grafana 的 Dashboard 上面下载监控数据,格式使用 CSV 及 JSON 都可以,我这里使用的是 CSV 格式。

    操作过程就省略了,下载完毕,我们的当前目录下面会有两个文件:

    ➜  降本增效 wc -l 20240627_cpu.csv 20240627_mem.csv 
         299 20240627_cpu.csv
         293 20240627_mem.csv
         592 total

    下载下来的 CSV 文件中有些字段是中文的,需要调整成为对应的英文,过程就省略了。

    主角登场

    既然原始数据有了,接下来就唤出我们的主角:DuckDB。创建一个名为 costsaving.db 的数据库,我们需要把数据保留一段时间(因为分析是需要时间的)。

    
    (venv311) ➜  降本增效 duckdb costsaving.db
    v1.0.0 1f98600c2c
    Enter ".help" for usage hints.
    -- 查看一下当前的数据库
    D .databases
    costsaving: costsaving.db
    
    -- 查看一下当前的表
    D .tables

    导入数据

    有了一个库之后,接下来我们就在这个库里面创建几张表:

    -- 查看一下本地的 CSV 文件里面的字段情况
    D DESCRIBE table './20240627_cpu.csv';
    ┌─────────────────────────────────────┬─────────────┬─────────┬─────────┬─────────┬─────────┐
    │             column_name             │ column_type │  null   │   key   │ default │  extra  │
    │               varchar               │   varchar   │ varchar │ varchar │ varchar │ varchar │
    ├─────────────────────────────────────┼─────────────┼─────────┼─────────┼─────────┼─────────┤
    │ Time                                │ TIMESTAMP   │ YES     │         │         │         │
    │ __name__                            │ VARCHAR     │ YES     │         │         │         │
    │ hostname                            │ VARCHAR     │ YES     │         │         │         │
    │ instance_id                         │ VARCHAR     │ YES     │         │         │         │
    │ ipgroup                             │ VARCHAR     │ YES     │         │         │         │
    │ zone_name                           │ VARCHAR     │ YES     │         │         │         │
    │ rmgroup_id                          │ VARCHAR     │ YES     │         │         │         │
    │ rmgroup_name                        │ VARCHAR     │ YES     │         │         │         │
    ......
    ......
    ......
    │ tag_name                            │ VARCHAR     │ YES     │         │         │         │
    │ percent                             │ VARCHAR     │ YES     │         │         │         │
    ├─────────────────────────────────────┴─────────────┴─────────┴─────────┴─────────┴─────────┤
    │ 21 rows                                                                         6 columns │
    └───────────────────────────────────────────────────────────────────────────────────────────┘
    
    D SELECT * from './20240627_cpu.csv';
    ┌──────────────────────┬──────────────────────┬──────────────────────┬───┬──────────────────────┬──────────────────────┬─────────┐
    │         Time         │       __name__       │       hostname       │ … │ tag_ccc_security_d…  │       tag_name       │ percent │
    │      timestamp       │       varchar        │       varchar        │   │       varchar        │       varchar        │ varchar │
    ├──────────────────────┼──────────────────────┼──────────────────────┼───┼──────────────────────┼──────────────────────┼─────────┤
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-xxxxxxxxxxxx-ac…  │ … │                      │                      │ 53.2%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-xxxxxxxxxxxx-ac…  │ … │                      │                      │ 37.6%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-cccccc-yyy-001-…  │ … │                      │                      │ 36.9%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-prod-xx-xxx-uip…  │ … │                      │                      │ 34.4%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-xxxxxxxxxxxx-ac…  │ … │                      │                      │ 34.2%   │
    │          ·           │          ·           │          ·           │ · │          ·           │          ·           │   ·     │
    │          ·           │          ·           │          ·           │ · │          ·           │          ·           │   ·     │
    │          ·           │          ·           │          ·           │ · │          ·           │          ·           │   ·     │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-staging-ddddddd…  │ … │                      │                      │ 0.212%  │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-qa-zzzzzz-002     │ … │                      │                      │ 0.196%  │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-qa-bbbb-manage-…  │ … │                      │                      │ 0.169%  │
    ├──────────────────────┴──────────────────────┴──────────────────────┴───┴──────────────────────┴──────────────────────┴─────────┤
    │ 298 rows (40 shown)                                                                                       21 columns (6 shown) │
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

    基础数据没有问题,接着我们就在 DuckDB 里面创建若干表,并把数据导入进来即可。操作如下:

    
    D SELECT COUNT(*) FROM './20240627_cpu.csv';
    ┌──────────────┐
    │ count_star() │
    │    int64     │
    ├──────────────┤
    │          298 │
    └──────────────┘

    确认非生产环境有多少台机器:

    
    D SELECT COUNT(*) FROM './20240627_cpu.csv' WHERE hostname NOT ILIKE '%prod%';
    ┌──────────────┐
    │ count_star() │
    │    int64     │
    ├──────────────┤
    │          178 │
    └──────────────┘

    确认生产环境有多少台机器:

    
    D SELECT COUNT(*) FROM './20240627_cpu.csv' WHERE hostname ILIKE '%prod%';
    ┌──────────────┐
    │ count_star() │
    │    int64     │
    ├──────────────┤
    │          120 │
    └──────────────┘

    非生产 178 + 生产 120 = 共 298 台,数量完全吻合,那么我们进行下一步。接着创建 4 张表:

    
    -- 分别创建测试及生产环境的 CPU 使用信息表
    D CREATE TABLE nonprod_cpu AS FROM './20240627_cpu.csv' WHERE hostname NOT ILIKE '%prod%';
    D CREATE TABLE prod_cpu AS FROM './20240627_cpu.csv' WHERE hostname ILIKE '%prod%';
    
    -- 分别创建测试及生产环境的 MEM 使用信息表
    D CREATE TABLE prod_mem AS FROM './20240627_mem.csv' WHERE hostname ILIKE '%prod%';
    D CREATE TABLE nonprod_mem AS FROM './20240627_mem.csv' WHERE hostname NOT ILIKE '%prod%';

    创建完成,验证一下:

    
    D .tables
    nonprod_cpu  nonprod_mem  prod_cpu     prod_mem

    验证数据

    验证一下数据是否正确:

    
    D FROM nonprod_cpu LIMIT 10;
    ┌──────────────────────┬──────────────────────┬──────────────────────┬───┬──────────────────────┬──────────────────────┬──────────┬─────────┐
    │         Time         │       __name__       │       hostname       │ … │ tag_ccc_security_c…  │ tag_ccc_security_d…  │ tag_name │ percent │
    │      timestamp       │       varchar        │       varchar        │   │       varchar        │       varchar        │ varchar  │ varchar │
    ├──────────────────────┼──────────────────────┼──────────────────────┼───┼──────────────────────┼──────────────────────┼──────────┼─────────┤
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-xxxxxxxxxxxx-ac…  │ … │                      │                      │          │ 53.2%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-xxxxxxxxxxxx-ac…  │ … │                      │                      │          │ 37.6%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-cccccc-yyy-001-…  │ … │                      │                      │          │ 36.9%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-xxxxxxxxxxxx-ac…  │ … │                      │                      │          │ 34.2%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-cccccc-yyy-001-…  │ … │                      │                      │          │ 31.6%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-xxxxxxxxxxxx-ac…  │ … │                      │                      │          │ 30.4%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-cccccc-yyy-001-…  │ … │                      │                      │          │ 25.2%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-qa-eeee-0002      │ … │                      │                      │          │ 24.7%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-cccccc-yyy-001-…  │ … │                      │                      │          │ 24.5%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-xxxxxxxxxxxx-ac…  │ … │                      │                      │          │ 22.9%   │
    ├──────────────────────┴──────────────────────┴──────────────────────┴───┴──────────────────────┴──────────────────────┴──────────┴─────────┤
    │ 10 rows                                                                                                              21 columns (7 shown) │
    └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
    
    D FROM prod_cpu LIMIT 10;
    ┌──────────────────────┬──────────────────────┬──────────────────────┬───┬──────────────────────┬──────────────────────┬──────────┬─────────┐
    │         Time         │       __name__       │       hostname       │ … │ tag_ccc_security_c…  │ tag_ccc_security_d…  │ tag_name │ percent │
    │      timestamp       │       varchar        │       varchar        │   │       varchar        │       varchar        │ varchar  │ varchar │
    ├──────────────────────┼──────────────────────┼──────────────────────┼───┼──────────────────────┼──────────────────────┼──────────┼─────────┤
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-prod-xx-xxx-uip…  │ … │                      │                      │          │ 34.4%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-prod-zzzzzz-Ent…  │ … │                      │                      │          │ 19.8%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-prod-zzzzzz-Ind…  │ … │                      │                      │          │ 17.9%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-prod-zzzzzz-Ind…  │ … │                      │                      │          │ 15.2%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-prod-zzzzzz-Ind…  │ … │                      │                      │          │ 14.9%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-prod-yyy001-wor…  │ … │                      │                      │          │ 12.9%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-prod-aaaaa-exp…   │ … │                      │                      │          │ 12.6%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-prod-zzzzzz-Sea…  │ … │                      │                      │          │ 12.1%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-prod-fff-server…  │ … │                      │                      │          │ 12.0%   │
    │ 2024-06-27 14:16:5…  │ AliyunEcs_CPUUtili…  │ yy-prod-ccccccc-se…  │ … │                      │                      │          │ 11.7%   │
    ├──────────────────────┴──────────────────────┴──────────────────────┴───┴──────────────────────┴──────────────────────┴──────────┴─────────┤
    │ 10 rows                                                                                                              21 columns (7 shown) │
    └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

    类型转换

    percent 字段是 varchar 类型的,我们需要把它转换成数字。

    D ALTER TABLE prod_cpu
          ALTER percent
          TYPE NUMERIC
          USING REPLACE(percent, '%', '')::NUMERIC(5,3);

    开始查询

    查看一下非生产环境的 CPU 低于 40% 使用率的 ECS,

    
    D SELECT hostname, instance_id, percent FROM nonprod_cpu WHERE percent < '40' ORDER BY hostname;
    ┌─────────────────────────────────────────────┬─────────────────────────┬───────────────┐
    │                  hostname                   │       instance_id       │    percent    │
    │                   varchar                   │         varchar         │ decimal(18,3) │
    ├─────────────────────────────────────────────┼─────────────────────────┼───────────────┤
    │ yy-staging-aaaaaaaa-bbbbbb-bff-server-01002 │ e-abc33abcdefghijklmno  │         0.314 │
    │ yy-qa-aaaaaaaa-big3-Server-0001             │ e-abcimabcdefghijklmno  │         2.590 │
    │ yy-qa-aaaaaaaa-bbbbbb-bff-server-0001       │ e-abc5babcdefghijklmno  │         1.710 │
    │ yy-staging-aaaaaaaa-big3-Server-01001       │ e-abc2rabcdefghijklmno  │         3.100 │
    │            ·                                │           ·             │           ·   │
    │            ·                                │           ·             │           ·   │
    │            ·                                │           ·             │           ·   │
    │ yy-staging-ddddddd-bastion-02               │ e-abc8zyxwvuabcdefghij  │         0.715 │
    │ yy-staging-aaa-bbbbbbbbbb-01                │ e-abc9zyxwvuabcdefghij  │         0.250 │
    ├─────────────────────────────────────────────┴─────────────────────────┴───────────────┤
    │ 177 rows (40 shown)                                                         3 columns │
    └───────────────────────────────────────────────────────────────────────────────────────┘

    查看生产环境的 CPU 低于 30% 使用率的 ECS:

    cent FROM prod_cpu WHERE percent < '30' ORDER BY hostname;
    ┌──────────────────────────────────────────────────────────┬────────────────────────┬───────────────┐
    │                         hostname                         │      instance_id       │    percent    │
    │                         varchar                          │        varchar         │ decimal(18,3) │
    ├──────────────────────────────────────────────────────────┼────────────────────────┼───────────────┤
    │ yy-Prod-aaaaaaaa-big3-Server-001                         │ e-abccabcdefghijklmnop │         8.310 │
    │ yy-Prod-aaaaaaaa-big3-Server-002                         │ e-abc8abcdefghijklmnop │         4.750 │
    │ yy-Prod-aaaaaaaa-bbbbbb-bff-server-001                   │ e-abc0abcdefghijklmnop │         6.980 │
    │ yy-Prod-aaaaaaaa-bbbbbb-bff-server-002                   │ e-abcaabcdefghijklmnop │         3.830 │
    │                ·                                         │           ·            │           ·   │
    │                ·                                         │           ·            │           ·   │
    │                ·                                         │           ·            │           ·   │
    │ yy-prod-awesome-yyyyyyyy-WAS-0001                        │ e-abcqrstuvwxyzabcdefg │         2.200 │
    │ yy-prod-awesome-yyyyyyyy-WAS-0002                        │ e-abcqrstuvwxyzabcdefg │         2.260 │
    ├──────────────────────────────────────────────────────────┴────────────────────────┴───────────────┤
    │ 119 rows (40 shown)                                                                     3 columns │
    └───────────────────────────────────────────────────────────────────────────────────────────────────┘

    单独查看 CPU 及 MEM 的意义不大,因此我们要进行关联查询,找出 MEM 及 CPU 都小于 40% 的实例。接下来我们就使用一个简单的关联查询。

    关联查询

    D SELECT
        c.hostname,
        c.percent AS cpu_percent,
        m.percent AS mem_percent
    FROM
        nonprod_cpu c
        LEFT JOIN nonprod_mem m ON c.hostname = m.hostname
    WHERE
        c."percent" < 40
        AND m."percent" < 40
    ORDER BY
        c.hostname;
    ┌─────────────────────────────────────────────┬───────────────┬───────────────┐
    │                  hostname                   │  cpu_percent  │  mem_percent  │
    │                   varchar                   │ decimal(18,3) │ decimal(18,3) │
    ├─────────────────────────────────────────────┼───────────────┼───────────────┤
    │ yy-staging-aaaaaaaa-bbbbbb-bff-server-01002 │         0.314 │        10.100 │
    │ yy-qa-aaaaaaaa-bbbbbb-bff-server-0001       │         1.710 │        28.000 │
    │             ·                               │           ·   │           ·   │
    │             ·                               │           ·   │           ·   │
    │             ·                               │           ·   │           ·   │
    │ yy-staging-ddddddd-bastion-02               │         0.715 │        22.500 │
    │ yy-staging-awesome-yyyyyy-01                │         0.250 │         4.810 │
    ├─────────────────────────────────────────────┴───────────────┴───────────────┤
    │ 84 rows (40 shown)                                                3 columns │
    └─────────────────────────────────────────────────────────────────────────────┘
    
    -- 或者 ORDER BY 1
    D SELECT
        c.hostname,
        c.percent AS cpu_percent,
        m.percent AS mem_percent
    FROM
        nonprod_cpu c
        LEFT JOIN nonprod_mem m ON c.hostname = m.hostname
    WHERE
        c."percent" < 40
        AND m."percent" < 40
    ORDER BY 1;

    最终结果

    跳板机不做降本处理,因此,我们需要把跳板机的机器排除掉:

    SELECT
        c.hostname,
        c.instance_id,
        c.percent AS cpu_percent,
        m.percent AS mem_percent,
        c.tag_application_name as bff_name
    FROM
        nonprod_cpu c
        LEFT JOIN nonprod_mem m ON c.hostname = m.hostname
    WHERE
        c. "percent" < 40
        AND m. "percent" < 40
        AND bff_name NOT NULL
        AND bff_name <> 'bastion'
    ORDER BY
        bff_name;
    +--------------------------------------------------+------------------------+-------------+-------------+---------------------------------+
    |                     hostname                     |      instance_id       | cpu_percent | mem_percent |            bff_name             |
    +--------------------------------------------------+------------------------+-------------+-------------+---------------------------------+
    | yy-qa-bbbbbbbbbb-aaaaa-aaaaaaaaaaaaa-vvv-v2-0001 | e-abcabdefghxyzopcbacd | 0.877       | 19.100      | Awesome Project XX              |
    | yy-staging-ddddddd-00099                         | e-abcabdefghxyzopcbacd | 0.212       | 4.970       | Awesome xx                      |
    | yy-staging-ddddddd-00100                         | e-abcabdefghxyzopcbacd | 1.700       | 19.400      | Awesome YY                      |
    ......
    ......
    ......
    | yy-staging-awesome-xxxxxxxx-001                  | e-abcopqrstuvwxyzabc12 | 3.830       | 28.100      | Awesome YYYYYYYY                |
    | yy-staging-awesome1-images-001                   | e-abcopqrstuvwxyzabc12 | 1.190       | 26.900      | Awesome YYYYYYYY                |
    | yy-staging-awesome-xxxxxxxx-002                  | e-abcopqrstuvwxyzabc12 | 1.980       | 25.900      | Awesome YYYYYYYY                |
    | yy-qa-awesome-win-01                             | e-abcopqrstuvwxyzabc12 | 1.200       | 22.600      | awesome XX                      |
    | yy-qa-awesome-client-02                          | e-abcopqrstuvwxyzabc12 | 4.730       | 36.100      | awesome XX                      |
    +--------------------------------------------------+------------------------+-------------+-------------+---------------------------------+

    现在数据已经梳理完成,接下来就可以按照业务组(以应用名进行分组)分批进行降本了。

    [!TIP] 如果要使用 Excel 进行上述分析,大概需要多久呢?是否可以做到两个或多个 Sheet 的关联呢?

    各个击破

    那么接下来的任务就是按应用为维度进行各个击破:

    1. 发邮件给相关的 PM 进行沟通及获取审批
    2. 审批之后,DevOps 团队开始对资源进行降本
    3. 测试环境可以随时进行,生产环境需要排期进行

    好的,现在就去发邮件。因为模板都具有通用性,因此每个业务都可以复用。那么我们的邮件模板如下:

    MAIL_TITLE: 申请测试环境 {BUSINESS_NAME} 业务的 ECS 降配
    
    Hi {PM_NAME},
    
    近期 DevOps 团队监控到 {BUSSINESS_NAME} 业务的 ECS 在最近 7 天的使用率
    比较低(CPU 及 MEM 均低于 40%)。因此,根据降本增效原则申请降配,以实现
    更为高效的资源利用和更为经济的运行方式。
    
    涉及到的降配资源信息如下:
    
    {RESOURCE_LIST}
    
    因此,申请上述资源的降配,由原来的规格进行减半。如果后续需要进行压测,
    届时再按要求进行资源的升配。还请审批,谢谢。
    
    如有任何问题还请及时沟通,再次感谢。

    有了邮件模板后,接下来的问题就是如何把相关的数据渲染到模板中。方法有很多,我这里使用了 BASH 脚本来生成邮件模板。脚本如下:

    
    #!/bin/bash
    
    declare -A PM_PROJECT_MAPPING_LIST
    
    PM_PROJECT_MAPPING_LIST=(
        ["Lebron_James"]="Awesome Project XXXXX" 
        ["Dwyane_Wade"]="Awesome Project AAAAA" 
        ["Chris_Bosh"]="Awesome Project CCCCC"
    )
    
    for PM in "${!PM_PROJECT_MAPPING_LIST[@]}"; do
        echo "MAIL_TITLE: 申请测试环境 ${PM_PROJECT_MAPPING_LIST[$PM]} 业务的 ECS 降配"
        echo
        echo "Hi `echo "${PM}" |cut -d'_' -f1`,"
        echo
        echo "近期 DevOps 团队监控到「${PM_PROJECT_MAPPING_LIST[$PM]}」业务的 ECS 在最近 7 天的使用率"
        echo 
        echo "比较低(**CPU及 MEM 均低于 40%**)。因此,根据降本增效原则申请降配,以实现"
        echo 
        echo "更为高效的资源利用和更为经济的运行方式。"
        echo
        echo "涉及到的降配资源信息如下:"
        echo
        duckdb -markdown -s "SELECT c.hostname, c.instance_id, c.percent AS cpu_percent, m.percent AS mem_percent, c.tag_application_name as app_name FROM nonprod_cpu c LEFT JOIN nonprod_mem m ON c.hostname = m.hostname WHERE c."percent" < 40 AND m."percent" < 40 AND app_name='${PM_PROJECT_MAPPING_LIST[$PM]}' AND app_name <> 'bastion' ORDER BY app_name;" costsaving.db
        echo
        echo "因此,**申请上述资源的降配,由原来的规格进行减半**。如果后续需要进行压测,"
        echo
        echo "届时再按要求进行资源的升配。还请审批,谢谢。"
        echo
        echo "如有任何问题还请及时沟通,再次感谢。"
        echo
        echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
        echo
    done

    执行结果如下:

    
    [root@mymssql01 ~]# sh generate_email.sh
    MAIL_TITLE: 申请测试环境 Awesome Project XXXXX 业务的 ECS 降配
    
    Hi Lebron,
    
    近期 DevOps 团队监控到「Awesome Project XXXXX」业务的 ECS 在最近 7 天的使用率
    
    比较低(**CPU及 MEM 均低于 40%**)。因此,根据降本增效原则申请降配,以实现
    
    更为高效的资源利用和更为经济的运行方式。
    
    涉及到的降配资源信息如下:
    
    |             hostname              |      instance_id       | cpu_percent | mem_percent | app_name              |
    |-----------------------------------|------------------------|------------:|------------:|-----------------------|
    | yy-qa-aaaaaa-bbbbbbb-web-001      | e-aaaabcdefghijklmnopq | 2.400       | 30.300      | Awesome Project XXXXX |
    | yy-qa-aaaaaa-bbbbbbb-web-002      | e-aaaabcdefghijklmnopq | 2.330       | 29.800      | Awesome Project XXXXX |
    | yy-staging-aaaaaa-bbbbbbb-web-001 | e-aaaabcdefghijklmnopq | 2.750       | 24.100      | Awesome Project XXXXX |
    | yy-staging-aaaaaa-bbbbbbb-web-002 | e-aaaabcdefghijklmnopq | 1.010       | 13.300      | Awesome Project XXXXX |
    
    因此,**申请上述资源的降配,由原来的规格进行减半**。如果后续需要进行压测,
    
    届时再按要求进行资源的升配。还请审批,谢谢。
    
    如有任何问题还请及时沟通,再次感谢。
    
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    生成的邮件模板是 Markdown 格式,因此,那么剩下的工作就是用鼠标粘贴复制到邮件中了。粘贴到邮件中的效果如下:

    如果连鼠标也不想用,可以在脚本里面发邮件;如果连脚本都不想执行,是不是可以集成到一个平台上呢?方法及思路有很多。

    04总结

    从有了想法开始到实现以及整个文档的初步编写,整个过程花了半天时间。所以,新的分析方式的效率是非常高的,这多亏了 DuckDB。但 DuckDB 所能提供的远不止这些,后续关于 DuckDB 更多有趣及好玩的场景,我们再做分享,谢谢大家。

    如有相关问题,请在文章后面给小编留言,小编安排作者第一时间和您联系,为您答疑解惑。

    «
    »
以专业成就每一位客户,让企业IT只为效果和安全买单

以专业成就每一位客户,让企业IT只为效果和安全买单