Най-добри практики за повторна употреба на контейнери с ламбда AWS

Оптимизиране на топли старти при свързване на AWS Lambda към други услуги

AWS Lambda осигурява висока мащабируемост, тъй като е без сървър и състояние, без това позволява много копия на функцията lambda да бъдат породени моментално (както е описано тук). Въпреки това, когато пишете код на приложение, е много вероятно да искате достъп до някои състоятелни данни. Това означава да се свържете с хранилище за данни, като например RDS инстанция или S3. Свързването с други услуги от AWS Lambda обаче добавя време към вашия функционален код. Възможно е да има и странични ефекти от висока мащабируемост, като достигане на максималния брой разрешени връзки към RDS инстанция. Една от възможностите за противодействие на това е използването на контейнер повторно използване в AWS Lambda, за да се поддържа връзката и да се намали времето за работа на ламбда.

Тук има няколко полезни диаграми, които обясняват жизнения цикъл на заявка за ламбда.

Следното се случва по време на студен старт, когато функцията ви се извиква за първи път или след период на неактивност:

  • Кодът и зависимостите се изтеглят.
  • Стартира се нов контейнер.
  • Времето за изпълнение е заредено.

Последното действие е да стартирате кода си, което се случва всеки път, когато се извика функцията lambda. Ако контейнерът се използва повторно за последващо извикване на функцията lambda, можем да преминем напред към стартиране на кода. Това се нарича топъл старт и това е стъпката, която можем да оптимизираме, когато се свързваме с други услуги, като дефинираме връзката извън обхвата на метода за обработка.

Свързване с други AWS услуги от Lambda

Пример: Свържете се с екземпляр RDS, икони на AWS, получени от тук

Имаме основен и общ пример, през който трябва да преминем - искаме да се свържем с ресурс на контейнер, за да извлечем данни за обогатяване. В този пример, полезен товар JSON идва с идентификатор и функцията Lambda се свързва към екземпляр RDS, изпълняващ PostgreSQL, за да намери съответното име на идентификатора, за да можем да върнем обогатения полезен товар. Тъй като функцията lambda се свързва с RDS, който живее във VPC, функцията lambda вече трябва да живее и в частна подмрежа. Това добавя няколко стъпки към студения старт - трябва да се прикачи VPC еластичен мрежов интерфейс (ENI) (както бе споменато в блога на Джеръми Дали, това добавя време за вашите студени старти).

Забележка: бихме могли да избегнем използването на VPC, ако използвахме ключ / стойност за съхранение с DynamoDB вместо RDS.

Ще разгледам две решения на тази задача, първото е моето "наивно" решение, докато второто решение оптимизира за топли времена на стартиране, като използва повторно връзката за следващи извиквания. Тогава ще сравним ефективността на всяко решение.

Вариант 1 - Свързване към RDS в рамките на манипулатора

Този пример с код показва как бих могъл наивно да подхождам към тази задача - връзката с базата данни е в метода на обработващия. Има проста заявка за избор, за да извлечете името на идентификатора, преди да върнете полезния товар, който сега включва името.

Нека да видим как се изпълнява тази опция по време на малък тест с изблик от 2000 извиквания с едновременност 20. Минималната продължителност е 18 ms със средно 51ms и малко над 1 секунда (продължителност на студения старт).

Продължителност на ламбда

Графиката по-долу показва, че има максимален брой осем връзки към базата данни.

Брой връзки към RDS базата данни в 5 минутен прозорец.

Вариант 2 - Използвайте глобална връзка

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

Вече не затваряме връзката с базата данни, така че връзката остава за последващо извикване на функцията. Използването на връзката значително намалява продължителността на топлия старт - средната продължителност е приблизително 3 пъти по-бърза, а минималната е 1 ms, а не 18 ms.

Ламбда трайност

Свързването с RDS инстанция е отнемаща време задача и не е необходимо да се свързвате за всяко извикване е полезно за ефективността. Когато се свързваме с базата данни за обикновена заявка към базата данни, постигаме максимален брой връзки към базата данни 20, което съответства на нивото на съвместимост (направихме 20 едновременни извиквания х 100 пъти). Когато сривът на извикванията спре, връзките постепенно се затварят.

Сега, когато AWS е увеличил квотата за продължителност на лямбда до 15 минути, това означава, че връзките с база данни могат да продължат по-дълго и може да сте в опасност да достигнете номера на RDS max връзки. Максималните връзки по подразбиране могат да бъдат презаписани в настройките на групата параметри на RDS, въпреки че увеличаването на максималния брой връзки може да доведе до проблеми с разпределението на паметта. По-малките инстанции могат да имат стойност по подразбиране max_connections по-малка от 100. Вземете предвид тези ограничения и добавете логика на приложението само за да се свържете с базата данни, когато е необходимо.

