Di chuyển từ hàng đợi công việc của App Engine để kéo công việc sang Cloud Pub/Sub (Mô-đun 19)

1. Tổng quan

Loạt lớp học lập trình Serverless Migration Station (hướng dẫn thực hành theo tốc độ của riêng bạn) và các video liên quan nhằm giúp các nhà phát triển Google Cloud không máy chủ hiện đại hoá các ứng dụng của họ bằng cách hướng dẫn họ thực hiện một hoặc nhiều quy trình di chuyển, chủ yếu là chuyển từ các dịch vụ cũ. Làm như vậy sẽ giúp ứng dụng của bạn dễ dàng di chuyển hơn, đồng thời mang đến cho bạn nhiều lựa chọn và sự linh hoạt hơn, cho phép bạn tích hợp và truy cập vào nhiều sản phẩm trên đám mây hơn, cũng như dễ dàng nâng cấp lên các bản phát hành ngôn ngữ mới hơn. Mặc dù ban đầu tập trung vào những người dùng Cloud sớm nhất, chủ yếu là các nhà phát triển App Engine (môi trường tiêu chuẩn), nhưng loạt bài này đủ rộng để bao gồm các nền tảng không máy chủ khác như Cloud FunctionsCloud Run, hoặc ở những nơi khác nếu có thể.

Mục đích của lớp học lập trình này là hướng dẫn nhà phát triển App Engine Python 2 cách di chuyển từ các tác vụ kéo của Hàng đợi tác vụ App Engine sang Cloud Pub/Sub. Ngoài ra, còn có một quy trình di chuyển ngầm từ App Engine NDB sang Cloud NDB để truy cập vào Datastore (chủ yếu được đề cập trong Mô-đun 2) cũng như một quy trình nâng cấp lên Python 3.

Trong Mô-đun 18, bạn sẽ tìm hiểu cách thêm việc sử dụng các tác vụ lấy trong ứng dụng. Trong mô-đun này, bạn sẽ lấy ứng dụng đã hoàn thành trong Mô-đun 18 và di chuyển việc sử dụng đó sang Cloud Pub/Sub. Những người sử dụng Hàng đợi tác vụ cho các tác vụ đẩy sẽ di chuyển sang Cloud Tasks và nên tham khảo các Mô-đun 7-9.

Bạn sẽ tìm hiểu cách

Bạn cần có

Khảo sát

Bạn sẽ sử dụng hướng dẫn này như thế nào?

Chỉ đọc qua Đọc và hoàn thành các bài tập

Bạn đánh giá thế nào về trải nghiệm của mình với Python?

Người mới bắt đầu Trung cấp Thành thạo

Bạn đánh giá thế nào về trải nghiệm khi sử dụng các dịch vụ của Google Cloud?

Người mới bắt đầu Trung cấp Thành thạo

2. Thông tin khái quát

Hàng đợi tác vụ App Engine hỗ trợ cả tác vụ đẩy và kéo. Để cải thiện khả năng di chuyển ứng dụng, Google Cloud đề xuất bạn di chuyển từ các dịch vụ cũ đi kèm (chẳng hạn như Hàng đợi tác vụ) sang các dịch vụ tương đương độc lập trên Cloud hoặc của bên thứ ba.

Các mô-đun 7-9 đề cập đến việc di chuyển tác vụ đẩy, trong khi các mô-đun 18-19 tập trung vào việc di chuyển tác vụ kéo. Mặc dù Cloud Tasks phù hợp hơn với các tác vụ đẩy của Hàng đợi tác vụ, nhưng Pub/Sub không tương tự như các tác vụ kéo của Hàng đợi tác vụ.

Pub/Sub có nhiều tính năng hơn so với chức năng kéo do Hàng đợi tác vụ cung cấp. Ví dụ: Pub/Sub cũng có chức năng push, tuy nhiên Cloud Tasks giống với các tác vụ push của Hàng đợi tác vụ hơn, nên chức năng push của Pub/Sub không thuộc bất kỳ Mô-đun di chuyển nào. Lớp học lập trình Mô-đun 19 này minh hoạ việc chuyển cơ chế xếp hàng từ hàng đợi kéo Hàng đợi tác vụ sang Pub/Sub cũng như di chuyển từ App Engine NDB sang Cloud NDB để truy cập vào Datastore, lặp lại quá trình di chuyển Mô-đùn 2.

Mặc dù mã của Mô-đun 18 được "quảng cáo" là một ứng dụng mẫu Python 2, nhưng bản thân nguồn này tương thích với cả Python 2 và 3, đồng thời vẫn giữ nguyên như vậy ngay cả sau khi di chuyển sang Cloud Pub/Sub (và Cloud NDB) trong Mô-đun 19.

Hướng dẫn này có các bước sau:

  1. Thiết lập/Công việc chuẩn bị
  2. Cập nhật cấu hình
  3. Sửa đổi mã xử lý ứng dụng

3. Thiết lập/Công việc chuẩn bị

Phần này giải thích cách:

  1. Thiết lập dự án trên đám mây
  2. Tải ứng dụng mẫu cơ sở
  3. (Triển khai lại) và xác thực ứng dụng cơ sở
  4. Bật các dịch vụ/API mới của Google Cloud

Các bước này đảm bảo bạn bắt đầu bằng mã đang hoạt động và mã đó đã sẵn sàng để di chuyển sang các dịch vụ đám mây.

1. Thiết lập dự án

