AWS Lambda في العمل. الجزء الثاني: التعرف على أدوات التطوير والاختبار



هذا الدليل هو نتيجة تجربة شخصية في تطوير واختبار تطبيقات بدون خادم ، وكذلك المناورة بين العكازات والدراجات عند محاولة اختبارها. عندما بدأت تطوير تطبيقات Serverless لأول مرة ، كان عليّ معرفة كل شيء بيدي ، لم تكن هناك أدلة واضحة أو أدوات ملائمة للتطوير والاختبار المحليين.

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

سوف تتعلم كيفية التطوير باستخدام وحدة تحكم مستعرض AWS و SAM-CLI و IntelljIDEA. سأتحدث أيضًا عن الاختبار: الاندماج واختبارات E2E والوحدات. وأخيرًا ، سنناقش كم سيكلف هذا الحل (المفسد: يمكنك توفير الكثير عليه).

ستكون هذه المقالة مفيدة لأولئك الذين يبدأون في تطوير تطبيقات بدون خادم ولا يعرفون حتى الآن أدواتها وأساليبها.


ما سيتم مناقشته


تحية للجميع! اسمي ألكسندر غروزديف ، ويسرني أن أعرض الجزء الثاني من المقالة حول استخدام وتطوير حلول بدون خادم على أساس AWS Lambda. في التكملة ، سنتحدث عن طرق تطوير واختبار الحل من الجزء الأول ( AWS Lambda in Action in Java 11. نزور Serverless في "الإنتاج" ).

منذ نشر المقال الأخير ، أعيد تصميم تطبيق الاختبار قليلاً ، لكن المعنى الرئيسي يبقى كما هو. هذا هو نموذج HTML تافه "اتصل بنا" ، والذي يرسل البيانات من النموذج إلى Gateway API من خلال طلبات HTTP ، وهو بدوره يرسل طلب المعالجة إلى AWS Lambda. أثناء المعالجة ، يكتب لامدا البيانات إلى جدول DynamoDB ويرسل رسالة من خلال AWS SES. يتم عرض مخطط المكون أدناه.

مخطط المكونات


المحتوى


  1. التطوير باستخدام وحدة تحكم متصفح AWS
  2. التطوير باستخدام SAM-CLI
  3. التطوير باستخدام IntelljIDEA
  4. أنواع الاختبار
  5. تكاليف بلا خادم
  6. روابط مفيدة



1. التطوير باستخدام وحدة تحكم متصفح AWS



وحدة تحكم AWS


توفر وحدة تحكم AWS الوصول إلى أي خدمة AWS ، سواء كانت خادم EC2 الظاهري ، أو إعدادات سياسة الوصول / الدور IAM أو AWS Lambda مع جميع المعلمات التي يمكن تغييرها في الوقت الفعلي دون إعادة النشر من خلال أنظمة التسليم المستمر / النشر المستمر.

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

وحدة تحكم بوابة API


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

دعنا نرى كيف تبدو وحدة التحكم "السحرية" في لقطة شاشة علامة التبويب "الموارد" في تطبيق "اتصل بنا": توضح لقطة الشاشة كيفية وصول الطلب من العميل عبر Gateway API إلى lambda وكيف سيتم إرجاع الاستجابة مرة أخرى إلى العميل عند استدعاء المورد / contact من خلال طريقة POST.

موارد البوابة



  • طلب الطريقة - الخطوة الأولى في معالجة الطلب. في حالتنا ، لا يحتوي على أي إعدادات ، ولكن قد يحتوي ، على سبيل المثال ، على إعدادات التفويض.
  • يعني طلب التكامل أن طلب HTTP سيتم إرساله إلى لامدا بتنسيق خاص: فهو يحتوي على جميع المعلومات التي يرسلها العميل وتفاصيل حول السياق الذي يتم استدعاؤه.
  • تقول استجابة التكامل أن عميل HTTP سيتلقى الاستجابة مباشرة من لامدا. لذلك ، أنت مسؤول عن تشكيل جسم الاستجابة في لامدا.


تعطيل تكامل الوكيل
API Gateway , Use Lambda Proxy integration Integration Request. . , , .


