Cách khắc phục sự cố Serverless API

cloudFun

blog-hero_troubleshooting-serverless-apis.png


Xây dựng API có thể coi là usecase phổ biến nhất đối với các kiến trúc Serverless. Có thể kết hợp dễ dàng API Gateway và AWS Lambda để tạo ra các API endpoints có tất cả các cơ sở hạ tầng quản lý tải và phục hồi sự cố cần thiết theo mặc định. Kết hợp điều đó với Serverless Framework và tạo chúng dễ dàng như sau:
Mã:
functions:
  myfunction:
    handler: myhandlerfile.myhandlerfunction
      events:
        - http:
          path: myendpoint
          method: get
Nhưng làm cách nào để debug và khắc phục sự cố API? CloudWatch trong AWS (có vẻ) sẽ cho phép truy cập dễ dàng vào Lambda log nhằm khởi động API Gateway logging. Nhưng điều này không cung cấp tất cả thông tin cần có nếu API gặp sự cố.

Đây gần như là toàn bộ lý do tại sao Serverless Framework Pro được tạo ra, như một cách giúp người dùng Serverless Framework theo dõi và debug các Serverless service; trong số đó API là sự cố đầu tiên cần được xử lý.

Nếu muốn biết cách kết nối một trong các service với bảng điều khiển, hãy đảm bảo phiên bản Serverless mới nhất đã được cài đặt (npm i -g serverless hoặc nếu đang sử dụng phiên bản nhị phân serverless upgrade) thì sau đó hãy chạy lệnh serverless trong cùng thư mục với service. Hướng dẫn thiết lập mọi thứ sẽ được đưa ra ngay sau đó.

Đăng nhập vào CloudWatch
Khi đang cố gắng debug thì cần có dữ liệu để giúp xác định nguyên nhân có thể gây ra vấn đề. Cách dễ nhất để làm điều đó là sử dụng phương pháp lưu lại các log của runtime khi cần thiết. Ví dụ: trong NodeJS Lambda, có thể biết được bất kỳ lỗi nào nếu có khi kết nối đến các AWS resource khác, chẳng hạn như DynamoDB. Code để chỉ ra lỗi trong trường hợp này sẽ như sau:
Mã:
const query = {
  TableName: process.env.DYNAMODB_USER_TABLE,
  KeyConditionExpression: '#id' = ':id',
  ExpressionAttributeNames: {
    '#id': id
  },
  ExpressionAttributeValues: {
    ':id':'someid'
  }
}
let result = {}
try {
  const dynamodb = new AWS.DynamoDB.DocumentClient()
  result = await dynamodb.query(userQuery).promise()
} catch (queryError) {
  console.log('There was an error attempting to retrieve the data')
  console.log('queryError', queryError)
  console.log('query', query)
  return new Error('There was an error retrieving the data: ' + queryError.message)
}
Như vậy, với sự sắp xếp này, nếu vì một lý do nào đó, truy vấn đến DynamoDB bị lỗi, nhìn vào log sẽ cho biết chính xác nguyên nhân. Mô hình tương tự có thể được áp dụng cho hầu hết các loại code có khả năng xảy ra lỗi trong khi chạy.

Giám sát tổng hợp
Trước khi có thể khắc phục bất kỳ lỗi cụ thể nào, thường thì rất khó để biết liệu lỗi nào xảy ra đầu tiên! Đặc biệt là khi đang làm việc với một hệ thống sản xuất hàng loạt, thật khó để biết liệu người dùng có gặp phải bất kỳ lỗi nào không và đây là lúc Serverless Framework Pro xuất hiện với màn hình tổng quan service.

Bằng cách nhìn vào các biểu đồ được cung cấp ở đây, có thể thấy ngay bất kỳ API request hoặc invoke Lambda nào bị trả về là lỗi và theo một cách nào đó đã ảnh hưởng đến người dùng, ngay cả khi chính họ còn không biết về nó.
Error+Visible.png


Với hình ảnh trên, không cần phải đợi người dùng khiếu nại hoặc báo cáo lỗi, có thể thấy ngay một số lỗi bắt đầu xảy ra vào khoảng 7 giờ tối. Nhưng nó không kết thúc ở đó. Sẽ tốt hơn nếu không bắt buộc người dùng phải xem những biểu đồ này, họ chỉ cần được thông báo nếu có chuyện gì xảy ra.

