Migracja z kolejki zadań App Engine do Cloud Pub/Sub (moduł 19)

1. Przegląd

Seria codelabów Serverless Migration Station (samodzielne, praktyczne samouczki) i powiązane z nimi filmy mają na celu pomóc deweloperom usług bezserwerowych Google Cloud w modernizacji aplikacji poprzez przeprowadzenie ich przez co najmniej jedną migrację, głównie z usług starszego typu. Dzięki temu Twoje aplikacje będą bardziej przenośne, a Ty zyskasz więcej opcji i elastyczności, co umożliwi Ci integrację z szerszą gamą usług w chmurze i łatwiejsze przechodzenie na nowsze wersje języka. Chociaż początkowo skupialiśmy się na pierwszych użytkownikach usług w chmurze, głównie na deweloperach App Engine (środowisko standardowe), ta seria jest wystarczająco szeroka, aby obejmować inne platformy bezserwerowe, takie jak Cloud FunctionsCloud Run, lub inne, jeśli ma to zastosowanie.

Celem tego laboratorium jest pokazanie deweloperom aplikacji App Engine w Pythonie 2, jak przeprowadzić migrację z zadań pull w kolejce zadań App Engine do Cloud Pub/Sub. W przypadku dostępu do Datastore (głównie w module 2) następuje też niejawna migracja z App Engine NDB do Cloud NDB, a także przejście na Pythona 3.

W module 18 dowiesz się, jak dodać do aplikacji zadania typu pull. W tym module weźmiesz gotową aplikację z modułu 18 i przeniesiesz jej funkcje do Cloud Pub/Sub. Użytkownicy, którzy korzystają z kolejek zadań do zadań push, powinni zamiast tego przejść na Cloud Tasks i zapoznać się z modułami 7–9.

Dowiesz się, jak:

Czego potrzebujesz

Ankieta

Jak zamierzasz korzystać z tego samouczka?

Tylko przeczytaj Przeczytaj i wykonaj ćwiczenia

Jak oceniasz swoje doświadczenie z Pythonem?

Początkujący Średnio zaawansowany Zaawansowany

Jak oceniasz korzystanie z usług Google Cloud?

Początkujący Średnio zaawansowany Zaawansowany

2. Tło

Kolejka zadań App Engine obsługuje zadania push i pull. Aby zwiększyć przenośność aplikacji, Google Cloud zaleca migrację z starszych usług pakietowych, takich jak kolejka zadań, do innych samodzielnych usług w chmurze lub usług równoważnych innych firm.

Moduły 7–9 dotyczą migracji zadań typu push, a moduły 18–19 – migracji zadań typu pull. Cloud Tasks jest bardziej podobny do kolejek push w kolejkach zadań, ale Pub/Sub nie jest tak podobny do kolejek pull w kolejkach zadań.

Pub/Sub ma więcej funkcji niż funkcja pull udostępniana przez kolejkę zadań. Na przykład Pub/Sub ma też funkcję push, ale Cloud Tasks bardziej przypomina zadania push w kolejce zadań, więc funkcja push w Pub/Sub nie jest objęta żadnym z modułów migracji. W tym module 19 znajdziesz ćwiczenia z programowania, które pokazują, jak zmienić mechanizm kolejkowania z kolejek pull w Task Queue na Pub/Sub, a także jak przenieść dostęp do Datastore z App Engine NDB do Cloud NDB, powtarzając migrację z modułu 2.

Chociaż kod modułu 18 jest „reklamowany” jako przykładowa aplikacja w języku Python 2, sam kod jest zgodny z językami Python 2 i 3 i pozostaje taki nawet po migracji do Cloud Pub/Sub (i Cloud NDB) w tym module 19.

Ten samouczek obejmuje te kroki:

  1. Konfiguracja/przygotowanie
  2. Aktualizacja konfiguracji
  3. Modyfikowanie kodu aplikacji

3. Konfiguracja/przygotowanie

Z tej sekcji dowiesz się, jak:

  1. Konfigurowanie projektu w chmurze
  2. Pobieranie przykładowej aplikacji podstawowej
  3. (Ponowne) wdrażanie i weryfikowanie aplikacji podstawowej
  4. Włączanie nowych usług i interfejsów API Google Cloud

