12、构建安全且经济高效的 AWS Lambda 应用

构建安全且经济高效的 AWS Lambda 应用

1. 加密环境变量

在 AWS Lambda 中,环境变量可以在不更改代码的情况下,动态地将数据传递给函数代码。根据十二要素应用方法,应将配置与代码分离,以避免将敏感凭证提交到代码仓库,并能使用相同的源代码定义 Lambda 函数的多个版本(如开发、生产和沙盒环境)。此外,环境变量还可用于基于不同设置更改函数行为,例如 A/B 测试。如果需要在多个 Lambda 函数之间共享机密信息,可以使用 AWS 的系统管理器参数存储。

以下是一个使用环境变量传递 MySQL 凭证到函数代码的示例:

func handler() error {
  MYSQL_USERNAME := os.Getenv("MYSQL_USERNAME")
  MYSQL_PASSWORD := os.Getenv("MYSQL_PASSWORD")
  MYSQL_DATABASE := os.Getenv("MYSQL_DATABASE")
  MYSQL_PORT := os.Getenv("MYSQL_PORT")
  MYSQL_HOST := os.Getenv("MYSQL_HOST")
  uri := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", MYSQL_USERNAME, MYSQL_PASSWORD, MYSQL_HOST, 
MYSQL_PORT, MYSQL_DATABASE)
  db, err := sql.Open("mysql", uri)
  if err != nil {
    return err
  }
  defer db.Close()
  _, err = db.Query(`CREATE TABLE IF NOT EXISTS movies(id INT PRIMARY KEY AUTO_INCREMENT, 
name VARCHAR(50) NOT NULL)`)
  if err != nil {
    return err
  }
  for _, movie := range []string{"Iron Man", "Thor", "Avengers", "Wonder Woman"} {
    _, err := db.Query("INSERT INTO movies(name) VALUES(?)", movie)
    if err != nil {
      return err
    }
  }
  movies, err := db.Query("SELECT id, name FROM movies")
  if err != nil {
    return err
  }
  for movies.Next() {
    var name string
    var id int
    err = movies.Scan(&id, &name)
    if err != nil {
      return err
    }
    log.Printf("ID=%d\tName=%s\n", id, name)
  }
  return nil
}

将函数部署到 AWS Lambda 并设置环境变量后,即可调用该函数,它将输出插入到数据库中的电影列表。但需要注意的是,数据库凭证是以明文形式存在的。幸运的是,AWS Lambda 使用 AWS 密钥管理服务(KMS)提供了传输中和静止时的两级加密。

1.1 静止数据加密

AWS Lambda 在部署函数时会对所有环境变量进行加密,并在函数调用时(即时)进行解密。默认情况下,AWS Lambda 使用默认的 Lambda 服务密钥对静止的环境变量进行加密,该密钥会在首次在特定区域创建 Lambda 函数时自动创建。

若要更改密钥并使用自己的密钥,可按以下步骤操作:
1. 导航到身份和访问管理控制台。
2. 点击“加密密钥”。
3. 点击“创建密钥”按钮创建新的客户主密钥(CMK)。
4. 选择一个 IAM 角色和账户,通过密钥管理服务(KMS)API 来管理该密钥,并选择创建 Lambda 函数时使用的 IAM 角色,以便 Lambda 函数能够使用该 CMK 并成功请求加密和解密方法。
5. 密钥创建完成后,返回 Lambda 函数配置页面,将密钥更改为刚创建的密钥。

此时,AWS Lambda 在将环境变量存储在 Amazon 时,将使用你自己的密钥对其进行静止加密。

1.2 传输数据加密

建议在部署函数之前对环境变量(敏感信息)进行加密。AWS Lambda 在控制台提供了加密助手,使此过程易于操作。

若要进行传输加密(使用前面提到的 KMS),可按以下步骤操作:
1. 勾选“启用传输加密助手”复选框。
2. 点击相应的“加密”按钮,对 MYSQL_USERNAME MYSQL_PASSWORD 进行加密。加密后的凭证将以密文形式显示在控制台中。
3. 更新函数的处理程序,使用 KMS SDK 对环境变量进行解密:

