DynamoDB, direto e reto
Resumo: #
- O DynamoDB é muito bom, mas cobra por isso; é uma solução de ótimo custo benefício para aplicações que não precisam de ferramentas avançadas de banco de dados.
- O DynamoDB não se comporta como um banco de dados comum. Entender isso é vital para criar soluções melhores e mais baratas.
- O DynamoDB é otimizado para buscas de dados, e as tabelas devem ser criadas com isso em mente.
- Prefira usar Query ao invés do Scan.
- Partition Key não é Primary Key.
O que é o DynamoDB? #
O DynamoDB é a solução nativa da AWS para armazenamento de dados, e diferente das outras soluções de banco de dados que a AWS fornece, esta é totalmente gerenciada, disponibilizando uma API para busca e gerenciamento de dados, e uma interface no AWS Console para estas tarefas.
Funciona assim: você cria a sua tabela, cria seu índice inicial, define como você vai pagar pelo uso dessa tabela, e começa a usar. Depois, quando precisar, pode criar mais índices.
Coisas que o DynamoDB tem em comum com outros bancos de dados:
- Armazenamento de dados em formato de documentos
- Índices
Coisas que o DynamoDB não tem em comum com outros bancos de dados:
- Relacionamentos
- Suporte a SQL
Comparando os serviços, o DynamoDB seria comparável ao MongoDB, mas com algumas características bem diferentes.
Como o DynamoDB armazena os dados? #
Os dados são armazenados como documentos, lembrando bastante o JSON. Os únicos campos obrigatórios são os definidos no índice inicial, e os outros podem ser definidos como necessário.
No exemplo, se criarmos uma tabela alunos e definimos o campo matricula como índice inicial com formato texto, os seguintes documentos são válidos:
{
"matricula": "123",
"nome": "Mario Lopes",
"nascimento": "12/10/2010"
}
{
"matricula": "124",
"nome": "Mariana Silva",
"nascimento": "12/10/1990",
"documento": {
"tipo": "rg",
"numero": "1234"
}
}
Tipos de dados #
Os campos dos itens armazenados podem ser de diferentes tipos:
- Simples: Number, String, Binary, Boolean, Null
- Sets (Conjuntos): String Set, Number Set, Binary Set
- Document (“Objetos”): List e Map
Você não precisa definir previamente o tipo de campo que quer usar, apenas insira o valor. A exceção é ao definir índices, onde informar o tipo de campo é obrigatório e pode ser apenas String, Number ou Binary. Mais sobre isso logo abaixo.
Índices, primeira parte #
Quando cria a tabela, você define um campo que é a Partition Key (PK) da tabela, e pode definir um segundo campo como Sort Key (SK). O primeiro campo define como, internamente, os dados serão agrupados para as pesquisas, e o segundo campo define a ordem desses dados.
Então a primeira diferença que o DynamoDB apresenta em relação a outros bancos de dados é que definir como os dados serão buscados é mais importante do que definir a integridade referencial da tabela. Isso
No caso acima, o campo matricula foi usado como chave de particionamento (PK), e por isso a busca por dados usando este campo retorna os dados rapidamente.
Se quiser manter dados relacionados numa mesma partição para melhorar a pesquisa, você pode definir uma PK com esse dado e depois usar uma Sort Key para refinar a busca.
Se quisermos criar uma tabela de matriculas e desenhar para que seja fácil buscar por curso onde os alunos estão matriculados, podemos definir o campo id_curso como PK e o campo matricula como SK, e os dados ficam armazenados como abaixo.
{
"id_curso": "banco-de-dados-2021-01",
"matricula": "88",
"nota_1": 8,
"nota_2": 6
}
{
"id_curso": "banco-de-dados-2021-01",
"matricula": "65",
"nota_1": 7,
"nota_2": 9
}
Buscas de dados (query ou scan) #
Com os dados na tabela e o índice definido, podemos começar a buscar os dados. O DynamoDB tem duas formas de fazer a pesquisa nos dados: a Query e a Scan. Elas tem diferenças importantes, e usar uma ou outra pode impactar na velocidade de busca e no custo mensal (mais sobre isso em Cobrança).
No momento de fazer uma busca, podemos especificar filtros, que ****podem ser definidos usando qualquer campo, seja chave de índice ou não.
Quando a busca é feita usando o comando Scan, toda a tabela é varrida, sem ordenação, e o retorno dos dados é feito apenas quando (1) o limite de dados da busca foi atingido ou (2) quando todas as linhas foram avaliadas. Neste caso, para uma tabela com 600.000 registros, todos os registros serão lidos, mas retornados em pacotes pequenos, e a pesquisa tem que ser refeita mais vezes para que se retorne o próximo “pacote” de dados. Esse tipo de operação é desencorajado em grandes tabelas, porque é demorado e custa caro.
Com o comando Query o processo é mais simples: informamos o valor a buscar na PK, caso necessário informamos um segundo valor para a SK e, caso necessário, definimos o filtro como definido acima. Usando o comando Query já iniciamos o filtro com um conjunto reduzido de dados, o que ajuda na aplicação do filtro ou no retorno dos dados desejados.
Índices, segunda parte #
Olhando a explicação sobre as buscas de dados e os filtros, podemos dizer que construir os índices de forma inteligente ajuda a retornar buscas mais eficientes e economizar dinheiro. Mas acredito que fica uma dúvida agora: só podemos ter um índice por tabela?
Não! Podemos criar novos índices, e aqui temos uma das principais funcionalidades do DynamoDB, uma que não é tão comentada. Criar índices para uma tabela existente é uma forma de, com o mesmo conjunto de dados, criar novas possibilidades de busca e sub-conjuntos de dados.
Quando cria um novo índice, você define:
- um novo campo para chave de particionamento (PK)
- um novo campo para chave de ordenação (SK), opcional
- define um nome para o índice
- define quais campos fazem parte desse índice, e que serão parte do retorno dos dados e dos filtros para este índice.
Com isso, criar um índice não é apenas útil para criar novos tipos de ordenação, mas também para criar subconjuntos de dados baseados na tabela que esse índice faz parte. Isso é especialmente útil em duas situações:
- Se sua tabela tem 10 campos mas em um dos usos você precisa apenas de 3 destes campos, pode criar um índice com apenas estes campos e, ao usar este índice, o conjunto de dados é reduzido no uso do filtro e no retorno. Como exemplo, imagine que na tabela
matriculasusualmente a pesquisa seja pra saber apenas quais alunos estão matriculados em qual curso; portanto, podemos criar um índicematriculas_alunossó com os camposid_cursoematriculae basear nossa Query neste índice. - Se você faz uma busca baseada na existência ou não de um campo no conjunto de dados, criar um índice que inclua explicitamente este campo pode reduzir o tamanho do conjunto de dados deste índice. Como exemplo, se queremos apenas os dados da tabela
matriculaque tenham o campodocumentopreenchido, podemos criar um índice com os camposmatriculaedocumentoque, neste caso, garantimos que, ao usar este índice, só existem dados com este campo preenchido.
Mais sobre filtros #
Agora que sabemos como os índices podem nos ajudar, os filtros são o complemento da inteligência de busca do DynamoDB: eles servem para restringir o que precisamos de um conjunto de dados, seja uma tabela completa ou um índice.
Ao usar um filtro, todos os registros daquela tabela ou índice são avaliados, mas só os que correspondem à regra definida no filtro são retornados. Pode parecer estranho usar filtros quando temos os índices, mas pode ser usado para pesquisas complexas que não podem ser atendidas pelas regras dos índices, como busca de dados em intervalos.
Um exemplo de uso de filtros e índices: se precisa obter, de um conjunto de alunos de um curso específico, todos com nota abaixo de 7, pode usar o índice para obter o subconjunto dos alunos daquele curso, e depois filtrar pelo campo de nota menor que 7.
Cobrança #
Com os argumentos acima, o DynamoDB é sua escolha? Ótimo, agora é entender como o uso é cobrado, e essa é a parte mais chata deste artigo.
Começando pelo armazenamento, você paga pelo quanto usa de espaço por mês.
Você escolhe entre duas formas de cobrança: Sob demanda (On-demand) e Provisionado (Provisioned). Mas as duas tem uma característica comum, as Units, seja a Read Unit (unidade de leitura) e a Write unit (unidade de escrita).
Uma Read Unit (RU) corresponde a um pacote de dados de 4kb buscados no banco (não retornados na pesquisa, e sim avaliados). Quando você faz um Scan em uma tabela com vários registros que totalizam 82kb, você paga 21 RCU (21 x 4 = 84). Se você faz uma Query nessa mesma tabela e os registros que resultam dessa Query totalizam 9kb, você paga 3 RCU (3 x 4 = 12). Por isso é importante desenhar sua tabela e seus índices para otimizar a busca; isso ajuda a economizar dinheiro.
Uma Write Unit (WU) corresponde a um pacote de dados de 1kb gravado na tabela. A ideia é a mesma acima.
Usando a cobrança Provisionada, você define antecipadamente quantas RU e WU são usadas por segundo, e uma taxa de tolerância para escalabilidade. A partir disso, você paga sempre o que está estabelecido, e tem um limite de de uso definido, o que ajuda a prevenir surpresas. Para fluxos de leitura e gravação já definidos é a melhor escolha, uma vez que você não tem surpresas na hora do pagamento.
Usando a cobrança sob-demanda, você é cobrado pelo que usa, acumulado em um mês. Isso é interessante quando o número de acessos não é conhecido, ou é inconsistente. Por ser baseado em uso, pode ser uma opção mais econômica, mas se acontecer um aumento de uso inesperado ou indevido, a conta pode pesar mais no fim do mês.
Existe a cobrança para trafego de dados do DynamoDB para fora da rede AWS, mas isso impacta apenas em aplicações rodando localmente, o que é raro.
Finalizando #
Neste artigo eu citei apenas uma visão geral do DynamoDB, para que você comece a usar a ferramenta sabendo como ela funciona. Faltou falar de outras funcionalidades como o DynamoDB Streams, Tabelas Globais. Posteriormente vou postar um vídeo mostrando como usar a partir do Console da AWS, e usando Python e NodeJS. Enquanto isso, vocês podem fazer um curso oferecido pela Coursera e AWS, sobre criação de aplicações com o DynamoDB, que é ótimo e gratuito.
Se você chegou até aqui, agradeço demais, e espero ter ajudado um pouco na sua jornada com a AWS. Qualquer dúvida, mande um email para erick@em.pro.br ou fale comigo pelo twitter ou instagram, @oerickmuller.
Até a próxima!