Nếu bạn đã hoàn thành lớp học lập trình Mô-đun 18, hãy dùng lại chính dự án (và mã) đó. Ngoài ra, bạn có thể tạo một dự án hoàn toàn mới hoặc sử dụng lại một dự án hiện có khác. Đảm bảo dự án có một tài khoản thanh toán đang hoạt động và một ứng dụng App Engine đã bật. Tìm mã dự án vì bạn cần có mã này trong lớp học lập trình này, hãy sử dụng mã dự án bất cứ khi nào bạn gặp biến PROJECT_ID.

2. Tải ứng dụng mẫu cơ sở

Một trong những điều kiện tiên quyết là ứng dụng App Engine hoạt động ở Mô-đun 18, vì vậy, hãy hoàn thành lớp học lập trình của ứng dụng đó (nên dùng; đường liên kết ở trên) hoặc sao chép mã Mô-đun 18 từ kho lưu trữ. Dù bạn dùng mã của mình hay mã của chúng tôi, đây là nơi chúng ta sẽ bắt đầu ("START"). Lớp học lập trình này sẽ hướng dẫn bạn quy trình di chuyển, kết thúc bằng mã tương tự như mã trong thư mục kho lưu trữ Mô-đun 19 ("FINISH").

Bất kể bạn sử dụng ứng dụng Module 18 nào, thư mục sẽ có dạng như bên dưới, có thể có cả thư mục lib:

$ ls
README.md               appengine_config.py     queue.yaml              templates
app.yaml                main.py                 requirements.txt

3. (Triển khai lại) và xác thực ứng dụng cơ sở

Thực hiện các bước sau để triển khai ứng dụng Mô-đun 18:

  1. Xoá thư mục lib (nếu có) rồi chạy pip install -t lib -r requirements.txt để điền lại lib. Bạn có thể cần dùng pip2 nếu đã cài đặt cả Python 2 và 3 trên máy phát triển.
  2. Đảm bảo bạn đã cài đặtkhởi chạy công cụ dòng lệnh gcloud, đồng thời đã xem xét cách sử dụng công cụ này.
  3. (không bắt buộc) Đặt dự án trên Đám mây bằng gcloud config set project PROJECT_ID nếu bạn không muốn nhập PROJECT_ID cho mỗi lệnh gcloud mà bạn đưa ra.
  4. Triển khai ứng dụng mẫu bằng gcloud app deploy
  5. Xác nhận rằng ứng dụng chạy như mong đợi mà không gặp vấn đề. Nếu bạn đã hoàn thành lớp học lập trình Mô-đun 18, thì ứng dụng sẽ hiển thị những khách truy cập hàng đầu cùng với những lượt truy cập gần đây nhất (minh hoạ bên dưới). Nếu không, có thể sẽ không có số lượt truy cập nào để hiển thị.

b667551dcbab1a09.png

Trước khi di chuyển ứng dụng mẫu của Mô-đun 18, trước tiên, bạn phải bật các dịch vụ đám mây mà ứng dụng đã sửa đổi sẽ sử dụng.

4. Bật các dịch vụ/API mới của Google Cloud

Ứng dụng cũ sử dụng các dịch vụ đi kèm của App Engine mà không yêu cầu thiết lập bổ sung, nhưng các dịch vụ Cloud độc lập thì có, và ứng dụng đã cập nhật sẽ sử dụng cả Cloud Pub/Sub và Cloud Datastore (thông qua thư viện ứng dụng Cloud NDB). App Engine và cả hai API Cloud đều có hạn mức "Luôn miễn phí". Vì vậy, miễn là bạn không vượt quá những giới hạn đó, bạn sẽ không phải trả phí khi hoàn thành hướng dẫn này. Bạn có thể bật Cloud API từ Cloud Console hoặc từ dòng lệnh, tuỳ theo lựa chọn ưu tiên của bạn.

Trên Cloud Console

Chuyển đến trang Thư viện của Trình quản lý API (cho đúng dự án) trong Cloud Console, rồi tìm kiếm API Cloud Datastore và Cloud Pub/Sub bằng thanh tìm kiếm ở giữa trang:

c7a740304e9d35b.png

Nhấp vào nút Bật cho từng API riêng biệt – bạn có thể được nhắc cung cấp thông tin thanh toán. Ví dụ: đây là trang Thư viện API Cloud Pub/Sub:

1b6c0a2a73124f6b.jpeg

Từ dòng lệnh

Mặc dù việc bật API từ bảng điều khiển có thể cung cấp thông tin trực quan, nhưng một số người lại thích dòng lệnh. Phát lệnh gcloud services enable pubsub.googleapis.com datastore.googleapis.com để bật cả hai API cùng một lúc:

$ gcloud services enable pubsub.googleapis.com datastore.googleapis.com
Operation "operations/acat.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.

Bạn có thể được nhắc nhập thông tin thanh toán. Nếu muốn bật các Cloud API khác và muốn biết URI của các API đó, bạn có thể tìm thấy chúng ở cuối trang thư viện của mỗi API. Ví dụ: hãy quan sát pubsub.googleapis.com là "Tên dịch vụ" ở cuối trang Pub/Sub ngay phía trên.

Sau khi hoàn tất các bước này, dự án của bạn sẽ có thể truy cập vào các API. Giờ là lúc cập nhật ứng dụng để sử dụng các API đó.

4. Tạo tài nguyên Pub/Sub

