Mẹo & thủ thuật

Tài liệu này mô tả các phương pháp hay nhất để thiết kế, triển khai, thử nghiệm và triển khai Chức năng đám mây.

Tính đúng đắn

Phần này mô tả các phương pháp chung tốt nhất để thiết kế và triển khai Chức năng đám mây.

Viết hàm lũy thừa

Các hàm của bạn sẽ tạo ra kết quả tương tự ngay cả khi chúng được gọi nhiều lần. Điều này cho phép bạn thử lại lệnh gọi nếu lệnh gọi trước đó không thực hiện được giữa chừng mã của bạn. Để biết thêm thông tin, hãy xem thử lại các hàm hướng sự kiện .

Không bắt đầu các hoạt động nền

Hoạt động nền là bất cứ điều gì xảy ra sau khi chức năng của bạn kết thúc. Lệnh gọi hàm kết thúc sau khi hàm trả về hoặc báo hiệu sự hoàn thành, chẳng hạn như bằng cách gọi đối số callback trong các hàm hướng sự kiện của Node.js. Bất kỳ mã nào chạy sau khi chấm dứt nhẹ nhàng đều không thể truy cập vào CPU và sẽ không đạt được bất kỳ tiến triển nào.

Ngoài ra, khi lệnh gọi tiếp theo được thực thi trong cùng một môi trường, hoạt động nền của bạn sẽ tiếp tục, gây trở ngại cho lệnh gọi mới. Điều này có thể dẫn đến hành vi không mong muốn và lỗi khó chẩn đoán. Truy cập mạng sau khi một chức năng chấm dứt thường dẫn đến kết nối bị đặt lại (mã lỗi ECONNRESET ).

Hoạt động nền thường có thể được phát hiện trong nhật ký từ các lệnh gọi riêng lẻ, bằng cách tìm bất kỳ nội dung nào được ghi lại sau dòng cho biết lệnh gọi đã kết thúc. Hoạt động nền đôi khi có thể được ẩn sâu hơn trong mã, đặc biệt khi có các hoạt động không đồng bộ như lệnh gọi lại hoặc bộ tính giờ. Xem lại mã của bạn để đảm bảo tất cả các hoạt động không đồng bộ kết thúc trước khi bạn chấm dứt chức năng.

Luôn xóa các tập tin tạm thời

Bộ nhớ đĩa cục bộ trong thư mục tạm thời là một hệ thống tập tin trong bộ nhớ. Các tệp bạn viết sẽ tiêu tốn bộ nhớ khả dụng cho hàm của bạn và đôi khi vẫn tồn tại giữa các lần gọi. Việc không xóa rõ ràng các tệp này cuối cùng có thể dẫn đến lỗi hết bộ nhớ và khởi động nguội sau đó.

Bạn có thể xem bộ nhớ được sử dụng bởi một chức năng riêng lẻ bằng cách chọn bộ nhớ đó trong danh sách các chức năng trong Bảng điều khiển GCP và chọn biểu đồ Sử dụng bộ nhớ .

Đừng cố ghi ra ngoài thư mục tạm thời và đảm bảo sử dụng các phương pháp độc lập với nền tảng/HĐH để xây dựng đường dẫn tệp.

Bạn có thể giảm yêu cầu bộ nhớ khi xử lý các tệp lớn hơn bằng cách sử dụng đường ống. Ví dụ: bạn có thể xử lý tệp trên Cloud Storage bằng cách tạo luồng đọc, chuyển nó qua quy trình dựa trên luồng và ghi trực tiếp luồng đầu ra vào Cloud Storage.

Khung chức năng

Khi bạn triển khai một chức năng, Khung chức năng sẽ tự động được thêm dưới dạng phần phụ thuộc, sử dụng phiên bản hiện tại của chức năng đó. Để đảm bảo rằng các phần phụ thuộc giống nhau được cài đặt nhất quán trên các môi trường khác nhau, chúng tôi khuyên bạn nên ghim hàm của mình vào một phiên bản cụ thể của Khung chức năng.

Để thực hiện việc này, hãy đưa phiên bản ưa thích của bạn vào tệp khóa liên quan (ví dụ: package-lock.json cho Node.js hoặc requirements.txt cho Python).

Công cụ

Phần này cung cấp hướng dẫn về cách sử dụng các công cụ để triển khai, kiểm tra và tương tác với Chức năng đám mây.

Phát triển địa phương

Việc triển khai hàm mất một chút thời gian, do đó, việc kiểm tra mã hàm của bạn cục bộ thường nhanh hơn.

Các nhà phát triển Firebase có thể sử dụng Trình mô phỏng chức năng đám mây Firebase CLI .

Sử dụng Sendgrid để gửi email

Cloud Functions không cho phép kết nối gửi đi trên cổng 25, do đó bạn không thể tạo kết nối không an toàn với máy chủ SMTP. Cách gửi email được khuyến nghị là sử dụng SendGrid . Bạn có thể tìm thấy các tùy chọn khác để gửi email trong phần Hướng dẫn gửi email từ phiên bản dành cho Google Computing Engine.

Hiệu suất

Phần này mô tả các phương pháp hay nhất để tối ưu hóa hiệu suất.

Sử dụng sự phụ thuộc một cách khôn ngoan

Vì các hàm không có trạng thái nên môi trường thực thi thường được khởi tạo từ đầu (trong quá trình được gọi là khởi động nguội ). Khi khởi động nguội xảy ra, bối cảnh chung của hàm sẽ được đánh giá.

Nếu các hàm của bạn nhập mô-đun, thời gian tải cho các mô-đun đó có thể làm tăng thêm độ trễ của lệnh gọi trong quá trình khởi động nguội. Bạn có thể giảm độ trễ này cũng như thời gian cần thiết để triển khai hàm của mình bằng cách tải các phần phụ thuộc một cách chính xác và không tải các phần phụ thuộc mà hàm của bạn không sử dụng.