Dzięki tym czynnościom masz pewność, że zaczynasz od działającego kodu, który jest gotowy do migracji do usług w chmurze.

1. Konfigurowanie projektu

Jeśli masz za sobą laboratorium programowania w module 18, użyj tego samego projektu (i kodu). Możesz też utworzyć zupełnie nowy projekt lub użyć innego istniejącego projektu. Upewnij się, że projekt ma aktywne konto rozliczeniowe i włączoną aplikację App Engine. Znajdź identyfikator projektu, ponieważ będzie Ci potrzebny podczas tego szkolenia. Używaj go zawsze, gdy napotkasz zmienną PROJECT_ID.

2. Pobieranie przykładowej aplikacji podstawowej

Jednym z wymagań wstępnych jest działająca aplikacja App Engine z modułu 18, więc wykonaj ćwiczenia z programowania (zalecane; link powyżej) lub skopiuj kod modułu 18 z repozytorium. Niezależnie od tego, czy używasz własnego, czy naszego, od tego miejsca zaczniemy („START”). Ten codelab przeprowadzi Cię przez proces migracji, a na końcu znajdziesz kod podobny do tego w folderze repozytorium modułu 19 („FINISH”).

Niezależnie od tego, której aplikacji z modułu 18 używasz, folder powinien wyglądać jak poniżej. Może też zawierać folder lib:

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

3. (Ponowne) wdrażanie i weryfikowanie aplikacji podstawowej

Aby wdrożyć aplikację z modułu 18, wykonaj te czynności:

  1. Usuń folder lib, jeśli istnieje, i uruchom polecenie pip install -t lib -r requirements.txt, aby ponownie wypełnić folder lib. Jeśli na komputerze używanym do programowania masz zainstalowane zarówno Pythona 2, jak i 3, może być konieczne użycie polecenia pip2.
  2. Sprawdź, czy narzędzie wiersza poleceń gcloud zostało zainstalowanezainicjowane oraz czy zapoznano się z jego użyciem.
  3. (opcjonalnie) Ustaw projekt w chmurze za pomocą polecenia gcloud config set project PROJECT_ID, jeśli nie chcesz wpisywać PROJECT_ID przy każdym poleceniu gcloud.
  4. Wdrażanie przykładowej aplikacji za pomocą gcloud app deploy
  5. Sprawdź, czy aplikacja działa zgodnie z oczekiwaniami i nie sprawia problemów. Jeśli udało Ci się ukończyć ćwiczenie z programowania w module 18, aplikacja wyświetli najważniejszych użytkowników wraz z najnowszymi wizytami (jak na ilustracji poniżej). W przeciwnym razie może nie być dostępnych żadnych danych o liczbie odwiedzających do wyświetlenia.

b667551dcbab1a09.png

Zanim przeprowadzisz migrację przykładowej aplikacji z modułu 18, musisz najpierw włączyć usługi w chmurze, z których będzie korzystać zmodyfikowana aplikacja.

4. Włączanie nowych usług i interfejsów API Google Cloud

Stara aplikacja korzystała z usług pakietowych App Engine, które nie wymagają dodatkowej konfiguracji. Jednak samodzielne usługi Cloud wymagają konfiguracji, a zaktualizowana aplikacja będzie korzystać zarówno z Cloud Pub/Sub, jak i z Cloud Datastore (za pomocą biblioteki klienta Cloud NDB). App Engine i oba interfejsy Cloud API mają limity poziomu „Zawsze bezpłatnie”, więc jeśli nie przekroczysz tych limitów, ukończenie tego samouczka nie powinno wiązać się z żadnymi opłatami. Interfejsy API Cloud możesz włączyć w konsoli Cloud lub w wierszu poleceń, w zależności od preferencji.

W konsoli Cloud

Otwórz stronę Biblioteka Menedżera interfejsów API (w odpowiednim projekcie) w konsoli Cloud i wyszukaj interfejsy Cloud Datastore i Cloud Pub/Sub API za pomocą paska wyszukiwania na środku strony:

c7a740304e9d35b.png

Kliknij przycisk Włącz przy każdym interfejsie API z osobna. Możesz zostać poproszony(-a) o podanie informacji rozliczeniowych. Na przykład tak wygląda strona biblioteki Cloud Pub/Sub API:

1b6c0a2a73124f6b.jpeg

W wierszu poleceń

Włączanie interfejsów API w konsoli jest bardzo wygodne, ale niektórzy wolą wiersz poleceń. Wydaj polecenie gcloud services enable pubsub.googleapis.com datastore.googleapis.com, aby włączyć oba interfejsy API jednocześnie:

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

Może pojawić się prośba o podanie informacji rozliczeniowych. Jeśli chcesz włączyć inne interfejsy Cloud API i poznać ich identyfikatory URI, znajdziesz je u dołu strony biblioteki każdego interfejsu API. Na przykład na dole strony Pub/Sub powyżej widać pubsub.googleapis.com jako „Nazwę usługi”.

Po wykonaniu tych czynności projekt będzie miał dostęp do interfejsów API. Teraz możesz zaktualizować aplikację, aby korzystała z tych interfejsów API.

4. Tworzenie zasobów Pub/Sub

Podsumowanie kolejności przepływu pracy kolejki zadań z modułu 18:

  1. W module 18 użyto pliku queue.yaml do utworzenia kolejki typu pull o nazwie pullq.
  2. Aplikacja dodaje zadania do kolejki pull, aby śledzić odwiedzających.
  3. Zadania są ostatecznie przetwarzane przez instancję roboczą, która jest dzierżawiona na określony czas (godzinę).
  4. Zadania są wykonywane w celu zliczenia ostatnich wizyt.
  5. Zadania są usuwane z kolejki po zakończeniu.

Podobny przepływ pracy odtworzysz za pomocą Pub/Sub. W następnej sekcji znajdziesz podstawowe terminy związane z Pub/Sub oraz 3 sposoby tworzenia niezbędnych zasobów Pub/Sub.

Terminologia kolejek zadań App Engine (pull) a Cloud Pub/Sub

Przejście na Pub/Sub wymaga niewielkiej zmiany słownictwa. Poniżej znajdziesz główne kategorie wraz z odpowiednimi terminami z obu usług. Zapoznaj się też z przewodnikiem po migracji, w którym znajdziesz podobne porównania.

  • Struktura danych kolejki: w przypadku kolejki zadań dane trafiają do kolejek pull, a w przypadku Pub/Sub – do tematów.
  • Jednostki danych w kolejce: zadania pull w kolejce zadań są nazywane wiadomościami w Pub/Sub.
  • Procesory danych: w przypadku kolejki zadań procesy robocze uzyskują dostęp do zadań pull, a w przypadku Pub/Sub do odbierania wiadomości potrzebne są subskrypcje/subskrybenci.
  • Wyodrębnianie danych: Dzierżawa zadania typu pull jest taka sama jak pobranie wiadomości z tematu (za pomocą subskrypcji).
  • Czyszczenie/ukończenie: usuwanie zadania z kolejki zadań typu pull po jego wykonaniu jest analogiczne do potwierdzania wiadomości Pub/Sub.

Chociaż produkt do kolejkowania ulega zmianie, przepływ pracy pozostaje stosunkowo podobny:

  1. Zamiast kolejki pull aplikacja używa tematu o nazwie pullq.
  2. Zamiast dodawać zadania do kolejki typu pull, aplikacja wysyła wiadomości do tematu (pullq).
  3. Zamiast pracownika dzierżawiącego zadania z kolejki pull, subskrybent o nazwie worker pobiera wiadomości z tematu pullq.
  4. Aplikacja przetwarza ładunki wiadomości, zwiększając liczbę odwiedzających w Datastore.
  5. Zamiast usuwać zadania z kolejki pull, aplikacja potwierdza przetworzone wiadomości.

W przypadku kolejki zadań konfiguracja obejmuje utworzenie kolejki pull. W przypadku Pub/Sub konfiguracja wymaga utworzenia zarówno tematu, jak i subskrypcji. W module 18 przetworzyliśmy queue.yaml poza wykonaniem aplikacji. Teraz to samo musimy zrobić w przypadku Pub/Sub.

Tematy i subskrypcje możesz utworzyć na 3 sposoby:

  1. W konsoli Cloud
  2. z wiersza poleceń lub
  3. Z kodu (krótki skrypt w Pythonie)

