AWS Lambda-MySQL缓存

时间:2019-03-01 14:55:07

标签: mysql node.js aws-lambda

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

我有Lambda(运行节点8),其中有几个文件与require一起使用。我将从主函数开始,直到到达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上运行它。而且,实际上,周末开始真是太棒了,知道我朝着正确的方向……还是不正确。

感谢您的投入。

2 个答案:

答案 0 :(得分:2)

第一件事是了解require在NodeJS中的工作方式。如果您有兴趣了解更多有关此知识的信息,我建议您阅读此article

现在,一旦您需要连接,便永久拥有它,并且不再需要它。这与您要查找的内容相匹配,因为您不想每次都通过创建新的连接来使数据库不堪重负。

但是,有一个问题...

Lambda冷启动

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

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

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

...另一种方法是

例如,在真正的缓存系统(例如ElasticCache)中缓存所需的数据。然后,您可以让某个运行特定时间的CloudWatch Event触发一个Lambda函数。然后,此函数将查询您的数据库并将结果存储在您的外部缓存中。这样,您可以确保一次只能由一个Lambda打开数据库连接,因为它将尊重CloudWatch Event,该事件每次触发仅运行一次。

编辑:OP在评论部分中发送了链接后,我决定添加一些其他信息,以澄清提到的文章想要说的话

“简单。您可以在我们的处理程序函数范围之外存储变量。这意味着您可以在处理程序函数之外创建数据库连接池,然后可以在以后每次对该函数的调用中共享该数据库连接池。这允许进行合并。再次,您可以查看我的GitHub以获取示例。”

这正是您在做什么。这有效!但是问题是,如果您同时拥有N个连接(Lambda请求)。如果未设置任何限制,则默认情况下最多可以同时启动1000个Lambda函数。现在,如果您在接下来的5分钟内同时发出另外1000个请求,则很可能不会打开任何新连接,因为在先前的调用中已经打开了这些新连接,并且这些容器仍然有效。

答案 1 :(得分:0)

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

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

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