Modelagem de dados

O documento de modelagem de dados é o primeiro documento de melhores práticas na série.... Ela mostra as melhores práticas a seguir:

  • O que você precisa saber sobre suas APIs.
  • Como modelar seus dados.
  • Os documentos de tamanho que você deve utilizar
  • O que evitar.
  • Como configurar os seus bancos de dados.

Para obter mais informações, consulte Indexação e consulta ou IBM Cloudant na prática.

O conteúdo neste documento foi originalmente escrito por Stefan Kruger como um post do blog Melhores e piores práticas em 21 de novembro de 2019.

Entenda a API que você está destinando

Você pode usar Java™, Python, Goou Node.js ou alguma outra linguagem ou plataforma específica de uso-case-specific. Uma dessas linguagens provavelmente vem com bibliotecas convenientes do lado do cliente que integram bem o acesso do IBM Cloudant, seguindo as convenções que você espera para suas ferramentas. Essas linguagens são ótimas para a eficiência do programador, mas também ocultam a API da visualização.

Esta abstração é o que você quer, a razão para usar uma biblioteca de cliente é evitar padrões repetidos e entediantes. No entanto, é fundamental compreender a API subjacente ao resolver e relatar problemas. Quando você relatar um problema suspeito ao IBM Cloudant, ele nos ajudará a ajudá-lo se você puder fornecer uma maneira de reproduzirmos o problema.

Essa solicitação não significa literalmente cortar e colar um grande chunk da fonte Java™ do seu aplicativo em um chamado de suporte, pois provavelmente não conseguiremos construí-lo. Além disso, seu código do lado do cliente introduz incertezas sobre onde o problema pode estar: do seu lado ou do nosso lado?

Em vez disso, as equipes de suporte do IBM Cloudant geralmente solicitam o conjunto de chamadas de API — de preferência, na forma de um conjunto de comandos curl que possam ser executados — que demonstre o problema. Adotar essa abordagem para a resolução de problemas como uma regra também facilita para você identificar onde os problemas estão falhando. Se o seu código está se comportando de forma inesperada, tente reproduzir o problema usando apenas o acesso direto à API.

Se você não conseguir, o problema não é com o serviço IBM Cloudant em si.

Se você está investigando um problema de desempenho, consulte aos logs que são fornecidos pela IBM Cloud®. Se os logs mostram que suas solicitações são tratadas rapidamente pelo IBM Cloudant, mas seu aplicativo é lento, a raiz desse problema encontra-se com o seu código de aplicativo do lado do cliente. Veja a regra sobre criação de log e monitoramento.

Se você suspeitar que um problema está com uma biblioteca do cliente oficialmente suportada, tente construir um pequeno exemplo de código autocontido que demonstra o problema. Neste exemplo de código autocontido, use o mínimo possível de outras dependências. Se você estiver usando o Java™, seria útil para nós se você pudesse usar um exemplo mínimo conjunto de testes para destacar os problemas da biblioteca.

Ocasionalmente, o IBM Cloudant recebe chamados de suporte que afirmam que o "IBM Cloudant está com erros porque meu aplicativo está lento" sem muito em termos de evidências de comprovação. Quase sempre este caso pode ser rastreado de volta para os problemas no código do aplicativo no lado do cliente, ou equívocos sobre como o IBM Cloudant funciona.

Nem sempre, mas quase sempre.

Ao entender melhor a API, você também ganha experiência com o comportamento do IBM Cloudant, especialmente em termos de desempenho. Se você estiver usando uma biblioteca do cliente, deverá ter como objetivo ao menos saber como descobrir quais solicitações HTTP são geradas por uma chamada de função específica. Para obter mais informações, consulte os websites a seguir:

Documentos devem agrupar dados que em sua maioria mudam juntos

Quando você começa a modelar seus dados, mais cedo ou mais tarde se depara com a questão de como seus documentos podem ser estruturados. Agora você sabe que o IBM Cloudant não impõe nenhuma normalização e que não possui transações do tipo com o qual você está acostumado, por exemplo, Postgres. A tentação pode ser colocar o máximo possível em cada documento, o que também economizaria no uso de HTTP.

Esta prática é muitas vezes uma má ideia.

Se o seu modelo agrupa informações que não mudam juntas, você tem mais chances de sofrer com conflitos de atualização.

Considere uma situação em que você tenha usuários, cada um deles com um conjunto de solicitações associadas a eles. Uma maneira pode ser representar as solicitações como uma matriz no documento do usuário:

{ // DON'T DO THIS
  "customer_id": 65522389,
  "orders": [
    {
      "order_id": 887865,
      "items": [
        {
          "item_id": 9982,
          "item_name": "Iron sprocket",
          "cost": 53.0
        },
        {
          "item_id": 2932,
          "item_name": "Rubber wedge",
          "cost": 3.0
        }
      ]
    }
  ]
}

Para incluir uma solicitação, eu preciso buscar o documento completo, desserializar o JSON, incluir o item, serializar o novo JSON e enviá-lo de volta como uma atualização. Se eu sou o único a fazer isso, pode funcionar por um tempo. Se o documento estiver sendo atualizado simultaneamente, ou sendo replicado, provavelmente veríamos conflitos de atualização.

Em vez disso, mantenha as solicitações separadas como seu próprio tipo de documento, referenciando o ID do cliente. Agora o modelo é imutável. Para adicionar um pedido, eu crio um novo documento de pedido no banco de dados, o que não pode gerar conflitos.

Para conseguirmos recuperar todas as solicitações para um cliente específico, podemos empregar uma visualização, o que cobrimos mais tarde.

Evite construções que dependem de atualizações para partes de documentos existentes, sempre que possível. Modelos de dados inadequados costumam ser difíceis de alterar depois que o sistema já está em produção.

O padrão anterior pode ser resolvido de forma eficiente com o uso de bancos de dados particionados, que serão cobertos com mais detalhes posteriormente.

Para obter mais informações, veja a documentação a seguir:

Mantenha os documentos pequenos

O IBM Cloudant impõe um tamanho máximo de doc de 1 MB. Esse limite não significa que um tamanho de documento close-to-1-MB seja uma boa ideia. Pelo contrário, se você achar que está criando documentos que excedam KB de um dígito, provavelmente precisará revisar seu modelo. Várias coisas no IBM Cloudant perdem desempenho à medida que os documentos aumentam. A decodificação JSON é custosa, por exemplo.

Vejamos as seções a seguir: Documentos devem agrupar dados que em sua maioria mudam juntos e Mantenha os documentos pequenos. Vale ressaltar que os modelos que contam com atualizações têm limite de volume máximo de 1 MB, limite para o tamanho do documento. Esse tamanho não é o que você quer.

Evite usar anexos

O IBM Cloudant tem suporte para armazenamento de anexos ao lado de documentos, um recurso antigo herdado do CouchDB. Se você usar o IBM Cloudant como backend para um aplicativo web, também poderá armazenar pequenos ícones e outros recursos estáticos, como arquivos CSS e JavaScript, junto com os dados.

Deve-se considerar algumas coisas antes de usar anexos no IBM Cloudant hoje, especialmente no caso de ativos maiores, como imagens e vídeos:

  1. O IBM Cloudant é caro como um armazenamento de bloco.
  2. A implementação interna do IBM Cloudant não é eficiente na manipulação de grandes quantidades de dados binários.

Portanto, lento e caro.

O IBM Cloudant é aceitável para pequenos ativos e uso ocasional. Como regra, se você precisa armazenar dados binários ao lado de documentos do IBM Cloudant, é melhor usar uma solução separada mais adequada para este fim. Você precisa armazenar apenas os metadados do anexo no documento IBM Cloudant. Sim, isso significa que você precisa gravar algum código extra para fazer upload do anexo em um armazenamento de bloco adequada de sua escolha. Verifique se ele conseguiu antes de armazenar o token ou URL para o anexo no documento do IBM Cloudant.

Seus bancos de dados são menores, mais baratos, mais rápidos e mais fáceis de replicar. Para obter mais informações, consulte os websites a seguir:

Menos bancos de dados são melhores do que muitos

Se você puder, limite o número de bancos de dados por conta do IBM Cloudant a 500 ou menos. Enquanto este número específico não é mágico (o IBM Cloudant pode lidar com mais seguramente), existem vários casos de uso que são negativamente afetados por grandes números de bancos de dados em uma conta.

O planejador do replicador tem um número limitado de tarefas de replicação simultâneas que ele está preparado para executar. À medida que o número de bancos de dados cresce, é provável que a latência de replicação aumente se você tentar replicar tudo contido em uma conta.

