Couchbase Mobile

Conflitos e resolução de documentos no Couchbase Mobile 2.0

Os conflitos de documentos podem ocorrer em ambientes distribuídos que suportam a sincronização de dados, em que um documento pode ser atualizado simultaneamente por um ou mais escritores. Isso é especialmente comum em ambientes móveis, onde conexões de rede não confiáveis podem fazer com que as alterações simultâneas de vários dispositivos não sejam sincronizadas em tempo hábil.

Isso também pode ocorrer no lado do cliente, por exemplo, se um documento estiver sendo atualizado localmente enquanto as alterações no documento estiverem sendo transferidas para o cliente a partir de um servidor remoto. Portanto, é necessário resolver esses conflitos de documentos.  Couchbase Mobile 2.0, apresenta "Resolução automática de conflitos" ou um "Livre de conflitos" em que os conflitos são tratados automaticamente e não há, efetivamente, revisões de documentos conflitantes no banco de dados do Couchbase.

Como desenvolvedor de aplicativos, você provavelmente nunca precisará fazer nada específico no aplicativo para lidar com conflitos, pois o resolvedor de conflitos padrão do sistema tratará automaticamente das coisas para você. No entanto, se for necessário, você tem a opção de ser notificado sobre conflitos e pode tomar as medidas adequadas. Esta postagem abordará os fundamentos de como os conflitos de documentos são tratados automaticamente no Couchbase Mobile 2.0 usando a função "resolução automática de conflitos" ou "livre de conflitos ".

 

Pressupostos

Esta postagem pressupõe que você esteja familiarizado com a arquitetura da pilha do Couchbase Mobile, que inclui o Couchbase Lite banco de dados incorporado para seus clientes móveis, o Gateway de sincronização e Servidor Couchbase. Se você for novo na plataforma, recomendo que comece com estes recursos.

Histórico

Se você ainda não o fez, vale a pena ler isto antes desmistificando a postagem de resolução de conflitos que discute os fundamentos de como a resolução de conflitos é tratada no modo "não livre de conflitos" no Couchbase Mobile, incluindo uma visão geral do sistema de controle de simultaneidade de várias versões (MVCC).

Árvore de revisão de documentos

Para entender o processo de resolução de conflitos, você precisa ter uma compreensão básica de como os documentos são armazenados. No Couchbase Mobile, cada documento recebe uma ID de revisão exclusiva gerada pelo sistema ou revID. Esse ID é adicional ao ID do documento, que permanece o mesmo em todas as revisões do documento. Toda alteração em um documento, seja uma modificação ou uma exclusão, é tratada como uma nova revisão do documento e, portanto, recebe um novo ID de revisão.

Além disso, cada revisão de documento tem um "ID da geração" associado a ele. Na primeira vez que um documento é criado, uma revisão é criada com um "ID da geração"Cada atualização de revisão subsequente incrementará esse número.

Toda vez que uma alteração (edição ou exclusão) for feita em um documento existente, o redator deverá incluir o ID de revisão da revisão atual do documento que está sendo atualizado. Uma nova revisão é criada para a alteração e adicionada como um nó filho à revisão atual que estava sendo atualizada, resultando em uma árvore de revisão para o documento.

OBSERVAÇÃO: O "revID" deve ser tratado como um objeto opaco pelo aplicativo, e o aplicativo não deve tentar gerar o "revID".

Como ocorrem os conflitos de documentos

Em um nível mais alto, um conflito ocorre quando são feitas alterações na mesma revisão principal de um documento por vários redatores.

Conflitos no Couchbase Lite

A ilustração abaixo descreve um cenário em que um aplicativo está atualizando uma revisão de documento na memória enquanto a mesma revisão está sendo atualizada como resultado de uma replicação pull.

Conflitos no gateway de sincronização

A ilustração abaixo descreve um cenário em que dois clientes enviam alterações para a mesma revisão do documento.

Resolução de conflitos no Couchbase Mobile 2.0

Em "Livre de conflitos" o Sync Gateway rejeita essencialmente todas as atualizações conflitantes. Os conflitos são resolvidos automaticamente no momento em que o documento é criado, atualizado ou excluído.
Portanto, a implicação disso é que não há documentos conflitantes armazenados no banco de dados e é efetivamente, "Livre de conflitos". Vamos dar uma olhada em como isso funciona.