نموذج طلب تكامل
SAM init events, , Integration request. , AWS , . AWS Lambda.


اضغط على زر الاختبار للتحقق من عمل التطبيق. سوف يمنحك هذا الوصول إلى مكالمات API بوابة HTTP.

في لقطة الشاشة التالية ، أرسلت طلبًا لتسخين لامدا: بالإضافة إلى الرد على الطلب ، تعرض واجهة برمجة تطبيقات البوابة بوابة مفصلة. بنفس الطريقة ، يمكنك تقديم طلب حقيقي عن طريق استبدال نص طلب JSON في النموذج:
طلب اختبار البوابة


{
    "subject": "Email subject",
    "question": "Your question…",
    "username": "Your name…",
    "phone": "Your phone…",
    "email": "Your email…"
} 


لذا يمكنك اختبار واجهة برمجة التطبيقات يدويًا بدون أي نماذج واجهة مستخدم وتطبيقات للواجهة الأمامية ، وبالتالي فصل تطوير الواجهة الأمامية والخلفية. كبديل لوحدة التحكم المضمنة ، يمكنك استخدام Postman أو أي عميل HTTP آخر.

ساعي البريد كبديل
HTTP- Postman. . , API Gateway AWS , API. , , AWS .


لامدا كونسول


للاختبار والتطوير ، بالإضافة إلى الطلبات من خلال Gateway API ، يمكنك استخدام وحدة تحكم مستعرض AWS Lambda.

تنقسم شاشته إلى عدة كتل:
  • يعرض المصمم المشغلات والطبقات الموجودة. في حالتنا ، فإن الزناد هو API Gateway. إذا نقرنا عليها ، سيتم فتح جميع المعلومات الضرورية: URL ، المسرح ، مسار المورد.
  • تسمح لك الأسماء المستعارة (المتاحة عند تحديد اسم مستعار محدد لامدا) بتكوين توزيع حركة المرور حسب إصدار لامدا. المزيد عن هذا في الفقرة التالية.
  • Function code — . zip- , . , Function code . Python/NodeJs.
  • Environment variables. , . , , . , . , , .
  • Tags — , , , , .
  • Execution role — ( ) , .
  • Basic settings — .
  • Network: - , VPC. — .
  • AWS X-Ray . AWS-.
  • Reserve concurrency , . .
    Provisioned concurrency
  • Provisioned concurrency — . , . , — . Free Tier .
  • يتيح لك الاستدعاء غير المتزامن تكوين معالجة خاصة للطلبات غير المتزامنة. نشير إلى عدد المكالمات المتكررة التي يتم إجراؤها في حالة حدوث خطأ ، وإلى متى يمكن تعليق الطلب في قائمة الانتظار. بشكل اختياري ، يمكنك تحديد قائمة انتظار لمعالجة الطلبات التي تفشل.

  • بروكسيات قواعد البيانات هي ميزة جديدة أخرى تسمح لك بتكوين الوصول إلى قاعدة البيانات من خلال الوكلاء في شكل API Gateway + Lambda.


