Лямбда-функция «Ошибка: подключите ETIMEDOUT», когда получаете слишком много запросов для запроса MySQL - PullRequest
0 голосов
/ 28 марта 2019

Я пытаюсь провести тестирование моей лямбда-функции AWS, которая выполняет запрос к RDS MySQL (t2.medium). Однако, если я запрашиваю API много раз, хотя я могу успешно получить запрос с правильными данными, это иногда приводит к «Ошибка: подключить ETIMEDOUT».

Что-то не так в моем коде или настройке?

Я прочитал несколько советов, чтобы установить некоторые параметры:

MySQL:

wait_timeout 1

max_connections 16000

interactive_timeout 6000

max_allowed_packet 1073741824

Lamdba:

Тайм-аут 60 сек. Поместите лямбда-функцию в тот же VPC, что и RDS

Добавлена ​​политика выполнения VPC AWSLambdaVPCAccessExecutionRole

назначить группу безопасности для лямбда-функции

В безопасности, прикрепленной к экземпляру RDS, добавлено входящее правило для mysql

Убедитесь, что функция Lambda имеет доступ к той же базе данных VPC RDS

Журнал лямбда-ошибок

2019-03-28T18: 51: 47.353Z ab4fbbaf-1ea2-458b-a5b5-781cdfdd80df {Ошибка: подключить ETIMEDOUT

at Connection._handleConnectTimeout

* +1039 * (/ вар / задача / node_modules / MySQL / Библиотека / Connection.js: 411: 13)

в Object.onceWrapper (events.js: 313: 30)

at emitNone (events.js: 106: 13)

в Socket.emit (events.js: 208: 7)

в Socket._onTimeout (net.js: 420: 8)

в ontimeout (timers.js: 482: 11)

в tryOnTimeout (timers.js: 317: 5)

в Timer.listOnTimeout (timers.js: 277: 5)


в Protocol._enqueue (/var/task/node_modules/mysql/lib/protocol/Protocol.js:144:48)

в Protocol.handshake (/var/task/node_modules/mysql/lib/protocol/Protocol.js:51:23)

на Connection.connect (/var/task/node_modules/mysql/lib/Connection.js:118:18)

at Connection._implyConnect (/var/task/node_modules/mysql/lib/Connection.js:453:10)

в Connection.query (/var/task/node_modules/mysql/lib/Connection.js:198:8)

на Promise (/var/task/db.js:62:9)

на новый Promise ()

в Object.retrieve (/var/task/db.js:55:10)

at exports.getAlerts (/var/task/index.js:59:24)

errorno: «ETIMEDOUT»,

код: 'ETIMEDOUT',

системный вызов: 'connect',

фатально: правда}

Журнал ошибок RDS

2019-03-28T18: 18: 49.378320Z 9500 [Примечание] Прерванное соединение 9500 в дБ: 'db' user: 'user' host: '123.123.123.123' (Получено время ожидания пакеты связи)

2019-03-28T18: 18: 49.392514Z 9498 [Примечание] Прервано соединение 9498 с дБ: 'db' user: 'user' host: '123.123.123.123' (Получено время ожидания пакеты связи)

2019-03-28T18: 18: 49.470617Z 9499 [Примечание] Прерванное соединение 9499 в дБ: 'db' user: 'user' host: '123.123.123.123' (Получено время ожидания пакеты связи)

2019-03-28T18: 18: 49.636775Z 9501 [Примечание] Прервано соединение 9501 в дБ: 'db' user: 'user' host: '123.123.123.123' (Получено время ожидания пакеты связи)

2019-03-28T18: 18: 49.694669Z 9502 [Примечание] Прервано соединение 9502 к дБ: 'db' user: 'user' host: '123.123.123.123' (Получено время ожидания пакеты связи)

2019-03-28T18: 18: 49.803457Z 9503 [Примечание] Прервано соединение 9503 с дБ: 'db' user: 'user' host: '123.123.123.123' (Получено время ожидания пакеты связи)

2019-03-28T18: 18: 49.824250Z 9504 [Примечание] Прервано соединение 9504 с дБ: 'db' user: 'user' host: '123.123.123.123' (Получено время ожидания пакеты связи)

Мой запрос db.js по лямбде

const mysql = require('mysql')
let retrieve = (sql, objectArr, entityName) => {
      return new Promise((resolve, reject) => {
        let con = mysql.createConnection(dbParams)
        con.query(sql, objectArr, (err2, results) => {
          con.end()
          if (err2) {
            console.log(err2)
            return reject(new apiError.DatabaseError('An error occurred in retrieve'))
          }
          console.log('Data retrieve successfully')
          return resolve(results)
        })
      })
    }

Мой скрипт test.js

const request = require('request')
let errorCount = 0
let success = 0