Resolução automática de conflitos no Couchbase Lite 2.0

Cada documento no Couchbase Lite 2.0 está associado a um "resolução de conflitos" que é executado se ocorrer um conflito quando é feita uma tentativa de salvar ou excluir um documento. A função de resolução de conflitos escolhe um "vencedor" entre as revisões conflitantes e esse vencedor é adicionado como um filho à árvore de revisão do documento.

Há duas políticas de controle de simultaneidade compatíveis com o Couchbase Lite.

Política de controle de simultaneidade

A última gravação sempre vence (padrão):

Essa também é a política padrão de resolução de conflitos. Nesse caso, a última atualização do banco de dados sempre vence.

Quando você liga salvarDocumento sem o argumento Controle de simultaneidade, essa é a política que está em vigor por padrão.

Este é um exemplo da chamada em swift.

Os exemplos abaixo devem esclarecer as implicações dessa política

  •  Por exemplo, nossa solicitação de salvar/atualizar é bem-sucedida, embora o documento no banco de dados tenha sido atualizado desde a última vez em que lemos o documento. O documento no banco de dados poderia ter sido atualizado por um thread diferente no aplicativo como resultado de algum acionador externo, como uma replicação pull ou uma busca de dados de um servidor remoto. A implicação é que todas as alterações feitas no documento entre o momento em que lemos o documento e o atualizamos seriam substituídas.
  • Conforme abaixo, nossa solicitação de salvar/atualizar é bem-sucedida, embora o documento no banco de dados tenha sido excluído desde a última vez em que lemos o documento. O documento no banco de dados poderia ter sido atualizado por um thread diferente no aplicativo como resultado de algum acionador externo, como uma replicação pull ou uma busca de dados de um servidor remoto. A implicação é que um documento excluído poderia ser ressuscitado como resultado do salvamento.
Falha no conflito

Embora prevamos que a política padrão de controle de simultaneidade de "a última gravação vence" deva funcionar na maioria dos casos, você pode substituir o comportamento padrão especificando que deseja ser notificado em caso de conflito ao salvar o documento. Isso pode ser feito incluindo o parâmetro opcional ConcurrentControl como parte da solicitação de salvamento.

Um valor de retorno falso com um Controle de simultaneidade política failOnConflict indica que o documento salvo falhou como resultado de um conflito. Examinaremos agora como você pode lidar com erros de conflito.

Manuseio de falhas em conflitos

O modo como você lida com os conflitos depende da semântica do aplicativo. Aqui estão alguns exemplos de como você pode lidar com isso no swift (que pode ser facilmente mapeado para outras linguagens)

  • Opção 1: Mesclar as versões conflitantes do documento e salvar

Este é um exemplo de como você mesclaria as revisões conflitantes. Novamente, a forma como você faria isso depende inteiramente do seu aplicativo. O objetivo é ser uma implementação de referência sobre como você poderia lidar com isso.

  • Opção 2: Force sua defesa para vencer

Essa opção é efetivamente a mesma que a política de simultaneidade padrão de "gravações sempre vencem". Exceto que, nesse caso, você examina o conteúdo do documento salvo no momento e, em seguida, determina se deve forçar um salvamento usando um salvarDocumento.
Observe que você ainda pode correr o risco de uma condição de corrida, pois o documento pode ser atualizado novamente antes de ser salvo.

  • Opção 3: Pular o salvamento

Nesse caso, você poderia examinar o conteúdo do documento salvo atualmente e determinar que prefere manter a versão salva atualmente do documento.

Implicações na criação de documentos com o mesmo ID

Como a política padrão de resolução de conflitos em salvarDocumento é que a última gravação sempre vence, se você tentar criar um documento novamente com um docId que já existe no banco de dados, ele atualizará o documento existente adicionando uma nova revisão a ele.

Portanto, se você quiser garantir que não atualizará inadvertidamente um documento existente, deverá especificar a opção "ConcurrenyControl argumento com failOnConflict. Isso retornará um erro que poderá ser tratado adequadamente.

Isso é muito semelhante à Opção 3 especificada anteriormente, exceto que, nesse caso, você não precisa examinar o conteúdo atual do documento. Uma falha de conflito implica que um documento com Id já existe.

Este é um exemplo em Swift

Modo livre de conflitos no Sync Gateway 2.0

Nesse modo, o gateway de sincronização rejeita as revisões que causam um conflito com um erro HTTP 409, garantindo efetivamente que não haja revisões conflitantes no banco de dados. Os conflitos são tratados no lado do cliente durante uma replicação pull.

Replicação por push

  1. O cliente envia as alterações de revisão para o Sync Gateway.
  2. O Sync Gateway detecta que a revisão de entrada está em conflito com a revisão atual salva no servidor (ou seja, o ancestral da revisão de entrada não é a revisão ativa no servidor)
  3. O Sync Gateway rejeita a alteração de revisão com uma mensagem 409 Erro. O Couchbase Lite não faz nada além de registrar o erro. O conflito é resolvido posteriormente durante uma replicação pull.

Replicação pull

Durante uma replicação pull, se o cliente detectar um conflito, ele será resolvido usando os seguintes critérios determinísticos

  • As exclusões sempre vencem. Um exemplo desse caso é o mostrado abaixo.

  • A alteração mais recente (maior ID de geração) vence ou a revisão com max revID ganha se as gerações forem as mesmas, ou seja, o revID que classifica mais alto em uma comparação ASCII simples. Um exemplo disso é mostrado abaixo.

 

Em seguida, examinamos os casos durante a replicação pull.

O Server Branch é o vencedor

  1. O cliente extrai as alterações de revisão do Sync Gateway
  2. O cliente detecta que a revisão de entrada está em conflito com a revisão salva atual (ou seja, a revisão de entrada e a revisão salva compartilham um pai comum)
  3. O cliente chama a função de resolução de conflitos que determina o vencedor entre a revisão salva atual e a revisão do servidor.
    1. Como a revisão de entrada (Rev2-B) do servidor é mais recente do que a revisão local (Rev2-A), a revisão do servidor é selecionada como a vencedora. Observe que esse também seria o caso se a revisão no servidor fosse excluída.
  4. A ramificação do servidor é enxertada na árvore de revisão local (e a ramificação local é tombada)
  5. Posteriormente, quando as alterações forem enviadas para o servidor, não haverá conflitos e o servidor será sincronizado com o lado do cliente.
A filial local é a vencedora
  1. O cliente extrai as alterações de revisão do Sync Gateway
  2. O cliente detecta que a revisão de entrada está em conflito com a revisão salva atual (ou seja, a revisão de entrada e a revisão salva compartilham um pai comum)
  3. O cliente chama a função de resolução de conflitos que determina o vencedor entre a revisão salva atual e a revisão do servidor.
    1. Como a revisão local (Rev2-B) é o mais recente do que a revisão do servidor de entrada (Rev2-A), a revisão local é selecionada como a vencedora. Observe que esse também seria o caso se a revisão no ramo local fosse excluída.
  4. O ramo do servidor é enxertado na árvore de revisão local e uma nova revisão Rev3 é adicionado, o que corresponde ao conteúdo da revisão vencedora, Rev2-B
  5. Posteriormente, quando as alterações forem enviadas para o servidor, não haverá conflitos e o servidor será sincronizado com o lado do cliente.

OBSERVAÇÃO: Como você observou, os conflitos são resolvidos no Couchbase Lite durante uma replicação pull. A implicação disso é que, se o replicador estiver configurado para ser apenas um replicador push, a visão do Couchbase Lite dos dados divergirá da do Sync Gateway (já que algumas das tentativas de gravação do CBL falhariam com 409). Portanto, se você prevê a ocorrência de conflitos, recomenda-se que o replicador do Couchbase Lite seja configurado no modo push-pull quando usado no modo Conflict Free

 

Configuração do modo livre de conflitos no Sync Gateway

O modo "Conflict Free" no Sync Gateway pode ser configurado por meio de allow_conflicts no arquivo de configuração do Sync Gateway. Ela deve ser definida como "falso" para ativar o modo livre de conflitos. Deve-se observar também que, independentemente da configuração dessa propriedade, não haverá revisões conflitantes adicionadas ao Sync Gateway ao sincronizar com clientes do Couchbase Lite 2.0. Discutimos isso anteriormente na seção sobre Replicação. A configuração "allow_conflicts" tem implicações apenas para clientes não 2.0 e clientes da API REST. A tabela abaixo resume as implicações

allow_conflicts_configuration

Impacto do modo livre de conflitos no tamanho do banco de dados

O impacto da resolução de conflitos no tamanho do banco de dados foi discutido em detalhes em nosso post anterior sobre Gerenciar tamanhos de bancos de dados. No sistema que permitia conflitos, à medida que as revisões conflitantes cresciam, o tamanho da árvore de revisão podia aumentar e afetar o tamanho do banco de dados. Portanto, era importante resolver os conflitos em tempo hábil. O Sync Gateway tem um revs_limit que determina o tamanho da árvore de revisão. A propriedade revs_limit tem como padrão 1000, o que significa que os metadados correspondentes às últimas 1000 revisões são armazenados no Sync Gateway antes de serem eliminados. Ao definir a propriedade revs_limit para um valor grande afetaria negativamente o tamanho do banco de dados, era importante não defini-lo para um valor muito baixo. Era importante manter os metadados correspondentes às revisões mais antigas, pois eles eram necessários para lidar com a resolução de conflitos; caso contrário, você correria o risco de ter uma floresta de árvores de revisão desconectadas para um documento. Portanto, o valor mínimo permitido de revs_limit é 20.

Entretanto, com o modo livre de conflitos, não há necessidade real de salvar os metadados correspondentes a revisões mais antigas. Isso implica que o revs_limit poderia ser apenas 1. Isso significa que apenas a revisão mais recente/ativa é armazenada. Isso gera uma grande economia no tamanho do banco de dados.

Agradecimentos

Agradecimentos especiais a Pasin Suriyentrakorn da equipe de engenharia móvel, por seu feedback sobre as seções do Couchbase Lite, para Adam FraserTambém à equipe de Engenharia Móvel, por seu feedback sobre as seções do Sync Gateway, e a Daniel Petersen, da equipe de Engenharia Móvel, por seu feedback.

O que vem a seguir

Esta postagem do blog discutiu como os conflitos são tratados automaticamente no Couchbase Mobile 2.0. Você pode fazer o download do Couchbase Mobile 2.0 em nosso downloads página.

Se tiver dúvidas ou comentários, deixe um comentário abaixo ou entre em contato comigo pelo Twitter em @rajagp ou envie-me um e-mail para priya.rajagopal@couchbase.com. O Fóruns do Couchbase são outro ótimo lugar para entrar em contato com perguntas.

 

Compartilhe este artigo
Receba atualizações do blog do Couchbase em sua caixa de entrada
Esse campo é obrigatório.

Autor

Postado por Priya Rajagopal, Diretora Sênior, Gerenciamento de Produtos

Priya Rajagopal é diretora sênior de gerenciamento de produtos da Couchbase, responsável pelas plataformas de desenvolvedor para a nuvem e a borda. Ela desenvolve software profissionalmente há mais de 20 anos em vários cargos técnicos e de liderança de produtos, com mais de 10 anos de foco em tecnologias móveis. Como delegada de padrões de IPTV da TISPAN, ela foi uma das principais colaboradoras das especificações de padrões de IPTV. Ela tem 22 patentes nas áreas de rede e segurança de plataforma.

14 Comentários

  1. Oi Priya,

    Se o Mobile 2.0 introduz o novo modo "Conflict Free", qual é o modo alternativo? Especialmente porque o Gateway só oferece suporte ao "Conflict Free" como EE. Como os conflitos seriam resolvidos/não seriam resolvidos na edição Community?

    Usando o ConcurrencyControl, é possível tratar e resolver conflitos manualmente em Save() no lado do cliente local. Para conflitos resultantes da replicação, você diz:
    > O cliente chama a função de resolução de conflitos
    Onde está definida essa função de resolução de conflitos? O Beta 2 não tem o antigo ConflictResolver na ReplicatorConfiguration. Isso se refere ao resolvedor automático interno ou é algo que pode ser resolvido manualmente? Se for apenas automático, não seria estranho que os conflitos internos de salvamento local possam ser tratados de forma personalizada, mas os conflitos externos replicados não?
    Além disso, como isso seria tratado de forma diferente quando você não tem o modo "Livre de conflitos" (EE)?

    Obrigado.

  2. Hi!
    No CE, os conflitos no SGW seriam tratados da mesma forma que na versão 1.x. Basicamente, não receberíamos o erro 409 em um conflito de envio.
    Sim, esse é o resolvedor de conflitos interno. Você não pode substituir isso na versão 2.0.
    Você está certo em sua observação de que os conflitos com salvamentos locais podem ser detectados pelo aplicativo, mas não é possível fazer isso com os conflitos resultantes da replicação. Mas observe também que a política padrão de resolução de conflitos é diferente nos dois casos - ao contrário do caso de salvamento local, no caso de replicação, ela é determinística e acreditamos que, na maioria dos casos, o usuário preferiria um estado determinístico.

    O objetivo é ser "livre de conflitos". Portanto, em ambos os casos, a resolução de conflitos ocorre automaticamente no momento em que o documento é atualizado (pull local ou remoto). Portanto, com esse objetivo em mente, diferentemente do primeiro caso, em que podemos rejeitar um salvamento local, como você pode facilmente deduzir, não é possível fazer o mesmo em uma replicação pull.

    Agora, dito isso, podemos considerar a possibilidade de oferecer uma opção para substituir a resolução automática de conflitos. Isso será feito após a versão 2.0, dependendo da demanda do usuário. Você vê a necessidade disso?

    1. Na documentação da versão 2.0, está escrito:
      > A partir do Couchbase Lite 2.0, os conflitos de documentos devem ser resolvidos usando a resolução automática de conflitos ou no aplicativo.
      Então, se o CE tiver que usar o método v1.x, isso não é verdade?

      Todos os itens usados na versão 1.x para gerenciar revisões e conflitos, como resolvedores de conflitos, classe de revisão de documentos etc., parecem ter sido removidos da API 2.x. Então, se o CE 2.x deve usar o método v1.x, como? Tudo parece ter sido projetado somente para o novo método automático. O CE Gateway ainda teria várias revisões para documentos em um estado de conflito, até que eles fossem resolvidos em algum lugar. Portanto, os clientes precisam ser capazes de ver quais documentos estão em um estado de conflito e quais revisões existem.

      Vejo a necessidade de substituir o resolvedor automático de conflitos, já que você permite substituí-lo no método save() do cliente. É claro que, se você emprega replicação contínua, é mais provável que ocorram conflitos ao salvar, pois as alterações são replicadas instantaneamente (espera-se). Mas se você estiver trabalhando principalmente off-line e replicando apenas ocasionalmente, os conflitos ocorrerão principalmente durante a replicação, não em save(). Nesse cenário, ter os recursos avançados de mesclagem personalizada em save() é muito menos útil, e você ficaria "preso" apenas ao padrão da árvore de revisão mais longa. Parece-me que, se você quisesse lidar com o conflito ao salvar(), também gostaria de poder lidar com o conflito da replicação da mesma forma.

      É claro que o problema técnico é diferente, pois você não pode "rejeitar" o pull. Na versão 1.x, isso foi resolvido com as várias revisões em um estado de conflito e, em seguida, com a resolução do mesmo. Acho que você ainda gostaria de ter essa opção na v2.x de alguma forma. Não acho que o desafio técnico de implementar isso deva ser o motivo para prejudicar a funcionalidade em comparação com a v1.x e com os recursos de save().

  3. O terceiro painel do primeiro diagrama (em "Conflitos no Couchbase Lite") apresenta a legenda: "O aplicativo tenta salvar a versão modificada localmente do documento. O documento não está em conflito!"

    A ilustração parece retratar claramente um conflito. Há algum erro na legenda?

  4. Além do comentário de avia_bdg acima, gostaria de obter alguns esclarecimentos sobre a estratégia de resolução de conflitos com relação à replicação. Pela minha leitura do artigo e do diálogo acima, parece que o design atual do CBL 2.0 praticamente garante a perda de dados por clientes off-line que usam o Sync Gateway. Isso tornaria o produto completamente inutilizável.

    Sem um meio de resolver de forma determinística os conflitos resultantes de uma replicação pull, o cliente joga os dados para saber se suas alterações serão descartadas. As mesclagens - um requisito fundamental em muitos aplicativos, inclusive no meu projeto principal, onde atualmente usamos o CBL 1.x - não são mais possíveis. Isso é um obstáculo.

    Por favor, garanta-me que eu não entendi direito.

    1. Obrigado por seu feedback. Seu entendimento está correto. Avaliaremos a possibilidade de incluir isso em...

  5. Perguntas muito boas!
    Primeiro, o mais simples: avaliaremos a opção de substituir a política personalizada de resolução de conflitos na replicação, mas isso será feito após a versão 2.0.
    Agora, a outra pergunta.
    Para esclarecer, os clientes do Couchbase Lite 2.0 sempre usarão o modo livre de conflitos (CE ou EE). A distinção entre CE e EE está no lado do SGW.
    Para saber os detalhes -
    Para esclarecer a distinção no lado do SGW, os envios de clientes 2.0 sempre estarão no modo "livre de conflitos". A implicação disso - sem entrar em muitos detalhes sobre o protocolo - é que o SGW (EE e CE) rejeitará a revisão se ela causar um conflito (conforme discutido na postagem do blog). A distinção entre CE e EE é quando as atualizações chegam de clientes não CBL 2.0/clientes da API REST. O SGW EE evitará conflitos de qualquer um desses clientes. Mas você pode ter conflitos no modo SGW CE ao interagir com clientes não CBL 2.0. Esses conflitos serão tratados pelo 1.x da maneira usual e os clientes CBL 2.0 obterão a revisão vencedora do servidor

    1. Felizmente, acho que não teremos esse problema de mistura de 1.x/2.x, portanto, não teremos problemas com a CE.

      Acho que Ben e eu concordamos que precisamos de uma maneira de resolver conflitos personalizados resultantes de replicações pull.

      Estamos aplicando o CBL no Xamarin mobile, em dispositivos que ficarão off-line em ambientes de disponibilidade esparsa de Internet e que serão replicados ocasionalmente. Como se trata de um aplicativo móvel, estamos pensando em ter um recurso de salvamento automático para nosso formulário de dados, caso o usuário suspenda o aplicativo e ele seja fechado, queira fazer edições parciais, etc. Isso significa uma taxa potencialmente alta de revisões, que seriam armazenadas localmente apenas até serem enviadas. Fiz alguns testes e isso significa que, se eu editar com o salvamento automático 2 ou 3 vezes, uma única edição feita off-line em outro dispositivo, feita em uma data posterior, perderá porque existem menos revisões. Isso não é aceitável. A última edição (por data e hora) seria melhor, um código personalizado para fazer alguma mesclagem seria ainda melhor, mas o número de edições (o algoritmo atual do resolvedor automático) não é adequado para isso.

      Mesmo que mudemos de salvamento automático instantâneo para menos salvamentos ou salvamentos manuais, o problema permanece: o algoritmo de resolução automática de conflitos só funcionará em cenários on-line e não será aceitável em cenários off-line, em que os clientes podem ficar off-line por períodos mais curtos ou mais longos (semanas ou meses) e fazer muitas edições enquanto estiverem off-line, ou fazer edições em proporções e quantidades diferentes de outros clientes off-line, e edições mais antigas podem descartar menos edições mais recentes.

      1. Obrigado pelos detalhes. Seu feedback é útil. Avaliaremos isso com mais detalhes... e o manteremos informado

      2. Atualização rápida: removi a nota sobre CE/EE .... e adicionei uma nova seção sobre a configuração do SGW para esclarecer o mesmo. Não há distinção no nível CE/EE.

  6. Olá, equipe,

    Atualmente, atualizei meu couchlite para a versão 2.1.2.
    Para resolver os conflitos, devo obter a revisão mais recente do servidor, mas como posso obter o documento específico da revisão? Na versão mais recente, não estamos obtendo o ID da revisão.

    1. Não é possível resolver conflitos no nível do aplicativo, pelo menos por enquanto. O Couchbase mudou para a resolução automática de conflitos na versão 2. Eles estão trabalhando em uma solução que permitiria algum controle novamente.

      1. A resolução personalizada de conflitos com mesclagem bidirecional agora está disponível no Couchbase Mobile 2.6 (https://docs.couchbase.com/couchbase-lite/2.6/index.html#custom-conflict-resolution)

Deixe um comentário

Pronto para começar a usar o Couchbase Capella?

Iniciar a construção

Confira nosso portal do desenvolvedor para explorar o NoSQL, procurar recursos e começar a usar os tutoriais.

Use o Capella gratuitamente

Comece a trabalhar com o Couchbase em apenas alguns cliques. O Capella DBaaS é a maneira mais fácil e rápida de começar.

Entre em contato

Deseja saber mais sobre as ofertas do Couchbase? Deixe-nos ajudar.