بعد ذلك ، دعنا نرى كيفية التطوير من وحدة التحكم هذه. بالإضافة إلى تغيير المعلمات ، يمكن استخدام وظيفة تكوين أحداث الاختبار لإنشاء طلب اختبار. تتوفر قائمة شاملة إلى حد ما ، ولكننا سنستفيد مما أرفقته بالفعل في المشروع:
طلب ContactUs
{
  "body": "{\"subject\": \"Question\",\"question\": \"How much does it cost\",\"username\": \"Alex\",\"phone\": \"+79999999999\",\"email\": \"alex@gmail.com\"}",
  "resource": "/{proxy+}",
  "path": "/path/to/resource",
  "httpMethod": "POST",
  "isBase64Encoded": false,
  "queryStringParameters": {
    "foo": "bar"
  },
  "pathParameters": {
    "proxy": "/path/to/resource"
  },
  "stageVariables": {
    "baz": "qux"
  },
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Accept-Encoding": "gzip, deflate, sdch",
    "Accept-Language": "en-US,en;q=0.8",
    "Cache-Control": "max-age=0",
    "CloudFront-Forwarded-Proto": "https",
    "CloudFront-Is-Desktop-Viewer": "true",
    "CloudFront-Is-Mobile-Viewer": "false",
    "CloudFront-Is-SmartTV-Viewer": "false",
    "CloudFront-Is-Tablet-Viewer": "false",
    "CloudFront-Viewer-Country": "US",
    "Host": "1234567890.execute-api.us-east-1.amazonaws.com",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Custom User Agent String",
    "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)",
    "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==",
    "X-Forwarded-For": "127.0.0.1, 127.0.0.2",
    "X-Forwarded-Port": "443",
    "X-Forwarded-Proto": "https"
  },
  "requestContext": {
    "accountId": "123456789012",
    "resourceId": "123456",
    "stage": "prod",
    "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
    "requestTime": "09/Apr/2015:12:34:56 +0000",
    "requestTimeEpoch": 1428582896000,
    "identity": {
      "cognitoIdentityPoolId": null,
      "accountId": null,
      "cognitoIdentityId": null,
      "caller": null,
      "accessKey": null,
      "sourceIp": "127.0.0.1",
      "cognitoAuthenticationType": null,
      "cognitoAuthenticationProvider": null,
      "userArn": null,
      "userAgent": "Custom User Agent String",
      "user": null
    },
    "path": "/prod/path/to/resource",
    "resourcePath": "/{proxy+}",
    "httpMethod": "POST",
    "apiId": "1234567890",
    "protocol": "HTTP/1.1"
  }
}


بعد إضافة الطلب ، انقر على اختبار وشاهد نتيجة لامدا: Lambda تُرجع JSON ، الذي يحتوي على رمز الحالة ونص الاستجابة. ستنتقل قيمة النص مباشرةً إلى العميل الذي يسمى Gateway API. بالإضافة إلى ذلك ، تحتوي لقطة الشاشة على خصائص المكالمة: وقت التنفيذ ، ووقت التنفيذ الذي سندفع مقابله ، والحد الأقصى من الذاكرة التي استهلكتها لامدا. بالاعتماد على هذه المقاييس ، يمكننا تكوين الحجم الأمثل للذاكرة بحيث تطابق لامدا متطلبات السعر / معدل الاستجابة.
موارد البوابة



استخدام وحدة تحكم AWS لاختبار نشر الكناري


الآن دعنا نتطرق إلى نقطة واحدة مهمة تتعلق بنشر نسخة جديدة من لامدا. لقد حددت هذه المعلمات عندما كتبت قالب SAM:
AutoPublishAlias: live
DeploymentPreference:
  Type: Canary10Percent10Minutes

المعلمة الأولى تلقائيا بإضافة اسم مستعار تعيش إلى كل نسخة جديدة من امدا .
قليلا عن الأسماء المستعارة
, . , , API Gateway. 1, 2, 3 . LATEST, . 2 3 API Gateway (Stage AWS), Gateway-Lambda. API Gateway (ARN ), LATEST.

— ( ), , , ARN . , Stage API Gateway . , API Gateway: dev, qa prod .

, , . , . , live, . live- , , , , CloudWatch.


لاختبار نشر الكناري ، يمكنك استخدام كل من وحدة تحكم واجهة برمجة تطبيقات Gateway ووحدة تحكم Lambda.

تحتاج أولاً إلى تغيير رمز لامدا بحيث يعيد إجابة مختلفة. على سبيل المثال ، في معالجة الإحماء ، حدد الإصدار 2 بدلاً من الإصدار 1 في الاستجابة. سيكون هذا هو العلامة الخاصة بنا.

الآن ، باستخدام وظيفة واجهة برمجة التطبيقات لاختبار البوابة ، يمكننا التأكد من أنه في غضون عشر دقائق عند إرسال طلبات WARM-UP ، سيكون 10٪ فقط من الردود يحتوي على الإصدار 2 في نص الاستجابة. بعد هذا الوقت ، سيعيد الإصدار 2 100٪ من الطلبات.