O outro lado da mesma moeda é o aspecto operacional: a equipe de operações do IBM Cloudant também depende da replicação para movimentar as contas. Ao manter o número de bancos de dados baixo, você nos ajuda a ajudá-lo se precisar deslocar sua conta de um local para outro.

Então, quando você deve usar um único banco de dados e distinguir entre diferentes tipos de documentos usando visualizações, e quando deve utilizar vários bancos de dados para modelar seus dados? O IBM Cloudant não pode federar visualizações em vários bancos de dados. Se você tiver dados não relacionados que nunca possam ser “unidos” ou consultados em conjunto, esses dados podem ser candidatos a serem distribuídos por vários bancos de dados.

Se você tem um conjunto de dados em constante crescimento (como um log, leituras de sensores ou outros tipos de séries temporais), também não é uma boa ideia criar um banco de dados único, massivo que sempre cresce. Este tipo de caso de uso requer caixa de tempo, que cobrimos em mais detalhes depois.

Evite o antipadrão de “banco de dados por usuário ” como se fosse uma praga

Se você estiver desenvolvendo um serviço multiusuário com base no IBM Cloudant, pode ser tentador permitir que cada usuário armazene seus dados em um banco de dados separado, sob a conta do aplicativo. Isso funciona bem, principalmente, se o número de usuários for pequeno.

Agora inclua a necessidade de derivar analítica de usuário cruzado. A maneira como você faz isso é replicar todos os bancos de dados do usuário em um único banco de dados de analítica. Tudo de bom. Esse app de repente se tornou bem-sucedido e o número de usuários cresceu na faixa de 150 - 20.000. Você tem 20.000 replicações apenas para manter o banco de dados de analítica atual. Se você também desejar executar em uma configuração de recuperação de desastre ativa-ativa, inclua outras 20.000 replicações e o sistema deixará de funcionar.

Em vez disso, multiplexe os dados do usuário em menos bancos de dados ou realize shard nos usuários em um conjunto de bancos de dados ou contas, ou ambos. Dessa forma, não é necessário replicar para fornecer um banco de dados de analítica, mas a autenticação torna-se mais complicada já que o IBM Cloudant fornece apenas autenticação no nível do banco de dados.

Vale a pena afirmar que a abordagem "banco de dados-por-usuário" é tentadora porque as permissões do IBM Cloudant são "por banco de dados", mas não é realmente culpa dos usuários o surgimento desse padrão.

Evite gravar funções reduce JavaScript customizadas

As visualizações MapReduce no IBM Cloudant são incríveis. No entanto, com grande poder vem grande responsabilidade. A parte do mapa de uma visualização MapReduce é construída incrementalmente, portanto, o código de má qualidade no mapa impacta apenas o tempo de indexação, não o tempo de consulta. O reduce-part, infelizmente, é executado no tempo de consulta. IBM Cloudant fornece um conjunto de funções de redução integradas que são implementadas internamente em Erlang. Essas funções são de desempenho em escala, enquanto suas reduções de JavaScript criadas manualmente não são.

Se você perceber que está escrevendo funções reduce, pare e pense se é possível reorganizar seus dados de forma que não seja necessário escrever essas funções. Ou para que você seja capaz de contar com os redutores integrados.

As visualizações em bancos de dados particionados não suportam operações “reduce” personalizadas, o que é um dos fatores que contribui para a aceleração significativa das consultas que somente essas visualizações podem oferecer.

Para obter mais informações, consulte IBM Cloudant docs em reduz.

Use bancos de dados de prazo fechado para conjuntos de dados em constante crescimento

Geralmente não é uma boa ideia para ter um banco de dados em constante crescimento no IBM Cloudant. Grandes bancos de dados podem ser difíceis de submeter a backup, requerem "reexecução de shard" para manter o bom desempenho à medida que crescem, e sofrem de tempos de construção de índice longos.

Uma maneira de mitigar esse problema é ter vários bancos de dados menores, com um padrão comum que é bancos de dados de prazo fechado: um conjunto de dados grande é dividido em bancos de dados menores, cada um representando uma janela de tempo, por exemplo, um mês.

  • orders_2019_01
  • orders_2019_02
  • orders_2019_02

Novos dados são gravados no banco de dados deste mês e as consultas para dados históricos podem ser direcionadas para bancos de dados de meses anteriores. Quando os dados de um mês não são mais de interesse, eles podem ser arquivados no Object Storage, o banco de dados IBM Cloudant mensal é excluído e o espaço em disco recuperado. Para obter mais informações, consulte o website a seguir.