Pular para o conteúdo principal
BlogBancos de dadosDjango e SQL: Seu Duo Dinâmico para Bancos de Dados em Escala

Django e SQL: Seu Duo Dinâmico para Bancos de Dados em Escala

ScaleDatabaseswithDjangoandSQL-BlogHeader

Dimensionar e otimizar bancos de dados para atender às necessidades de suas aplicações pode ser um desafio significativo. Se você ainda não leu meu recente blog sobre como Django pode fazer o trabalho pesado para Python e aplicações de bancos de dados SQL, recomendo vivamente que você dê uma olhada. Mas a versão TL;DR é que SQL é otimizada para bancos de dados SQL, Python não é, e Django é um grande intermediário para ajudá-lo a construir aplicações mais eficazes, com menos atrito, complexidade e código ao usar estas duas linguagens juntas.

Assim, enquanto Django faz o trabalho pesado de criar o aplicativo de banco de dados, você ainda é responsável pelo gerenciamento e monitoramento diário de seus bancos de dados. Algumas destas tarefas de gerenciamento podem ser adiadas para seu provedor de nuvens, utilizando serviços como Linode Managed Databases, mas você poderá descobrir novos bloqueios à medida que escalar, como por exemplo:

  • Migrações de banco de dados. Conversão de um banco de dados existente para um novo estado desejado com mudanças controladas no esquema do banco de dados.
  • Implantações em bancos de dados múltiplos. Para otimizar o desempenho, os desenvolvedores podem projetar suas aplicações para utilizar bases de dados separadas para funções segmentadas. Por exemplo, um banco de dados primário de leitura/gravação e um banco de dados de réplicas de leitura para consultas comuns.

Se um de seus bancos de dados usa SQL, você pode usar Django para reduzir o atrito e tornar sua vida muito mais fácil enquanto manipula uma quantidade significativa de dados.

Esta introdução a dois conceitos-chave de gerenciamento de banco de dados se une com as instruções passo a passo para construir uma aplicação Django pronta para a produção, encontradas no ebook Understanding Databases e na minha nova série de vídeos educativos. Qualquer um dos caminhos de aprendizado ajudará você a fazer com que o Django faça o levantamento pesado do SQL para você.

Migrações de banco de dados
Quando você está começando, obter os tipos de dados corretos para qualquer coluna pode ser um pouco complicado, especialmente porque suas necessidades de dados inevitavelmente mudarão com o tempo. E se você quisesse que seu campo de título tivesse apenas 80 caracteres? E se você precisar adicionar um campo de carimbo de data/hora para poder acompanhar exatamente quando os itens foram adicionados ao banco de dados?

A mudança de uma mesa após sua criação pode ficar bastante bagunçada por algumas razões:

  • O que você faz com os valores pré-existentes?
  • E se faltarem linhas preexistentes para novas colunas/campos?
  • E se você remover uma coluna/campo? O que acontece com os dados?
  • E se você acrescentar uma relação que não existia antes (ou seja, chaves estrangeiras)?

Felizmente para os desenvolvedores Django, temos algo chamado makemigrations e migrate.

Vamos dar uma olhada em como funciona em ação.

Aqui está nosso exemplo de modelo de dados Django:

class BlogArticle(models.Model):
    user = models.ForeignKey(User, default=1, on_delete=models.SET_DEFAULT)
    title = models.CharField(max_length=120)
    slug = models.SlugField(blank=True, null=True)
    content = models.TextField(blank=True, null=True)
    publish_timestamp = models.DateTimeField(
        auto_now_add=False,
        auto_now=False,
        blank=True,
        null=True,
    )

Vamos acrescentar o campo:

updated_by = models.ForeignKey(
        User, related_name="editor", null=True, blank=True, on_delete=models.SET_NULL
)

Este campo nos permitirá rastrear o último usuário a fazer uma mudança em nosso modelo. 

Vamos atualizar nosso modelo:

class BlogArticle(models.Model):
    user = models.ForeignKey(User, default=1, on_delete=models.SET_DEFAULT)
    title = models.CharField(max_length=120)
    slug = models.SlugField(blank=True, null=True)
    content = models.TextField(blank=True, null=True)
    publish_timestamp = models.DateTimeField(
        auto_now_add=False,
        auto_now=False,
        blank=True,
        null=True,
    )
    # our new field
    updated_by = models.ForeignKey(
        User, related_name="editor", null=True, blank=True, on_delete=models.SET_NULL
    )

Agora, depois de salvarmos este arquivo, este BlogArticle classe é declarada em (models.py), como informar ao nosso banco de dados que esta mudança ocorreu?

Há duas maneiras:

  1. python manage.py makemigrations
  2. python manage.py migrate

Vamos discutir o que estes dois comandos fazem:

python gerenciar.py makemigrations