Tóm tắt thứ tự của quy trình công việc Hàng đợi tác vụ trong Mô-đun 18:

  1. Mô-đun 18 đã dùng tệp queue.yaml để tạo một hàng đợi kéo có tên là pullq.
  2. Ứng dụng sẽ thêm các tác vụ vào hàng đợi kéo để theo dõi khách truy cập.
  3. Cuối cùng, các tác vụ sẽ được một worker xử lý trong một khoảng thời gian nhất định (1 giờ).
  4. Các tác vụ được thực thi để tính tổng số lượt truy cập gần đây.
  5. Các tác vụ sẽ bị xoá khỏi hàng đợi sau khi hoàn tất.

Bạn sẽ sao chép một quy trình tương tự bằng Pub/Sub. Phần tiếp theo giới thiệu thuật ngữ cơ bản về Pub/Sub, với 3 cách tạo tài nguyên Pub/Sub cần thiết.

Thuật ngữ Hàng đợi tác vụ App Engine (kéo) so với Cloud Pub/Sub

Để chuyển sang Pub/Sub, bạn cần điều chỉnh một chút về từ vựng. Dưới đây là các danh mục chính cùng với các thuật ngữ liên quan của cả hai sản phẩm. Ngoài ra, hãy xem hướng dẫn di chuyển có các nội dung so sánh tương tự.

  • Cấu trúc dữ liệu xếp hàng: Với Hàng đợi tác vụ, dữ liệu sẽ đi vào hàng đợi kéo; với Pub/Sub, dữ liệu sẽ đi vào các chủ đề.
  • Đơn vị dữ liệu trong hàng đợi: Tác vụ kéo bằng Hàng đợi tác vụ được gọi là thông báo bằng Pub/Sub.
  • Trình xử lý dữ liệu: Với Hàng đợi tác vụ, worker truy cập vào các tác vụ kéo; với Pub/Sub, bạn cần có các thuê bao/người đăng ký để nhận tin nhắn
  • Trích xuất dữ liệu: Cho thuê một tác vụ kéo cũng giống như kéo một thông báo từ một chủ đề (thông qua một thuê bao).
  • Dọn dẹp/hoàn thành: Xoá một việc cần làm trong Hàng đợi tác vụ khỏi hàng đợi kéo khi bạn hoàn tất tương tự như việc xác nhận một thông báo Pub/Sub

Mặc dù có thay đổi về sản phẩm trong hàng đợi, nhưng quy trình vẫn tương đối giống nhau:

  1. Thay vì hàng đợi kéo, ứng dụng này sử dụng một chủ đề có tên là pullq.
  2. Thay vì thêm các việc cần làm vào hàng đợi kéo, ứng dụng sẽ gửi thông báo đến một chủ đề (pullq).
  3. Thay vì một worker thuê các tác vụ từ hàng đợi kéo, một subscriber có tên là worker sẽ kéo các thông báo từ chủ đề pullq.
  4. Ứng dụng xử lý tải trọng thông báo, tăng số lượng khách truy cập trong Datastore.
  5. Thay vì xoá các tác vụ khỏi hàng đợi kéo, ứng dụng sẽ xác nhận các thông báo đã xử lý.

Với Hàng đợi tác vụ, quá trình thiết lập bao gồm việc tạo hàng đợi kéo. Với Pub/Sub, bạn cần tạo cả chủ đề và gói thuê bao để thiết lập. Trong Mô-đun 18, chúng ta đã xử lý queue.yaml bên ngoài quá trình thực thi ứng dụng; giờ đây, chúng ta phải làm điều tương tự với Pub/Sub.

Có 3 cách để tạo chủ đề và lượt đăng ký:

  1. Trên bảng điều khiển Cloud
  2. Từ dòng lệnh hoặc
  3. Từ mã (tập lệnh Python ngắn)

Chọn một trong các lựa chọn bên dưới và làm theo hướng dẫn tương ứng để tạo tài nguyên Pub/Sub.

Trên bảng điều khiển Cloud

Để tạo một chủ đề trên Cloud Console, hãy làm theo các bước sau:

  1. Chuyển đến trang Chủ đề Pub/Sub trên bảng điều khiển Cloud.
  2. Nhấp vào Tạo chủ đề ở trên cùng; một cửa sổ hộp thoại mới sẽ mở ra (xem hình bên dưới)
  3. Trong trường Topic ID (Mã nhận dạng chủ đề), hãy nhập pullq.
  4. Bỏ chọn tất cả các lựa chọn đã đánh dấu và chọn Khoá mã hoá do Google quản lý.
  5. Nhấp vào nút Tạo chủ đề.

Đây là giao diện của hộp thoại tạo chủ đề:

a05cfdbf64571ceb.png

Bây giờ, bạn đã có một chủ đề, bạn phải tạo một gói thuê bao cho chủ đề đó:

  1. Chuyển đến trang Gói thuê bao Pub/Sub trên bảng điều khiển Cloud.
  2. Nhấp vào Tạo gói thuê bao ở trên cùng (xem hình ảnh bên dưới).
  3. Nhập worker vào trường Mã nhận dạng gói thuê bao.
  4. Chọn pullq trong trình đơn thả xuống Chọn một chủ đề Cloud Pub/Sub, lưu ý đến "tên đường dẫn đủ điều kiện" của chủ đề đó, ví dụ: projects/PROJECT_ID/topics/pullq
  5. Đối với Loại phân phối, hãy chọn Kéo.
  6. Giữ nguyên tất cả các lựa chọn khác rồi nhấp vào nút Tạo.

Đây là giao diện của màn hình tạo gói thuê bao:

c5444375c20b0618.jpeg

Ngoài ra, bạn cũng có thể tạo một gói thuê bao trên trang Chủ đề. "Lối tắt" này có thể hữu ích cho bạn trong việc liên kết các chủ đề với gói thuê bao. Để tìm hiểu thêm về cách tạo gói thuê bao, hãy xem tài liệu này.

