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 về Trạm di chuyển không máy chủ (hướng dẫn thực hành theo tiến độ riêng) và video có liên quan nhằm giúp các nhà phát triển Google Cloud không máy chủ không 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 quá trình di chuyển, chủ yếu là ngừng sử dụng các dịch vụ cũ. Việc này giúp ứng dụng của bạn dễ di chuyển hơn, đồng thời mang đến cho bạn nhiều lựa chọn và độ 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 của Cloud hơn, đồng thời dễ dàng nâng cấp lên 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ó.

Mục đích của lớp học lập trình này là hướng dẫn các nhà phát triển App Engine sử dụng Python 2 cách di chuyển từ Hàng đợi tác vụ của App Engine (kéo các tác vụ) sang Cloud Pub/Sub. Ngoài ra còn có quá trình di chuyển ngầm từ App Engine NDB sang Cloud NDB để truy cập Datastore (chủ yếu được đề cập trong Mô-đun 2) cũng 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 tác vụ kéo trong ứng dụng. Trong mô-đun này, bạn sẽ sử dụng ứng dụng hoàn chỉnh của Mô-đun 18 và di chuyển dữ liệu sử dụng đó sang Cloud Pub/Sub. Những người sử dụng Hàng đợi công việc cho các tác vụ đẩy sẽ chuyển sang Cloud Tasks và nên tham khảo 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 bài tập

Bạn đánh giá thế nào về trải nghiệm sử dụng Python?

Người mới tập Trung cấp Thành thạo

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

Người mới tập Trung cấp Thành thạo

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

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

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

Pub/Sub có nhiều tính năng hơn chức năng lấy dữ liệu do Hàng đợi tác vụ cung cấp. Ví dụ: Pub/Sub cũng có chức năng đẩy, tuy nhiên, Cloud Tasks giống với các tác vụ đẩy vào Hàng đợi tác vụ, vì vậy tính năng đẩy Pub/Sub không được hỗ trợ trong Mô-đun di chuyển nào. Lớp học lập trình của Mô-đun 19 này minh hoạ cách chuyển đổi cơ chế xếp hàng từ Hàng đợi tác vụ (Task List) sang hàng đợi Pub/Sub cũng như di chuyển từ App Engine NDB sang Cloud NDB để truy cập Datastore, lặp lại quá trình di chuyển Mô-đun 2.

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

Hướng dẫn này bao gồm các bước sau:

  1. Thiết lập/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/Chuẩn bị

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

  1. Thiết lập dự án trên Cloud
  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 API/dịch vụ Google Cloud mới

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

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

Nếu bạn đã hoàn thành Lớp học lập trình của Mô-đun 18, hãy sử dụng lại chính dự án (và đoạn mã) đó. Ngoài ra, hãy 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. Hãy đảm bảo dự án này có một tài khoản thanh toán đang hoạt động và có một ứng dụng App Engine đã bật. Tìm mã dự án của bạn khi cần có sẵn trong lớp học lập trình này, sử dụng mã này 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 của Mô-đun 18 đang hoạt động, vì vậy, hãy hoàn thành lớp học lập trình của ứng dụng (đề xuất; đường liên kết ở trên) hoặc sao chép mã Mô-đun 18 từ kho lưu trữ. Cho dù bạn sử dụng tài khoản của bạn hay của chúng tôi, đây là nơi chúng tôi sẽ bắt đầu ("START"). Lớp học lập trình này sẽ hướng dẫn bạn thực hiện quá trình di chuyển, kết thúc bằng mã tương tự như những gì trong thư mục kho lưu trữ Mô-đun 19 ("Finish").