python manage.py makemigrations procura por mudanças em todos models.py arquivos em seu projeto Django e procura por mudanças. Se forem encontradas mudanças, um novo arquivo python será criado com o mudanças propostas que nosso banco de dados SQL necessidades a fazer. As mudanças propostas são algo parecidas:

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ('articles', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='article',
            name='updated_by',
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='editor', to=settings.AUTH_USER_MODEL),
        ),
    ]

Este, é claro, é apenas mais um arquivo Python . Este arquivo está nos deixando (aos desenvolvedores) saber o que deve acontecer em nosso banco de dados. Está escrito em Python e não em SQL para manter a coesão e alavancar as características embutidas do Django ORM.

Mas por que este é um arquivo para o que deveria acontecer? Bem, há algumas razões para isto:

  • Se precisarmos rever o que deve acontecer antes, podemos pegá-lo aqui.
  • Este makemigrations não verificar com o banco de dados para ver se esta mudança pode até mesmo acontecer.
  • O banco de dados pode já ter sido alterado para atender a essas exigências (dependendo de uma série de fatores relacionados a quem/quem está gerenciando o banco de dados).
  • Se precisarmos fazer testes antes de mudar um banco de dados de produção, agora mesmo seria um momento incrível para fazer isso.

Assumindo que esta mudança é válida (tanto quanto podemos dizer), podemos comprometer as mudanças:

python manage.py migrate

python manage.py migrate tentará mudar nosso banco de dados - todos os campos, colunas, tabelas, chaves estrangeiras, o que você indicar - Django fará o trabalho para ajudar a garantir que o banco de dados seja atualizado da maneira que pretendíamos.

É importante notar que Django pode não conseguir fazer essas mudanças por uma série de razões. Para os novos desenvolvedores Django, isto se deve quase sempre à adição e remoção de campos e colunas e à falha em executar as migrações corretamente.

Quando feito corretamente, python manage.py migrate garante um sistema estável que combina nosso código Python com nossas tabelas SQL, permitindo-nos assim todas as maravilhas que tanto o banco de dados Django quanto o SQL nos proporcionam.

Como isso nos dá mais flexibilidade?

Python tem aplicações amplas onde o SQL não tem. A Structured Query Language tem suas limitações escritas no nome. Quem está criando animações Pixar apenas com SQL?

OK, tudo isso é para dizer que a simplicidade do Python na verdade ajuda os desenvolvedores a adotarem o poder do SQL e possivelmente sem mesmo sabê-lo.

Por que bancos de dados gerenciados e Django Make Sense

Quando se trata de criar uma aplicação web, incluindo o Django, você precisará decidir algumas coisas:

  • Que solução(ões) de armazenamento de dados desejamos? MySQL, Postgres, MongoDB, Redis, Object Storage, etc
  • Como vamos executar/integrar com a solução de armazenamento de dados?
  • Como vamos nos recuperar da interrupção ou do tempo de inatividade?
  • Como vamos manter a solução de armazenamento?
  • Como vamos garantir nossa solução de armazenamento?
  • Como vamos fazer backup de nossa solução de armazenamento?

As respostas a estas perguntas podem mudar conforme seu projeto cresce em complexidade, mas todas elas começam no mesmo lugar: decidir entre autogerido e gerenciado por terceiros.

Auto-gerenciado:

  • Prós: Controle e custo.
  • (Significativo) Con: Você é responsável por tudo.

Serviços gerenciados muitas vezes custam mais dinheiro desde o início, enquanto que a auto-gestão significa que você pode usar sua distro Linux preferida que é de alguma forma (ou de alguma forma) otimizada para o que você precisa. Isto pode incluir a execução de uma versão bifurcada do MySQL que sua equipe tenha modificado. Você pode economizar dólares na execução de seu serviço, mas isto sempre levará mais tempo para ser mantido.

Bancos de dados administrados por terceiros: 

Sim, pode ser um pouco mais caro em dólares e centavos, mas levará muito menos tempo para ser mantido. Esta opção e as soluções de armazenamento de dados gerenciados são minha escolha de fato para minhas aplicações web. Neste exemplo, já estamos utilizando o Django para gerenciar transações de banco de dados. A SQLAlchemy também compartilha esta força, pois é utilizada com estruturas como FastAPI, Flask e muitas outras. Se você já está terceirizando sua escrita SQL para um pacote Python , por que não terceirizar a execução de seus servidores SQL?

Agora, dada a eficácia do Python ORMs (como Django ORM e SQLAlchemy), recomendo que você utilize o banco de dados gerenciado e/ou serviços de armazenamento de dados gerenciados sempre que possível, aqui está o que você tem a ganhar se o fizer:

  • Redução do tempo de desenvolvimento
  • Redução do tempo de gerenciamento
  • Redução do tempo de recuperação
  • Redução das interrupções de serviço
  • Redução da complexidade de implantação e desenvolvimento
  • Redução da complexidade nas migrações de banco de dados (de outros serviços)
  • Redução de atividades repetitivas/ineficazes/ineficientes para desenvolvedores de SQL
  • Redução da complexidade DevOps/Ops
  • Aumento da eficácia dos desenvolvedores não-SQL
  • Aumento da velocidade de implantação e desenvolvimento
  • Aumento da confiabilidade (muitas vezes apoiada por um Acordo de Nível de Serviço)
  • Aumento da segurança
  • Aumento da capacidade de manutenção
  • Aumento nos backups e redundância
  • Aumento marginal do custo

Fiz a lista acima com a mentalidade de usar um cluster de banco de dados MySQL gerenciado no Linode e também no Linode Object Storage (para armazenar arquivos como CSS, JavaScript, imagens, vídeos, etc.). Em termos práticos, o uso desses serviços nos ajuda a manter o foco na criação de um excelente aplicativo Web com Django, FastAPI, Flask, Node.js ou qualquer outro. Em outras palavras, mudamos o foco para a criação das ferramentas e do software que seus usuários realmente desejam. Você sabe, onde está o valor real para eles.

MySQL, PostgreSQL, Redis, e Django

Durante muito tempo, o banco de dados líder da Django foi o PostgreSQL. Eu diria que isto se deve, em grande parte, ao fato de que você poderia usar um JSONField somente dentro do Postgres. Com Django 3.2+ e MySQL 5.7.8+, o JSONField agora está disponível também para o MySQL.

Por que isso é importante?

O armazenamento de dados não estruturados, como JSON, geralmente é necessário ao lidar com conteúdo gerado pelo usuário ou ao armazenar dados de outros serviços de API. Vamos ver como:

from django.db import models

class Pet(models.Model):
    name = models.CharField(max_length=200)
    data = models.JSONField(null=True)

    def __str__(self):
        return self.name

Aqui estão os dados que eu quero armazenar em relação a este animal de estimação:

pet1 = {
    "name": "Bruno",
    "type": "Rat",
    "nickname": "We don't talk about it",
    "age": 2,
    "age_interval": "months"
}

pet2 = {
    "name": "Tom",
    "type": "Cat",
    "breed": "Mixed"
    "age": 4,
    "age_interval: "years",
    "favorite_food": [{"brand": "Acme", "flavor": "Tuna" }]
}

pet3 = {
    "name": "Stewey",
    "type": "Dog",
    "breed": "unknown"
    "age": 34,
    "age_interval: "dog years",
    "nickname": "Football"
}

Estes dados nos mostram quando podemos precisar de um JSONField . Podemos armazenar todos os nomes dos animais de estimação (usando o name chave) e manter o resto para ser armazenado no JSONField. A coisa legal sobre JSONFields é que eles podem ser consultados como qualquer outro campo Django padrão, mesmo com estes esquemas variáveis.

Há um debate contínuo entre os desenvolvedores da Django sobre qual banco de dados utilizar: MySQL ou PostgreSQL. Por muito tempo, eu sempre optei pelo PostgreSQL devido ao fato de que o JSONField só estava disponível no PostgreSQL, e isso não é mais o caso. Eu digo para escolher um e ficar com ele até que ele não atenda mais às suas necessidades.

Mas para que usamos Redis?

Redis é um datastore in-memory que é incrivelmente rápido e frequentemente usado como um banco de dados temporário (mais sobre isso em um segundo), um serviço de cache, e/ou uma fila de mensagens. A razão pela qual eu o chamo de banco de dados temporário se deve ao fato de ser in-memory. A memória é freqüentemente mais cara do que o armazenamento em disco e, portanto, o armazenamento de dados a longo prazo na memória muitas vezes não é viável.

Meu principal caso de uso para Redis e Django são o cache e a fila de espera

Caching: Digamos que você tenha várias páginas web que os usuários visitam muito. Você quer que os dados nessas páginas sejam mostrados aos usuários o mais rápido possível. Redis, como um sistema de cache para Django, faz com que isso seja incrivelmente fácil. Os dados dentro destas páginas podem ser renderizados de um banco de dados SQL, mas Redis pode armazenar os dados renderizados a partir do cache. Em outras palavras, usar Redis com SQL pode muitas vezes acelerar suas respostas ao mesmo tempo em que reduz a quantidade de consultas a seus bancos de dados SQL.

Enfileiramento: Outro caso de uso popular da Redis é descarregar tarefas de longa duração para outro processo (muitas vezes através de um pacote Python chamado Celery). Quando você precisa fazer isso, você pode usar Redis como uma fila das tarefas que devem ser concluídas em outro momento.