Từ dòng lệnh

Người dùng Pub/Sub có thể tạo chủ đề và gói thuê bao bằng các lệnh gcloud pubsub topics create TOPIC_IDgcloud pubsub subscriptions create SUBSCRIPTION_ID --topic=TOPIC_ID, tương ứng. Việc thực thi các lệnh này với TOPIC_IDpullqSUBSCRIPTION_IDworker sẽ dẫn đến kết quả sau cho dự án PROJECT_ID:

$ gcloud pubsub topics create pullq
Created topic [projects/PROJECT_ID/topics/pullq].

$ gcloud pubsub subscriptions create worker --topic=pullq
Created subscription [projects/PROJECT_ID/subscriptions/worker].

Ngoài ra, hãy xem trang này trong tài liệu Bắt đầu nhanh. Việc sử dụng dòng lệnh có thể đơn giản hoá quy trình làm việc khi các chủ đề và lượt đăng ký được tạo thường xuyên. Bạn có thể sử dụng các lệnh như vậy trong tập lệnh shell cho mục đích này.

Từ mã (tập lệnh Python ngắn)

Một cách khác để tự động hoá việc tạo chủ đề và gói thuê bao là sử dụng API Pub/Sub trong mã nguồn. Dưới đây là mã cho tập lệnh maker.py trong thư mục kho lưu trữ Mô-đun 19.

from __future__ import print_function
import google.auth
from google.api_core import exceptions
from google.cloud import pubsub

_, PROJECT_ID = google.auth.default()
TOPIC = 'pullq'
SBSCR = 'worker'
ppc_client = pubsub.PublisherClient()
psc_client = pubsub.SubscriberClient()
TOP_PATH = ppc_client.topic_path(PROJECT_ID, TOPIC)
SUB_PATH = psc_client.subscription_path(PROJECT_ID, SBSCR)

def make_top():
    try:
        top = ppc_client.create_topic(name=TOP_PATH)
        print('Created topic %r (%s)' % (TOPIC, top.name))
    except exceptions.AlreadyExists:
        print('Topic %r already exists at %r' % (TOPIC, TOP_PATH))

def make_sub():
    try:
        sub = psc_client.create_subscription(name=SUB_PATH, topic=TOP_PATH)
        print('Subscription created %r (%s)' % (SBSCR, sub.name))
    except exceptions.AlreadyExists:
        print('Subscription %r already exists at %r' % (SBSCR, SUB_PATH))
    try:
        psc_client.close()
    except AttributeError:  # special Py2 handler for grpcio<1.12.0
        pass

make_top()
make_sub()

Việc thực thi tập lệnh này sẽ cho ra kết quả như mong đợi (miễn là không có lỗi):

$ python3 maker.py
Created topic 'pullq' (projects/PROJECT_ID/topics/pullq)
Subscription created 'worker' (projects/PROJECT_ID/subscriptions/worker)

Việc gọi API để tạo các tài nguyên đã tồn tại sẽ dẫn đến một ngoại lệ google.api_core.exceptions.AlreadyExists do thư viện ứng dụng gửi, được tập lệnh xử lý một cách suôn sẻ:

$ python3 maker.py
Topic 'pullq' already exists at 'projects/PROJECT_ID/topics/pullq'
Subscription 'worker' already exists at 'projects/PROJECT_ID/subscriptions/worker'

Nếu bạn mới sử dụng Pub/Sub, hãy xem Sách trắng về kiến trúc Pub/Sub để biết thêm thông tin chi tiết.

5. Cập nhật cấu hình

Các nội dung cập nhật trong cấu hình bao gồm cả việc thay đổi nhiều tệp cấu hình cũng như tạo nội dung tương đương với hàng đợi kéo của App Engine nhưng nằm trong hệ sinh thái Cloud Pub/Sub.

Xoá queue.yaml

Chúng tôi sẽ loại bỏ hoàn toàn Hàng đợi tác vụ, vì vậy, hãy xoá queue.yaml vì Pub/Sub không dùng tệp này. Thay vì tạo một hàng đợi kéo, bạn sẽ tạo một chủ đề Pub/Sub (và gói thuê bao).

requirements.txt

Nối cả google-cloud-ndbgoogle-cloud-pubsub vào requirements.txt để kết hợp flask từ Phụ lục 18. requirements.txt của Mô-đun 19 sau khi cập nhật sẽ có dạng như sau:

flask
google-cloud-ndb
google-cloud-pubsub

Tệp requirements.txt này không có số phiên bản, tức là các phiên bản mới nhất sẽ được chọn. Nếu có bất kỳ vấn đề không tương thích nào, hãy làm theo phương pháp tiêu chuẩn là sử dụng số phiên bản để khoá các phiên bản hoạt động cho một ứng dụng.

app.yaml

Những thay đổi đối với app.yaml sẽ khác nhau tuỳ thuộc vào việc bạn tiếp tục dùng Python 2 hay nâng cấp lên Python 3.

Python 2

Bản cập nhật trên cho requirements.txt bổ sung việc sử dụng thư viện ứng dụng Google Cloud. Những thư viện này cần có sự hỗ trợ bổ sung từ App Engine, cụ thể là một số thư viện tích hợp sẵn, setuptoolsgrpcio. Việc sử dụng các thư viện tích hợp sẵn yêu cầu phải có phần libraries trong app.yaml và số phiên bản thư viện hoặc "mới nhất" cho phiên bản mới nhất có trên máy chủ App Engine. Mô-đun 18 app.yaml chưa có một trong các phần đó:

TRƯỚC:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

Thêm một phần libraries vào app.yaml cùng với các mục nhập cho cả setuptoolsgrpcio, chọn phiên bản mới nhất của chúng. Ngoài ra, hãy thêm một mục giữ chỗ runtime cho Python 3, được nhận xét cùng với bản phát hành 3.x hiện tại, ví dụ: 3.10, tại thời điểm viết bài này. Với những thay đổi này, app.yaml hiện sẽ có dạng như sau:

SAU:

#runtime: python310
runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

libraries:
- name: setuptools
  version: latest
- name: grpcio
  version: latest

Python 3

Đối với người dùng Python 3 và app.yaml, tất cả đều là về việc xoá các thành phần. Trong phần này, bạn sẽ xoá phần handlers, các chỉ thị threadsafeapi_version, đồng thời không tạo phần libraries.

Các môi trường thời gian chạy thế hệ thứ hai không cung cấp các thư viện tích hợp sẵn của bên thứ ba, vì vậy, bạn không cần phần libraries trong app.yaml. Hơn nữa, bạn không cần phải sao chép (đôi khi còn gọi là cung cấp hoặc tự đóng gói) các gói không phải của bên thứ ba. Bạn chỉ cần liệt kê các thư viện của bên thứ ba mà ứng dụng của bạn sử dụng trong requirements.txt.

Phần handlers trong app.yaml dùng để chỉ định trình xử lý tệp tĩnh và ứng dụng (tập lệnh). Vì thời gian chạy Python 3 yêu cầu các khung web thực hiện định tuyến riêng, nên bạn phải thay đổi tất cả trình xử lý tập lệnh thành auto. Nếu ứng dụng của bạn (như Module 18) không phân phát các tệp tĩnh, thì tất cả các tuyến đường sẽ là auto, khiến chúng không liên quan. Do đó, bạn cũng không cần đến phần handlers, nên hãy xoá phần đó.

Cuối cùng, cả chỉ thị threadsafeapi_version đều không được dùng trong Python 3, vì vậy, hãy xoá cả hai chỉ thị này. Điểm mấu chốt là bạn nên xoá tất cả các phần của app.yaml để chỉ còn lại chỉ thị runtime, chỉ định một phiên bản Python 3 hiện đại, chẳng hạn như 3.10. Sau đây là giao diện của app.yaml trước và sau khi có những nội dung cập nhật này:

TRƯỚC:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

SAU:

runtime: python310

Đối với những người chưa sẵn sàng xoá mọi thứ khỏi app.yaml cho Python 3, chúng tôi đã cung cấp một tệp thay thế app3.yaml trong thư mục kho lưu trữ Mô-đun 19. Nếu bạn muốn sử dụng tệp này cho các hoạt động triển khai, hãy nhớ thêm tên tệp này vào cuối lệnh: gcloud app deploy app3.yaml (nếu không, tệp này sẽ mặc định và triển khai ứng dụng của bạn bằng tệp app.yaml Python 2 mà bạn không thay đổi).

appengine_config.py

Nếu đang nâng cấp lên Python 3, bạn không cần đến appengine_config.py nên có thể xoá thành phần hiển thị này. Lý do không cần thiết là vì tính năng hỗ trợ thư viện bên thứ ba chỉ yêu cầu bạn chỉ định các thư viện đó trong requirements.txt. Người dùng Python 2, hãy đọc tiếp.

appengine_config.py của Mô-đun 18 có mã phù hợp để hỗ trợ các thư viện bên thứ ba, ví dụ: Flask và các thư viện ứng dụng Cloud vừa được thêm vào requirements.txt:

TRƯỚC:

from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)

Tuy nhiên, chỉ mã này thôi là chưa đủ để hỗ trợ các thư viện tích hợp vừa được thêm (setuptools, grpcio). Bạn cần thêm một vài dòng nữa, vì vậy hãy cập nhật appengine_config.py để có dạng như sau:

SAU:

import pkg_resources
from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
# Add libraries to pkg_resources working set to find the distribution.
pkg_resources.working_set.add_entry(PATH)

Bạn có thể xem thêm thông tin chi tiết về những thay đổi cần thiết để hỗ trợ các thư viện ứng dụng Cloud trong tài liệu về việc di chuyển các dịch vụ đi kèm.

Các nội dung cập nhật khác về cấu hình

Nếu bạn có thư mục lib, hãy xoá thư mục đó. Nếu bạn là người dùng Python 2, hãy bổ sung thư mục lib bằng cách đưa ra lệnh sau:

pip install -t lib -r requirements.txt  # or pip2

Nếu đã cài đặt cả Python 2 và 3 trên hệ thống phát triển, bạn có thể cần dùng pip2 thay vì pip.

6. Sửa đổi mã xử lý ứng dụng

Phần này có các nội dung cập nhật cho tệp ứng dụng chính, main.py, thay thế việc sử dụng hàng đợi kéo của Hàng đợi tác vụ App Engine bằng Cloud Pub/Sub. Không có thay đổi nào đối với mẫu trang web templates/index.html. Cả hai ứng dụng đều hoạt động giống hệt nhau và hiển thị cùng một dữ liệu.

Cập nhật các hoạt động nhập và khởi tạo