Wybierz jedną z opcji poniżej i postępuj zgodnie z odpowiednimi instrukcjami, aby utworzyć zasoby Pub/Sub.

W konsoli Cloud

Aby utworzyć temat w konsoli Google Cloud, wykonaj te czynności:

  1. Otwórz stronę Tematy Pub/Sub w konsoli Cloud.
  2. U góry kliknij Utwórz temat. Otworzy się nowe okno dialogowe (patrz obraz poniżej).
  3. W polu Identyfikator tematu wpisz pullq.
  4. Odznacz wszystkie zaznaczone opcje i wybierz Klucz szyfrowania zarządzany przez Google.
  5. Kliknij przycisk Utwórz temat.

Okno tworzenia tematu wygląda tak:

a05cfdbf64571ceb.png

Teraz, gdy masz już temat, musisz utworzyć subskrypcję tego tematu:

  1. Otwórz stronę Subskrypcje Pub/Sub w konsoli Cloud.
  2. U góry kliknij Utwórz subskrypcję (patrz obraz poniżej).
  3. W polu Identyfikator subskrypcji wpisz worker.
  4. Wybierz pullq z menu Wybierz temat Cloud Pub/Sub, zwracając uwagę na jego „pełną i jednoznaczną ścieżkę”, np. projects/PROJECT_ID/topics/pullq.
  5. Jako Sposób dostarczania wybierz Pull.
  6. Pozostaw inne opcje bez zmian i kliknij przycisk Utwórz.

Tak wygląda ekran tworzenia subskrypcji:

c5444375c20b0618.jpeg

Subskrypcję możesz też utworzyć na stronie Tematy. Ten „skrót” może Ci pomóc w powiązaniu tematów z subskrypcjami. Więcej informacji o tworzeniu subskrypcji znajdziesz w dokumentacji.

W wierszu poleceń

Użytkownicy Pub/Sub mogą tworzyć tematy i subskrypcje za pomocą poleceń gcloud pubsub topics create TOPIC_ID i gcloud pubsub subscriptions create SUBSCRIPTION_ID --topic=TOPIC_ID. Wykonanie tych działań z wartością TOPIC_ID równą pullq i wartością SUBSCRIPTION_ID równą worker spowoduje wygenerowanie następujących danych wyjściowych dla projektu 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].

Zapoznaj się też z tą stroną w dokumentacji krótkiego wprowadzenia. Korzystanie z wiersza poleceń może uprościć procesy, w których tematy i subskrypcje są tworzone regularnie. W tym celu można używać takich poleceń w skryptach powłoki.

Z kodu (krótki skrypt w Pythonie)

Innym sposobem na zautomatyzowanie tworzenia tematów i subskrypcji jest użycie interfejsu Pub/Sub API w kodzie źródłowym. Poniżej znajduje się kod maker.pyskryptu w folderze repozytorium Moduł 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()

Wykonanie tego skryptu daje oczekiwane dane wyjściowe (pod warunkiem, że nie ma błędów):

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

Wywołanie interfejsu API w celu utworzenia zasobów, które już istnieją, powoduje zgłoszenie przez bibliotekę klienta wyjątku google.api_core.exceptions.AlreadyExists, który jest obsługiwany przez skrypt w odpowiedni sposób:

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

Jeśli dopiero zaczynasz korzystać z Pub/Sub, więcej informacji znajdziesz w raporcie o architekturze Pub/Sub.

5. Aktualizacja konfiguracji

Aktualizacje konfiguracji obejmują zarówno zmianę różnych plików konfiguracyjnych, jak i utworzenie odpowiednika kolejek pobierania App Engine, ale w ekosystemie Cloud Pub/Sub.

Usuń plik queue.yaml

Całkowicie wycofujemy kolejki zadań, więc usuń plik queue.yaml, ponieważ Pub/Sub go nie używa. Zamiast tworzyć kolejkę pull, utworzysz temat Pub/Sub (i subskrypcję).

requirements.txt

Dołącz do flask z modułu 18, dodając do requirements.txt zarówno google-cloud-ndb, jak i google-cloud-pubsub. Zaktualizowany moduł 19 requirements.txt powinien wyglądać tak:

flask
google-cloud-ndb
google-cloud-pubsub