Bất kể bạn dùng ứng dụng Mô-đun 18 nào, thư mục đó sẽ có dạng như dưới đây, cũng 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 thi 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 phải sử dụng pip2 nếu đã cài đặt cả Python 2 và 3 trên máy phát triển.
  2. Hãy đảm bảo bạn đã cài đặtkhởi chạy công cụ dòng lệnh gcloud, đồng thời xem lại việc sử dụng công cụ này.
  3. (không bắt buộc) Thiết lập dự án trên Cloud bằng gcloud config set project PROJECT_ID nếu bạn không muốn nhập PROJECT_ID với mỗi lệnh gcloud 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 hoạt động như mong đợi mà không gặp vấn đề nào. Nếu bạn đã hoàn thành lớp học lập trình Mô-đun 18, ứng dụng sẽ hiển thị những khách truy cập hàng đầu cùng với các lượt truy cập gần đây nhất (minh hoạ bên dưới). Nếu không, có thể không có bất kỳ số lượng khách 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 API/dịch vụ Google Cloud mới

Ứng dụng cũ sử dụng các dịch vụ đi kèm của App Engine 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ó. Ứng dụng mới 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 Cloud API đều có "Luôn miễn phí" và miễn là bạn không phải trả các giới hạn đó, bạn sẽ không phải chịu phí khi hoàn thành hướng dẫn này. Tuỳ thuộc vào lựa chọn ưu tiên của bạn mà bạn có thể bật Cloud API từ Cloud Console hoặc bằng dòng lệnh.

Trên Cloud Console

Truy cập vào trang Thư viện của API Manager (để tìm đúng dự án) trong Cloud Console, rồi tìm các 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ù bảng điều khiển cung cấp nhiều thông tin về mặt hình ảnh, nhưng một số API lại thích dùng dòng lệnh hơn. Phát lệnh gcloud services enable pubsub.googleapis.com datastore.googleapis.com để bật cả hai API cùng 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 cung cấ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ể xem các URI đó ở cuối trang thư viện của mỗi API. Ví dụ: quan sát pubsub.googleapis.com là "Tên dịch vụ" ở cuối trang Pub/Sub ngay phía trên.

Sau khi các bước này hoàn tất, dự án của bạn sẽ có thể truy cập vào các API này. Đã đến 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 làm việc Hàng đợi tác vụ trong Mô-đun 18:

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

Bạn sẽ nhân bản quy trình làm việc tương tự với Pub/Sub. Phần tiếp theo giới thiệu các thuật ngữ cơ bản về Pub/Sub, cùng với ba cách khác nhau để tạo các tài nguyên Pub/Sub cần thiết.

Danh sách công việc của App Engine (kéo) so với thuật ngữ Cloud Pub/Sub

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

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

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

  1. Thay vì hàng đợi kéo, ứng dụng dùng một chủ đề có tên là pullq.
  2. Thay vì thêm công việc vào hàng đợi kéo, ứng dụng này sẽ gửi tin nhắn đến một chủ đề (pullq).
  3. Thay vì một worker thuê công việc từ hàng đợi kéo, một người đăng ký có tên worker lấy thông báo từ chủ đề pullq.
  4. Ứng dụng sẽ 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ông việc khỏi hàng đợi kéo, ứng dụng sẽ xác nhận các thông báo đã được xử lý.

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

Có ba cách để tạo chủ đề và gói thuê bao:

  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)

Hãy chọn một trong các cách bên dưới rồi 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ủ đề từ Cloud Console, hãy làm theo các bước sau:

  1. Truy cập vào trang Chủ đề Pub/Sub trên Cloud Console.
  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 ảnh dưới đây)
  3. Trong trường Mã chủ đề, hãy nhập pullq.
  4. Bỏ chọn tất cả các mục đã đánh dấu rồi chọn Khoá mã hoá do Google quản lý.
  5. Nhấp vào nút Tạo chủ đề.

Hộp thoại tạo chủ đề sẽ có dạng như sau:

a05cfdbf64571ceb.png

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

  1. Truy cập vào trang Gói thuê bao Pub/Sub của Cloud Console.
  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ã gói thuê bao.
  4. Chọn pullq trong danh sách kéo xuống Chọn chủ đề Cloud Pub/Sub, lưu ý rằng "tên đường dẫn đủ điều kiện" của nó ví dụ: projects/PROJECT_ID/topics/pullq
  5. Trong phần Loại gửi, hãy chọn Lấy.
  6. Giữ nguyên tất cả các tuỳ chọn khác rồi nhấp vào nút Create (Tạo).

Màn hình tạo gói thuê bao sẽ có giao diện như sau:

c5444375c20b0618.jpeg

Bạn cũng có thể tạo 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 giúp liên kết các chủ đề với các kênh đăng ký. Để 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 lệnh gcloud pubsub topics create TOPIC_IDgcloud pubsub subscriptions create SUBSCRIPTION_ID --topic=TOPIC_ID. Thực thi các thao tác này với TOPIC_ID của pullqSUBSCRIPTION_ID của worker sẽ dẫn đến kết quả sau đây 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 trong đó các chủ đề và gói thuê bao được tạo thường xuyên. Đồng thời, bạn có thể sử dụng các lệnh như vậy trong các 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ữ của 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ẽ mang lại kết quả dự kiến (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 đã có sẵn sẽ dẫn đến một ngoại lệ google.api_core.exceptions.AlreadyExists do thư viện ứng dụng gửi ra và được tập lệnh xử lý linh hoạt:

$ 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ề cấu 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 cập nhật về cấu hình bao gồm việc thay đổi nhiều tệp cấu hình cũng như tạo ra những hàng đợi tương đương với hàng đợi kéo của App Engine nhưng trong hệ sinh thái Cloud Pub/Sub.

Xoá hàng đợi.yaml

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

requirements.txt

Thêm cả google-cloud-ndbgoogle-cloud-pubsub vào requirements.txt để kết nối flask từ Mô-đun 18. requirements.txt Mô-đun 19 được cập nhật giờ đây 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 nào, nghĩa là các phiên bản mới nhất đã được chọn. Nếu phát sinh bất kỳ sự không tương thích nào, hãy thực hiện theo phương pháp tiêu chuẩn về sử dụng số phiên bản để cố định các phiên bản hoạt động của ứng dụng.

app.yaml

Những thay đổi đối với app.yaml còn tuỳ thuộc vào việc bạn dùng Python 2 hay nâng cấp lên Python 3.

Python 2

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

TRƯỚC KHI:

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 cho cả setuptoolsgrpcio rồi chọn phiên bản mới nhất. Ngoài ra, hãy thêm một mục giữ chỗ runtime cho Python 3, 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 giờ đây sẽ có dạng như sau:

SAU KHI:

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

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

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

Python

Đối với người dùng Python 3 và app.yaml, việc cần làm là xoá mọi thứ. Trong phần này, bạn sẽ xoá phần handlers, các lệnh threadsafeapi_version, nhưng sẽ không tạo phần libraries.

Môi trường thời gian chạy thế hệ thứ hai không cung cấp thư viện tích hợp sẵn của bên thứ ba, vì vậy, phần libraries không cần thiết trong app.yaml. Ngoài ra, bạn không cần phải sao chép (đôi khi gọi là nhà cung cấp hoặc tự nhóm) các gói bên thứ ba tích hợp sẵn nữa. 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 ứng dụng (tập lệnh) và trình xử lý tệp tĩnh. Vì môi trường 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 tất cả trình xử lý tập lệnh phải được thay đổi thành auto. Nếu ứng dụng của bạn (chẳng hạn như Mô-đun 18) không phân phát tệp tĩnh, thì tất cả các tuyến sẽ là auto, khiến chúng không liên quan. Do đó, phần handlers cũng không cần thiết, vì vậy hãy xoá phần đó.

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

TRƯỚC KHI:

runtime: python27
threadsafe: yes
api_version: 1

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

SAU KHI:

runtime: python310

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

appengine_config.py

Nếu đang nâng cấp lên Python 3, bạn không cần appengine_config.py, vì vậy hãy xoá ngôn ngữ này. Lý do là 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 chúng trong requirements.txt. Người dùng Python 2, hãy đọc tiếp.

appengine_config.py của Mô-đun 18 có mã thích hợp để hỗ trợ các thư viện của 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 KHI:

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ỉ riêng mã này thì chưa đủ để hỗ trợ các thư viện tích hợp sẵn vừa thêm (setuptools, grpcio). Cần thêm một vài dòng, vì vậy, hãy cập nhật appengine_config.py để ứng dụng có dạng như sau:

SAU KHI:

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 về những thay đổi cần thiết để hỗ trợ 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 phát 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ể phải sử dụng pip2 thay vì pip.

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

Phần này 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 về Hàng đợi tác vụ của App Engine bằng Cloud Pub/Sub. Không có thay đổi nào đối với mẫu web templates/index.html. Cả hai ứng dụng phải hoạt động giống nhau và hiển thị cùng một dữ liệu.

Cập nhật lệnh nhập và khởi chạy

Có một số điểm cập nhật đối với việc nhập và khởi chạy:

  1. Để 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 tác vụ kéo, worker cho thuê chúng trong một giờ, nhưng với Pub/Sub, thời gian chờ được đo trên cơ sở từng tin nhắn, vì vậy, hãy xoá hằng số HOUR.
  4. API Cloud yêu cầu sử dụng một ứng dụng API, vì vậy hãy khởi tạo các ứng dụng đó cho Cloud NDB và Cloud Pub/Sub, trong đó các ứng dụng sau cung cấp ứng dụng 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 chủ đề và gói thuê bao, nên hãy tạo những chủ đề và gói thuê bao đó bằng các hàm tiện lợi *_path().

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

TRƯỚC KHI:

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 KHI:

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)