for (let i = 0; i < 4000; i++) {
  console.log('Send')
  request.get('https://myapi/users', {
    headers: {
      'client_id': 'app',
      'Content-Type': 'application/json'
    }
  }, (error, response, body) => {
    if (error) {
      console.log('some error')
      errorCount++
    } else {
      let jsonBody = JSON.parse(body)
      if (jsonBody.code === 0) {
        success++
      } else {
        errorCount++
      }
    }

    console.log('Success: ', success)
    console.log('Error: ', errorCount)
  })
}

Edit:Я также пытался изменить i <1 в тестовом скрипте, затем он всегда выдает «Ошибка: подключите ETIMEDOUT. Но с i <900 он иногда работает успешно </p>

index.js

const db = require('./db.js')
exports.getUsers = async (event, context) => {
  context.callbackWaitsForEmptyEventLoop = false
  try {
    let sql = 'SELECT * FROM User'
    let abc = await db.retrieve(sql, [], 'user')

    let response = {
      statusCode: 200,
      abc: abc,
      code: 0
    }
    return response
  } catch (err) {
    console.log(err)
    errorHandler(err)
  }
}

db.js с пулом

const mysql = require('mysql')
const constants = require('./constants.js')

let dbParams = {
  host: constants.SQL_CONNECTION_HOST,
  user: constants.SQL_CONNECTION_USER,
  password: constants.SQL_CONNECTION_PASSWORD,
  database: constants.SQL_CONNECTION_DATABASE,
  multipleStatements: true,
  maxConnections: 4
}

const pool = mysql.createPool(dbParams)
let retrieve = (sql, objectArr, entityName) => {
  return new Promise((resolve, reject) => {
    pool.getConnection((err1, con) => {
      if (err1) {
        console.log(err1)
        return reject(new apiError.DatabaseError('An error occurred in retrieve pool'))
      }
      console.log('Pool connect successfully')
      con.query(sql, objectArr, (err2, results) => {
        con.end()
        if (err2) {
          console.log(err2)
          return reject(new apiError.DatabaseError('An error occurred in retrieve'))
        }
        console.log('Data retrieve successfully')
        return resolve(results)
      })
    })
  })
}

Журнал ошибок после использованного пула

2019-03-28T23: 35: 24.144Z 91b0fc78-e4d1-4fd9-bdf7-923715b165c0 {Ошибка: Тайм-аут неактивного рукопожатия

при рукопожатии. (/Var/task/node_modules/mysql/lib/protocol/Protocol.js:163:17)

в emitNone (events.js: 106: 13)

в Handshake.emit (events.js: 208: 7)

в Handshake._onTimeout (/ var / task / node_modules / mysql / lib / protocol / sequence / Sequence.js: 124: 8)

в Timer._onTimeout (/var/task/node_modules/mysql/lib/protocol/Timer.js:32:23)

в ontimeout (timers.js): 482: 11)

в tryOnTimeout (timers.js: 317: 5)

в Timer.listOnTimeout (timers.js: 277: 5)


в Protocol._enqueue (/var/task/node_modules/mysql/lib/protocol/Protocol.js:144:48)

в Protocol.handshake (/var/task/node_modules/mysql/lib/protocol/Protocol.js:51:23)

в PoolConnection.connect (/ var / task / node_modules / mysql / lib/Connection.js:118:18)

в Pool.getConnection (/var/task/node_modules/mysql/lib/Pool.js:48:16)

в Promise (/ var/task/db.js:72:10)

в новом Promise ()

в Object.retrieve (/var/task/db.js:67:10)

at exports.getAlerts (/var/task/index.js:59:24)

код: 'PROTOCOL_SEQUENCE_TIMEOUT',

неустранимый: true,

время ожидания:10000}

Установить сейчас с помощью пула и проверить его с помощью цикла запроса:

i <100 result => Success: 866 и Error: 134 request.

i <10 результат => Успешно: 8 и Ошибка: 2 запроса.

Ошибка с таймаутом неактивности рукопожатия

db.js с con.createConnection outside

const mysql = require('mysql')
// initialize dbParams
let con = mysql.createConnection(dbParams)

let retrieve = (sql, objectArr, entityName) => {
  return new Promise((resolve, reject) => {
    con.query(sql, objectArr, (err2, results) => {
      //con.end() commet out connection end here 
      if (err2) {
        console.log(err2)
        return reject(new apiError.DatabaseError('An error occurred in retrieve'))
      }
      console.log('Data retrieve successfully')
      return resolve(results)
    })
  })
}

1 Ответ

0 голосов
/ 29 марта 2019

В вопросе не объясняется, как вызывается функция retrieve внутри вашей лямбда-функции.

Несмотря на то, что, похоже, она будет выполняться для каждой итерации внутри вашего теста, чтосоздает очень большое количество соединений и может объяснить поведение, которое вы видите.

Я предлагаю создать соединение во время лямбда-инициализации (или «холодный старт»), перемещая строку кода let con = mysql.createConnection(dbParams) вне какой-либо функции (так что будет иметь место только одно соединение).

Другим хорошим вариантом является использование пула соединений .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...