Ten plik requirements.txt nie zawiera numerów wersji, co oznacza, że wybrane są najnowsze wersje. Jeśli wystąpią jakiekolwiek niezgodności, postępuj zgodnie ze standardową procedurą używania numerów wersji, aby zablokować działające wersje aplikacji.

app.yaml

Zmiany w app.yaml różnią się w zależności od tego, czy pozostajesz przy Pythonie 2, czy przechodzisz na Pythona 3.

Python 2

Powyższa aktualizacja requirements.txt dodaje korzystanie z bibliotek klienta Google Cloud. Wymagają one dodatkowej obsługi ze strony App Engine, a mianowicie kilku wbudowanych bibliotek, setuptoolsgrpcio. Korzystanie z wbudowanych bibliotek wymaga sekcji libraries w pliku app.yaml oraz numerów wersji bibliotek lub słowa „latest” (najnowsza) w przypadku najnowszej wersji dostępnej na serwerach App Engine. Moduł 18 app.yaml nie ma jeszcze jednej z tych sekcji:

PRZED:

runtime: python27
threadsafe: yes
api_version: 1

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

Dodaj sekcję libraries do app.yaml wraz z wpisami dla setuptoolsgrpcio, wybierając ich najnowsze wersje. Dodaj też wpis zastępczy runtime dla Pythona 3, zakomentowany wraz z aktualną wersją 3.x, np. 3.10 (w momencie pisania tego artykułu). Po wprowadzeniu tych zmian app.yaml wygląda tak:

PO:

#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

W przypadku użytkowników Pythona 3 i app.yaml chodzi o usuwanie elementów. W tej sekcji usuniesz sekcję handlers oraz dyrektywy threadsafe i api_version. Nie utworzysz też sekcji libraries.

Środowiska wykonawcze 2 generacji nie udostępniają wbudowanych bibliotek innych firm, więc w sekcji app.yaml nie jest potrzebna sekcja libraries. Ponadto kopiowanie (czasami nazywane udostępnianiem lub samodzielnym łączeniem w pakiety) niewbudowanych pakietów innych firm nie jest już wymagane. W requirements.txt musisz podać tylko biblioteki innych firm, których używa Twoja aplikacja.

Sekcja handlersapp.yaml służy do określania modułów obsługi aplikacji (skryptów) i plików statycznych. Środowisko wykonawcze Pythona 3 wymaga, aby platformy internetowe wykonywały własne routingi, więc wszystkie moduły obsługi skryptów muszą zostać zmienione na auto. Jeśli Twoja aplikacja (np. z modułu 18) nie obsługuje plików statycznych, wszystkie ścieżki będą miały wartość auto, co sprawi, że będą nieistotne. W związku z tym sekcja handlers też nie jest potrzebna, więc ją usuń.

Na koniec w Pythonie 3 nie używa się dyrektyw threadsafe ani api_version, więc je też usuń. Najważniejsze jest to, aby usunąć wszystkie sekcje app.yaml, tak aby pozostała tylko dyrektywa runtime określająca nowoczesną wersję Pythona 3, np. 3.10. Tak wygląda app.yaml przed i po tych zmianach:

PRZED:

runtime: python27
threadsafe: yes
api_version: 1

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

PO:

runtime: python310

Dla osób, które nie są gotowe na usunięcie wszystkiego z app.yaml dla Pythona 3, udostępniliśmy app3.yaml alternatywny plik w folderze repozytorium modułu 19. Jeśli chcesz użyć tego pliku do wdrożeń, dodaj jego nazwę na końcu polecenia: gcloud app deploy app3.yaml (w przeciwnym razie domyślnie zostanie użyty plik app.yaml w języku Python 2, który pozostawisz bez zmian).

appengine_config.py

Jeśli przechodzisz na Pythona 3, nie potrzebujesz już appengine_config.py, więc usuń ten plik. Nie jest to konieczne, ponieważ obsługa bibliotek innych firm wymaga tylko określenia ich w requirements.txt. Użytkownicy języka Python 2, czytajcie dalej.

Moduł 18 appengine_config.py zawiera odpowiedni kod do obsługi bibliotek innych firm, np. Flask i bibliotek klienta Cloud, które właśnie zostały dodane do requirements.txt:

PRZED:

from google.appengine.ext import vendor

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

Ten kod nie wystarczy jednak do obsługi nowo dodanych bibliotek wbudowanych (setuptools, grpcio). Potrzeba jeszcze kilku wierszy, więc zaktualizuj appengine_config.py, aby wyglądał tak:

PO:

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)

Więcej informacji o zmianach wymaganych do obsługi bibliotek klienta Cloud znajdziesz w dokumentacji dotyczącej migracji usług pakietowych.

Inne aktualizacje konfiguracji

Jeśli masz folder lib, usuń go. Jeśli używasz Pythona 2, uzupełnij folder lib, wydając to polecenie:

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

Jeśli na komputerze deweloperskim masz zainstalowane zarówno Pythona 2, jak i 3, zamiast pip może być konieczne użycie pip2.

6. Modyfikowanie kodu aplikacji

Ta sekcja zawiera aktualizacje głównego pliku aplikacji, main.py, które zastępują kolejki pull w App Engine Task Queue usługą Cloud Pub/Sub. W szablonie internetowym nie ma żadnych zmian templates/index.html. Obie aplikacje powinny działać identycznie i wyświetlać te same dane.

Aktualizowanie importów i inicjowanie

Wprowadziliśmy kilka zmian w importach i inicjowaniu:

  1. W przypadku importów zastąp App Engine NDB i Task Queue usługami Cloud NDB i Pub/Sub.
  2. Zmień nazwę pullqQUEUE na TOPIC.
  3. W przypadku zadań typu pull instancja robocza wypożyczała je na godzinę, ale w przypadku Pub/Sub limity czasu są mierzone dla każdej wiadomości, więc usuń stałą HOUR.
  4. Interfejsy Cloud API wymagają użycia klienta API, więc zainicjuj je dla Cloud NDB i Cloud Pub/Sub. Ten ostatni udostępnia klientów zarówno dla tematów, jak i subskrypcji.
  5. Pub/Sub wymaga identyfikatora projektu w chmurze, więc zaimportuj go i pobierz z google.auth.default().
  6. Pub/Sub wymaga „w pełni kwalifikowanych nazw ścieżek” w przypadku tematów i subskrypcji, więc utwórz je za pomocą funkcji pomocniczych *_path().

Poniżej znajdziesz importy i inicjalizację z modułu 18, a także wygląd sekcji po wprowadzeniu powyższych zmian. Większość nowego kodu to różne zasoby Pub/Sub:

PRZED:

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__)

PO:

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)

Aktualizacje modelu danych

Model danych Visit nie ulegnie zmianie. Dostęp do Datastore wymaga jawnego użycia menedżera kontekstu klienta Cloud NDB API, ds_client.context(). W kodzie oznacza to, że wywołania Datastore należy umieścić w blokach store_visit()fetch_visits() w blokach with w Pythonie. Ta aktualizacja jest identyczna z tą, którą omówiliśmy w module 2.

Najważniejsza zmiana w przypadku Pub/Sub polega na zastąpieniu kolejkowania zadania pull w kolejce zadań publikowaniem wiadomości Pub/Sub w temacie pullq. Poniżej znajdziesz kod przed wprowadzeniem tych zmian i po nich:

PRZED:

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)

PO:

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)

Aktualizacje modelu danych VisitorCount

Model danych VisitorCount nie ulega zmianie i fetch_counts(), z wyjątkiem umieszczenia zapytania Datastore w bloku with, jak pokazano poniżej:

PRZED:

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)

PO:

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)

Aktualizowanie kodu pracownika

Kod procesu roboczego jest aktualizowany w zakresie zastąpienia NDB przez Cloud NDB i kolejki zadań przez Pub/Sub, ale jego przepływ pracy pozostaje taki sam.

  1. Umieść wywołania Datastore w bloku menedżera kontekstu Cloud NDB with.
  2. Czyszczenie kolejki zadań polega na usunięciu wszystkich zadań z kolejki pull. W Pub/Sub „identyfikatory potwierdzeń” są zbierane w acks, a następnie usuwane lub potwierdzane na końcu.
  3. Zadania pull w kolejce zadań są wypożyczane w podobny sposób jak wiadomości Pub/Sub. Zadania typu pull są usuwane za pomocą samych obiektów zadań, a wiadomości Pub/Sub – za pomocą identyfikatorów potwierdzenia.
  4. Ładunki wiadomości Pub/Sub wymagają bajtów (nie ciągów znaków w języku Python), więc podczas publikowania wiadomości w temacie i pobierania ich z niego następuje odpowiednio kodowanie i dekodowanie w UTF-8.