Xem thông tin cập nhật về mô hình dữ liệu

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

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

TRƯỚC KHI:

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 KHI:

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 QueryCount

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

TRƯỚC KHI:

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 KHI:

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 cho đến khi thay thế NDB bằng Cloud NDB và Hàng đợi tác vụ bằng Pub/Sub, nhưng quy trình làm việc của mã này vẫn giữ nguyên.

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

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

TRƯỚC KHI:

@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 KHI:

@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 không cần thay đổi gì trong tệp mẫu HTML, templates/index.html, do đó, tất cả nội dung cập nhật cần thiết sẽ được gói. Chúc mừng bạn đã đến với ứng dụng mới của Mô-đun 19 bằng Cloud Pub/Sub!

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

Triển khai ứng dụng của bạn để xác minh rằng ứng dụng hoạt động như dự định và trong mọi đầu ra được phản ánh. Đồng thời chạy worker để xử lý số lượng khách 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à xem xét các bước tiếp theo.

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

Hãy đảm bảo rằng bạn đã tạo chủ đề pullq và gói thuê bao worker. Nếu quá trình này hoàn tất và ứng dụng mẫu của bạn đã sẵn sàng hoạt động, hãy triển khai ứng dụng bằng gcloud app deploy. Kết quả phải giống với ứng dụng 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

Giao diện người dùng web của ứng dụng hiện xác minh phần này của ứng dụng đang hoạt độ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 cũng như những lượt truy cập gần đây nhất, nhưng hãy nhớ lại ứng dụng đă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. Việc cần làm đó hiện đã nằm trong hàng đợi để chờ được xử lý.

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

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

Sau đó, số lượng đã cập nhật sẽ được phản ánh vào lần truy cập trang web tiếp theo. Vậy là xong!

Dọn dẹp

Giải pháp chung

Nếu bạn đã hoàn tất, chúng tôi khuyên bạn nên tắt ứng dụng App Engine để tránh phát sinh thanh toán. Tuy nhiên, nếu bạn muốn kiểm tra hoặc thử nghiệm thêm, nền tảng App Engine có hạn mức miễn phí, và bạn sẽ không bị tính phí, miễn là bạn không vượt quá cấp sử dụng đó. Đó là cho dịch vụ điện toán nhưng bạn cũng có thể bị tính phí cho các dịch vụ có liên quan của App Engine, vì vậy hãy xem trang 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ụ khác trên Google Cloud, thì những 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 "Dành riêng cho lớp học lập trình này" phần dưới đây.