Có một số điểm cập nhật đối với hoạt động nhập và khởi tạo:

  1. Đối với các hoạt động nhập, hãy thay thế App Engine NDB và Hàng đợi tác vụ bằng Cloud NDB và Pub/Sub.
  2. Đổi tên pullq từ tên QUEUE thành tên TOPIC.
  3. Với các tác vụ kéo, nhân viên thuê chúng trong một giờ, nhưng với Pub/Sub, thời gian chờ được đo lường trên cơ sở từng thông báo, vì vậy, hãy xoá hằng số HOUR.
  4. Cloud APIs yêu cầu sử dụng một ứng dụng khách API, vì vậy, hãy khởi tạo các API đó cho Cloud NDB và Cloud Pub/Sub, trong đó Cloud Pub/Sub cung cấp ứng dụng khách cho cả chủ đề và gói thuê bao.
  5. Pub/Sub yêu cầu mã dự án trên đám mây, vì vậy, hãy nhập và lấy mã này từ google.auth.default().
  6. Pub/Sub yêu cầu "tên đường dẫn đủ điều kiện" cho các chủ đề và gói thuê bao, vì vậy, hãy tạo các tên đường dẫn đó bằng cách sử dụng các hàm tiện ích *_path().

Dưới đây là các hoạt động nhập và khởi tạo từ Mô-đun 18, sau đó là cách các phần sẽ xuất hiện sau khi triển khai các thay đổi ở trên, trong đó hầu hết mã mới là các tài nguyên Pub/Sub:

TRƯỚC:

from flask import Flask, render_template, request
from google.appengine.api import taskqueue
from google.appengine.ext import ndb

HOUR = 3600
LIMIT = 10
TASKS = 1000
QNAME = 'pullq'
QUEUE = taskqueue.Queue(QNAME)
app = Flask(__name__)

SAU:

from flask import Flask, render_template, request
import google.auth
from google.cloud import ndb, pubsub

LIMIT = 10
TASKS = 1000
TOPIC = 'pullq'
SBSCR = 'worker'

app = Flask(__name__)
ds_client  = ndb.Client()
ppc_client = pubsub.PublisherClient()
psc_client = pubsub.SubscriberClient()
_, PROJECT_ID = google.auth.default()
TOP_PATH = ppc_client.topic_path(PROJECT_ID, TOPIC)
SUB_PATH = psc_client.subscription_path(PROJECT_ID, SBSCR)

Truy cập vào phần cập nhật mô hình dữ liệu

Mô hình dữ liệu Visit không thay đổi. Để truy cập vào Datastore, bạn cần sử dụng rõ ràng trình quản lý bối cảnh ứng dụng Cloud NDB API, ds_client.context(). Trong mã, điều này có nghĩa là bạn sẽ bao bọc các lệnh gọi Datastore trong cả store_visit()fetch_visits() bên trong các khối with của Python. Bản cập nhật này giống hệt với nội dung trong Mô-đun 2.

Thay đổi phù hợp nhất đối với Pub/Sub là thay thế việc xếp hàng một tác vụ kéo Hàng đợi tác vụ bằng việc xuất bản một thông báo Pub/Sub cho chủ đề pullq. Dưới đây là mã trước và sau khi thực hiện những nội dung cập nhật này:

TRƯỚC:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)

def store_visit(remote_addr, user_agent):
    'create new Visit in Datastore and queue request to bump visitor count'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
    QUEUE.add(taskqueue.Task(payload=remote_addr, method='PULL'))

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)

SAU:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)

def store_visit(remote_addr, user_agent):
    'create new Visit in Datastore and queue request to bump visitor count'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
    ppc_client.publish(TOP_PATH, remote_addr.encode('utf-8'))

def fetch_visits(limit):
    'get most recent visits'
    with ds_client.context():
        return Visit.query().order(-Visit.timestamp).fetch(limit)

Nội dung cập nhật về mô hình dữ liệu VisitorCount

Mô hình dữ liệu VisitorCount không thay đổi và không fetch_counts(), ngoại trừ việc bao bọc truy vấn Datastore bên trong một khối with, như minh hoạ dưới đây:

TRƯỚC:

class VisitorCount(ndb.Model):
    visitor = ndb.StringProperty(repeated=False, required=True)
    counter = ndb.IntegerProperty()

def fetch_counts(limit):
    'get top visitors'
    return VisitorCount.query().order(-VisitorCount.counter).fetch(limit)

SAU:

class VisitorCount(ndb.Model):
    visitor = ndb.StringProperty(repeated=False, required=True)
    counter = ndb.IntegerProperty()

def fetch_counts(limit):
    'get top visitors'
    with ds_client.context():
        return VisitorCount.query().order(-VisitorCount.counter).fetch(limit)

Cập nhật mã worker

Mã worker cập nhật trong phạm vi thay thế NDB bằng Cloud NDB và Task Queue bằng Pub/Sub, nhưng quy trình của mã này vẫn giữ nguyên.

  1. Bao bọc các lệnh gọi Datastore trong khối trình quản lý ngữ cảnh Cloud NDB with.
  2. Dọn dẹp Hàng đợi tác vụ bao gồm việc xoá tất cả các tác vụ khỏi hàng đợi kéo. Với Pub/Sub, "mã nhận dạng xác nhận" được thu thập trong acks rồi bị xoá/xác nhận ở cuối.
  3. Các tác vụ kéo của Hàng đợi tác vụ được cho thuê theo cách tương tự như các thông báo Pub/Sub được kéo. Mặc dù việc xoá các tác vụ kéo được thực hiện bằng chính các đối tượng tác vụ, nhưng các thông báo Pub/Sub sẽ bị xoá thông qua mã nhận dạng xác nhận của chúng.
  4. Tải trọng thông báo Pub/Sub yêu cầu byte (không phải chuỗi Python), vì vậy, có một số hoạt động mã hoá và giải mã UTF-8 khi xuất bản và kéo thông báo từ một chủ đề, tương ứng.

