Knex: كيف أستخدم Knex مع AWS Lambda؟

تم إنشاؤها على ٢٠ يناير ٢٠١٧  ·  34تعليقات  ·  مصدر: knex/knex

أواجه مشكلات في تجميع الاتصالات أثناء اختبار بعض التعليمات البرمجية. أتوقع أن يتم استدعاء وظيفة lambda الخاصة بي ربما عدة آلاف من المرات خلال بضع ثوانٍ ، وأواجه مشكلة في اكتشاف أفضل طريقة للاتصال بـ db الخاص بي. إليك مشكلة مشابهة جدًا للعقدة / postgres: المشكلة الأساسية هي أنني بحاجة إلى الحصول على اتصال من المجموعة إذا كان أحدها متاحًا ، ولكن لا يمكنني الاعتماد على المجموعة الموجودة بسبب كيفية إعادة استخدام AWS (بشكل غير موثوق) حاويات لامدا.

ما أبحث عنه أساسًا هو طريقة للحصول على اتصال أو إنشاء اتصال به بشكل موثوق به. لم أتمكن من العثور على أي أمثلة (مثل while(!availableConnections) { tryToGetConnection() } . هل أحتاج إلى التفاعل مع node-pool ؟ كيف يمكنني القيام بذلك مع Knex؟

insightful question

التعليق الأكثر فائدة

آسف ، لقد ارتكبت في منتصف الجملة ، ألقى طفلي للتو 3 لترات من الماء على الأرض: 1st_place_medal: سأقوم بتحديث التعليق أعلاه بعد قليل ...

ال 34 كومينتر

يعمل تجميع Knex فقط إذا تم إجراء الاتصالات من نفس عملية العقدة.

إذا كانت مثيلات AWS lambda لا تشغل عملية عقدة مشتركة ، فكل ما عليك فعله هو إنشاء مجموعة جديدة مع الحد الأدنى / الحد الأقصى للاتصالات 1 في كل مثيل lambda وتأمل أن تحتوي قاعدة البيانات الخاصة بك على إعدادات كافية كافية للسماح بمئات الاتصالات المتزامنة (في RDS يعتمد ذلك على حجم المثيل ).

بعد قراءة هذا https://forums.aws.amazon.com/thread.jspa؟threadID=216000

يبدو أن lambda تشارك بالفعل بعض العمليات ، لذلك إذا كان بإمكانك معرفة الحد الأقصى لعدد حاويات lambda ، التي تم إنشاؤها ، فيجب أن تكون قادرًا على حساب الحجم الأمثل للتجمع (كل حاوية لها تجمع منفصل ، لذا فإن إجمالي الاتصالات بقاعدة البيانات عبارة عن تجمع. ماكس * ماكس عدد الحاويات).

على أي حال ، ليست هناك حاجة لإجراء طلب اتصال يدوي من المسبح ، ينتظر knex الاتصال تلقائيًا وإذا انتهى كل شيء في غضون ثوانٍ ، فلن يتم تشغيل أي من المهلات في ذلك الوقت.

إذا تلقيت خطأ من DB والذي يفيد بأنه تم الوصول إلى الحد الأقصى لعدد الاتصال ، فأنت بحاجة إلى تقليل حجم التجمع الأقصى.

آسف ، لقد ارتكبت في منتصف الجملة ، ألقى طفلي للتو 3 لترات من الماء على الأرض: 1st_place_medal: سأقوم بتحديث التعليق أعلاه بعد قليل ...

شكرا على الرد. يبدو أن تقدير الحد الأقصى لحجم التجمع سيكون أفضل رهان ، على الرغم من أن عدد الاتصالات سيختلف بشكل كبير بمرور الوقت.

للتوضيح ، لا توجد طريقة لإغلاق الاتصال في Knex ، أليس كذلك؟ فقط القدرة على تدمير تجمع الاتصال؟ حقيقة أن Lambda ستعيد أحيانًا استخدام الحاويات نوعًا ما يلقي بكل شيء.

يؤدي تدمير تجمع الاتصال إلى تدمير جميع الاتصالات أيضًا (الانتظار برشاقة حتى تكتمل أولاً) وأعتقد أنه عندما تدمر lambda الحاوية ، سيتم إغلاق جميع مآخذ TCP المفتوحة بشكل ضمني عند موت العملية.

لا أفهم لماذا يجب على المرء أن يحاول إغلاق الاتصالات صراحة بعد كل طلب لأنه سيدمر فائدة التجميع. ستحصل على نفس التأثير من خلال إنشاء تجمع بالحجم 1 وتدميره بعد ذلك.

يمكنك أيضًا تكوين مهلة الخمول للتجمع والتي ستغلق الاتصال تلقائيًا إذا لم يتم استخدامها وتنتظر فقط الإجراء في التجمع.

هل يمكنني استخدام Knex لإرسال استعلام COPY إلى مجموعة RedShift ، وعدم انتظار النتائج؟

يؤدي القيام بذلك مع pg Pool إلى إنهاء الاستعلام بمجرد الوصول إلى نهاية وظيفة Lambda.

BardiaAfshin إذا تم إتلاف حاوية lambda وتم تحرير جميع مآخذ التوصيل الخاصة بها عند الوصول إلى نهاية وظيفة lambda ، في هذه الحالة أيضًا سيموت استعلام db وقد لا يتم الانتهاء منه.

لست متأكدًا من كيفية تفاعل postgresql مع انتهاء الاتصال من جانب العميل إذا تم التراجع عن استعلام COPY بسبب عدم إنهاء المعاملة الضمنية قبل قراءة قيم النتيجة ...

على أي حال ، إذا كان من الممكن إرسال الاستعلام أم لا بهذه الطريقة ، فإن الأمر لا يعتمد على knex ، ولكنه يعتمد على كيفية عمل aws lambda و postgresql.

ملاحظتي هي أن الاستعلام تم إيقافه على RedShift ويتم التراجع عنه.

على أي حال ، ليست هناك حاجة لإجراء طلب اتصال يدوي من المسبح ، ينتظر knex الاتصال تلقائيًا وإذا انتهى كل شيء في غضون ثوانٍ ، فلن يتم تشغيل أي من المهلات في ذلك الوقت.

أنا أقوم بتشغيل برنامج نصي لاختبار تحميل db وهذا لا يبدو صحيحًا. تنتهي مهلة أي شيء أعلى من 30 اتصالاً متزامنًا على الفور ، بدلاً من انتظار اتصال مفتوح.

هل هناك طريقة لتحرير الاتصال المستخدم حاليًا يدويًا بمجرد الانتهاء من الاستعلام؟

هل لدى أي شخص مثال على التعليمات البرمجية يمكنه مشاركتها لمن يدخلون للتو في AWS Lambda؟ آمل أن يتمكن أحدهم من مشاركة الأنماط و / أو الأنماط المضادة لمفهوم knex / postgres / lambda.

هذا هو ما أستخدمه الآن - أنا متأكد من أنه يمكن تحسينه ، لكنني آمل في بعض التبرير فيما إذا كنت على الطريق الصحيح أم لا ...

'use strict';
var pg = require('pg');

function initKnex(){
  return require('knex')({
      client: 'pg',
      connection: { ...details... }
  });
}

module.exports.hello = (event, context) =>
{
  var knex = initKnex();

  // Should I be returning knex here or in the final catch?
  knex
  .select('*')
  .from('my_table')
  .then(function (rows) {
    context.succeed('Succeeded: ' + JSON.stringify(rows || []));
  })
  .catch(function (error) {
    context.fail(error);
  })
  .then(function(){
    // is destroy overkill? - is there an option for knex.client.release, etc?
    knex.destroy();
  })
}

أنا في نفس القارب - ما زلت لم أتوصل إلى أفضل طريقة على الرغم من الكثير من البحث والاختبار في googling. ما أفعله الآن هو:

const dbConfig = require('./db');
const knex = require('knex')(dbConfig);

exports.handler = function (event, context, callback) {
...
connection = {..., pool: { min: 1, max: 1 },

بهذه الطريقة سيبقى الاتصال (بحد أقصى 1 لكل حاوية) على قيد الحياة حتى يمكن إعادة استخدام الحاوية بسهولة. لا أدمر اتصالي في النهاية.

http://blog.rowanudell.com/database-connections-in-lambda/

لست متأكدًا مما إذا كانت هذه هي أفضل طريقة ولكنها نجحت بالنسبة لي حتى الآن.

/ تتغاضى

تضمين التغريدة

لست متأكدًا تمامًا مما يحدث عند الإعلان عن const knex - هل هذا هو المكان الذي يتم فيه إعداد الاتصال الأولي؟ هل يستطيع احد ان يوضح؟ (أفترض أن لديك معلومات اتصال في dbConfig الخاص بك)

في التعليمات البرمجية الخاصة بك ، ألا تتم الكتابة فوق الاتصال نفسه وإعادة إنشائه في كل مرة يتم استدعاء المعالج؟

مجرد دق في شخص موجود في نفس القارب ، لم يحالفني الحظ كثيرًا في محاولة معرفة الحاويات مقابل حجم البركة (وفقًا لاقتراحelhigu ). كان الحل الخاص بي هو تدمير المسبح بعد كل اتصال (أعلم أنه ليس هو الأمثل 😒):

const knex = require('knex');

const client = knex(dbConfig);

client(tableName).select('*')
  .then((result) => { 

    return Promise.all([
      result,
      client.destroy(),
    ])  
  })
  .then(([ result ]) => {

    return result;
  });

TL ؛ DR: ما عليك سوى تعيين context.callbackWaitsForEmptyEventLoop = false قبل استدعاء رد الاتصال.

تنتظر AWS Lambda حلقة حدث فارغة (افتراضيًا). لذلك يمكن أن تؤدي الوظيفة إلى حدوث خطأ مهلة حتى يتم تنفيذ رد الاتصال.

يرجى الاطلاع على الروابط أدناه للحصول على التفاصيل:
https://github.com/apex/apex/commit/1fe6e91a46e76c2d5c77877be9ce0c206e9ef9fb

لtgriesserelhigu: هذه ليست قضية knex. هذه بالتأكيد قضية بيئة لامدا. أعتقد أن وضع علامة على هذه المشكلة في السؤال ويجب إغلاقها :)

mooyoul نعم ، بالتأكيد ليست مشكلة knex ، ولكن ربما مشكلة في التوثيق ... على الرغم من أنني أعتقد أنني لا أريد أي أشياء محددة من aws lambda إلى مستندات knex ، لذا أغلق.

الرجاء إلقاء نظرة على هذا الرابط
https://stackoverflow.com/questions/49347210/why-aws-lambda-keeps-timing-out-when-using-knex-js
تحتاج إلى إغلاق اتصال db وإلا ستعمل Lambda حتى تنتهي مهلتها.

هل وجد أي شخص نمطًا يعمل بلا عيب في استخدام Knex مع Lambda؟

هل لديك أي مشاكل أخرى عند إغلاق الاتصال بشكل صحيح؟

الشيء الذي أحاول تجنبه هو إغلاق الاتصال وإتاحته عبر مكالمات Lambda.

هل أنت متأكد من أن Lambda تسمح بالحفاظ على الحالة بين المكالمات؟

تحقق من جزء node.js من https://scalegrid.io/blog/how-to-use-mongodb-connection-pooling-on-aws-lambda/ فهو يقترح حلاً للتعليق في حلقة حدث غير فارغة.

لا أحب ضرب الخيط بهذا الشكل ، لكن بما أنني أعتقد أنه يضيع في التعليقات ، فإن إجابة mooyoul أعلاه كانت رائعة بالنسبة لنا.

إذا لم تقم بتحويل هذا العلم إلى false ، فستنتظر Lambda حتى تصبح حلقة الحدث فارغة. إذا قمت بذلك ، فستنتهي الوظيفة من التنفيذ بمجرد استدعاء رد الاتصال.

بالنسبة لي ، لقد عملت على جهازي المحلي ولكن ليس بعد النشر. كنت مضللا نوعا ما.

اتضح أن مصدر RDS الداخلي ليس مفتوحًا لوظيفة Lambda الخاصة بي. تم العثور على حل في Stack Overflow : إما تغيير مصدر RDS الداخلي إلى 0.0.0.0/0 أو استخدام VPC.

بعد تحديث مصدر RDS الداخلي ، يمكنني استخدام Lambda مع Knex بنجاح.

وقت تشغيل Lambda الذي أستخدمه هو Node.js 8.10 مع الحزم:

knex: 0.17.0
pg: 7.11.0

الكود أدناه باستخدام غير متزامن يعمل فقط

const Knex = require('knex');

const pg = Knex({ ... });

module.exports. submitForm = async (event) => {
  const {
    fields,
  } = event['body-json'] || {};

  return pg('surveys')
    .insert(fields)
    .then(() => {
      return {
        status: 200
      };
    })
    .catch(err => {
      return {
        status: 500
      };
    });
};

نأمل أن يساعد الأشخاص الذين قد يواجهون نفس المشكلة في المستقبل.

هناك شيء أود لفت انتباه الناس إليه هو حزمة mysql-serverless ، والتي تغلف برنامج التشغيل القياسي mysql ولكنها تتعامل مع الكثير من نقاط الألم الخاصة بـ lambda حول إدارة تجمع الاتصال الموضحة في هذا الموضوع.

ومع ذلك ، لا أعتقد أن Knex ستعمل مع serverless-mysql في هذا الوقت (وفقًا لهذه المشكلة ) نظرًا لعدم وجود طريقة للتبديل في برنامج تشغيل مختلف. قد يكون هناك أيضًا حالات عدم توافق نظرًا لأن serverless-mysql يستخدم الوعود بدلاً من عمليات رد النداء.

من المحتمل أن يكون أفضل نهج هو إضافة تطبيق عميل جديد في Knex. سأكون سعيدًا بإعطاء هذه اللقطة ، لكني أحب أن يخبرني شخص أكثر دراية بـ Knex إذا كان يعتقد أنه معقول / قابل للتنفيذ؟

أيضًا ، كنت أفكر في هذه الأثناء ، يمكنني استخدام Knex في _إنشاء_ ولكن _لا يتم تنفيذ_ استعلامات MySQL. لذلك فقط اتصل بـ toSQL() وقم بتمرير المخرجات إلى serverless-mysql للتنفيذ.

ما أتساءل عنه هو ما إذا كان يمكن تكوين Knex بدون أي اتصالات db؟ ليس هناك معنى لفتح اتصال لم يتم استخدامه أبدًا.

هل يعمل ما يلي؟

connection = {..., pool: { min: 0, max: 0 ) },

disbelief يمكنك تهيئة knex بدون اتصال. يوجد مثال عن كيفية القيام بذلك في نهاية هذا القسم في المستندات https://knexjs.org/#Installation -client

const knex = require('knex')({client: 'mysql'});

const generatedQuery = knex('table').where('id',1).toSQL().toNative();

elhigu آه رائع ، شكرًا. سوف يعطي ذلك فرصة في غضون ذلك.

تحديث: ما ورد أعلاه لا يبدو أنه يعمل. يطرح Knex خطأ إذا لم يتمكن من إنشاء اتصال db ، حتى إذا لم يكن هناك أي استدعاء لتنفيذ استعلام.

disbelief هل وجدت حلاً لذلك؟

تضمين التغريدة في الوقت الحالي ، أقوم ببساطة ببناء استعلامات مع Squel ، toString() عليها ، وأمررها إلى العميل serverless-mysql .

disbelief إنه من المدهش بالنسبة لي أن فشل إنشاء الاستعلامات بدون اتصال db.

هل تمانع في نشر الكود والتكوين الذي تستخدمه لبناء عميل knex؟ أيضا نسخة knex.

ما يلي يعمل بشكل جيد بالنسبة لي مع
العقدة v8.11.1
mysql : 2.13.0
knex : 0.18.3

const k = require('knex')

const client = k({ client: 'mysql' })

console.log('Knex version:', require('knex/package.json').version)
// => 0.18.3
console.log('sql:', client('table').where('id',1).toSQL().toNative())
// => { sql: 'select * from `table` where `id` = ?', bindings: [ 1 ] }

وفقًا لكيفية عمل إعادة تدوير موارد Lambda ، يجب دائمًا الاحتفاظ بمثيل Knex خارج أي وظيفة أو فصل دراسي. أيضًا ، من المهم أن يكون لديك 1 كحد أقصى في الاتصال في المسبح.

شيء مثل:

const Knex = require('knex');
let instance = null;

module.exports = class DatabaseManager {
  constructor({ host, user, password, database, port = 3306, client = 'mysql', pool = { min: 1, max: 1 }}) {
    this._client = client;
    this._poolOptions = pool;
    this._connectionOptions = {
      host: DB_HOST || host,
      port: DB_PORT || port,
      user: DB_USER || user,
      password: DB_PASSWORD || password,
      database: DB_NAME || database,
    };
  }

  init() {
    if (instance !== null) {
      return;
    }

    instance = Knex({
      client: this._client,
      pool: this._poolOptions,
      connection: this._connectionOptions,
      debug: process.env.DEBUG_DB == true,
      asyncStackTraces: process.env.DEBUG_DB == true,
    });
  }

  get instance() {
    return instance;
  }
}

بهذه الطريقة ، ستحصل على أقصى استفادة من إعادة تدوير Lambda ، أي أن كل حاوية نشطة (مجمدة) ستحتوي على نفس الاتصال فقط.

كملاحظة جانبية ، ضع في اعتبارك أن Lambda تتدرج بشكل افتراضي إذا لم تحد من عدد الحاويات المتزامنة.

لقد قمت بتشغيل Knex في Lambda لمدة عام تقريبًا دون أي مشاكل. أعلن عن مثيل Knex الخاص بي خارج وظيفة Lambda الخاصة بي وأستخدم context.callbackWaitsForEmptyEventLoop = false كما هو مذكور في المنشورات الأخرى.

ومع ذلك ، خلال اليوم الماضي ، يبدو أن شيئًا ما قد تغير في جانب لامدا حيث أرى الآن ارتفاعًا كبيرًا في الاتصال في Postgres ؛ لا يبدو أن الاتصالات مغلقة.

هل رأى أي شخص آخر يستخدم النهج المذكور أعلاه أي فرص خلال اليوم الماضي أو نحو ذلك؟

jamesdixon فقط قرأ هذا الآن أثناء إعادة هيكلة بعض تطبيقات knex الخاصة بنا على lambda. أي تحديثات على هذا؟ هل توقف context.callbackWaitsForEmptyEventLoop = false عن العمل؟

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات