Quando nós, desenvolvedores, ouvimos o termo expansão de dados, ele pode parecer um pouco com um termo comercial como TCO, ROI e similares. Todos esses termos têm uma realidade para os desenvolvedores, fora do âmbito do analista e do gerente. Portanto, hoje quero falar sobre a realidade da expansão de dados para os desenvolvedores. Como isso afeta nosso trabalho.
O Data Sprawl pode ser resumido no fato de que temos dados, uma quantidade enorme, armazenados em muitos armazenamentos de dados diferentes. Além disso, nós, como desenvolvedores, temos que fazer com que esses armazenamentos de dados interajam entre si. E, é claro, quanto mais, melhor, certo 😬?
Geralmente está associado a custos financeiros mais altos:
-
- Infraestrutura
- Licenças
- Integração
- Treinamento
- Operacional
- Custos de suporte
Plataformas separadas com várias interfaces lhe darão dores de cabeça por causa disso:
-
- Implementação e gerenciamento independentes
- Diferentes modelos de dados e interfaces de programação
- Integração entre vários produtos
- Tíquetes de suporte com diferentes fornecedores
E precisamos gastar mais tempo, esforços e custos por causa disso:
-
- Licença e contrato
- Treinamento para desenvolvedores e operações
- Suporte
- Criar API ou conector para o banco de dados
- Aquisição de infraestrutura
É um pouco sombrio quando se olha dessa forma, mas é um desafio cotidiano para muitas empresas. E não apenas com diferentes cargas de trabalho de dados, isso também se aplica aos aplicativos em nuvem.
Vamos dar uma olhada em um exemplo específico. Criei um aplicativo que usa CRUD de um banco de dados de documentos, cache de um armazenamento de cache e pesquisa de um mecanismo de pesquisa de texto completo. (Fonte do GitHub)
Dando uma olhada nesse esquema, você pode basicamente contar cada seta que vê como uma interação entre diferentes sistemas que os desenvolvedores precisam pensar e codificar.
Aqui estamos sincronizando automaticamente os bancos de dados de cache e pesquisa usando streaming de eventos. São 8 interações e 4 armazenamentos de dados para aprender e gerenciar. Como você precisa garantir que cada armazenamento esteja conectado ao serviço de streaming e que receba as atualizações corretas, é necessário gerenciar o serviço de streaming, a pesquisa, o cache e o armazenamento de dados. Você também precisa integrar o cache ao seu serviço CRUD (idealmente com os outros serviços, mas vamos manter isso simples). Em resumo: há muito o que fazer.
Podemos limitar essas interações eliminando os serviços de streaming e garantindo que outros serviços sejam atualizados manualmente. Essa é uma licença a menos, algo a ser operado, algo a ser aprendido, algo a ser integrado. Ainda não é o ideal, mas poderia ser assim:
É um pouco mais simples, apenas 6 interações e 3 armazenamentos de dados em vez de 8 e 4. Mas ainda há muitas interações e parte da integração de streaming precisa ser feita manualmente. Antes, porém, poderíamos ter aprendido e usado os conectores existentes entre os serviços existentes. Vamos dar uma olhada rápida no código de amostra Java/Spring Boot escrito para isso.
Há quatro interfaces que representam o que os desenvolvedores podem fazer com os armazenamentos de dados. CRUD, Cache, Consulta e Pesquisa.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
público interface CRUD { StoredFileDocument ler(Cordas id); vazio criar(Cordas id, StoredFileDocument doc); vazio atualização(Cordas id, StoredFileDocument doc); vazio upsert(Cordas id, StoredFileDocument doc); vazio excluir(Cordas id); } público interface Cache { vazio writeInCache(StoredFileDocument doc); StoredFileDocument readFromCache(Cordas id); vazio toque(Cordas id); vazio despejar(Cordas id); } público interface Consulta { Lista<Mapa<Cordas, Objeto>> consulta(Cordas whereClause); Lista<Mapa<Cordas, Objeto>> findAll(); } público interface Pesquisa { Lista<Mapa<Cordas, Objeto>> pesquisa(Cordas prazo); vazio índice(StoredFileDocument doc); vazio excluir(Cordas id); } |
Não mostraremos todo o código nesta postagem, mas apenas algumas das partes interessantes.
Estamos em uma configuração em que o serviço CRUD tem links para os serviços Search e Cache. Vamos ver como seria em uma versão simplificada. Temos de importar o serviço de cache e de pesquisa, pois eles são necessários. A partir daí, todos os métodos são afetados por eles. O Read precisa primeiro consultar o cache, atualizar a última vez que o objeto foi encontrado no cache ou obtê-lo do banco de dados e inseri-lo no cache. Em seguida, os métodos Create, Update e Delete afetam o Cache e a Pesquisa, pois os dados recém-criados, atualizados ou excluídos precisam ser propagados para o Cache ou para os índices do armazenamento de dados da Pesquisa.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
@Serviço público classe MongoCRUD implementa CRUD { privado Coleção Mongo<StoredFileDocument> coleção; privado Cache cache; privado Pesquisa pesquisa; público MongoCRUD(Coleção Mongo<StoredFileDocument> coleção, Cache cache, Pesquisa pesquisa) { este.coleção = coleção; este.cache = cache; este.pesquisa = pesquisa; } @Override público StoredFileDocument ler(Cordas id) { StoredFileDocument doc = cache.readFromCache(id); se (doc == nulo) { Sistema.fora.println(id); doc = coleção.encontrar(eq("fileId", id)).primeiro(); cache.writeInCache(doc); } mais { cache.toque(id); } retorno doc; } @Override público vazio criar(Cordas id, StoredFileDocument doc) { doc.setFileId(id); coleção.insertOne(doc); cache.writeInCache(doc); pesquisa.índice(doc); } @Override público vazio atualização(Cordas id, StoredFileDocument doc) { coleção.findOneAndReplace(eq("fileId", id), doc); cache.toque(id); pesquisa.índice(doc); } @Override público vazio upsert(Cordas id, StoredFileDocument doc) { FindOneAndReplaceOptions opções = novo FindOneAndReplaceOptions().upsert(verdadeiro); coleção.findOneAndReplace(eq("fileId", id), doc, opções); cache.toque(id); pesquisa.índice(doc); } @Override público vazio excluir(Cordas id) { coleção.deleteOne(eq("fileId", id)); cache.despejar(id); pesquisa.excluir(id); } } |
Com o Couchbase, isso estaria mais próximo de algo como isto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
@Serviço @Profile("couchbase") público classe CouchbaseCRUD implementa CRUD { privado Coleção coleção; público CouchbaseCRUD(Coleção coleção) { este.coleção = coleção; } @Override público StoredFileDocument ler(Cordas id) { ObterResultado res = coleção.obter(id); retorno res.contentAs(StoredFileDocument.classe); } @Override público vazio criar(Cordas id, StoredFileDocument doc) { Resultado da mutação res = coleção.inserir(id, doc); } @Override público vazio atualização(Cordas id, StoredFileDocument doc) { Resultado da mutação res = coleção.substituir(id, doc); } @Override público vazio upsert(Cordas id, StoredFileDocument doc) { Resultado da mutação res = coleção.upsert(id, doc); } @Override público vazio excluir(Cordas id) { Resultado da mutação res = coleção.remover(id); } } |
O motivo pelo qual não precisamos de uma dependência do serviço de Cache e Pesquisa é que o Couchbase já integra um cache e um mecanismo de pesquisa. Não há necessidade de implementar a interface do cache e não há necessidade de implementar o método de exclusão e indexação da interface de pesquisa. É tudo automatizado e integrado.
Normalmente, quando explico isso a alguém, segue-se uma conversa sobre como isso deve ser ruim, porque é preciso fazer concessões para poder fazer todas as coisas. Todas as plataformas de dados, multimodelos, cargas de trabalho múltiplas, como você quiser falar sobre elas, não são criadas da mesma forma, ou pelo menos não com a mesma arquitetura em mente.
O Couchbase pode ser visto como vários bancos de dados diferentes, todos responsáveis por cargas de trabalho diferentes e todos integrados por meio de seu serviço de streaming interno. Dessa forma, cada parte do Couchbase é mantida atualizada automaticamente e cada parte pode se especializar em sua própria carga de trabalho de dados. No final, você obtém 3 interações e 1 datastore.
Isso já é muito bom, mas temos mais uma coisa. Nossos serviços estão integrados à nossa linguagem de consulta SQL++. Vamos dar um exemplo. Você tem um CMS que contém uma árvore de documentos, com várias permissões em cada documento, e essas permissões podem ser herdadas por documentos filhos nos quais você deseja executar uma pesquisa como um usuário conectado com um conjunto específico de permissões. Se você estiver usando um mecanismo de busca externo, o que normalmente acontece é o seguinte:
-
- Execute uma consulta de pesquisa no mecanismo de pesquisa
- Reúna os identificadores dos documentos retornados porque nem todo o conteúdo do documento está indexado
- Executar uma consulta para obter os documentos completos
- Se o seu serviço de consulta não for compatível com JOIN, execute outra consulta para obter permissões herdadas e filtrar os documentos
Se quiséssemos tornar as coisas mais complicadas (e talvez também mais reais), poderíamos adicionar uma lógica de cache personalizada a cada etapa. Mas isso já é complicado o suficiente.
O Couchbase pode fazer tudo em uma única etapa. Em uma única consulta SQL++, podemos pesquisar, selecionar os campos que desejamos e fazer JOIN em outros documentos para classificar as permissões. É tão simples quanto isso. Como o Couchbase é uma plataforma de dados bem integrada, sua linguagem de consulta permite que você aproveite todos os seus poderes. Se você estiver interessado, os detalhes podem ser encontrados em outro post.
Encerramento
Então, o que aprendemos hoje? O uso de uma plataforma de dados bem arquitetada pode economizar muito tempo, dinheiro, esforço e dor de cabeça. Porque, no final, você tem menos coisas em que pensar, menos código para escrever, o que significa menos código para manter e uma capacidade mais rápida de enviar para a produção. Felizmente, ela também simplifica e economiza em questões como licenças, treinamento, conformidade e todas aquelas coisas com as quais os gerentes, analistas, seu chefe e o chefe do seu chefe se preocupam!
- Assista à minha palestra com a RedMonk: O que é dispersão de dados? Como aproveitar uma plataforma para lidar com eles
- Confira o código do meu exemplo de expansão de dados
- Saiba mais sobre como Serviços do Couchbase são projetados para tornar o desenvolvimento fácil e simples.
- Experimente o Couchbase Capella DBaaS para colocá-lo à prova