Използване на глобална връзка за други задачи

Ламбда Свързване към S3

Обща задача, която може да се наложи да изпълним с Lambda, е достъпът до състоятелни данни от S3. Кодният фрагмент по-долу е снабден с AWS план Python Lambda Function, който можете да навигирате, като влезете в конзолата AWS и щракнете тук. Можете да видите в кода, че клиентът S3 е напълно дефиниран извън обработчика, когато контейнерът се инициализира, докато за пример RDS глобалната връзка беше зададена вътре в обработващия. И двата подхода ще зададат глобалните променливи, позволявайки им да бъдат достъпни за следващи извиквания.

s3-get-object lambda план за кода на фрагмента https://console.aws.amazon.com/lambda/home?region=us-east-1#/create/new?bp=s3-get-object-python

Дешифриране на променливи на околната среда

Ламбда конзолата ви дава възможност да криптирате променливите на вашата среда за допълнителна сигурност. Следният фрагмент на кода е AWS, предоставен от Java пример на помощен скрипт за дешифриране на променливи от среда от функция Lambda. Можете да отидете до фрагмента на кода, като следвате този урок (по-специално стъпка 6). Тъй като DECRYPTED_KEY е дефиниран като глобален клас, функцията и логиката decryptKey () се извиква само веднъж на ламбда контейнер. Следователно ще видим значително подобрение в продължителността на топлите стартове.

https://console.aws.amazon.com/lambda/home?region=us-east-1#/functions и https://docs.aws.amazon.com/lambda/latest/dg/tutorial-env_console.html

Използване на глобални променливи в други FaaS решения

Този подход не е изолиран от AWS Lambda. Методът за използване на глобална връзка може да се приложи и за други сървърни функции на други облачни доставчици. Страницата за съвети и трикове на Google Cloud Functions дава добро обяснение за не мързеливи променливи (когато променливата винаги се инициализира извън метода на обработващия) срещу мързеливите променливи (глобалната променлива се задава само когато е необходимо) глобални променливи.

Други най-добри практики

Ето някои други най-добри практики, които трябва да имате предвид.

Тестване

Използването на FaaS улеснява архитектурата на микросервизи. И наличието на малки, дискретни части от функционалността върви ръка за ръка с ефективно тестване на единица. За да подпомогнете тестовете на вашето устройство:

  • Не забравяйте да изключите тестовите зависимости от пакета lambda.
  • Отделете логиката далеч от метода за обработка, както бихте направили с основен метод на програма.

Зависимости и размер на пакета

Намаляването на размера на пакета за внедряване означава, че изтеглянето на кода ще бъде по-бързо при инициализация и следователно ще подобри вашите студени времена на стартиране. Премахнете неизползваните библиотеки и мъртвия код, за да намалите размера на ZIP файла за внедряване. AWS SDK се предлага за Python и JavaScript време за изпълнение, така че не е необходимо да ги включвате в своя пакет за внедряване.

Ако Node.js е предпочитаното от вас ламбда време за изпълнение, можете да приложите минимизация и улификация, за да намалите размера на функционалния си код и да сведете до минимум размера на пакета си за внедряване. Някои, но не всички аспекти на минимизирането и улифицирането могат да бъдат приложени към други изпълнения, напр. не можете да премахнете бялото пространство от python код, но можете да премахнете коментари и да съкратите имена на променливи.

Настройка на паметта

Експериментирайте, за да намерите оптималното количество памет за функцията Lambda. Вие плащате за разпределение на паметта, така че удвояването на паметта означава, че трябва да платите двойно на милисекунда; но изчислителният капацитет се увеличава с разпределена памет, така че потенциално може да намали времето за работа до по-малко от половината от това, което беше. Вече има някои полезни инструменти за избор на оптималната настройка на паметта за вас, като тази.

Заключение ...

Едно нещо, което трябва да се вземе предвид, е дали прилагането на метода за повторно използване на връзката е необходимо. Ако вашата ламбда функция се извиква само рядко, например веднъж на ден, тогава няма да имате полза от оптимизирането за топли старти. Често има компромис между оптимизиране на производителността и четливостта на вашия код - терминът „улификация“ говори сам за себе си! Освен това добавянето на глобални променливи в кода ви за повторна употреба на връзки с други услуги потенциално може да затрудни кода ви да бъде проследен. Два въпроса идват на ум:

  • Дали нов член на екипа ще разбере кода ви?
  • Вие и вашият екип ще можете да отстраните грешката в бъдеще?

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

Тези мнения са на автора. Ако не е посочено друго в този пост, Capital One не е свързан, нито е одобрен от никоя от споменатите компании. Всички използвани търговски марки и друга интелектуална собственост са собственост на съответните им собственици. Тази статия е © 2019 Capital One.