Migrar do Memcache do App Engine para o Cloud Memorystore (módulo 13)

1. Visão geral

A série de codelabs da Serverless Migration Station (tutoriais práticos e autoguiados) e os vídeos relacionados têm como objetivo ajudar os desenvolvedores sem servidor do Google Cloud a modernizar os aplicativos orientando-os em uma ou mais migrações, principalmente a migração de serviços legados. Isso torna seus apps mais portáteis e oferece mais opções e flexibilidade, permitindo que você se integre e acesse uma variedade maior de produtos do Cloud e faça upgrade mais fácil para versões de linguagem mais recentes. Embora o foco inicial seja nos primeiros usuários do Cloud, principalmente desenvolvedores do App Engine (ambiente padrão), esta série é ampla o suficiente para incluir outras plataformas sem servidor, como o Cloud Functions e o Cloud Run, ou em outro lugar, se aplicável.

O objetivo deste codelab é mostrar aos desenvolvedores do App Engine em Python 2 como migrar do Memcache do App Engine para o Cloud Memorystore (para Redis). Há também uma migração implícita do App Engine ndb para o Cloud NDB, mas isso é abordado principalmente no codelab do módulo 2. Confira para mais informações detalhadas.

Você vai aprender a

  • Configure uma instância do Cloud Memorystore (no Console do Cloud ou na ferramenta gcloud)
  • Configure um conector de acesso VPC sem servidor do Cloud (no Console do Cloud ou na ferramenta gcloud)
  • Migrar do Memcache do App Engine para o Cloud Memorystore
  • Implementar o armazenamento em cache com o Cloud Memorystore em um app de exemplo
  • Migrar do App Engine ndb para o Cloud NDB

O que é necessário

Pesquisa

Como você usará este tutorial?

Apenas leitura Leitura e exercícios

Como você classificaria sua experiência com Python?

Iniciante Intermediário Proficiente

Como você classificaria sua experiência de uso dos serviços do Google Cloud?

Iniciante Intermediário Proficiente

2. Contexto

Este codelab demonstra como migrar um app de exemplo do Memcache do App Engine (e NDB) para o Cloud Memorystore (e Cloud NDB). Esse processo envolve a substituição de dependências nos serviços incluídos do App Engine, tornando seus apps mais portáteis. Você pode continuar usando o App Engine ou considerar a migração para qualquer uma das alternativas descritas anteriormente.

Essa migração exige mais esforço em comparação com as outras desta série. A substituição recomendada para o Memcache do App Engine é o Cloud Memorystore, um serviço de armazenamento em cache totalmente gerenciado e baseado na nuvem. O Memorystore é compatível com dois mecanismos de armazenamento em cache de código aberto conhecidos: Redis e Memcached. Este módulo de migração usa o Cloud Memorystore para Redis. Saiba mais na visão geral do Memorystore e do Redis.

Como o Memorystore exige um servidor em execução, também é necessário ter uma VPC do Cloud. Especificamente, um conector de acesso VPC sem servidor precisa ser criado para que o app do App Engine possa se conectar à instância do Memorystore usando o endereço IP particular dela. Ao concluir este exercício, você terá atualizado o app para que, embora ele se comporte como antes, o Cloud Memorystore seja o serviço de cache, substituindo o serviço Memcache do App Engine.

Este tutorial começa com o app de exemplo do Módulo 12 em Python 2, seguido por um upgrade adicional, opcional e secundário para o Python 3. Se você já sabe como acessar os serviços incluídos do App Engine no Python 3 usando o SDK do App Engine para Python 3, comece com a versão em Python 3 do app de exemplo do módulo 12. Isso vai exigir a remoção do uso do SDK, já que o Memorystore não é um serviço integrado do App Engine. Aprender a usar o SDK do App Engine para Python 3 está fora do escopo deste tutorial.

Este tutorial inclui as seguintes etapas principais:

  1. Configuração/pré-trabalho
  2. Configurar serviços de armazenamento em cache
  3. Atualizar os arquivos de configuração
  4. Atualizar aplicativo principal

3. Configuração/pré-trabalho

Preparar o projeto na nuvem

Recomendamos que você reutilize o mesmo projeto usado para concluir o codelab do Módulo 12. Se preferir, crie um novo projeto ou reutilize outro. Cada codelab desta série tem um "INÍCIO" (o código de base para começar) e um "FIM" (o app migrado). O código FINISH é fornecido para que você possa comparar suas soluções com as nossas em caso de problemas. Você sempre pode voltar ao INÍCIO se algo der errado. Esses pontos de verificação foram criados para garantir que você aprenda a realizar as migrações.

Qualquer projeto na nuvem que você usar precisa ter uma conta de faturamento ativa. Verifique também se o App Engine está ativado. Analise e entenda as implicações gerais de custo ao fazer estes tutoriais. Ao contrário de outros codelabs desta série, este usa recursos do Cloud que não têm um nível sem custo financeiro. Portanto, haverá alguns custos para concluir o exercício. Informações mais específicas sobre custos serão fornecidas com recomendações para reduzir o uso, incluindo instruções no final sobre como liberar recursos para minimizar as cobranças de faturamento.

Receber app de amostra do valor de referência

Com base no código do módulo 12, este codelab mostra a migração etapa por etapa. Quando concluído, você vai chegar a um app do Módulo 13 funcionando, muito parecido com o código em uma das pastas FINISH. Confira esses recursos:

A pasta START deve conter os seguintes arquivos:

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

Se você estiver começando com a versão em Python 2, também haverá um arquivo appengine_config.py e possivelmente uma pasta lib se você tiver concluído o codelab do Módulo 12.

(Re)implantar o app do módulo 12

As etapas de pré-trabalho restantes:

  1. Familiarize-se com a ferramenta de linha de comando gcloud (se necessário).
  2. (Re)implante o código do módulo 12 no App Engine (se necessário)

Os usuários do Python 2 precisam excluir e reinstalar a pasta lib com estes comandos:

rm -rf ./lib; pip install -t lib -r requirements.txt                

Agora, todos (usuários do Python 2 e 3) precisam fazer upload do código para o App Engine com este comando:

gcloud app deploy                

Depois de implantado, confirme se o app tem a mesma aparência e funciona da mesma forma que o app do módulo 12, um web app que rastreia visitas, armazenando em cache para o mesmo usuário por uma hora:

dfe56a02ae59ddd8.png

Como as visitas mais recentes são armazenadas em cache, as atualizações de página devem ser carregadas com bastante rapidez.

4. Configurar serviços de armazenamento em cache

O Cloud Memorystore não é sem servidor. Uma instância é necessária. Neste caso, uma instância do Redis em execução. Ao contrário do Memcache, o Memorystore é um produto independente do Cloud e não tem um nível sem custo financeiro. Por isso, confira as informações de preços do Memorystore para Redis antes de continuar. Para minimizar os custos deste exercício, recomendamos a menor quantidade de recursos para operar: um nível de serviço Básico e uma capacidade de 1 GB.

A instância do Memorystore está em uma rede diferente do aplicativo do App Engine (instâncias). Por isso, é necessário criar um conector de acesso VPC sem servidor para que o App Engine possa acessar os recursos do Memorystore. Para minimizar os custos da VPC, escolha o tipo de instância (f1-micro) e o menor número de instâncias a serem solicitadas (sugerimos mínimo de 2 e máximo de 3). Confira também a página de informações sobre preços da VPC.

Repetimos essas recomendações para reduzir custos enquanto mostramos como criar cada recurso necessário. Além disso, ao criar recursos do Memorystore e da VPC no console do Cloud, você vai encontrar a calculadora de preços de cada produto no canto superior direito, com uma estimativa de custo mensal (veja a ilustração abaixo). Esses valores são ajustados automaticamente se você mudar as opções. É mais ou menos isso que você vai encontrar:

7eb35ebf7248c010.png

Os dois recursos são obrigatórios, e não importa qual você cria primeiro. Se você criar a instância do Memorystore primeiro, o app do App Engine não poderá acessá-la sem o conector de VPC. Da mesma forma, se você criar o conector de VPC primeiro, não haverá nada nessa rede VPC para o app do App Engine se comunicar. Neste tutorial, você vai criar primeiro a instância do Memorystore e depois o conector de VPC.

Depois que os dois recursos estiverem on-line, adicione as informações relevantes a app.yaml para que o app possa acessar o cache. Você também pode consultar os guias do Python 2 ou do Python 3 na documentação oficial. O guia de armazenamento em cache de dados na página de migração do Cloud NDB ( Python 2 ou Python 3) também é uma boa referência.

Criar uma instância do Cloud Memorystore

Como o Cloud Memorystore não tem um nível sem custo financeiro, recomendamos alocar a menor quantidade de recursos possível para concluir o codelab. Para manter os custos no mínimo, use estas configurações:

  • Selecione o nível de serviço mais baixo: Básico (padrão do console: "Padrão", padrão do gcloud: "Básico").
  • Escolha a menor quantidade de armazenamento: 1 GB (padrão do console: 16 GB, padrão do gcloud: 1 GB).
  • Normalmente, as versões mais recentes de qualquer software exigem a maior quantidade de recursos, mas selecionar a versão mais antiga também não é recomendado. A segunda versão mais recente é Redis versão 5.0 (padrão do console: 6.x)

Com essas configurações em mente, a próxima seção vai orientar você na criação da instância no console do Cloud. Se preferir fazer isso na linha de comando, pule para a frente.

No Console do Cloud

Acesse a página do Cloud Memorystore no console do Cloud. Talvez seja necessário informar dados de faturamento. Se você ainda não tiver ativado o Memorystore, será solicitado a fazer isso:

68318997e3105db6.png

Depois de ativar (e talvez junto com o faturamento), você vai acessar o painel do Memorystore. É aqui que você pode conferir todas as instâncias criadas no seu projeto. O projeto mostrado abaixo não tem nenhuma, por isso aparece a mensagem "Nenhuma linha para mostrar". Para criar uma instância do Memorystore, clique em Criar instância na parte de cima:

63547aa575838a36.png

Esta página tem um formulário para preencher com as configurações desejadas e criar a instância do Memorystore:

b77d927287fdf4c7.png

Para manter os custos baixos neste tutorial e no app de exemplo, siga as recomendações abordadas anteriormente. Depois de fazer as seleções, clique em Criar. O processo de criação leva vários minutos. Quando terminar, copie o endereço IP e o número da porta da instância para adicionar a app.yaml.

Na linha de comando

Embora seja visualmente informativo criar instâncias do Memorystore no Console do Cloud, algumas pessoas preferem a linha de comando. Verifique se o gcloud está instalado e inicializado antes de continuar.

Assim como no Console do Cloud, o Cloud Memorystore para Redis precisa estar ativado. Emita o comando gcloud services enable redis.googleapis.com e aguarde a conclusão, como neste exemplo:

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

Se o serviço já estiver ativado, executar o comando (de novo) não terá efeitos colaterais (negativos). Com o serviço ativado, vamos criar uma instância do Memorystore. O comando tem esta aparência:

gcloud redis instances create NAME --redis-version VERSION \
    --region REGION --project PROJECT_ID

Escolha um nome para sua instância do Memorystore. Este laboratório usa "demo-ms" como nome e o ID do projeto "my-project". A região deste app de exemplo é us-central1 (igual a us-central), mas você pode usar uma mais próxima se a latência for um problema. Selecione a mesma região do seu app do App Engine. Você pode escolher qualquer versão do Redis, mas estamos usando a versão 5, conforme recomendado anteriormente. Com essas configurações, este é o comando que você vai emitir (junto com a saída associada):

$ gcloud redis instances create demo-ms --region us-central1 \
    --redis-version redis_5_0 --project my-project

Create request issued for: [demo-ms]
Waiting for operation [projects/my-project/locations/us-central1/operations/operation-xxxx] to complete...done.
Created instance [demo-ms].

Ao contrário dos padrões do console do Cloud, gcloud usa recursos mínimos por padrão. O resultado é que nem o nível de serviço nem a quantidade de armazenamento foram necessários nesse comando. A criação de uma instância do Memorystore leva alguns minutos. Quando ela estiver pronta, anote o endereço IP e o número da porta da instância, porque eles serão adicionados a app.yaml em breve.

Confirmar a criação da instância

No console do Cloud ou na linha de comando

Se você criou a instância no Console do Cloud ou na linha de comando, confirme se ela está disponível e pronta para uso com este comando: gcloud redis instances list --region REGION

Confira o comando para verificar instâncias na região us-central1 e a saída esperada mostrando a instância que acabamos de criar:

$ gcloud redis instances list --region us-central1
INSTANCE_NAME  VERSION    REGION       TIER   SIZE_GB  HOST         PORT  NETWORK  RESERVED_IP     STATUS  CREATE_TIME
demo-ms        REDIS_5_0  us-central1  BASIC  1        10.aa.bb.cc  6379  default  10.aa.bb.dd/29  READY   2022-01-28T09:24:45

Quando for solicitado a informar os dados da instância ou configurar o app, use HOST e PORT (não RESERVED_IP). O painel do Cloud Memorystore no Console do Cloud agora vai mostrar essa instância:

c5a6948ec1c056ed.png

De uma máquina virtual do Compute Engine

Se você tiver uma máquina virtual (VM) do Compute Engine, também poderá enviar comandos diretos da VM para a instância do Memorystore e confirmar se ela está funcionando. O uso de uma VM pode ter custos associados, independentemente dos recursos que você já está usando.

Criar um conector de acesso VPC sem servidor

Assim como no Cloud Memorystore, é possível criar o conector de VPC sem servidor do Cloud no Console do Cloud ou na linha de comando. Da mesma forma, a VPC do Cloud não tem um nível sem custo financeiro. Por isso, recomendamos alocar a menor quantidade de recursos para concluir o codelab e manter os custos no mínimo. Isso pode ser feito com estas configurações:

  • Selecione o menor número máximo de instâncias: 3 (console e padrão do gcloud: 10)
  • Escolha o tipo de máquina de menor custo: f1-micro (padrão do console: e2-micro, sem padrão gcloud)

A próxima seção vai mostrar como criar o conector no console do Cloud usando as configurações de VPC do Cloud acima. Se você preferir fazer isso na linha de comando, avance para a próxima seção.

No Console do Cloud

Acesse a página Rede do Cloud "Acesso VPC sem servidor" no console do Cloud. Talvez seja necessário informar dados de faturamento. Se você ainda não tiver ativado a API, será solicitado a fazer isso:

e3b9c0651de25e97.png

Depois de ativar a API (e possivelmente o faturamento), você vai acessar o painel que mostra todos os conectores de VPC criados. O projeto usado na captura de tela abaixo não tem nenhuma, por isso a mensagem "Nenhuma linha para mostrar". No console, clique em Criar conector na parte de cima:

b74b49b9d73b7dcf.png

Preencha o formulário com as configurações desejadas:

6b26b2aafa719f73.png

Escolha as configurações adequadas para seus aplicativos. Para este tutorial e o app de exemplo com necessidades mínimas, faz sentido minimizar os custos. Portanto, siga as recomendações abordadas anteriormente. Depois de fazer as seleções, clique em Criar. A solicitação de um conector de VPC leva alguns minutos para ser concluída.

Pela linha de comando

Antes de criar um conector de VPC, ative a API de acesso VPC sem servidor. Você vai ver uma saída semelhante depois de executar o seguinte comando:

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

Com a API ativada, um conector de VPC é criado com um comando semelhante a este:

gcloud compute networks vpc-access connectors create CONNECTOR_NAME \
    --range 10.8.0.0/28 --region REGION --project PROJECT_ID

Escolha um nome para o conector e um endereço IP inicial de bloco CIDR /28 não utilizado. Este tutorial parte das seguintes premissas:

  • Project ID: my-project
  • Nome do conector de VPC: demo-vpc
  • Instâncias mínimas: 2 (padrão) e instâncias máximas: 3
  • Tipo de instância: f1-micro
  • Região: us-central1
  • Bloco CIDR IPv4: 10.8.0.0/28 (conforme recomendado no console do Google Cloud)

A saída será semelhante a esta se você executar o comando a seguir com as proposições acima:

$ gcloud compute networks vpc-access connectors create demo-vpc \
    --max-instances 3 --range 10.8.0.0/28 --machine-type f1-micro \
    --region us-central1  --project my-project

Create request issued for: [demo-vpc]
Waiting for operation [projects/my-project/locations/us-central1/operations/xxx] to complete...done.
Created connector [demo-vpc].

O comando acima omite a especificação de valores padrão, como um mínimo de duas instâncias e uma rede chamada default. A criação de um conector de VPC leva vários minutos.

Confirmar se o conector foi criado

Quando o processo for concluído, execute o seguinte comando gcloud, supondo que seja a região us-central1, para confirmar que ele foi criado e está pronto para uso:

$ gcloud compute networks vpc-access connectors list --region us-central1
CONNECTOR_ID  REGION       NETWORK  IP_CIDR_RANGE  SUBNET  SUBNET_PROJECT  MIN_THROUGHPUT  MAX_THROUGHPUT  STATE
demo-vpc      us-central1  default  10.8.0.0/28                            200             300             READY

Da mesma forma, o painel agora vai mostrar o conector que você acabou de criar:

e03db2c8140ed014.png

Anote o ID do projeto na nuvem, o nome do conector de VPC e a região.

Agora que você criou os recursos adicionais do Cloud necessários, seja por linha de comando ou no console, é hora de atualizar a configuração do aplicativo para oferecer suporte ao uso deles.

5. Atualizar os arquivos de configuração

A primeira etapa é fazer todas as atualizações necessárias nos arquivos de configuração. Ajudar os usuários do Python 2 a migrar é o principal objetivo deste codelab. No entanto, esse conteúdo geralmente é seguido de informações sobre a portabilidade para o Python 3 em cada seção abaixo.

requirements.txt

Nesta seção, vamos adicionar pacotes para oferecer suporte ao Cloud Memorystore e ao Cloud NDB. Para o Cloud Memorystore para Redis, basta usar o cliente Redis padrão para Python (redis), já que não há uma biblioteca de cliente do Cloud Memorystore. Anexe redis e google-cloud-ndb a requirements.txt, unindo flask do Módulo 12:

flask
redis
google-cloud-ndb

Esse arquivo requirements.txt não tem números de versão, o que significa que as versões mais recentes estão selecionadas. Se houver incompatibilidades, especifique os números de versão para bloquear as versões em funcionamento.

app.yaml

Novas seções para adicionar

O ambiente de execução do Python 2 do App Engine exige pacotes específicos de terceiros ao usar APIs do Cloud, como o Cloud NDB, ou seja, grpcio e setuptools. Os usuários do Python 2 precisam listar bibliotecas integradas como essas junto com uma versão disponível em app.yaml. Se você ainda não tiver uma seção libraries, crie uma e adicione as duas bibliotecas da seguinte maneira:

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

Ao migrar seu app, ele já pode ter uma seção libraries. Se houver e grpcio ou setuptools estiverem faltando, adicione-os à seção libraries.

Em seguida, nosso app de exemplo precisa das informações da instância do Cloud Memorystore e do conector de VPC. Por isso, adicione as duas novas seções a seguir a app.yaml, independente de qual ambiente de execução do Python você está usando:

env_variables:
    REDIS_HOST: 'YOUR_REDIS_HOST'
    REDIS_PORT: 'YOUR_REDIS_PORT'

vpc_access_connector:
    name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR

Essas são as atualizações necessárias. Seu app.yaml atualizado vai ficar assim:

runtime: python27
threadsafe: yes
api_version: 1

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

libraries:
- name: grpcio
  version: 1.0.0
- name: setuptools
  version: 36.6.0

env_variables:
    REDIS_HOST: 'YOUR_REDIS_HOST'
    REDIS_PORT: 'YOUR_REDIS_PORT'