Sử dụng các biến toàn cục để tái sử dụng các đối tượng trong các lệnh gọi trong tương lai

Không có gì đảm bảo rằng trạng thái của Chức năng đám mây sẽ được giữ nguyên cho các yêu cầu trong tương lai. Tuy nhiên, Cloud Functions thường tái chế môi trường thực thi của lệnh gọi trước đó. Nếu bạn khai báo một biến trong phạm vi toàn cục, giá trị của nó có thể được sử dụng lại trong các lần gọi tiếp theo mà không cần phải tính toán lại.

Bằng cách này, bạn có thể lưu vào bộ nhớ đệm các đối tượng có thể tốn nhiều chi phí để tạo lại trên mỗi lần gọi hàm. Việc di chuyển các đối tượng như vậy từ phần thân hàm sang phạm vi toàn cục có thể mang lại những cải thiện hiệu suất đáng kể. Ví dụ sau chỉ tạo một đối tượng nặng một lần cho mỗi phiên bản hàm và chia sẻ nó trên tất cả các lệnh gọi hàm đến phiên bản đã cho:

Node.js

console.log('Global scope');
const perInstance = heavyComputation();
const functions = require('firebase-functions');

exports.function = functions.https.onRequest((req, res) => {
  console.log('Function invocation');
  const perFunction = lightweightComputation();

  res.send(`Per instance: ${perInstance}, per function: ${perFunction}`);
});

Python

import time

from firebase_functions import https_fn

# Placeholder
def heavy_computation():
  return time.time()

# Placeholder
def light_computation():
  return time.time()

# Global (instance-wide) scope
# This computation runs at instance cold-start
instance_var = heavy_computation()

@https_fn.on_request()
def scope_demo(request):

  # Per-function scope
  # This computation runs every time this function is called
  function_var = light_computation()
  return https_fn.Response(f"Instance: {instance_var}; function: {function_var}")
  

Hàm HTTP này nhận một đối tượng yêu cầu ( flask.Request ) và trả về văn bản phản hồi hoặc bất kỳ tập hợp giá trị nào có thể được chuyển thành đối tượng Response bằng cách sử dụng make_response .

Điều đặc biệt quan trọng là lưu trữ các kết nối mạng, tham chiếu thư viện và đối tượng máy khách API trong phạm vi toàn cầu. Xem Tối ưu hóa mạng để biết ví dụ.

Khởi tạo lười biếng các biến toàn cục

Nếu bạn khởi tạo các biến trong phạm vi toàn cục, mã khởi tạo sẽ luôn được thực thi thông qua lệnh gọi khởi động nguội, làm tăng độ trễ của hàm. Trong một số trường hợp nhất định, điều này gây ra hiện tượng hết thời gian chờ không liên tục đối với các dịch vụ được gọi nếu chúng không được xử lý thích hợp trong khối try / catch . Nếu một số đối tượng không được sử dụng trong tất cả các đường dẫn mã, hãy cân nhắc việc khởi tạo chúng một cách lười biếng theo yêu cầu:

Node.js

const functions = require('firebase-functions');
let myCostlyVariable;

exports.function = functions.https.onRequest((req, res) => {
  doUsualWork();
  if(unlikelyCondition()){
      myCostlyVariable = myCostlyVariable || buildCostlyVariable();
  }
  res.status(200).send('OK');
});

Python

from firebase_functions import https_fn

# Always initialized (at cold-start)
non_lazy_global = file_wide_computation()

# Declared at cold-start, but only initialized if/when the function executes
lazy_global = None

@https_fn.on_request()
def lazy_globals(request):

  global lazy_global, non_lazy_global

  # This value is initialized only if (and when) the function is called
  if not lazy_global:
      lazy_global = function_specific_computation()

  return https_fn.Response(f"Lazy: {lazy_global}, non-lazy: {non_lazy_global}.")
  

Hàm HTTP này sử dụng các giá trị toàn cục được khởi tạo một cách lười biếng. Nó nhận một đối tượng yêu cầu ( flask.Request ) và trả về văn bản phản hồi hoặc bất kỳ tập hợp giá trị nào có thể được chuyển thành đối tượng Response bằng cách sử dụng make_response .

Điều này đặc biệt quan trọng nếu bạn xác định một số hàm trong một tệp và các hàm khác nhau sử dụng các biến khác nhau. Trừ khi bạn sử dụng tính năng khởi tạo lười biếng, bạn có thể lãng phí tài nguyên cho các biến được khởi tạo nhưng không bao giờ được sử dụng.

Giảm khởi động nguội bằng cách đặt số lượng phiên bản tối thiểu

Theo mặc định, Cloud Functions chia tỷ lệ số lượng phiên bản dựa trên số lượng yêu cầu đến. Bạn có thể thay đổi hành vi mặc định này bằng cách đặt số lượng phiên bản tối thiểu mà Chức năng đám mây phải luôn sẵn sàng phân phát yêu cầu. Việc đặt số lượng phiên bản tối thiểu sẽ giúp giảm khả năng khởi động nguội ứng dụng của bạn. Chúng tôi khuyên bạn nên đặt số lượng phiên bản tối thiểu nếu ứng dụng của bạn nhạy cảm với độ trễ.

Xem Kiểm soát hành vi chia tỷ lệ để biết thêm thông tin về các tùy chọn thời gian chạy này.

Tài nguyên bổ sung

Tìm hiểu thêm về cách tối ưu hóa hiệu suất trong video "Google Cloud Performance Atlas" Chức năng đám mây Thời gian khởi động nguội .