بالإضافة إلى وحدة تحكم Gateway API ، يمكننا استخدام وحدة تحكم Lambda ، حيث بعد تحديد الاسم المستعار الضروري ، نرى سياسة توزيع حركة المرور التي يمكن التحكم فيها.
الاسم المستعار لامدا



2. التنمية المحلية باستخدام SAM-CLI


منذ بعض الوقت ، كان أحد العيوب الرئيسية لاستخدام لامدا يعتبر مزعجًا في التطوير والاختبار على الجهاز المحلي. الآن تغير الوضع كثيرًا: ظهر إطار SAM ، والذي لا يسمح فقط بجمع الحلول ونشرها ، بل يبسط أيضًا التنمية المحلية.

على سبيل المثال ، يمكنك استدعاء لامدا الخاص بك مباشرة من وحدة التحكم:
sam local invoke -e ./events/warm_up_request.json ContactUsFunction

يتم تشغيل هذا الأمر من الدليل بقالب SAM وينقل محتويات ملف JSON إلى مدخلات ContactUsFunction لامدا (هذا هو الاسم المنطقي في القالب).

أي ، باستخدام هذا الأمر ، تقوم SAM برفع الصورة lambci / lambda: java11 في عامل الميناء ، وتشغيل التعليمات البرمجية الخاصة بك فيه. للوصول إلى الخدمات عن بعد ، مثل SES ، يتم استخدام تكوين AWS الخاص بك مع مفتاح سر / وصول ، لذلك يجب أن يكون محدثًا. نقطة أخرى مهمة: إذا لم تقم بإضافة رأس لوضع الإحماء ، فسيتم استدعاء خدمات AWS SES و DynamoDB الحقيقية.