var encryptedMysqlUsername string = os.Getenv("MYSQL_USERNAME")
var encryptedMysqlPassword string = os.Getenv("MYSQL_PASSWORD")
var mysqlDatabase string = os.Getenv("MYSQL_DATABASE")
var mysqlPort string = os.Getenv("MYSQL_PORT")
var mysqlHost string = os.Getenv("MYSQL_HOST")
var decryptedMysqlUsername, decryptedMysqlPassword string
func decrypt(encrypted string) (string, error) {
  kmsClient := kms.New(session.New())
  decodedBytes, err := base64.StdEncoding.DecodeString(encrypted)
  if err != nil {
    return "", err
  }
  input := &kms.DecryptInput{
    CiphertextBlob: decodedBytes,
  }
  response, err := kmsClient.Decrypt(input)
  if err != nil {
    return "", err
  }
  return string(response.Plaintext[:]), nil
}
func init() {
  decryptedMysqlUsername, _ = decrypt(encryptedMysqlUsername)
  decryptedMysqlPassword, _ = decrypt(encryptedMysqlPassword)
}
func handler() error {
  uri := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", decryptedMysqlUsername, decryptedMysqlPassword, 
mysqlHost, mysqlPort, mysqlDatabase)
  db, err := sql.Open("mysql", uri)
  if err != nil {
    return err
  }
  ...
}

若使用了自己的 KMS 密钥,需要为附加到 Lambda 函数的执行角色(IAM 角色)授予 kms:Decrypt 权限,并适当增加默认执行超时时间,以确保函数代码有足够的时间完成执行。

2. 使用 CloudTrail 记录 AWS Lambda API 调用

捕获 Lambda 函数进行的所有调用对于审计、安全和合规性至关重要,它能让你全面了解 Lambda 函数与哪些 AWS 服务进行了交互。CloudTrail 就是利用这一特性的服务之一。

CloudTrail 会记录 Lambda 函数进行的 API 调用,使用起来简单直接。具体操作如下:
1. 从 AWS 管理控制台导航到 CloudTrail。
2. 按事件源过滤事件,事件源应为 lambda.amazonaws.com

在那里,你将看到每个 Lambda 函数进行的所有调用。除了展示事件历史记录,还可以在每个 AWS 区域创建一个跟踪,将 Lambda 函数的事件记录到单个 S3 存储桶中,然后使用 ELK(Elasticsearch、Logstash 和 Kibana)堆栈实现日志分析管道来处理日志。最后,还可以在 Kibana 中创建交互式和动态小部件,构建仪表板以查看 Lambda 函数事件。

3. 依赖项的漏洞扫描

由于大多数 Lambda 函数代码包含多个第三方 Go 依赖项,因此对这些依赖项进行审计非常重要。对 Golang 依赖项进行漏洞扫描应成为 CI/CD 的一部分,必须使用第三方工具(如 Snyk)自动进行安全分析,以持续扫描依赖项中已知的安全漏洞。

通过将漏洞扫描纳入工作流程,可以发现并修复包中可能导致数据丢失、服务中断和未经授权访问敏感信息的已知漏洞。此外,应用程序的最佳实践在无服务器架构中仍然适用,例如代码审查、使用 Git 分支以及进行输入验证或清理以避免 SQL 注入等安全检查。

4. AWS Lambda 定价模型

AWS Lambda 改变了运维团队配置和管理组织基础设施的方式,客户现在可以运行代码而无需担心底层基础设施,并且成本较低。每月前 100 万个请求是免费的,之后每 100 万个请求收费 0.20 美元,因此你可以无限期使用 Lambda 的免费层。但如果使用强度较大或处理大量工作负载的应用程序,若不特别关注函数的资源使用和代码优化,可能会产生不必要的高额费用。

Lambda 函数的成本由以下三个因素决定:
| 因素 | 说明 |
| ---- | ---- |
| 执行次数 | 调用次数,每次请求收费 0.0000002 美元。 |
| 分配内存 | 为函数分配的 RAM 量,范围在 128 MB 到 3,008 MB 之间。 |
| 执行时间 | 从代码开始执行到返回响应或终止的持续时间,时间将四舍五入到最接近的 100 毫秒(Lambda 按 100 毫秒增量计费),最大超时时间可设置为 5 分钟。 |
| 数据传输 | 如果 Lambda 函数发起外部数据传输,将按 EC2 数据传输费率收费。 |