Por exemplo, se você tem um usuário que precisa de um relatório de todas as suas transações nos últimos cinco anos, o software pode levar horas para realmente gerar esse relatório. Obviamente, ninguém vai ficar olhando para uma máquina durante horas. Portanto, descarregaríamos este pedido de nosso usuário para uma fila Redis. Uma vez na Redis, podemos ter um processo de trabalho em execução (como usar o aipo com Django) para gerar de fato o relatório. Uma vez feito o relatório, não importa quanto tempo demorasse, o usuário seria notificado. Esta notificação, como com outras notificações, também poderia ser feita através de uma Redis Queue acoplada a um processo de trabalhador com Aipo/Django.

Isso tudo para dizer que o Redis e o MySQL realmente se complementam muito bem. Você pode implantar um servidor de banco de dados Redis autogerenciado por meio do Linode Marketplace.

Object Storage

O último serviço gerenciado relacionado a dados que recomendo usar é o Linode Object Storage. Object Storage é responsável por todos os outros tipos de dados que você pode precisar armazenar. Por exemplo, não armazenaríamos todos os bytes de um vídeo no MySQL. Em vez disso, armazenaríamos metadados relacionados a esse vídeo e armazenaríamos o vídeo em Object Storage.

Aqui estão algumas coisas para as quais você usaria o armazenamento de objetos:

  • Folhas de Estilo em Cascata (CSS)
  • JavaScript (como React.js, Vue.js, Vanilla.js, etc.)
  • Vídeos
  • Images (bruto e compactado)
  • CSVs, XLSX
  • Banco de dados Backups
  • Camadas de Imagem de Container de Docker (se auto-geridas)
  • Iterações de Algoritmos de Aprendizagem de Máquina Treinada
  • Terraform Arquivos do Estado
  • PDFs (grandes e pequenos)
  • Qualquer arquivo persistente que precise ser baixado com freqüência (ou carregado)

Sumário

Depois de ler isto, espero que você se sinta motivado a alavancar o poder dos serviços gerenciados com seus projetos de aplicação web. Django é uma excelente solução para construir aplicações web sobre bases de dados SQL, mas certamente não é a única. Se você quiser mergulhar no interior dos servidores SQL e SQL, acho que vale a pena ver quantas aplicações de sucesso alavancam Django para lidar com a maior parte do que Django pode fazer.

Aqui estão alguns (ou muitos) destaques que tornam o Django com o Managed MySQL em Linode impressionante:

  • Django faz o levantamento SQL pesado para você (assim como ferramentas como SQLAlchemy para Flask/FastAPI)
  • Django também permite comandos SQL brutos (novamente, assim como ferramentas como SQLAlchemy)
  • Django ajuda os iniciantes a aprender os comandos SQL
  • Django tem suporte integrado para MySQL e PostgreSQL (além de um cliente python específico para db)
  • Aumenta a velocidade para as implantações de produção
  • Maior confiabilidade e capacidade de recuperação
  • Permite que os ambientes de desenvolvimento e produção correspondam quase exatamente à tecnologia de banco de dados
  • Torna o Django em contêineres mais fácil e mais confiável
  • Desbloqueia o escalonamento de uma implantação de um único nó para uma transição de vários nós ou até mesmo de uma transição completa para Kubernetes
  • Mais fácil para os novos desenvolvedores Django/Python utilizarem sistemas de grau de produção
  • Compartilhar bancos de dados através de múltiplos aplicativos baseados em python é mais fácil e mais seguro (como um aplicativo de leitura/escrita FastAPI de/para um banco de dados MySQL baseado em Django).
  • O JSONField da Django agora é suportado usando o MySQL (anteriormente apenas o PostgreSQL)
  • Fácil de testar (durante CI/CD ou em ambientes de desenvolvimento local)
  • Escalas para atender as demandas da Django
  • Suporte para múltiplos bancos de dados em um único projeto Django, tais como: uso do MySQL como banco de dados primário de leitura/gravação e um banco de dados de réplicas de leitura MySQL para consultas comuns.
  • Controles de Acesso Estritos (Linode Private IPs, desenvolvimento local)
  • Requer Certificado SSL para conexão (adiciona complexidade às implantações, mas também aumenta a segurança)
  • Permite a conexão privada (na mesma região; reduz os custos de conexão)

Se você estiver interessado em uma abordagem moderna para implantar aplicações Django no Linode junto com um banco de dados MySQL gerenciado, ações GitHub para CI/CD, Terraform e Ansible, entre em toneladas de conteúdo educacional passo-a-passo gratuito:

Para ajudar você a começar, o Código para Empresários GitHub tem um repositório de código que acompanha cada etapa da série. Boa sorte, e não deixe de me informar como as coisas estão indo através do Twitter @JustinMitchel.


Comentários

Deixe uma resposta

Seu endereço de e-mail não será publicado. Os campos obrigatórios estão marcados com *