Bằng cách vào app settings và chọn notifications trong menu, có thể cài đặt để gửi thông báo đến email hoặc Slack, call webhook hoặc thậm chí gửi thông báo tới SNS để có thể có hàm Lambda của riêng mình, ví dụ, xử lý các thông báo như mong muốn.
NotificationsScreen.png


Có thể cài đặt cho mỗi service và theo từng giai đoạn và có nhiều cách thông báo như mong muốn; có thể dev đổi thành báo cáo qua email vì chúng không nghiêm trọng nhưng lỗi trong quá trình sản xuất luôn được thông báo trên kênh Slack cho cả nhóm biết.

Lấy chi tiết lỗi
Bây giờ đã có thể nhìn thấy và được thông báo lỗi, nên cần một số cách để giúp tìm ra lỗi là gì và cách khắc phục. Điều này một lần nữa trở nên tương đối dễ dàng nhờ Serverless Framework Pro.
SeeSomeErrors.png


Bắt đầu với một màn hình tổng quan như thế này và có thể thấy một số lỗi. Hãy click vào đó…

ErrorsList.png


Bây giờ có thể thấy một số thông tin tóm tắt về các lỗi trong khung thời gian đó. Hãy chọn trong một số đó để phân tích sâu hơn
StackTraceAndLogs.png


Kéo xuống một chút ở chế độ xem tiếp theo có thể thấy rằng Serverless Framework Pro cung cấp stack trace của dòng code có lỗi để có thể biết chính xác vị trí cần tìm. Nhờ có các dòng console.log , CloudWatch có thể hiển thị dữ liệu liên quan đến lỗi. (Trong trường hợp này lỗi được cố tình tạo ra cho mục đích làm demo, nhưng cũng áp dụng tương tự cho các lỗi thực tế).
LƯU Ý: CloudWatch log được lấy từ tài khoản AWS. Chúng không được lưu trữ ở bất cứ đâu trong Serverless Framework Pro, vì vậy khi mở chế độ xem chi tiết này, Serverless Framework Pro sẽ yêu cầu tài khoản AWS để có thể cập nhật log. Nếu xóa CloudWatch log khỏi tài khoản, nó sẽ không được hiển thị ở đây.

Phòng bệnh hơn chữa bệnh
Phần đầu đã cho biết cách phản ứng với các lỗi. Phần này sẽ đi sâu hơn vào những nguyên nhân có thể gây ra vấn đề sau này. Ví dụ: nếu có các hàm Lambda thường chạy trong một khoảng thời gian nhất định, trong khoảng từ 50 đến 100 ms, và đột nhiên có một sự tăng đột biến trong đó Lambdas đang chạy hơn 200ms, điều này có thể cho thấy một vấn đề tiềm ẩn; ví dụ, một số downstream provider đang gặp vấn đề và nếu nhận được một số cảnh báo trước thời hạn thì có thể giải quyết vấn đề đó ngay lập tức. Điều tương tự có thể áp dụng cho số lượng invoke. Thông thường danh sách các invoke Lambda rất đồng đều nhưng nếu có bất kỳ sự tăng đột biến nào trong các invoke thì đó là vấn đề cần chú ý.
Serverless Framework Pro đã tự động tạo cảnh báo và có thể chọn gửi thông báo về bằng hệ thống thông báo được hiển thị trước đó.

Điều chỉnh hiệu suất
Khắc phục sự cố không phải là tất cả khi nói về lỗi. Có thể cần phải đáp ứng các tiêu chí hiệu suất nhất định và Serverless Framework Pro cũng cung cấp các cách để đánh giá điều này.

Đánh giá thời gian thực hiện
Mỗi hàm Lambda có một set giá trị kích thước bộ nhớ. Nhưng cài đặt này không chỉ dành cho bộ nhớ và cũng ảnh hưởng đến việc phân bổ CPU và mạng theo cách tuyến tính; nếu tăng gấp đôi bộ nhớ, đông nghĩa với việc sẽ nhân đôi tác động đến CPU và mạng. Bằng cách nhấp qua phần functions trên menu bên trái, sau đó chọn một chức năng cụ thể, có thể xem thống kê thời lượng được thể hiện bằng các đường thẳng đứng đứt nét để deploy. Bây giờ có thể thấy ngay một thay đổi được thực hiện ảnh hưởng đến thời gian thực hiện trung bình của các invoke sau khi deploy.
RequestDurationDropped.png


Yêu cầu SDK và HTTP
Thông thường trong Lambda, cần yêu cầu các AWS service khác thông qua SDK AWS hoặc thậm chí các yêu cầu HTTP đối với các service bên thứ 3 khác và chúng có thể có tác động nhất định đến hiệu suất của các endpoints. Vì vậy, có thể đánh giá tác động này sẽ thực sự hữu ích.