Zastąp zmienną log_visitors() zaktualizowanym kodem poniżej, który wprowadza opisane wyżej zmiany:

PRZED:

@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))

PO:

@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))

Główny moduł obsługi aplikacji root() pozostaje bez zmian. Nie musisz też wprowadzać żadnych zmian w pliku szablonu HTML templates/index.html. W ten sposób zakończysz wszystkie niezbędne aktualizacje. Gratulujemy dotarcia do nowej aplikacji modułu 19 korzystającej z Cloud Pub/Sub.

7. Podsumowanie i czyszczenie

Wdróż aplikację, aby sprawdzić, czy działa zgodnie z przeznaczeniem i czy wszystkie dane wyjściowe są prawidłowe. Uruchom też proces roboczy, aby przetworzyć liczbę odwiedzających. Po zweryfikowaniu aplikacji wykonaj czynności związane z czyszczeniem i zastanów się, co dalej zrobić.

Wdrażanie i weryfikowanie aplikacji

Sprawdź, czy masz już utworzony temat pullq i subskrypcję worker. Jeśli to zrobisz i przykładowa aplikacja będzie gotowa, wdróż ją za pomocą polecenia gcloud app deploy. Dane wyjściowe powinny być identyczne z aplikacją z modułu 18, z tym wyjątkiem, że cały mechanizm kolejkowania został zastąpiony:

b667551dcbab1a09.png

Interfejs internetowy aplikacji weryfikuje teraz, czy ta część aplikacji działa. Ta część aplikacji prawidłowo wysyła zapytania o najważniejszych użytkowników i najnowsze wizyty oraz wyświetla te informacje. Pamiętaj, że aplikacja rejestruje tę wizytę i tworzy zadanie pobierania, aby dodać tego użytkownika do ogólnej liczby. To zadanie jest teraz w kolejce i czeka na przetworzenie.

Możesz to zrobić za pomocą usługi backendu App Engine, zadania cron, przeglądając /log lub wysyłając żądanie HTTP w wierszu poleceń. Oto przykładowe wykonanie i dane wyjściowe wywołania kodu roboczego za pomocą curl (zastąp PROJECT_ID):

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

Zaktualizowana liczba zostanie uwzględniona podczas następnej wizyty w witrynie. To wszystko.

Czyszczenie danych

Ogólne

Jeśli na razie nie chcesz już korzystać z usługi, zalecamy wyłączenie aplikacji App Engine, aby uniknąć naliczania opłat. Jeśli jednak chcesz przeprowadzić więcej testów lub eksperymentów, platforma App Engine ma bezpłatny limit, więc dopóki nie przekroczysz tego poziomu wykorzystania, nie powinny być naliczane żadne opłaty. Dotyczy to obliczeń, ale mogą też wystąpić opłaty za odpowiednie usługi App Engine, więc więcej informacji znajdziesz na stronie z cennikiem. Jeśli migracja obejmuje inne usługi w chmurze, są one rozliczane oddzielnie. W każdym przypadku, jeśli to konieczne, zapoznaj się z sekcją „Specyficzne dla tego laboratorium” poniżej.

Wdrożenie na bezserwerowej platformie obliczeniowej Google Cloud, takiej jak App Engine, wiąże się z niewielkimi kosztami kompilacji i przechowywania. Cloud Build ma własny bezpłatny limit, podobnie jak Cloud Storage. Przechowywanie tego obrazu wykorzystuje część tego limitu. Możesz jednak mieszkać w regionie, w którym nie ma takiego bezpłatnego pakietu, więc kontroluj wykorzystanie miejsca na dane, aby zminimalizować potencjalne koszty. Sprawdź te „foldery” Cloud Storage:

  • 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
  • Linki do pamięci masowej powyżej zależą od PROJECT_ID i *LOC*acji, np. „us”, jeśli Twoja aplikacja jest hostowana w Stanach Zjednoczonych.