4.1 Lambda 成本计算示例

假设为 FindAllMovies 函数分配了 128 MB 的内存,并将执行超时时间设置为 3 秒,该函数每秒执行 10 次(每月 2500 万次),则费用计算如下:
- 每月计算费用 :每月计算价格为每 GB/秒 0.00001667 美元,免费层提供 400,000 GB/秒。
- 总计算时间(秒) = 2500 万 * 1 秒 = 25,000,000 秒。
- 总计算量(GB/秒) = 25,000,000 * 128 MB / 1,024 = 3,125,000 GB/秒。
- 每月应计费计算量(GB/秒) = 总计算量 - 免费层计算量 = 3,125,000 GB/秒 - 400,000 免费层 GB/秒 = 2,725,000 GB/秒。
- 每月计算费用 = 2,725,000 GB/秒 * 0.00001667 美元 = 45.42 美元。
- 每月请求费用 :每月请求价格为每 100 万个请求 0.20 美元,免费层每月提供 100 万个请求。
- 每月应计费请求数 = 总请求数 - 免费层请求数 = 2500 万请求 - 100 万免费层请求 = 2400 万每月应计费请求。
- 每月请求费用 = 2400 万 * 0.2 美元/百万 = 4.8 美元。

因此,每月总费用 = 计算费用 + 请求费用 = 45.42 美元 + 4.8 美元 = 50.04 美元。

5. 最佳内存大小选择

如前文所述,分配的 RAM 量会影响计费,同时也会影响函数获得的 CPU 和网络带宽。因此,需要选择最佳的内存大小。为了找到函数价格和性能的最佳平衡点,必须使用不同的内存设置测试 Lambda 函数,并分析函数实际使用的内存。

AWS Lambda 会在关联的日志组中写入日志条目,其中包含每个请求分配和使用的内存量。通过比较“内存大小”和“最大使用内存”字段,可以确定函数是否需要更多内存,或者是否过度配置了函数的内存大小。如果函数需要更多内存,可以在“基本设置”部分增加内存,点击“保存”后再次调用函数,会发现内存大小会影响执行时间。

增加函数的内存设置可以显著提高性能,但成本也会随着内存设置的增加而线性增加。同样,减少函数的内存设置可能有助于降低成本,但会增加执行时间,在最坏的情况下,可能会导致超时或内存不足错误。为 Lambda 函数配置最小的内存设置并不总是能提供最低的总成本,因为函数可能会因内存不足而失败或超时,执行时间也可能会更长,从而导致支付更多费用。

6. 代码优化

在优化资源使用之前,应先优化函数代码,以减少函数执行所需的内存和 CPU 资源。与传统应用程序不同,AWS Lambda 会为你管理和修补基础设施,使开发人员能够专注于编写高质量、高效且执行速度快的代码。

在设计具有成本效益的 AWS Lambda 函数时,可参考以下几点:
- 利用热容器 :对于某些请求,可以使用热容器。可以通过以下方式提高 Lambda 函数的性能:
- 使用全局变量和单例模式,避免每次调用时重新初始化变量。
- 保持并重用之前调用期间建立的数据库和 HTTP 连接。在 Go 语言中,可以使用 init 函数设置所需的状态,并在加载函数处理程序时运行一次性计算。
- 设计异步架构 :解耦的组件完成工作所需的计算时间可能比紧密耦合的组件少,同时避免在等待同步请求响应时浪费 CPU 周期。
- 使用监控和调试工具 :如 AWS X-Ray,用于分析和排查影响 Lambda 应用程序性能的瓶颈、延迟峰值和其他问题。
- 设置限制 :使用并发预留设置限制,防止无限制的自动扩展和冷启动,并保护下游服务。还可以在 Lambda 触发器和函数之间放置简单队列服务(SQS),调整 Lambda 函数的触发频率,从而限制执行次数。

7. Lambda 成本和内存跟踪

设计具有成本效益的 AWS Lambda 无服务器应用程序的关键在于监控成本和资源使用情况。遗憾的是,CloudWatch 并未直接提供有关资源使用或 Lambda 函数成本的指标。不过,每次执行时,Lambda 函数会将执行日志写入 CloudWatch,示例如下:

REPORT RequestId: 147e72f8-5143-11e8-bba3-b5140c3dea53 Duration: 12.00 ms Billed Duration: 
100 ms  Memory Size: 128 MB Max Memory Used: 21 MB 

该日志显示了特定请求分配和使用的内存量,可以使用简单的 CloudWatch 日志指标过滤器提取这些值。具体操作步骤如下:
1. 打开 AWS CloudWatch 控制台,从导航窗格中选择“日志组”。
2. 搜索与 Lambda 函数关联的日志组,其名称应为 /aws/lambda/FUNCTION_NAME
3. 点击“创建指标过滤器”按钮。
4. 定义一个解析以空格分隔的术语的指标过滤器模式,该模式需指定字段名称,用逗号分隔,整个模式用方括号括起来,例如 [a,b,c] 。点击“测试模式”,测试过滤器模式对日志中现有数据的过滤结果。
5. 如果不知道字段数量,可以使用方括号括起来的省略号。
6. 第 13 列将存储分配给函数的内存,第 18 列表示实际使用的内存。点击“分配指标”,为分配的内存创建一个指标,然后点击“创建过滤器”保存。
7. 重复上述步骤,为内存使用情况创建另一个过滤器。
8. 定义好两个过滤器后,确保 Lambda 函数正在运行,等待几秒钟,让函数为新的 CloudWatch 指标填充一些值。
9. 返回 CloudWatch,基于之前创建的两个指标创建一个新图表。

还可以进一步创建近乎实时的 CloudWatch 警报,当使用的内存超过一定阈值(例如分配内存的 80%)时触发。此外,密切关注函数的执行时间也很重要,可以按照上述步骤从 Lambda 执行日志中提取计费持续时间,并根据提取的值设置警报,以便在函数执行时间过长时收到通知。

综上所述,使用 AWS Lambda 入门很容易,无需配置和管理底层基础设施,且能在短时间内以低成本让应用程序运行起来。与 EC2 相比,AWS Lambda 的一大优势是无需为闲置资源付费,但这也是 Lambda 的一大风险。在开发过程中很容易忽略成本问题,但在生产环境中运行大量工作负载和多个函数时,成本可能会变得很高。因此,在问题出现之前,密切跟踪 Lambda 的成本和使用情况非常重要。

8. 总结与展望

在构建基于 AWS Lambda 的无服务器应用时,安全性和成本效益是两个至关重要的方面。通过前面的介绍,我们了解了一系列保障安全和优化成本的方法。

8.1 安全保障总结

  • 加密环境变量 :利用 AWS KMS 对环境变量进行传输中和静止时的加密,保护敏感信息不被泄露。在静止数据加密中,可使用默认的 Lambda 服务密钥或自定义的客户主密钥;在传输数据加密时,借助 AWS Lambda 控制台的加密助手,结合 KMS SDK 实现加密和解密操作。
  • 日志记录与分析 :使用 CloudTrail 记录 Lambda 函数的 API 调用,有助于审计、安全和合规性检查。还可结合 ELK 堆栈进行日志分析,在 Kibana 中创建仪表板查看函数事件。
  • 依赖项漏洞扫描 :将对 Golang 依赖项的漏洞扫描纳入 CI/CD 流程,使用第三方工具(如 Snyk)持续检测依赖项中的安全漏洞,避免潜在的安全风险。

8.2 成本优化总结

  • 定价模型理解 :明确 Lambda 函数成本由执行次数、分配内存、执行时间和数据传输四个因素决定,通过合理规划这些因素来控制成本。
  • 最佳内存选择 :通过测试不同内存设置,分析函数实际内存使用情况,找到价格和性能的最佳平衡点。避免过度配置或配置不足的内存,以免影响成本和性能。
  • 代码优化 :采用利用热容器、设计异步架构、使用监控和调试工具、设置限制等方法优化代码,减少资源消耗,提高执行效率。
  • 成本和内存跟踪 :通过 CloudWatch 日志指标过滤器提取 Lambda 函数的内存分配和使用情况,创建图表和警报,实时监控成本和资源使用,及时发现并解决问题。

8.3 未来展望

接下来,我们可以引入基础设施即代码(IaC)的概念,实现 N 层无服务器应用的自动化设计和部署。IaC 可以将基础设施的配置和部署过程以代码的形式进行管理,避免人为错误和重复劳动,提高部署的一致性和可靠性。以下是一个简单的 mermaid 流程图,展示了 IaC 在无服务器应用部署中的基本流程:

graph LR
    A[编写 IaC 代码] --> B[代码审查]
    B --> C[部署到测试环境]
    C --> D{测试是否通过?}
    D -- 是 --> E[部署到生产环境]
    D -- 否 --> F[修改 IaC 代码]
    F --> B

通过 IaC,我们可以将无服务器应用的部署过程标准化和自动化,进一步提高开发和运维效率,降低成本。同时,结合前面介绍的安全和成本优化方法,构建更加安全、高效、经济的无服务器应用。

总之,在使用 AWS Lambda 构建无服务器应用时,我们要始终关注安全和成本问题,不断优化和改进,以适应不断变化的业务需求和技术环境。通过合理运用各种工具和方法,我们可以充分发挥 AWS Lambda 的优势,实现无服务器应用的成功部署和运行。

基于径向基函数神经网络RBFNN的自适应滑模控制学习(Matlab代码实现)内容概要:本文介绍了基于径向基函数神经网络(RBFNN)的自适应滑模控制方法,并提供了相应的Matlab代码实现。该方法结合了RBF神经网络的非线性逼近能力和滑模控制的强鲁棒性,用于解决复杂系统的控制问题,尤其适用于存在不确定性和外部干扰的动态系统。文中详细阐述了控制算法的设计思路、RBFNN的结构与权重更新机制、滑模面的构建以及自适应律的推导过程,并通过Matlab仿真验证了所提方法的有效性和稳定性。此外,文档还列举了大量相关的科研方向和技术应用,涵盖智能优化算法、机器学习、电力系统、路径规划等多个领域,展示了该技术的广泛应用前景。; 适合人群:具备一定自动控制理论基础和Matlab编程能力的研究生、科研人员及工程技术人员,特别是从事智能控制、非线性系统控制及相关领域的研究人员; 使用场景及目标:①学习和掌握RBF神经网络与滑模控制相结合的自适应控制策略设计方法;②应用于电机控制、机器人轨迹跟踪、电力电子系统等存在模型不确定性或外界扰动的实际控制系统中,提升控制精度与鲁棒性; 阅读建议:建议读者结合提供的Matlab代码进行仿真实践,深入理解算法实现细节,同时可参考文中提及的相关技术方向拓展研究思路,注重理论分析与仿真验证相结合。
先展示下效果 https://pan.quark.cn/s/a4b39357ea24 本项目是本人参加BAT等其他公司电话、现场面试之后总结出来的针对Java面试的知识点或真题,每个点或题目都是在面试中被问过的。 除开知识点,一定要准备好以下套路: 个人介绍,需要准备一个1分钟的介绍,包括学习经历、工作经历、项目经历、个人优势、一句话总结。 一定要自己背得滚瓜烂熟,张口就来 抽象概念,当面试官问你是如何理解多线程的时候,你要知道从定义、来源、实现、问题、优化应用方面系统性地回答 项目强化,至少与知识点的比例是五五开,所以必须针对简历中的两个以上的项目,形成包括【架构和实现细节】,【正常流程和异常流程的处理】,【难点+坑+复盘优化】三位一体的组合拳 压力练习,面试的时候难免紧张,可能会严重影响发挥,通过平时多找机会参与交流分享,或找人做压力面试来改善 表达练习,表达能力非常影响在面试中的表现,能否简练地将答案告诉面试官,可以通过给自己讲解的方式刻意练习 重点针对,面试官会针对简历提问,所以请针对简历上写的所有技术点进行重点准备 Java基础 JVM原理 集合 多线程 IO 问题排查 Web框架、数据库 Spring MySQL Redis 通用基础 操作系统 网络通信协议 排序算法 常用设计模式 从URL到看到网页的过程 分布式 CAP理论 锁 事务 消息队列 协调器 ID生成方式 一致性hash 限流 微服务 微服务介绍 服务发现 API网关 服务容错保护 服务配置中心 算法 数组-快速排序-第k大个数 数组-对撞指针-最大蓄水 数组-滑动窗口-最小连续子数组 数组-归并排序-合并有序数组 数组-顺时针打印矩形 数组-24点游戏 链表-链表反转-链表相加 链表-...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值