Một lần nữa, Serverless Framework Pro cho phép điều tra việc này. Trong chế độ xem chi tiết của Lambda, phần spans sẽ cho biết nếu các yêu cầu gửi đi chậm hơn so với tiêu chuẩn. Giống như vấn đề với các service của bên thứ ba được đề cập ở trên, các span có thể thấy các yêu cầu mất bao lâu để được truyền đi và sau đó thực hiện hành động thích hợp.
SpansDynamoDB.png


Đẩy dữ liệu trong runtime
Tuy nhiên, không phải tất cả dữ liệu muốn xem đều dễ dàng nắm bắt như vậy. Đôi khi cần có khả năng phân tích các số liệu và dữ liệu chỉ có sẵn trong runtime. Đó là lý do tại sao Serverless Framework Pro SDK kết hợp một số tính năng để giúp theo dõi dữ liệu này dễ dàng hơn một chút. Theo mặc định, Serverless Framework Pro nạp chồng runtime trong context object và cung cấp một số chức năng bổ sung nhằm nắm bắt runtime data.

Tất cả các tùy chọn này được ghi lại trên trang web Serverless và bao gồm các tùy chọn cho runtime của Node và Python.

Capture Error
Có nhiều trường hợp muốn tìm hiểu về một lỗi tiềm ẩn nhưng không gửi lại kết quả lỗi cuối cùng khi người dùng thực hiện yêu cầu. Có thể sử dụng chức năng capture errors trong trường hợp này:
Mã:
if (context.hasOwnProperty('serverlessSdk')) {
  context.serverlessSdk.captureError('Could not put the user')
}
return {
    statusCode: 200,
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Credentials': true,
      'Access-Control-Allow-Headers': 'Authorization'
    }
  }
Như có thể thấy ở trên, chỉ đẩy một thông báo lỗi nhưng có 200 phản hồi trả về. Và bộ phận giám sát sẽ hiển thị nó như là một lỗi.
CapturedErrorsOnly.png


Capture Span
Có thể làm tương tự để bắt kỳ code nào tốn nhiều thời gian để thực thi. Có thể tách code đó trong tùy chỉnh span và xem hiệu suất của data được cung cấp:
Mã:
if(context.hasOwnProperty(‘serverlessSdk’)) {
  await context.serverlessSdk.span('HASH', async () => {
    return new Promise((resolve, reject) => {
      bcrypt.hash("ARANDMOMSTRING", 13, () => {
        resolve()
      })
    })
  })
}
Quá trình trên tạo ra span sau:
HashCustomSpan.png


Chỉ cần nhìn vào đó có thể thấy trọng tâm bất kỳ tối ưu hóa nào cần phải nằm trong khoảng HASH. Cố gắng tối ưu hóa cái khác sẽ không có ý nghĩa.

Capture Tag
Cuối cùng, có một cách để bắt các cặp khóa-giá trị từ các lệnh trong runtime được lọc trong chế độ xem trên trình duyệt. Xem ví dụ sau để hiểu rõ hơn.
Quy trình thanh toán được tạo ra để nắm bắt chi tiết thẻ tín dụng của người dùng và sau đó chuyển các chi tiết đó cho nhà cung cấp thanh toán bên thứ ba. Trong quá khứ rất nhiều người phải xây dựng các chức năng như vậy. Và thông thường những gì xảy ra là phản hồi, sau khi truyền những chi tiết đó, sẽ đưa ra kết quả thành công hay thất bại và giải thích tại sao nó thất bại như thiếu tiền, thẻ hết hạn, bị ngân hàng từ chối, v.v. Có thể gắn tag các trạng thái khác nhau để tìm kiếm dễ dàng hơn. Về cơ bản, nó cho phép truyền thông tin về khóa, giá trị và dữ liệu ngữ cảnh bổ sung nếu cần thiết:
Mã:
if (paymentProvider.status === ‘success’) {
  context.serverlessSdk.tagEvent('checkout-status', event.body.customerId, paymentProvider.response
  });
}
Điều này cho phép tìm tất cả các yêu cầu liên quan đến ID khách hàng cụ thể. Vì vậy nếu cần tìm nhật ký rất cụ thể từ nhà cung cấp thanh toán xử lý các chi tiết thẻ, có thể dễ dàng lọc theo ID khách hàng đó.

Nguồn: https://serverless.com/
 
Top