Để công bố đầy đủ thông tin, việc triển khai cho một nền tảng điện toán không máy chủ của Google Cloud như App Engine sẽ làm phát sinh chi phí bản dựng và bộ nhớ thấp. Cloud Build cũng 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ẽ sử dụng hết một phần hạn mức đó. Tuy nhiên, bạn có thể sống ở một khu vực không có bậc miễn phí như vậy, vì vậy hãy chú ý đến mức sử dụng bộ nhớ của bạn để giảm thiểu chi phí tiềm ẩn. "Thư mục" cụ thể trên Cloud Storage bạn nên xem xét, 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 lưu trữ ở trên phụ thuộc vào PROJECT_ID và hoạt động *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 định tiếp tục sử dụng ứng dụng này hoặc các lớp học lập trình di chuyển khác có liên quan và muốn xoá hoàn toàn mọi thứ, hãy ngừng dự án của bạn.

Dành riêng cho lớp học lập trình này

Các dịch vụ được liệt kê dưới đây là những dịch vụ dành riêng cho 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 thành phần khác nhau của Cloud Pub/Sub có một bậc miễn phí; hãy xác định mức sử dụng tổng thể của bạn để nắm rõ hơn tác động của chi phí và xem trang giá của ứng dụng để biết thêm chi tiết.
  • Dịch vụ App Engine Datastore do Cloud Datastore (Cloud Firestore ở chế độ Datastore) cung cấp, cũng có một bậc miễn phí; hãy xem trang giá của YouTube để biết thêm thông tin.

Các bước tiếp theo

Ngoài hướng dẫn này, bạn cũng cần cân nhắc những mô-đun di chuyển khác tập trung vào việc ngừng sử dụng các dịch vụ cũ theo gói:

  • Mô-đun 2: di chuyển từ App Engine ndb sang Cloud NDB
  • Mô-đun 7-9: di chuyển từ Hàng đợi tác vụ của App Engine (tác vụ đẩy) sang Cloud Tasks
  • Mô-đun 12-13: di chuyển từ App Engine Memcache sang Cloud Memorystore
  • Mô-đun 15-16: di chuyển từ App Engine Blobstore sang Cloud Storage

App Engine không còn là nền tảng không máy chủ duy nhất 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 dịch vụ vi mô độ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ể sử dụng lại, thì đây là những lý do chính đáng để bạn cân nhắc chuyển sang Cloud Functions. Nếu việc tích hợp vùng chứa đã trở thành một phần trong quy trình phát triển ứng dụng, đặc biệt là khi quy trình đó bao gồm một quy trình CI/CD (tích hợp liên tục/phân phối hoặc triển khai liên tục), hãy cân nhắc chuyển sang Cloud Run. Những 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 Học phần 11
  • Di chuyển từ App Engine sang Cloud Run: xem Mô-đun 4 để vùng chứa ứng dụng của bạn bằng Docker, hoặc Mô-đun 5 để triển khai mà không cần vùng chứa, kiến thức về Docker hoặc Dockerfile

Việc chuyển sang một nền tảng không máy chủ khác là không bắt buộc. Bạn nên cân nhắc các 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 điều chỉnh bất cứ điều gì.

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 Trạm di chuyển không máy chủ (lớp học lập trình, video, mã nguồn [nếu có]) tại kho lưu trữ nguồn mở của chúng. README của kho lưu trữ này cũng cung cấp hướng dẫn về những quá trình di chuyển cần xem xét và mọi "đơn đặt hàng" có liên quan 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à phát triển đang tìm hiểu thêm về Phụ lục di chuyển này hoặ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ó cả những nơi để đưa ra ý kiến phản hồi về nội dung này, các đường liên kết đến mã nguồn và nhiều thông tin hữu ích khác của tài liệu.

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 vấn đề của bạn trước khi gửi. Đường liên kết để tìm kiếm và báo cáo vấn đề mới:

Tài nguyên di chuyển

Bạn có thể tìm thấy các đường liên kết đến các thư mục repo cho Mô-đun 18 (START) và Mô-đun 19 (Finish) trong bảng bên dưới.

Codelab

Python 2

Python 3

Học phần 18

(không áp dụng)

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

(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 có liên quan cho hướng dẫn này:

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

Cloud Pub/Sub

App Engine NDB và Cloud NDB (Datastore)

Nền tảng App Engine

Thông tin khác về đám mây

Video

Giấy phép

Tác phẩm này được cấp phép theo Giấy phép chung Ghi nhận tác giả Creative Commons 2.0.