Jeśli nie zamierzasz kontynuować pracy z tą aplikacją ani innymi powiązanymi z nią samouczkami dotyczącymi migracji i chcesz wszystko całkowicie usunąć, wyłącz projekt.

Dotyczy tych ćwiczeń z programowania

Usługi wymienione poniżej są dostępne tylko w tym laboratorium. Więcej informacji znajdziesz w dokumentacji poszczególnych usług:

  • Poszczególne komponenty Cloud Pub/Sub mają bezpłatny poziom. Określ ogólne wykorzystanie, aby lepiej poznać konsekwencje kosztowe. Więcej informacji znajdziesz na stronie z cenami.
  • Usługa App Engine Datastore jest udostępniana przez Cloud Datastore (Cloud Firestore w trybie Datastore), która również ma bezpłatny poziom. Więcej informacji znajdziesz na stronie z cennikiem.

Dalsze kroki

Oprócz tego samouczka możesz też zapoznać się z innymi modułami migracji, które skupiają się na przejściu z starszych usług w pakiecie:

App Engine nie jest już jedyną platformą bezserwerową w Google Cloud. Jeśli masz małą aplikację App Engine lub aplikację o ograniczonej funkcjonalności i chcesz przekształcić ją w samodzielny mikroserwis albo podzielić aplikację monolityczną na wiele komponentów wielokrotnego użytku, warto rozważyć przejście na Cloud Functions. Jeśli konteneryzacja stała się częścią procesu tworzenia aplikacji, zwłaszcza jeśli obejmuje potok CI/CD (tryb ciągłej integracji/tryb ciągłego dostarczania lub wdrażanie), rozważ migrację do Cloud Run. Te scenariusze są omówione w tych modułach:

  • Migracja z App Engine do Cloud Functions: patrz moduł 11
  • Migracja z App Engine do Cloud Run: w module 4 dowiesz się, jak skonteneryzować aplikację za pomocą Dockera, a w module 5 – jak to zrobić bez kontenerów, wiedzy o Dockerze ani Dockerfiles

Przejście na inną platformę bezserwerową jest opcjonalne. Zanim wprowadzisz jakiekolwiek zmiany, zalecamy rozważenie najlepszych opcji dla Twoich aplikacji i przypadków użycia.

Niezależnie od tego, który moduł migracji wybierzesz, wszystkie materiały dotyczące Serverless Migration Station (ćwiczenia z programowania, filmy, kod źródłowy [jeśli jest dostępny]) znajdziesz w repozytorium open source. W repozytorium README znajdziesz też wskazówki dotyczące migracji, które warto rozważyć, oraz odpowiednią „kolejność” modułów migracji.

8. Dodatkowe materiały

Poniżej znajdziesz dodatkowe materiały dla programistów, którzy chcą dowiedzieć się więcej o tym lub powiązanym module migracji, a także o powiązanych produktach. Znajdziesz tu m.in. miejsca, w których możesz przesłać opinię o tych treściach, linki do kodu i różne dokumenty, które mogą Ci się przydać.

Problemy z Codelabs lub opinie na ich temat

Jeśli zauważysz jakieś problemy z tym kursem, najpierw poszukaj rozwiązania, a dopiero potem zgłoś problem. Linki do wyszukiwania i tworzenia nowych problemów:

Materiały dotyczące migracji

Linki do folderów repozytorium dla modułu 18 (START) i modułu 19 (FINISH) znajdziesz w tabeli poniżej.

Ćwiczenia z programowania

Python 2

Python 3

Moduł 18

kod

(n/a)

Moduł 19 (te ćwiczenia z programowania)

kod

(tak samo jak w przypadku Pythona 2, z tym że zamiast app.yaml użyj app3.yaml, chyba że plik app.yaml został zaktualizowany zgodnie z powyższymi instrukcjami)

Odsyłacze online

Poniżej znajdziesz zasoby przydatne w tym samouczku:

Kolejka zadań App Engine

Cloud Pub/Sub

App Engine NDB i Cloud NDB (Datastore)

Platforma App Engine

Inne informacje o chmurze

Filmy

Licencja

To zadanie jest licencjonowane na podstawie ogólnej licencji Creative Commons Attribution 2.0.