AWS Lambda - MySQL 缓存

Posted

技术标签:

【中文标题】AWS Lambda - MySQL 缓存【英文标题】:AWS Lambda - MySQL caching 【发布时间】:2019-07-23 15:09:52 【问题描述】:

我有使用 RDS 的 Lambda。我想改进它并使用 Lambda 连接缓存。据我所知,我找到了几篇文章,并在我身边实施了它。但现在,我不确定这是正确的方法。

我有 Lambda(运行节点 8),它有几个与 require 一起使用的文件。我将从 main 函数开始,直到到达 mysql 初始化程序,这是确切的路径。一切都将超级简单,只显示运行 MySQL 的代码流:

主 Lambda:

const jobLoader = require('./Helpers/JobLoader');

exports.handler = async (event, context) => 
    const emarsysPayload = event.Records[0];
    let validationSchema;

    const body = jobLoader.loadJob('JobName');
     ...
    return;
...//

职位代码:

const MySQLQueryBuilder = require('../Helpers/MySqlQueryBuilder');

exports.runJob = async (params) => 
      const data = await MySQLQueryBuilder.getBasicUserData(userId);

MySQLBuilder:

const mySqlConnector = require('../Storage/MySqlConnector');

    class MySqlQueryBuilder 
        async getBasicUserData (id) 
            let query = `
    SELECT * from sometable WHERE id= $id 
    `;

            return mySqlConnector.runQuery(query);
        
    

最后是连接器本身:

const mySqlConnector = require('promise-mysql');
const pool = mySqlConnector.createPool(
        host: process.env.MY_SQL_HOST,
        user: process.env.MY_SQL_USER,
        password: process.env.MY_SQL_PASSWORD,
        database: process.env.MY_SQL_DATABASE,
        port: 3306
    );

    exports.runQuery = async query => 
        const con = await pool.getConnection();
        const result = con.query(query);
        con.release();
        return result;
    ;

我知道测量性能会显示实际结果,但是今天是星期五,我要到下周晚些时候才能在 Lambda 上运行它......真的,知道这将是一个很棒的周末开始我的方向是正确的……或者不是。

感谢您的意见。

【问题讨论】:

我实际上没有得到你的问题。想知道如何用 Lambda 实现缓存? 是的。上面的代码是我在 Lambda 上创建缓存的尝试。 你的意思是在你的函数被执行之前你需要你的连接,对吧?当我第一次阅读缓存时,我考虑过缓存结果一段时间。 是的。我希望避免为每个查询创建连接,而是依赖 Lambda 容器缓存。 感谢您的出色回答,它确实解释了很多。但是,我想实现本文中提到的一些事情:spotinst.com/blog/2017/11/19/… 【参考方案1】:

首先要了解require 在 NodeJS 中的工作原理。如果您有兴趣了解更多信息,我建议您阅读此article。

现在,一旦您需要连接,您就可以永久拥有它,并且不再需要它。这符合您正在寻找的内容,因为您不想每次都创建新连接而使数据库不堪重负。

但是,有个问题……

Lambda 冷启动

每当您第一次调用 Lambda 函数时,它都会启动一个包含您的函数的容器,并使其保持活动状态大约 5 分钟。只要您一次发出 1 个请求,您很可能(尽管不能保证)每次都会访问同一个容器。但是如果你同时有 2 个请求会发生什么?然后另一个容器将与前一个已经预热的容器并行旋转。您刚刚在数据库上创建了另一个连接,现在您有 2 个容器。现在,猜猜如果你有 3 个并发请求会发生什么?是的!多一个容器,等于多一个数据库连接。

只要您的 Lambda 函数有新请求,默认情况下,它们就会扩展以满足需求(您可以在控制台中对其进行配置,以将执行限制为任意数量的并发执行 - 尊重您的账户限制)

您无法通过简单地在函数调用时要求您的代码来安全地确保与数据库的连接数量固定。好消息是这不是你的错。这就是 Lambda 函数的行为方式。

...另一种方法是

在真实的缓存系统中缓存您想要的数据,例如ElasticCache。然后,您可以让一个以特定时间频率运行的 CloudWatch Event 触发一个 Lambda 函数。然后,此函数将查询您的数据库并将结果存储在您的外部缓存中。通过这种方式,您可以确保您的数据库连接一次仅由一个 Lambda 打开,因为它将尊重 CloudWatch 事件,结果证明每个触发器仅运行一次。

编辑:在OP在评论部分发送链接后,我决定添加更多信息以澄清所提到的文章想说什么

来自文章:

“很简单。您可以在我们的范围之外存储变量 处理函数。这意味着您可以创建数据库 处理程序函数之外的连接池,然后可以 与该函数的每个未来调用共享。这允许 发生池化。”

这正是你正在做的。这行得通!但问题是如果您同时有 N 个连接(Lambda 请求)。如果您不设置任何限制,默认情况下,最多可以同时启动 1000 个 Lambda 函数。现在,如果您在接下来的 5 分钟内同时发出另外 1000 个请求,那么您很可能不会打开任何新连接,因为它们已经在之前的调用中打开并且容器仍然处于活动状态。

【讨论】:

很好的答案!!!。我会将 Lambda 中的并发控制在一些正常且可接受的值。我很高兴我做对了。现在我可以去度过一个体面的周末了。谢谢楼主! 非常感谢。当然,我们非常欢迎您。普罗斯特 :) 还有一件事。在您的回答中,您提到:“再次,您可以查看我的 GitHub 以获取示例”...您能否提供指向它们的链接? 这是您发送的文章的复制和粘贴。我认为是在最后一段或其他内容中【参考方案2】:

Thales Minussi 添加到上面的答案,但对于 Python Lambda。我正在使用 PyMySQL 并创建一个连接池,我在获取数据的 Lambda 中的处理程序上方添加了连接代码。一旦我这样做了,在执行 Lambda 实例后,我没有得到任何添加到数据库的新数据。我发现了与此问题相关的 here 和 here 报告的错误。

对我有用的 solution 是在 Lambda 中执行 SELECT 查询之后添加 conn.commit()

根据 PyMySQL documentation,conn.commit() 应该提交任何更改,但 SELECT 不会对数据库进行更改。所以我不确定为什么会这样。

【讨论】:

以上是关于AWS Lambda - MySQL 缓存的主要内容,如果未能解决你的问题,请参考以下文章

确定我们是否在AWS Lambda + Zappa下运行?

从 AWS API Gateway Web 界面配置 AWS Lambda 时无法选择/查看 Lambda 函数

如何将 Python Lambda 函数集成到 AWS Amplify 的管道中

使用 Node.JS 调用 AWS 胶水的 lambda 函数不使用 console.log 的原因是啥?

主网001提案|销毁Lambda研发团队持有的7亿LAMB投票通过

如何TBB获得150%LAMB的质押挖矿收益?