Thay thế log_visitors() bằng đoạn mã đã cập nhật bên dưới để triển khai những thay đổi vừa mô tả:

TRƯỚC:

@app.route('/log')
def log_visitors():
    'worker processes recent visitor counts and updates them in Datastore'
    # tally recent visitor counts from queue then delete those tasks
    tallies = {}
    tasks = QUEUE.lease_tasks(HOUR, TASKS)
    for task in tasks:
        visitor = task.payload
        tallies[visitor] = tallies.get(visitor, 0) + 1
    if tasks:
        QUEUE.delete_tasks(tasks)

    # increment those counts in Datastore and return
    for visitor in tallies:
        counter = VisitorCount.query(VisitorCount.visitor == visitor).get()
        if not counter:
            counter = VisitorCount(visitor=visitor, counter=0)
            counter.put()
        counter.counter += tallies[visitor]
        counter.put()
    return 'DONE (with %d task[s] logging %d visitor[s])\r\n' % (
            len(tasks), len(tallies))

SAU:

@app.route('/log')
def log_visitors():
    'worker processes recent visitor counts and updates them in Datastore'
    # tally recent visitor counts from queue then delete those tasks
    tallies = {}
    acks = set()
    rsp = psc_client.pull(subscription=SUB_PATH, max_messages=TASKS)
    msgs = rsp.received_messages
    for rcvd_msg in msgs:
        acks.add(rcvd_msg.ack_id)
        visitor = rcvd_msg.message.data.decode('utf-8')
        tallies[visitor] = tallies.get(visitor, 0) + 1
    if acks:
        psc_client.acknowledge(subscription=SUB_PATH, ack_ids=acks)
    try:
        psc_client.close()
    except AttributeError:  # special handler for grpcio<1.12.0
        pass

    # increment those counts in Datastore and return
    if tallies:
        with ds_client.context():
            for visitor in tallies:
                counter = VisitorCount.query(VisitorCount.visitor == visitor).get()
                if not counter:
                    counter = VisitorCount(visitor=visitor, counter=0)
                    counter.put()
                counter.counter += tallies[visitor]
                counter.put()
    return 'DONE (with %d task[s] logging %d visitor[s])\r\n' % (
            len(msgs), len(tallies))

Không có thay đổi nào đối với trình xử lý ứng dụng chính root(). Bạn cũng không cần thay đổi tệp mẫu HTML templates/index.html. Như vậy là bạn đã hoàn tất mọi nội dung cập nhật cần thiết. Chúc mừng bạn đã đến được ứng dụng Mô-đun 19 mới bằng Cloud Pub/Sub!

7. Tóm tắt/Dọn dẹp

Triển khai ứng dụng để xác minh rằng ứng dụng hoạt động như dự kiến và trong mọi đầu ra được phản ánh. Ngoài ra, hãy chạy worker để xử lý số lượt truy cập. Sau khi xác thực ứng dụng, hãy thực hiện mọi bước dọn dẹp và cân nhắc các bước tiếp theo.

Triển khai và xác minh ứng dụng

Đảm bảo bạn đã tạo chủ đề pullq và gói thuê bao worker. Nếu bạn đã hoàn tất bước này và ứng dụng mẫu đã sẵn sàng hoạt động, hãy triển khai ứng dụng bằng gcloud app deploy. Đầu ra sẽ giống hệt với ứng dụng trong Mô-đun 18, ngoại trừ việc bạn đã thay thế thành công toàn bộ cơ chế xếp hàng cơ bản:

b667551dcbab1a09.png

Giờ đây, giao diện người dùng web của ứng dụng sẽ xác minh phần này của ứng dụng. Mặc dù phần này của ứng dụng truy vấn và hiển thị thành công những khách truy cập hàng đầu và lượt truy cập gần đây nhất, nhưng hãy nhớ rằng ứng dụng sẽ đăng ký lượt truy cập này cùng với việc tạo một tác vụ kéo để thêm khách truy cập này vào tổng số lượt truy cập. Giờ đây, tác vụ đó nằm trong hàng đợi chờ xử lý.

Bạn có thể thực thi việc này bằng dịch vụ phụ trợ App Engine, một công việc cron, duyệt đến /log hoặc đưa ra yêu cầu HTTP dòng lệnh. Sau đây là một ví dụ về việc thực thi và gọi mã worker bằng curl (thay thế PROJECT_ID của bạn):

$ curl https://PROJECT_ID.appspot.com/log
DONE (with 1 task[s] logging 1 visitor[s])

Sau đó, số lượt truy cập đã cập nhật sẽ xuất hiện trong lần truy cập tiếp theo vào trang web. Vậy là xong!

Dọn dẹp

Giải pháp chung

Nếu đã hoàn tất, bạn nên tắt ứng dụng App Engine để tránh bị tính phí. Tuy nhiên, nếu muốn kiểm thử hoặc thử nghiệm thêm, nền tảng App Engine có một hạn mức miễn phí. Vì vậy, miễn là không vượt quá cấp sử dụng đó, bạn sẽ không bị tính phí. Đó là mức phí cho hoạt động tính toán, nhưng cũng có thể có các khoản phí cho các dịch vụ App Engine có liên quan. Vì vậy, hãy xem trang định giá của dịch vụ này để biết thêm thông tin. Nếu quá trình di chuyển này liên quan đến các dịch vụ đám mây khác, thì các dịch vụ đó sẽ được tính phí riêng. Trong cả hai trường hợp, nếu có, hãy xem phần "Cụ thể cho lớp học lập trình này" bên dưới.

