Migrar do CouchBase para o Azure Cosmos DB for NoSQL
APLICA-SE A: NoSQL
O Azure Cosmos DB é um banco de dados escalonável, distribuído globalmente e totalmente gerenciado. Ele fornece acesso garantido de baixa latência aos seus dados. Para saber mais sobre a API do Azure Cosmos DB, veja o artigo de visão geral. Esse artigo fornece instruções para migrar aplicações Java que estão ligadas ao Couchbase para uma conta API para NoSQL no Azure Cosmos DB.
Diferenças na nomenclatura
A seguir estão os principais recursos que funcionam de maneira diferente no Azure Cosmos DB em comparação com o Couchbase:
Couchbase | Azure Cosmos DB |
---|---|
Servidor do Couchbase | Conta |
Bucket | Banco de dados |
Bucket | Contêiner/coleção |
Documento JSON | Item/documento |
Principais diferenças
O Azure Cosmos DB tem um campo “ID” dentro do documento, enquanto o Couchbase tem a ID como parte do bucket. O campo “ID” é exclusivo na partição.
O Azure Cosmos DB é dimensionado usando a técnica de particionamento ou fragmentação. Isso significa que ele divide os dados em vários fragmentos/partições. Essas partições/fragmentos são criados com base na propriedade da chave de partição que você fornece. Você pode selecionar a chave de partição para otimizar as operações de leitura e gravação ou também a leitura/gravação otimizada. Para saber mais, consulte o artigo particionamento.
No Azure Cosmos DB, não é necessário que a hierarquia de nível superior indique a coleção porque o nome da coleção já existe. Esse recurso torna a estrutura JSON mais simples. Veja a seguir um exemplo que mostra as diferenças no modelo de dados entre o Couchbase e o Azure Cosmos DB:
Couchbase: ID do documento = "99FF4444"
{ "TravelDocument": { "Country":"India", "Validity" : "2022-09-01", "Person": { "Name": "Manish", "Address": "AB Road, City-z" }, "Visas": [ { "Country":"India", "Type":"Multi-Entry", "Validity":"2022-09-01" }, { "Country":"US", "Type":"Single-Entry", "Validity":"2022-08-01" } ] } }
Azure Cosmos DB: Consulte a “ID” dentro do documento, conforme mostrado abaixo
{ "id" : "99FF4444", "Country":"India", "Validity" : "2022-09-01", "Person": { "Name": "Manish", "Address": "AB Road, City-z" }, "Visas": [ { "Country":"India", "Type":"Multi-Entry", "Validity":"2022-09-01" }, { "Country":"US", "Type":"Single-Entry", "Validity":"2022-08-01" } ] }
Suporte ao SDK do Java
O Azure Cosmos DB tem os seguintes kits de desenvolvimento de software (SDKs) para suportar diferentes estruturas Java:
- SDK assíncrono
- SDK do Spring Boot
As seções a seguir descrevem quando usar cada um desses SDKs. Considere um exemplo em que temos três tipos de cargas de trabalho:
Couchbase como repositório de documentos e consultas personalizadas baseadas em dados da primavera
Se a carga de trabalho que você está migrando for baseada no SDK baseado em Spring Boot, você poderá usar as seguintes etapas:
Adicione o pai ao arquivo POM.xml:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.5.RELEASE</version> <relativePath/> </parent>
Adicione propriedades ao arquivo POM.xml:
<azure.version>2.1.6</azure.version>
Adicione dependências ao arquivo POM.xml:
<dependency> <groupId>com.microsoft.azure</groupId> <artifactId>azure-cosmosdb-spring-boot-starter</artifactId> <version>2.1.6</version> </dependency>
Adicione propriedades do aplicativo em recursos e especifique o seguinte. Certifique-se de substituir os parâmetros de URL, chave e nome do banco de dados:
azure.cosmosdb.uri=<your-cosmosDB-URL> azure.cosmosdb.key=<your-cosmosDB-key> azure.cosmosdb.database=<your-cosmosDB-dbName>
Defina o nome da coleção no modelo. Você também pode especificar mais anotações. Por exemplo, ID, chave de partição para denotá-los explicitamente:
@Document(collection = "mycollection") public class User { @id private String id; private String firstName; @PartitionKey private String lastName; }
A seguir estão os snippets de código para operações CRUD:
Operações de inserção e atualização
Onde _repo é o objeto do repositório e doc é o objeto da classe POJO. Você pode usar .save
para inserir ou upsert (se o documento com a ID especificada for encontrado). O snippet de código a seguir mostra como inserir ou atualizar um objeto doc:
_repo.save(doc);
Operação de Exclusão
Considere o seguinte snippet de código, em que o objeto doc terá a ID e a chave de partição obrigatórias para localizar e excluir o objeto:
_repo.delete(doc);
Operação de Leitura
Você pode ler o documento especificando ou não a chave de partição. Se você não especificar a chave de partição, ela será tratada como uma consulta entre partições. Considere os códigos de exemplo a seguir: o primeiro executará a operação usando o campo ID e chave de partição. O segundo exemplo usa um campo comum e sem especificar o campo da chave da partição.
_repo.findByIdAndName(objDoc.getId(),objDoc.getName());
_repo.findAllByStatus(objDoc.getStatus());
É isso! Agora você pode usar seu aplicativo com o Azure Cosmos DB. O código de exemplo completo para o exemplo descrito neste doc está disponível repositório CouchbaseToCosmosDB-SpringCosmos do GitHub.
Couchbase como repositório de documentos e usando consultas N1QL
As consultas N1QL são a maneira de definir consultas no Couchbase.
Consulta N1QL | Consulta do Azure Cosmos DB |
---|---|
SELECT META(TravelDocument ).id AS id, TravelDocument .* FROM TravelDocument WHERE _type = "com.xx.xx.xx.xxx.xxx.xxxx " and country = 'India’ and ANY m in Visas SATISFIES m.type == 'Multi-Entry' and m.Country IN ['India', Bhutan’] ORDER BY Validity DESC LIMIT 25 OFFSET 0 |
SELECT c.id,c FROM c JOIN m in c.country=’India’ WHERE c._type = " com.xx.xx.xx.xxx.xxx.xxxx" and c.country = 'India' and m.type = 'Multi-Entry' and m.Country IN ('India', 'Bhutan') ORDER BY c.Validity DESC OFFSET 0 LIMIT 25 |
Você pode observar as seguintes alterações nas consultas N1QL:
Você não precisa usar a palavra-chave META ou consultar o documento de primeiro nível. Em vez disso, você pode criar sua própria referência ao contêiner. Neste exemplo, consideramos como “c” (pode ser qualquer coisa). Essa referência é usada como um prefixo para todos os campos de primeiro nível. Por exemplo, c.id, c.country etc.
Em vez de “ANY”, agora você pode fazer uma junção no subdocumento e consultá-lo com um alias dedicado, como “m”. Depois de criar o alias para um subdocumento, você precisará usar o alias. Por exemplo, m.Country.
A sequência de OFFSET é diferente na consulta do Azure Cosmos DB, primeiro você precisa especificar OFFSET e LIMIT. Recomenda-se não utilizar o Spring Data SDK se estiver a utilizar o máximo de consultas personalizadas definidas, pois pode ter sobrecarga desnecessária no lado do cliente ao passar a consulta para o Azure Cosmos DB. Em vez disso, temos um SDK do Java assíncrono direto, que pode ser utilizado com muita eficiência nesse caso.
Operação de leitura
Use o SDK do Java assíncrono com as seguintes etapas:
Configure a seguinte dependência no arquivo POM.xml:
<!-- https://mvnrepository.com/artifact/com.microsoft.azure/azure-cosmosdb --> <dependency> <groupId>com.microsoft.azure</groupId> <artifactId>azure-cosmos</artifactId> <version>3.0.0</version> </dependency>
Crie um objeto de conexão para o Azure Cosmos DB usando o método
ConnectionBuilder
, como mostrado no exemplo a seguir. Certifique-se de colocar essa declaração no bean de modo que o código a seguir seja executado apenas uma vez:ConnectionPolicy cp=new ConnectionPolicy(); cp.connectionMode(ConnectionMode.DIRECT); if(client==null) client= CosmosClient.builder() .endpoint(Host)//(Host, PrimaryKey, dbName, collName).Builder() .connectionPolicy(cp) .key(PrimaryKey) .consistencyLevel(ConsistencyLevel.EVENTUAL) .build(); container = client.getDatabase(_dbName).getContainer(_collName);
Para executar a consulta, você precisa executar o seguinte snippet de código:
Flux<FeedResponse<CosmosItemProperties>> objFlux= container.queryItems(query, fo);
Agora, com a ajuda do método acima, você pode passar várias consultas e executá-las sem complicações. Caso você tenha a necessidade de executar uma consulta grande, que pode ser dividida em várias consultas, tente o seguinte snippet de código em vez do anterior:
for(SqlQuerySpec query:queries)
{
objFlux= container.queryItems(query, fo);
objFlux .publishOn(Schedulers.elastic())
.subscribe(feedResponse->
{
if(feedResponse.results().size()>0)
{
_docs.addAll(feedResponse.results());
}
},
Throwable::printStackTrace,latch::countDown);
lstFlux.add(objFlux);
}
Flux.merge(lstFlux);
latch.await();
}
Você pode executar consultas em paralelo com o código anterior e aumentar as execuções distribuídas para otimização. Além disso, você também pode executar as operações de inserção e atualização:
Operação de Inserção
Para inserir o documento, execute o seguinte código:
Mono<CosmosItemResponse> objMono= container.createItem(doc,ro);
Em seguida, assine Mono como:
CountDownLatch latch=new CountDownLatch(1);
objMono .subscribeOn(Schedulers.elastic())
.subscribe(resourceResponse->
{
if(resourceResponse.statusCode()!=successStatus)
{
throw new RuntimeException(resourceResponse.toString());
}
},
Throwable::printStackTrace,latch::countDown);
latch.await();
Operação upsert
A operação upsert exige que você especifique o documento que precisa ser atualizado. Para buscar o documento completo, você pode usar o snippet mencionado em operação de leitura de cabeçalho e modificar os campos obrigatórios. O seguinte snippet de código upserts o documento:
Mono<CosmosItemResponse> obs= container.upsertItem(doc, ro);
Em seguida, assine mono. Consulte o snippet de assinatura do mono na operação de inserção.
Operação de exclusão
O snippet a seguir fará a operação de exclusão:
CosmosItem objItem= container.getItem(doc.Id, doc.Tenant);
Mono<CosmosItemResponse> objMono = objItem.delete(ro);
Em seguida, assine mono, consulte o snippet de assinatura mono na operação de inserção. O código de exemplo completo está disponível no repositório CouchbaseToCosmosDB-AsyncInSpring do GitHub.
Couchbase como um par de chave/valor
Esse é um tipo simples de carga de trabalho no qual você pode executar pesquisas em vez de consultas. Use as seguintes etapas para pares de chave/valor:
Considere ter “/ID” como chave primária, o que garantirá que você possa executar a operação de pesquisa diretamente na partição específica. Crie uma coleção e especifique “/ID” como chave de partição.
Desative completamente a indexação. Como você executará operações de pesquisa, não há sentido em sobrecarregar a indexação. Para desativar a indexação, entre no portal do Azure, vá para Conta do Azure Cosmos DB. Abra o Data Explorer, selecione seu Banco de Dados e o Contêiner. Abra a guia Escala e configurações e selecione a Política de indexação. A política de indexação atualmente é semelhante ao seguinte:
{ "indexingMode": "consistent", "automatic": true, "includedPaths": [ { "path": "/*" } ], "excludedPaths": [ { "path": "/\"_etag\"/?" } ] }
Substitua a política de indexação acima pela seguinte política:
{ "indexingMode": "none", "automatic": false, "includedPaths": [], "excludedPaths": [] }
Use o seguinte snippet de código para criar o objeto de conexão. Objeto de conexão (a ser colocado em @Bean ou torná-lo estático):
ConnectionPolicy cp=new ConnectionPolicy(); cp.connectionMode(ConnectionMode.DIRECT); if(client==null) client= CosmosClient.builder() .endpoint(Host)//(Host, PrimaryKey, dbName, collName).Builder() .connectionPolicy(cp) .key(PrimaryKey) .consistencyLevel(ConsistencyLevel.EVENTUAL) .build(); container = client.getDatabase(_dbName).getContainer(_collName);
Agora você pode executar as operações CRUD da seguinte maneira:
Operação de leitura
Para ler o item, use o seguinte snippet:
CosmosItemRequestOptions ro=new CosmosItemRequestOptions();
ro.partitionKey(new PartitionKey(documentId));
CountDownLatch latch=new CountDownLatch(1);
var objCosmosItem= container.getItem(documentId, documentId);
Mono<CosmosItemResponse> objMono = objCosmosItem.read(ro);
objMono .subscribeOn(Schedulers.elastic())
.subscribe(resourceResponse->
{
if(resourceResponse.item()!=null)
{
doc= resourceResponse.properties().toObject(UserModel.class);
}
},
Throwable::printStackTrace,latch::countDown);
latch.await();
Operação de Inserção
Para inserir um item, você pode executar o seguinte código:
Mono<CosmosItemResponse> objMono= container.createItem(doc,ro);
Em seguida, assine mono como:
CountDownLatch latch=new CountDownLatch(1);
objMono.subscribeOn(Schedulers.elastic())
.subscribe(resourceResponse->
{
if(resourceResponse.statusCode()!=successStatus)
{
throw new RuntimeException(resourceResponse.toString());
}
},
Throwable::printStackTrace,latch::countDown);
latch.await();
Operação upsert
Para atualizar o valor de um item, consulte o snippet de código abaixo:
Mono<CosmosItemResponse> obs= container.upsertItem(doc, ro);
Em seguida, assine mono, consulte o snippet de assinatura mono na operação de inserção.
Operação de exclusão
Use o snippet a seguir para executar a operação de exclusão:
CosmosItem objItem= container.getItem(id, id);
Mono<CosmosItemResponse> objMono = objItem.delete(ro);
Em seguida, assine mono, consulte o snippet de assinatura mono na operação de inserção. O código de exemplo completo está disponível no repositório CouchbaseToCosmosDB-AsyncKeyValue do GitHub.
Migração de Dados
Use Azure Data Factory para migrar dados. Esse é o método mais recomendado para migrar os dados. Configure a origem como Couchbase e o coletor como Azure Cosmos DB for NoSQL. Consulte o artigo Conector do Data Factory do Azure Cosmos DB do Azure para obter as etapas detalhadas.
Próximas etapas
- Para realizar testes de desempenho, consulte o artigo Teste de desempenho e escala com o Azure Cosmos DB.
- Para otimizar o código, consulte o artigo Dicas de desempenho para o Azure Cosmos DB.
- Explore o SDK do Java assíncrono V3, repositório de Referência do SDK do GitHub.