vpc_access_connector:
    name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR

Confira abaixo um "antes e depois" ilustrando as atualizações que você precisa aplicar a app.yaml:

ec2bb027a67debb6.png

*Diferenças do Python 3

Esta seção é opcional e só é necessária se você estiver fazendo a portabilidade para o Python 3. Para isso, é necessário fazer várias mudanças na configuração do Python 2. Pule esta seção se você não estiver fazendo upgrade no momento.

Nem threadsafe nem api_version são usados no ambiente de execução do Python 3. Portanto, exclua essas duas configurações. O ambiente de execução mais recente do App Engine não é compatível com bibliotecas de terceiros integradas nem com a cópia de bibliotecas não integradas. O único requisito para pacotes de terceiros é listá-los em requirements.txt. Como resultado, toda a seção libraries de app.yaml pode ser excluída.

Em seguida, o ambiente de execução do Python 3 exige o uso de frameworks da Web que fazem o próprio roteamento. Por isso, mostramos aos desenvolvedores como migrar do webp2 para o Flask no módulo 1. Como resultado, todos os gerenciadores de script precisam ser alterados para auto. Como esse app não veicula arquivos estáticos, é "inútil" ter gerenciadores listados (já que todos são auto). Portanto, toda a seção handlers também pode ser removida. Como resultado, seu novo app.yaml abreviado e ajustado para Python 3 deve ser encurtado para ficar assim:

runtime: python39

env_variables:
    REDIS_HOST: 'YOUR_REDIS_HOST'
    REDIS_PORT: 'YOUR_REDIS_PORT'

vpc_access_connector:
    name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR

Resumindo as diferenças em app.yaml ao migrar para o Python 3:

  • Excluir as configurações de threadsafe e api_version
  • Excluir a seção libraries
  • Exclua a seção handlers (ou apenas os gerenciadores script se o app veicular arquivos estáticos)

Substitua os valores

Os valores nas novas seções do Memorystore e do conector de VPC são apenas marcadores de posição. Substitua esses valores em maiúsculas (YOUR_REDIS_HOST, YOUR_REDIS_PORT, PROJECT_ID, REGION, CONNECTOR_NAME) pelos valores salvos quando você criou esses recursos anteriormente. Em relação à instância do Memorystore, use HOST (não RESERVED_IP) e PORT. Confira uma maneira rápida de linha de comando para receber o HOST e o PORT, supondo um nome de instância demo-ms e que o REGION seja us-central1:

$ gcloud redis instances describe demo-ms --region us-central1 \
    --format "value(host,port)"
10.251.161.51   6379

Se o endereço IP da nossa instância de exemplo do Redis fosse 10.10.10.10 usando a porta 6379 no projeto my-project localizado na região us-central1 com um nome de conector de VPC demo-vpc, estas seções em app.yaml seriam assim:

env_variables:
    REDIS_HOST: '10.10.10.10'
    REDIS_PORT: '6379'

vpc_access_connector:
    name: projects/my-project/locations/us-central1/connectors/demo-vpc

Criar ou atualizar appengine_config.py

Adicionar suporte a bibliotecas integradas de terceiros

Assim como fizemos com app.yaml antes, adicione o uso das bibliotecas grpcio e setuptools. Modifique appengine_config.py para oferecer suporte a bibliotecas integradas de terceiros. Se isso parece familiar, é porque também era necessário no Módulo 2 ao migrar do App Engine ndb para o Cloud NDB. A mudança exata necessária é adicionar a pasta lib ao conjunto de trabalho setuptools.pkg_resources:

4140b3800694f77e.png

*Diferenças do Python 3

Esta seção é opcional e só é necessária se você estiver fazendo a portabilidade para o Python 3. Uma das mudanças bem-vindas da segunda geração do App Engine é que não é mais necessário copiar (às vezes chamado de "vendoring") pacotes de terceiros (não integrados) e referenciar pacotes de terceiros integrados em app.yaml. Isso significa que você pode excluir todo o arquivo appengine_config.py.

6. Atualizar arquivos do aplicativo

Há apenas um arquivo de aplicativo, main.py, então todas as mudanças nesta seção afetam apenas esse arquivo. Fornecemos uma representação ilustrada das mudanças que vamos fazer para migrar esse aplicativo para o Cloud Memorystore. Ele é apenas para fins ilustrativos e não deve ser analisado com atenção. Todo o trabalho está nas mudanças que fazemos no código.

5d043768ba7be742.png

Vamos abordar cada seção por vez, começando de cima para baixo.

Atualizar importações

A seção de importação em main.py do módulo 12 usa o Cloud NDB e o Cloud Tasks. Confira as importações:

ANTES:

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

Para mudar para o Memorystore, é necessário ler variáveis de ambiente. Isso significa que precisamos do módulo os do Python e do redis, o cliente Redis do Python. Como o Redis não pode armazenar em cache objetos Python, faça o marshall da lista de visitas mais recentes usando pickle. Portanto, importe isso também. Um benefício do Memcache é que a serialização de objetos acontece automaticamente, enquanto o Memorystore é um pouco mais "faça você mesmo". Por fim, faça upgrade do App Engine ndb para o Cloud NDB substituindo google.appengine.ext.ndb por google.cloud.ndb. Depois de essas mudanças, as importações vão ficar assim:

AFTER:

import os
import pickle
from flask import Flask, render_template, request
from google.cloud import ndb
import redis

Atualizar inicialização

A inicialização do módulo 12 consiste em instanciar o objeto do aplicativo Flask app e definir uma constante para uma hora de armazenamento em cache:

ANTES:

app = Flask(__name__)
HOUR = 3600

O uso das APIs do Cloud exige um cliente. Portanto, crie uma instância de um cliente do Cloud NDB logo após o Flask. Em seguida, extraia o endereço IP e o número da porta da instância do Memorystore das variáveis de ambiente definidas em app.yaml. Com essas informações, crie uma instância de um cliente Redis. Veja como fica o código após essas atualizações:

AFTER:

app = Flask(__name__)
ds_client = ndb.Client()
HOUR = 3600
REDIS_HOST = os.environ.get('REDIS_HOST', 'localhost')
REDIS_PORT = os.environ.get('REDIS_PORT', '6379')
REDIS = redis.Redis(host=REDIS_HOST, port=REDIS_PORT)

*Migração para o Python 3

Esta seção é opcional e se você estiver começando com a versão em Python 3 do app do módulo 12. Se for o caso, há várias mudanças necessárias relacionadas a importações e inicialização.

Primeiro, como o Memcache é um serviço incluído do App Engine, o uso dele em um app Python 3 exige o SDK do App Engine, especificamente o encapsulamento do aplicativo WSGI (além de outras configurações necessárias):

ANTES:

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

app = Flask(__name__)
app.wsgi_app = wrap_wsgi_app(app.wsgi_app)
HOUR = 3600

Como estamos migrando para o Cloud Memorystore (não um serviço incluído do App Engine, como o Memcache), o uso do SDK precisa ser removido. É simples, basta excluir toda a linha que importa memcache e wrap_wsgi_app. Exclua também a linha que chama wrap_wsgi_app(). Essas atualizações deixam essa parte do app (na verdade, o app inteiro) idêntica à versão do Python 2.

AFTER:

import os
import pickle
from flask import Flask, render_template, request
from google.cloud import ndb
import redis

app = Flask(__name__)
ds_client = ndb.Client()
HOUR = 3600
REDIS_HOST = os.environ.get('REDIS_HOST', 'localhost')
REDIS_PORT = os.environ.get('REDIS_PORT', '6379')
REDIS = redis.Redis(host=REDIS_HOST, port=REDIS_PORT)

Por fim, remova o uso do SDK de app.yaml (exclua a linha: app_engine_apis: true) e requirements.txt (exclua a linha: appengine-python-standard).

Migrar para o Cloud Memorystore (e o Cloud NDB)

O modelo de dados do Cloud NDB foi criado para ser compatível com o ndb do App Engine. Isso significa que a definição de objetos Visit permanece a mesma. Imitando a migração do módulo 2 para o Cloud NDB, todas as chamadas do Datastore em store_visit() e fetch_visits() são aumentadas e incorporadas em um novo bloco with, já que o uso do gerenciador de contexto do Cloud NDB é obrigatório. Confira as chamadas antes dessa mudança:

ANTES:

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

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

Adicione um bloco with ds_client.context() às duas funções e coloque as chamadas do Datastore dentro dele (com recuo). Nesse caso, não é necessário fazer mudanças nas próprias chamadas:

AFTER:

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

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

Em seguida, vamos analisar as mudanças no armazenamento em cache. Esta é a função main() do Módulo 12:

ANTES:

@app.route('/')
def root():
    'main application (GET) handler'
    # check for (hour-)cached visits
    ip_addr, usr_agt = request.remote_addr, request.user_agent
    visitor = '{}: {}'.format(ip_addr, usr_agt)
    visits = memcache.get('visits')

    # register visit & run DB query if cache empty or new visitor
    if not visits or visits[0].visitor != visitor:
        store_visit(ip_addr, usr_agt)
        visits = list(fetch_visits(10))
        memcache.set('visits', visits, HOUR)  # set() not add()

    return render_template('index.html', visits=visits)

O Redis tem chamadas "get" e "set", assim como o Memcache. Tudo o que fazemos é trocar as bibliotecas de cliente respectivas, certo? Quase. Como mencionado anteriormente, não é possível armazenar em cache uma lista do Python com o Redis, porque ela precisa ser serializada primeiro, algo que o Memcache faz automaticamente. Portanto, na chamada set(), faça o "pickle" das visitas em uma string com pickle.dumps(). Da mesma forma, ao recuperar visitas do cache, é necessário usar pickle.loads() logo após o get(). Este é o gerenciador principal depois de implementar essas mudanças:

AFTER:

@app.route('/')
def root():
    'main application (GET) handler'
    # check for (hour-)cached visits
    ip_addr, usr_agt = request.remote_addr, request.user_agent
    visitor = '{}: {}'.format(ip_addr, usr_agt)
    rsp = REDIS.get('visits')
    visits = pickle.loads(rsp) if rsp else None

    # register visit & run DB query if cache empty or new visitor
    if not visits or visits[0].visitor != visitor:
        store_visit(ip_addr, usr_agt)
        visits = list(fetch_visits(10))
        REDIS.set('visits', pickle.dumps(visits), ex=HOUR)

    return render_template('index.html', visits=visits)

Concluímos as mudanças necessárias em main.py para converter o uso do Memcache pelo app de exemplo no Cloud Memorystore. E o modelo HTML e a portabilidade para o Python 3?

Atualizar o arquivo de modelo HTML e migrar para o Python 3?

Surpresa! Não é necessário fazer nada aqui, já que o aplicativo foi projetado para ser executado no Python 2 e 3 sem alterações no código nem bibliotecas de compatibilidade. Você vai encontrar main.py. idênticos nas pastas "FINISH" do mod13a (2.x) e do mod13b (3.x). O mesmo vale para requirements.txt , além de diferenças nos números de versão (se usados). Como a interface do usuário não muda, não há atualizações no templates/index.html.

Tudo o que é necessário para executar esse app no Python 3 do App Engine foi concluído anteriormente na configuração: diretivas desnecessárias foram removidas de app.yaml, e appengine_config.py e a pasta lib foram excluídos porque não são usados no Python 3.

7. Resumo/limpeza

Esta seção conclui o codelab implantando o app e verificando se ele funciona conforme o esperado e em qualquer saída refletida. Depois da validação do app, faça uma limpeza e pense nas próximas etapas.

Implantar e verificar o aplicativo

A última verificação é sempre implantar o app de exemplo. Desenvolvedores do Python 2: exclua e reinstale o lib com os comandos abaixo. Se você tiver o Python 2 e o 3 instalados no sistema, talvez seja necessário executar pip2 explicitamente.

rm -rf ./lib
pip install -t lib -r requirements.txt

Agora, os desenvolvedores de Python 2 e 3 precisam implantar os apps com:

gcloud app deploy

Como você apenas reconectou as coisas por baixo dos panos para um serviço de armazenamento em cache completamente diferente, o app em si vai operar de maneira idêntica ao app do Módulo 12:

App visitme do módulo 7

Esta etapa conclui o codelab. Compare o app de exemplo atualizado com uma das pastas do módulo 13, mod13a (Python 2) ou mod13b (Python 3).

Limpar

Geral

Se você terminou por enquanto, recomendamos que desative o app do App Engine para evitar cobranças. No entanto, se você quiser testar ou experimentar mais, a plataforma do App Engine tem uma cota sem custo financeiro. Portanto, enquanto você não exceder esse nível de uso, não vai receber cobranças. Isso é para computação, mas também pode haver cobranças por serviços relevantes do App Engine. Consulte a página de preços para mais informações. Se essa migração envolver outros serviços do Cloud, eles serão cobrados separadamente. Em qualquer caso, se aplicável, consulte a seção "Específico para este codelab" abaixo.

Para total transparência, a implantação em uma plataforma de computação sem servidor do Google Cloud, como o App Engine, gera custos mínimos de build e armazenamento. O Cloud Build e o Cloud Storage têm cotas sem custo financeiro próprias. O armazenamento dessa imagem usa parte dessa cota. No entanto, talvez você more em uma região que não tem um nível sem custo financeiro. Por isso, fique de olho no uso do armazenamento para minimizar possíveis custos. As "pastas" específicas do Cloud Storage que você precisa analisar incluem:

  • 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
  • Os links de armazenamento acima dependem da sua PROJECT_ID e *LOC*ação. Por exemplo, "us" se o app estiver hospedado nos EUA.

Por outro lado, se você não quiser continuar com este aplicativo ou outros codelabs de migração relacionados e quiser excluir tudo completamente, desligue seu projeto.

Específico para este codelab

Os serviços listados abaixo são exclusivos deste codelab. Consulte a documentação de cada produto para mais informações:

Neste tutorial, usamos quatro produtos do Cloud:

  • App Engine
  • Cloud Datastore
  • Cloud Memorystore
  • Cloud VPC

Confira abaixo as instruções para liberar esses recursos e evitar/minimizar cobranças.

Desativar a instância do Memorystore e o conector de VPC

Esses são os produtos sem um nível sem custo financeiro, então você está recebendo cobranças agora. Se você não encerrar o projeto do Cloud (consulte a próxima seção), será necessário excluir a instância do Memorystore e o conector da VPC para interromper o faturamento. Assim como na criação desses recursos, você também pode liberá-los no console do Cloud ou na linha de comando.

No Console do Cloud

Para excluir a instância do Memorystore, volte ao painel do Memorystore e clique no ID da instância:

2b09baf1aa2e0a25.png

Na página de detalhes da instância, clique em "Excluir" e confirme:

f9d9eb1c1d4c6107.png