سجل المكالمات هنا
F:\aws\projects\contact-us-sam-app>sam local invoke -e ./events/warm_up_request.json ContactUsFunction
Invoking com.gralll.sam.App::handleRequest (java11)
Fetching lambci/lambda:java11 Docker container image......
Mounting F:\aws\projects\contact-us-sam-app\.aws-sam\build\ContactUsFunction as /var/task:ro,delegated inside runtime container
?[32mSTART RequestId: a86d65fa-1f19-15c5-93b8-d87631c80ee2 Version: $LATEST?[0m
2020-01-06 19:09:17 a86d65fa-1f19-15c5-93b8-d87631c80ee2 INFO  App - Request was received
2020-01-06 19:09:17 a86d65fa-1f19-15c5-93b8-d87631c80ee2 DEBUG App - {
  "body" : "{\"subject\": \"Question\",\"question\": \"How much does it cost\",\"username\": \"Alex\",\"phone\": \"+79999999999\",\"email\": \"alex@gmail.com\"}",
  "resource" : "/{proxy+}",
  "requestContext" : {
    "resourceId" : "123456",
    "apiId" : "1234567890",
    "resourcePath" : "/{proxy+}",
    "httpMethod" : "POST",
    "requestId" : "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
    "extendedRequestId" : null,
    "accountId" : "123456789012",
    "identity" : {
      "apiKey" : null,
      "apiKeyId" : null,
      "userArn" : null,
      "cognitoAuthenticationType" : null,
      "caller" : null,
      "userAgent" : "Custom User Agent String",
      "user" : null,
      "cognitoIdentityPoolId" : null,
      "cognitoIdentityId" : null,
      "cognitoAuthenticationProvider" : null,
      "sourceIp" : "127.0.0.1",
      "accountId" : null,
      "accessKey" : null
    },
    "authorizer" : null,
    "stage" : "prod",
    "path" : "/prod/path/to/resource",
    "protocol" : "HTTP/1.1",
    "requestTime" : "09/Apr/2015:12:34:56 +0000",
    "requestTimeEpoch" : 1428582896000,
    "elb" : null
  },
  "multiValueQueryStringParameters" : { },
  "multiValueHeaders" : {
    "X-WARM-UP" : [ "13" ]
  },
  "pathParameters" : {
    "proxy" : "/path/to/resource"
  },
  "httpMethod" : "POST",
  "stageVariables" : {
    "baz" : "qux"
  },
  "path" : "/path/to/resource",
  "isBase64Encoded" : false,
  "requestSource" : "API_GATEWAY"
}
2020-01-06 19:09:17 a86d65fa-1f19-15c5-93b8-d87631c80ee2 INFO  App - Lambda was warmed up
?[32mEND RequestId: a86d65fa-1f19-15c5-93b8-d87631c80ee2?[0m
?[32mREPORT RequestId: a86d65fa-1f19-15c5-93b8-d87631c80ee2     Init Duration: 1984.55 ms       Duration: 42.22 ms      Billed Duration: 100 ms Memory Size: 256 MB     Max Memory Used: 102 MB ?[0m
{"statusCode":201,"multiValueHeaders":{"Access-Control-Allow-Origin":["*"]},"body":{"response":"Lambda was warmed up. V1"},"isBase64Encoded":false}


بالإضافة إلى سجل لامدا ، تتم كتابة معلومات الخدمة المتعلقة بحالة المكالمة والاستجابة بتنسيق JSON إلى وحدة التحكم.

يمكن تشغيل Gateway API ، مثل lambda ، محليًا.
نقوم بتنفيذ الأمر:
sam local start-api

سجل وحدة التحكم عند بدء التشغيل
F:\aws\projects\contact-us-sam-app>sam local start-api
Mounting ContactUsFunction at http://127.0.0.1:3000/contact [POST, OPTIONS]
You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
2020-01-06 22:20:30  * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)


بعد بدء تشغيل الخادم ، يمكننا تنفيذ الطلبات. سأستخدم Postman وأرسل طلبًا لتدفئة لامدا.

في وحدة التحكم نرى
Invoking com.gralll.sam.App::handleRequest (java11)
Fetching lambci/lambda:java11 Docker container image......
Mounting F:\aws\projects\contact-us-sam-app\.aws-sam\build\ContactUsFunction as /var/task:ro,delegated inside runtime container
?[32mSTART RequestId: 27868750-3637-1f80-3d80-53a724da16ef Version: $LATEST?[0m
2020-01-06 19:28:09 27868750-3637-1f80-3d80-53a724da16ef INFO  App - Request was received
2020-01-06 19:28:09 27868750-3637-1f80-3d80-53a724da16ef DEBUG App - {
  "body" : "{\r\n  \"subject\": \"Question\",\r\n  \"question\": \"How much does it cost\",\r\n  \"username\": \"Alex\",\r\n  \"phone\": \"+79999999999\",\r\n  \"email\": \"alex@gmail.com\"\r\n}",
  "resource" : "/contact",
  "requestContext" : {
    "resourceId" : "123456",
    "apiId" : "1234567890",
    "resourcePath" : "/contact",
    "httpMethod" : "POST",
    "requestId" : "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
    "extendedRequestId" : null,
    "accountId" : "123456789012",
    "identity" : {
      "apiKey" : null,
      "apiKeyId" : null,
      "userArn" : null,
      "cognitoAuthenticationType" : null,
      "caller" : null,
      "userAgent" : "Custom User Agent String",
      "user" : null,
      "cognitoIdentityPoolId" : null,
      "cognitoIdentityId" : null,
      "cognitoAuthenticationProvider" : null,
      "sourceIp" : "127.0.0.1",
      "accountId" : null,
      "accessKey" : null
    },
    "authorizer" : null,
    "stage" : "Prod",
    "path" : "/contact",
    "protocol" : null,
    "requestTime" : null,
    "requestTimeEpoch" : 0,
    "elb" : null
  },
  "multiValueQueryStringParameters" : null,
  "multiValueHeaders" : {
    "Accept" : [ "application/json" ],
    "Accept-Encoding" : [ "gzip, deflate, br" ],
    "Accept-Language" : [ "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7" ],
    "Cache-Control" : [ "no-cache" ],
    "Connection" : [ "keep-alive" ],
    "Content-Length" : [ "150" ],
    "Content-Type" : [ "text/plain;charset=UTF-8" ],
    "Host" : [ "127.0.0.1:3000" ],
    "Origin" : [ "chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop" ],
    "Postman-Token" : [ "5cadaccd-6fae-5bc2-b4ef-63900a1725ff" ],
    "Sec-Fetch-Mode" : [ "cors" ],
    "Sec-Fetch-Site" : [ "cross-site" ],
    "User-Agent" : [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36" ],
    "X-Forwarded-Port" : [ "3000" ],
    "X-Forwarded-Proto" : [ "http" ],
    "X-Warm-Up" : [ "123" ]
  },
  "pathParameters" : null,
  "httpMethod" : "POST",
  "stageVariables" : null,
  "path" : "/contact",
  "isBase64Encoded" : false,
  "requestSource" : "API_GATEWAY"
}
2020-01-06 19:28:09 27868750-3637-1f80-3d80-53a724da16ef INFO  App - Lambda was warmed up
?[32mEND RequestId: 27868750-3637-1f80-3d80-53a724da16ef?[0m
?[32mREPORT RequestId: 27868750-3637-1f80-3d80-53a724da16ef     Init Duration: 1951.87 ms       Duration: 42.91 ms      Billed Duration: 100 ms Memory Size: 256 MB     Max Memory Used: 102 MB ?[0m
2020-01-06 22:28:11 127.0.0.1 - - [06/Jan/2020 22:28:11] "POST /contact HTTP/1.1" 201 -


بالطبع ، لا يتم تنسيق السجلات بأفضل طريقة. نأمل أن يتم إصلاح هذا في المستقبل.

هام: عند تغيير رمز lambda ، ليس من الضروري إعادة تشغيل API. يكفي إعادة بناء لامدا باستخدام أمر بناء سام .
قليلا عن البق
Java- aws-serverless-java-container-core, : 502 . :
Invalid API Gateway Response Keys: {'base64Encoded'} in {'statusCode': 200, 'headers': {'Content-Type': 'text/plain'}, 'body': 'Hello World', 'base64Encoded': False} 

- , API Gateway AWS JsonProperty. 'isBase64Encoded' 'base64Encoded', , , . , Java- ContactUsProxyResponse AwsProxyRequest.



3. مكالمات محلية من IDEA


كل شيء موضح في الفقرة أعلاه هو وظيفة أداة SAM. يتم التحكم فيه من سطر الأوامر ويمكن دمجه في أي واجهة. هذا هو بالضبط ما تم القيام به في البرنامج المساعد لمجموعة أدوات IntelljIDEA AWS.

يضيف هذا البرنامج المساعد تكوينات إضافية لإطلاق لامدا مباشرة من IDE. هذا ما تبدو عليه نافذة التكوين. يجب عليك إما تحديد قالب مع وصف لامدا ، أو تكوين الإعدادات يدويًا. في الحالة الأولى ، سيتم أخذ مقدار الذاكرة واللغة الخاصة بالتجميع تلقائيًا من النموذج. في الحالة الثانية ، يمكنك تكوين كمية ذاكرة الوصول العشوائي بنفسك وإجراء حساب تقريبي للحد. يسمح لك مكون إضافي آخر بتشغيل التكوين مباشرة من نافذة محرر كود Java أو قالب yaml. لقطات الشاشة أدناه:











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


4. الاختبار


هنا نتحدث عن أنواع اختبارات لامداس. نظرًا لأنني استخدمت Java في المثال ، فستتضمن الاختبارات أيضًا أدوات قياسية إلى حد ما لاختبار الوحدة والتكامل: Junit 4 و Mockito و PowerMockito.

اختبارات الوحدة


لتغطية كود لامدا باختبارات الوحدة ، لا تحتاج إلى معرفة محددة. يكفي تطبيق ممارسات Java القياسية: قفل جميع التبعيات في الفصل ومحاولة اختبار جميع الحالات الممكنة لمعالجة الطلب.

لم أضيف كل سيناريوهات الاختبار واقتصرت على سيناريوهين إيجابيين وسيناريوهين سلبيين.

يتحقق الاختبار الإيجابي الأول من أنه في حالة وجود رأس X-WARM-UP ، فلن تكون هناك طلبات في DbService و EmailService. وتتحقق الحالة الثانية من أنه سيتم استدعاء هذه الخدمات إذا كان الطلب حقيقيًا. هذه أبسط الاختبارات ، وقد حذفت جزءًا من الشيكات فيها.

السيناريوهات السلبية هي التحقق من الاستجابة في حالة وجود خطأ في معالجة العميل أو الخادم.

اختبارات التكامل


بالنسبة لاختبارات التكامل ، قررت التحقق من DbService وعمله مع جدول DynamoDB.

في هذه الحالة ، استخدمت أداة Localstack . يوفر هذا الحل mokas المجاني لخدمات AWS التي تعمل كحاويات عامل ميناء.

لتثبيت هذا الحل ، فقط قم بتشغيل الأوامر:
pip install localstack
localstack start

أو يمكنك استخدام ملف إنشاء عامل الميناء .
تكوين عامل الميناء لرفع DynamoDB فقط
version: '2.1'
services:
  localstack:
    container_name: "${LOCALSTACK_DOCKER_NAME-localstack_main}"
    image: localstack/localstack
    ports:
      - "4567-4599:4567-4599"
      - "${PORT_WEB_UI-8080}:${PORT_WEB_UI-8080}"
    environment:
      - SERVICES=dynamodb
      - DEBUG=${DEBUG- }
      - DATA_DIR=${DATA_DIR- }
      - PORT_WEB_UI=${PORT_WEB_UI- }
      - LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR- }
      - KINESIS_ERROR_PROBABILITY=${KINESIS_ERROR_PROBABILITY- }
      - DOCKER_HOST=unix:///var/run/docker.sock
    volumes:
      - "${TMPDIR:-/tmp/localstack}:/tmp/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"


يقوم الأمر start برفع جميع خدمات AWS المتاحة افتراضيًا. لرفع DynamoDB على وجه التحديد ، ما عليك سوى تعيين متغير البيئة:
set SERVICES=dynamodb


هناك LocalstackTestRunner خاص بـ Junit يسمح لك ببدء الخدمات الضرورية باستخدام التكوين LocalstackDockerProperties .
ونتيجة لذلك ، تبدو كتابة اختبار DbService كما يلي:
  • أضف فوق فئة الاختبار.
    @RunWith(LocalstackTestRunner.class)
    @LocalstackDockerProperties(services = { "dynamodb" })
    

  • قم بإنشاء جدول
    جافا
    @Before
    public void setUp() {
        AmazonDynamoDB clientDynamoDB = TestUtils.getClientDynamoDB();
        dynamoDB = new DynamoDB(clientDynamoDB);
        dbService = new DbService(dynamoDB);
    
        dynamoDB.createTable(
                new CreateTableRequest()
                        .withTableName("ContactUsTable")
                        .withKeySchema(new KeySchemaElement("Id", KeyType.HASH))
                        .withAttributeDefinitions(new AttributeDefinition("Id", ScalarAttributeType.S))
                        .withProvisionedThroughput(new ProvisionedThroughput(10L, 10L)));
    }
                    


  • نحن نصف سيناريو الاختبار
    جافا
    // given
    ContactUsRequest contactUsRequest = new ContactUsRequest("subject", "name", "+79991234545", "123@mail.ru", "Qeustion");
    
    // when
    dbService.putContactUsRequest("123", contactUsRequest);
    
    // then
    Item item = dynamoDB.getTable("ContactUsTable").getItem(new PrimaryKey("Id", "123"));
    assertEquals(contactUsRequest.getSubject(), item.get("Subject"));
    assertEquals(contactUsRequest.getUsername(), item.get("Username"));
    assertEquals(contactUsRequest.getPhone(), item.get("Phone"));
    assertEquals(contactUsRequest.getEmail(), item.get("Email"));
    assertEquals(contactUsRequest.getQuestion(), item.get("Question"));
                  


  • لا تنس حذف الجدول بعد الاختبار.
    جافا
    @After
    public void tearDown() {
        dynamoDB.getTable("ContactUsTable").delete();
    }
                   



ونتيجة لذلك ، باستخدام Localstack ، نحصل على مجموعة واسعة إلى حد ما من نماذج AWS التي تسمح لك بمحاكاة عمل هذه الخدمات.

اختبارات E2E


لتشغيل سيناريوهات E2E ، من الأفضل رفع خدمات اختبار AWS خصيصًا لتشغيل الاختبارات ، إذا كانت هناك ، بالطبع ، مثل هذه الفرصة. يمكن القيام بذلك باستخدام قالب CloudFormation الاختياري ، حيث سيتم نسخ الموارد من القالب الرئيسي.

يمكن إجراء الاختبار عن طريق استدعاء لامدا من خلال AWS-CLI ومعالجة النتيجة باستخدام أي أداة متاحة. لا يزال بإمكانك إجراء مكالمة في اختبارات الوحدة ، ولكن دون إنشاء الغوغاء.

اختبارات الأداء


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

إذا كنت تريد تقييم الموارد اللازمة لامدا ، استخدم وحدة تحكم واجهة المستخدم وقم بإجراء بعض المكالمات التجريبية. بعد ذلك ، باستخدام المنطق والرياضيات الشائعة ، قم بتقييم مدى زيادة أداء لامدا اعتمادًا على كمية الموارد المتاحة.

لا تنسى CloudWatch. بمساعدتها ، يمكنك بناء لوحات تحكم إرشادية تمامًا وعلى أساسها تحديد معلمات لامدا والإنفاق الذي يمكنك تحمله.


5. تكلفة الحلول بدون خادم


يكون تقييم الحل دائمًا محددًا ، لأنك لا تحتاج فقط إلى مراعاة تكلفة مكالمة واحدة ، ولكن أيضًا حركة المرور الواردة / الصادرة ، وتكلفة التخزين المؤقت وتسجيل الدخول والمراقبة. إذا كنت تفكر في استخدام لامدا ، فحاول التنبؤ بالحمل الذي ستتعامل معه خدمتك.

إذا كانت هذه مكالمات فردية أو عملية ETL يتم تشغيلها كل بضع ساعات / أيام ، فمن المرجح أن تؤتي ثمرة لامدا. إذا كنت تتوقع تحميل عدة طلبات بحث في الثانية ، فتأكد من عمل تقدير دقيق.

فيما يلي أعطي تقديرات تقريبية لتكلفة لامدا وأرخص خادم EC2 ، حتى تفهم ما هي القيم المعنية: تم أخذ المعلمات التالية لامدا لحساب:




  • مهلة: 150 مللي ثانية
  • السعر: 0.00001667 دولارًا مقابل 1 غيغابايت-ثانية
  • الذاكرة: 256 ميجابايت

بالنسبة إلى EC2 t2.nano:

  • السعر: 4.75 دولار في الشهر
  • الذاكرة: 512 ميجابايت
  • vCPU: 1
  • الحمل الأقصى: 5٪ وحدة المعالجة المركزية في الشهر

لقد أخذت بيانات تحميل EC2 من هنا ، ووفقًا لهذه الحسابات ، يمكن للخادم المحدد أن يتحمل حمولة ثابتة تبلغ 0.3 طلبًا في الثانية. كلما زاد الحمل ، سيزداد وقت الاستجابة ، مما سيقلل من كفاءة هذا الخادم.

جميع هذه الحسابات مجردة تمامًا ولا تأخذ في الاعتبار العديد من العوامل: خصومات على دفعة مقدمة أو عدد كبير من الطلبات ، ووقت تنفيذ لامدا ، وما إلى ذلك. لكنهم يظهرون أنه مع حمولة أقل من طلب واحد في الثانية ، فإن تكلفة لامدا أقل من أرخص خادم EC2.

بالمناسبة ، لا تنس أن تضيف سعر ALB إلى سعر EC2 إذا كنت بحاجة إلى الاحتفاظ بالعديد من النسخ المتماثلة للتطبيق أو عناوين IP المرنة.


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

لا أدعي أنني خبير في مجال اختبار حلول Serverless ، ولكن بناءً على تجربتي الإيجابية الشخصية ، قررت إبراز النقاط الرئيسية في هذه المقالة. آمل أن تكون مفيدة لشخص ما ، وربما يمكن لبعضكم أن يكملني أو حتى يصلحوني ، وهو ما سأكون سعيدًا جدًا بشأنه.


روابط مفيدة



All Articles