Để công bố đầy đủ, việc triển khai trên một nền tảng điện toán không máy chủ của Google Cloud như App Engine sẽ phát sinh một khoản chi phí nhỏ cho việc tạo và lưu trữ. Cloud Build có hạn mức miễn phí riêng, tương tự như Cloud Storage. Việc lưu trữ hình ảnh đó sẽ chiếm một phần hạn mức. Tuy nhiên, có thể bạn sinh sống ở một khu vực không có gói miễn phí như vậy, vì vậy, hãy lưu ý đến mức sử dụng bộ nhớ để giảm thiểu chi phí phát sinh. Bạn nên xem xét các "thư mục" cụ thể trên Cloud Storage, bao gồm:

  • console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • Các đường liên kết đến bộ nhớ ở trên phụ thuộc vào PROJECT_ID và *LOC*của bạn, ví dụ: "us" nếu ứng dụng của bạn được lưu trữ ở Hoa Kỳ.

Mặt khác, nếu bạn không tiếp tục với ứng dụng này hoặc các lớp học lập trình di chuyển có liên quan khác và muốn xoá hoàn toàn mọi thứ, hãy tắt dự án của bạn.

Cụ thể đối với lớp học lập trình này

Các dịch vụ trong danh sách dưới đây là riêng biệt đối với lớp học lập trình này. Hãy tham khảo tài liệu của từng sản phẩm để biết thêm thông tin:

Các bước tiếp theo

Ngoài hướng dẫn này, bạn nên cân nhắc các mô-đun di chuyển khác tập trung vào việc chuyển từ các dịch vụ cũ đi kèm, bao gồm:

App Engine không còn là nền tảng duy nhất không cần máy chủ trên Google Cloud nữa. Nếu bạn có một ứng dụng App Engine nhỏ hoặc một ứng dụng có chức năng hạn chế và muốn biến ứng dụng đó thành một vi dịch vụ độc lập, hoặc bạn muốn chia một ứng dụng nguyên khối thành nhiều thành phần có thể dùng lại, thì đây là những lý do chính đáng để cân nhắc việc chuyển sang Cloud Functions. Nếu việc tạo vùng chứa đã trở thành một phần trong quy trình phát triển ứng dụng của bạn, đặc biệt là nếu quy trình này bao gồm một quy trình CI/CD (tích hợp liên tục/phân phối liên tục hoặc triển khai liên tục), hãy cân nhắc việc di chuyển sang Cloud Run. Các trường hợp này được đề cập trong các mô-đun sau:

  • Di chuyển từ App Engine sang Cloud Functions: xem Mô-đun 11
  • Di chuyển từ App Engine sang Cloud Run: xem Mô-đun 4 để đóng gói ứng dụng của bạn bằng Docker hoặc Mô-đùn 5 để thực hiện việc này mà không cần vùng chứa, kiến thức về Docker hoặc Dockerfile

Bạn không bắt buộc phải chuyển sang một nền tảng không máy chủ khác. Bạn nên cân nhắc những lựa chọn phù hợp nhất cho ứng dụng và trường hợp sử dụng của mình trước khi thực hiện bất kỳ thay đổi nào.

Bất kể bạn cân nhắc mô-đun di chuyển nào tiếp theo, bạn đều có thể truy cập vào tất cả nội dung của Serverless Migration Station (lớp học lập trình, video, mã nguồn [nếu có]) tại kho lưu trữ nguồn mở. README của kho lưu trữ này cũng cung cấp hướng dẫn về những hoạt động di chuyển cần cân nhắc và "thứ tự" liên quan của các Mô-đun di chuyển.

8. Tài nguyên khác

Dưới đây là các tài nguyên bổ sung dành cho những nhà phát triển muốn tìm hiểu thêm về Mô-đun di chuyển này hoặc các mô-đun di chuyển có liên quan, cũng như các sản phẩm có liên quan. Trong đó có những nơi để bạn gửi ý kiến phản hồi về nội dung này, đường liên kết đến mã và nhiều phần tài liệu mà bạn có thể thấy hữu ích.

Vấn đề/ý kiến phản hồi về Lớp học lập trình

Nếu bạn gặp vấn đề với lớp học lập trình này, vui lòng tìm kiếm vấn đề của bạn trước khi báo cáo. Đường liên kết để tìm kiếm và tạo vấn đề mới:

Tài nguyên di chuyển

Bạn có thể tìm thấy đường liên kết đến các thư mục kho lưu trữ cho Mô-đun 18 (BẮT ĐẦU) và Mô-đun 19 (KẾT THÚC) trong bảng bên dưới.

Lớp học lập trình

Python 2

Python 3

Mô-đun 18

code

(không áp dụng)

Mô-đun 19 (lớp học lập trình này)

code

(tương tự như Python 2, ngoại trừ việc sử dụng app3.yaml, trừ phi bạn đã cập nhật app.yaml như đã đề cập ở trên)

Tài liệu tham khảo trực tuyến

Dưới đây là các tài nguyên liên quan đến hướng dẫn này:

Hàng đợi tác vụ App Engine

Cloud Pub/Sub

App Engine NDB và Cloud NDB (Datastore)

Nền tảng App Engine

Thông tin khác về Cloud

Video

Giấy phép

Tác phẩm này được cấp phép theo giấy phép Ghi công theo Creative Commons 2.0 Chung.