Para excluir o conector de VPC, acesse o painel dele, marque a caixa de seleção ao lado do conector que você quer excluir, clique em "Excluir" e confirme:

ca5fbd9f4c7c9b60.png

Na linha de comando

O par de comandos gcloud a seguir exclui a instância do Memorystore e o conector de VPC, respectivamente:

  • gcloud redis instances delete INSTANCE --region REGION
  • gcloud compute networks vpc-access connectors delete CONNECTOR --region REGION

Se você não tiver definido o ID do projeto com gcloud config set project, talvez seja necessário fornecer --project PROJECT_ID. Se a instância do Memorystore for chamada de demo-ms e o conector de VPC de demo-vpc, e ambos estiverem na região us-central1, execute o seguinte par de comandos e confirme:

$ gcloud redis instances delete demo-ms --region us-central1
You are about to delete instance [demo-ms] in [us-central1].
Any associated data will be lost.

Do you want to continue (Y/n)?

Delete request issued for: [demo-ms]
Waiting for operation [projects/PROJECT/locations/REGION/operations/operation-aaaaa-bbbbb-ccccc-ddddd] to complete...done.
Deleted instance [demo-ms].
$
$ gcloud compute networks vpc-access connectors delete demo-vpc --region us-central1
You are about to delete connector [demo-vpc] in [us-central1].
Any associated data will be lost.

Do you want to continue (Y/n)?

Delete request issued for: [demo-vpc]
Waiting for operation [projects/PROJECT/locations/REGION/operations/aaaaa-bbbb-cccc-dddd-eeeee] to complete...done.
Deleted connector [demo-vpc].

Cada solicitação leva alguns minutos para ser executada. Essas etapas são opcionais se você optar por desligar todo o projeto na nuvem, conforme descrito anteriormente. No entanto, o faturamento será cobrado até que o processo de desligamento seja concluído.

Próximas etapas

Além deste tutorial, outros módulos de migração que se concentram em migrar dos serviços agrupados legados incluem:

  • Módulo 2: migrar do App Engine ndb para o Cloud NDB
  • Módulos 7 a 9: migrar das tarefas push da fila de tarefas do App Engine para o Cloud Tasks
  • Módulos 12 e 13: migrar do Memcache do App Engine para o Cloud Memorystore
  • Módulos 15 e 16: migrar do Blobstore do App Engine para o Cloud Storage
  • Módulos 18 e 19: migrar da fila de tarefas do App Engine (tarefas pull) para o Cloud Pub/Sub

O App Engine não é mais a única plataforma sem servidor no Google Cloud. Se você tem um app pequeno do App Engine ou um com funcionalidade limitada e quer transformá-lo em um microsserviço independente, ou se quer dividir um app monolítico em vários componentes reutilizáveis, esses são bons motivos para considerar a migração para o Cloud Functions. Se a contêinerização se tornou parte do seu fluxo de trabalho de desenvolvimento de aplicativos, principalmente se ele consistir em um pipeline de CI/CD (integração contínua/entrega ou implantação contínua), considere migrar para o Cloud Run. Esses cenários são abordados nos seguintes módulos:

  • Migrar do App Engine para o Cloud Functions: consulte o Módulo 11
  • Migrar do App Engine para o Cloud Run: consulte o Módulo 4 para contentorizar seu app com o Docker ou o Módulo 5 para fazer isso sem contêineres, conhecimento do Docker ou Dockerfiles

A mudança para outra plataforma sem servidor é opcional. Recomendamos considerar as melhores opções para seus apps e casos de uso antes de fazer qualquer mudança.

Independente do módulo de migração que você considerar em seguida, todo o conteúdo da Estação de migração sem servidor (codelabs, vídeos, código-fonte [quando disponível]) pode ser acessado no repositório de código aberto. O README do repositório também oferece orientações sobre quais migrações considerar e a "ordem" relevante dos módulos de migração.

8. Outros recursos

Confira abaixo mais recursos para desenvolvedores que querem saber mais sobre este ou outros módulos de migração e produtos relacionados. Isso inclui locais para enviar feedback sobre o conteúdo, links para o código e vários documentos que podem ser úteis.

Problemas/feedback dos codelabs

Se você encontrar problemas com este codelab, pesquise seu problema antes de preenchê-lo. Links para pesquisar e criar novos problemas:

Recursos de migração

Os links para as pastas do repositório do módulo 12 (START) e do Módulo 13 (FINISH) podem ser encontrados na tabela abaixo. Elas também podem ser acessadas no repositório de todas as migrações de codelab do App Engine, que você pode clonar ou fazer o download de um arquivo ZIP.

Codelab

Python 2

Python 3

Módulo 12

código

código

Módulo 13 (este codelab)

código

código

Referências on-line

Confira abaixo recursos on-line que podem ser relevantes para este tutorial:

App Engine

NDB do App Engine e NDB do Cloud

Memcache do App Engine e Cloud Memorystore

Cloud VPC

Outras informações da nuvem

Licença

Este conteúdo está sob a licença Atribuição 2.0 Genérica da Creative Commons.