O Couchbase Server 5.0 e 5.5 foram dois grandes lançamentos. Vamos ver alguns dos novos recursos interessantes e antigos que os desenvolvedores não podem perder:
1) Subdocumentos
Esse recurso já existe há algum tempo, mas ainda vale a pena mencioná-lo. Alguns armazenamentos de valores-chave só permitem que você traga o documento inteiro, o que é uma característica razoável. Afinal de contas, trata-se de um Key-Value Store. No entanto, se você estiver usando o Couchbase como um KV, ainda poderá manipular partes do documento especificando o caminho para ele. Ex:
Dado o seguinte documento:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
{ "name" (nome): "Douglas Reynholm", "email": "douglas@reynholmindustries.com", "endereços": { "faturamento": { "line1": "123 Any Street" (123 Qualquer Rua), "line2": "Qualquer cidade", "país": "Reino Unido" }, "entrega": { "line1": "123 Any Street" (123 Qualquer Rua), "line2": "Qualquer cidade", "país": "Reino Unido" } }, "compras": { "completo": [ 339, 976, 442, 666 ], "abandonado": [ 157, 42, 999 ] } } |
Você pode manipular partes do documento simplesmente especificando o caminho para ele, como GET('addresses.billing') ou ARRAY_APPEND('purchases.abandoned', 42)
Se você quiser ler mais, dê uma olhada em postagem no blog ou nosso documentação oficial.
2) Eventos
A geração de eventos é claramente um dos recursos mais interessantes do Couchbase 5.5 e já temos várias postagens no blog sobre isso, como aqui ou aqui. Para aqueles que ainda não ouviram falar, o Eventing Service permite que você escreva funções no lado do servidor que são acionadas automaticamente sempre que um documento é inserido/atualizado/excluído. Essas funções podem ser facilmente escritas usando uma sintaxe semelhante à do JavaScript:

Além disso, você também pode chamar endpoints em seu aplicativo via curl:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
função Sobre a atualização(doc, meta) { se (doc.tipo de recurso != "Observação) retorno; deixar referência = doc.assunto.referência; deixar url = "https://localhost:8080/events/" + referência.substrato(9); deixar dados = JSON.stringify({ "referência": doc.assunto.referência, "código": doc.código.codificação[0].código, "recordedAt": doc.emitido, "valor": doc.valueQuantity.valor }); deixar enrolar = SELECIONAR CURL($url, { "request" (solicitação): "POST", "cabeçalho": [ "Content-Type: application/json", "accept: application/json" ], "dados": $dados }); enrolar.execQuery(); } função OnDelete(meta) {} |
3) Uniões ANSI
O Couchbase permite que você use junções em suas consultas há muito tempo, mas, até agora, isso só podia ser feito usando nossa própria sintaxe. Desde o Couchbase 5.5, você também pode usar a sintaxe ANSI JOIN:
|
1 2 3 4 5 6 7 |
SELECIONAR DISTINTO rota.aeroporto de destino DE `viagens-amostra` aeroporto JUNTAR `viagens-amostra` rota ON aeroporto.faa = rota.aeroporto de origem E rota.tipo = "route" (rota) ONDE aeroporto.tipo = "aeroporto" E aeroporto.cidade = "São Francisco" E aeroporto.país = "Estados Unidos"; |
Você pode ler mais sobre isso aqui.
4) Pesquisa de texto completo
A maioria dos aplicativos voltados para o usuário precisa, eventualmente, implementar algum tipo de pesquisa avançada. Esse tipo de recurso geralmente exige que você envie dados para uma ferramenta de terceiros, como o Solr ou o Elastic Search. No entanto, adicionar essas ferramentas aumenta significativamente o custo e a complexidade de sua infraestrutura, sem mencionar todo o código necessário para enviar alterações de objetos/documentos para essas ferramentas.
A partir do Couchbase 5.0, você pode simplesmente criar um índice de pesquisa de texto completo no console da Web e começar a fazer pesquisas de texto completo diretamente no banco de dados:

Destaque dos resultados da pesquisa:

É fácil fazer uma pesquisa simples por meio do SDK:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@Override público Lista<SearchQueryRow> pesquisa(Cordas palavra) { Cordas indexName = "movies_index"; QueryStringQuery consulta = Pesquisa.queryString(palavra); Resultado da pesquisa resultado = movieRepository.getCouchbaseOperations().getCouchbaseBucket().consulta( novo Pesquisa(indexName, consulta).destaque().limite(20)); Lista<SearchQueryRow> sucessos = novo ArrayList<>(); se (resultado != nulo && resultado.erros().isEmpty()) { Iterador<SearchQueryRow> resultadoIterador = resultado.iterador(); enquanto (resultadoIterador.hasNext()) { sucessos.adicionar(resultadoIterador.próxima()); } } retorno sucessos; } |
Você pode ver a documentação oficial aqui.
5) Consultas mais rápidas, GROUP BYs e Aggregation Pushdown
Independentemente do banco de dados, as operações de agregação (min, max, avg, etc.) e GROUP BYs sempre foram problemáticas em termos de desempenho. Para resolver esse problema, com o Couchbase 5.5, você pode aproveitar seus índices para acelerar esses tipos de consultas:
|
1 2 3 4 5 |
SELECIONAR país, estado, cidade, CONTAGEM(1) AS total DE `viagens-amostra` ONDE tipo = 'hotel' e país é não nulo GRUPO BY país, estado, cidade ORDEM BY CONTAGEM(1) DESC; |
~90ms - Plano de consulta da consulta acima

~7ms - A mesma consulta anterior, mas usando um índice adequado

Você pode ler o artigo completo aqui.
6) Controle de acesso baseado em função e certificado X509
Os bancos de dados são o grande prêmio para qualquer invasor mal-intencionado, e é por isso que nunca é demais adicionar uma camada extra de segurança. Com o Couchbase, você pode autenticar clientes usando certificados X.509 e limitar seu acesso por meio do RBAC (Role Based Access Control):

Você também pode conceder permissões por meio do N1QL. Vamos ver como conceder uma permissão SELECT para o usuário denis no balde algum_bucket seria semelhante:
|
1 |
CONCESSÃO FUNÇÃO consulta_seleção(algum_bucket) PARA denis; |
Você pode ler mais sobre isso aqui ou aqui.
7) Criptografia de campo
A criptografia em repouso é uma das formas mais básicas de segurança, e você pode facilmente criptografar/descriptografar campos usando o Criptografia Java do Couchbase:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
público estático classe Pessoa { @Id público Cordas id; @EncryptedField(provedor = "AES") público Cordas senha; /O restante será transportado e armazenado sem criptografia público Cordas firstName; público Cordas lastName; público Cordas nome de usuário; público int idade; } |
Leia mais sobre o assunto aqui ou aqui.
8) SDK reativo
Também oferecemos um SDK reativo, o que não é fácil de encontrar em boa parte dos provedores de banco de dados. Isso se deve principalmente ao fato de que nosso próprio SDK é implementado de forma reativa.
A programação reativa é muito importante para a otimização do desempenho e dos recursos. Se você ainda não está familiarizado com esse conceito, recomendo fortemente este artigoque oferece uma visão geral rápida de por que você pode considerar o uso da programação reativa em sua camada de persistência.
Temos um extenso material sobre esse tópico. Se quiser saber mais, você pode começar aqui ou aqui.
9) "Ajuste fino de velocidade" via SDK
No Couchbase, tentamos capacitar os desenvolvedores a ajustar o desempenho até mesmo no nível do documento, para que eles possam decidir, caso a caso, qual é a melhor opção para cada cenário.
Vamos dar uma olhada, por exemplo, em como o Couchbase armazena dados. Por padrão, assim que o servidor reconhece que um novo documento deve ser armazenado, ele já envia a resposta de volta ao cliente dizendo que sua "solicitação foi recebida com sucesso" e, de forma assíncrona, armazenamos e replicamos o documento.
Essa abordagem é muito boa em termos de velocidade, mas há uma pequena chance de perda de dados se o servidor falhar quando o documento ainda estiver na memória do servidor. Se quiser evitar isso, você pode especificar por meio do SDK que gostaria de receber a confirmação somente depois que o documento tiver sido replicado ou armazenado no disco:
|
1 2 3 4 5 |
movieRepository.getCouchbaseOperations().salvar(filme, PersistTo.UM, ReplicarPara.NENHUM); /ou movieRepository.getCouchbaseOperations().salvar(filme, PersistTo.UM, ReplicarPara.DOIS); ... movieRepository.getCouchbaseOperations().salvar(filme, PersistTo.NENHUM, ReplicarPara.UM); |
Por que permitir isso? Bem, porque se você puder arcar com a pequena chance de perder esses dados em caso de falha do servidor, poderá melhorar significativamente o seu desempenho. Essa não é uma decisão do tipo "tudo ou nada", pois você pode decidir quais partes do sistema valem esse risco.
Você também pode fazer algo semelhante com suas consultas. Nesse caso, se deseja esperar que os índices/visualizações sejam atualizados com base nas últimas alterações ou se está satisfeito com a pequena chance de não retornar a versão mais recente dos seus documentos:
|
1 2 3 4 |
//Você pode usar ScanConsistency.REQUEST_PLUS, ScanConsistency.NOT_BOUNDED ou ScanConsistency.STATEMENT_PLUS N1qlParams parâmetros = N1qlParams.construir().consistência(Consistência de varredura.REQUEST_PLUS).adhoc(verdadeiro); ParametrizadoN1qlQuery consulta = N1qlQuery.parametrizado(queryString, JsonObject.criar(), parâmetros); resourceRepository.getCouchbaseOperations().getCouchbaseBucket().consulta(consulta); |
Há alguns outros recursos em nosso SDK que também podem ser otimizados, e todas essas pequenas decisões podem melhorar significativamente seu desempenho em escala.
10) Observabilidade do tempo de resposta
Já mencionei esse item em meu postagem anterior do blogmas acho que vale a pena mencioná-lo novamente. Desde a versão 5.5, introduzimos um novo recurso chamado Response Time Observability, que fornecerá aos desenvolvedores de sistemas uma maneira muito simples de observar os tempos de resposta em relação a um limite (ajustável).
Esse recurso, que usa o formato OpenTracing, registra solicitações lentas seguidas de uma série de detalhes sobre elas após cada intervalo de tempo, para que você possa identificar facilmente as operações com desempenho insatisfatório.
|
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 |
Abril 04, 2018 9:42:57 AM com.couchbase.cliente.núcleo.rastreamento.ThresholdLogReporter logOverThreshold AVISO: Operações sobre limite: [ { "top" : [ { "server_us" : 8, "local_id" : "41837B87B9B1C5D1/000000004746B9AA", "local_address" (endereço local) : "127.0.0.1:55011", "operation_id" : "get:0x6", "dispatch_us" : 315, "remote_address" (endereço remoto) : "127.0.0.1:11210", "total_us" : 576 }, { "server_us" : 8, "local_id" : "41837B87B9B1C5D1/000000004746B9AA", "local_address" (endereço local) : "127.0.0.1:55011", "operation_id" : "get:0x5", "dispatch_us" : 319, "remote_address" (endereço remoto) : "127.0.0.1:11210", "total_us" : 599 }, { "server_us" : 8, "local_id" : "41837B87B9B1C5D1/000000004746B9AA", "local_address" (endereço local) : "127.0.0.1:55011", "operation_id" : "get:0x4", "dispatch_us" : 332, "remote_address" (endereço remoto) : "127.0.0.1:11210", "total_us" : 632 }, { "server_us" : 11, "local_id" : "41837B87B9B1C5D1/000000004746B9AA", "local_address" (endereço local) : "127.0.0.1:55011", "operation_id" : "get:0x3", "dispatch_us" : 392, "remote_address" (endereço remoto) : "127.0.0.1:11210", "total_us" : 762 }, { "server_us" : 23, "local_id" : "41837B87B9B1C5D1/000000004746B9AA", "local_address" (endereço local) : "127.0.0.1:55011", "operation_id" : "get:0x1", "decode_us" : 9579, "dispatch_us" : 947, "remote_address" (endereço remoto) : "127.0.0.1:11210", "total_us" : 16533 }, { "server_us" : 56, "encode_us" : 12296, "local_id" : "41837B87B9B1C5D1/000000004746B9AA", "local_address" (endereço local) : "127.0.0.1:55011", "operation_id" : "upsert:0x2", "dispatch_us" : 1280, "remote_address" (endereço remoto) : "127.0.0.1:11210", "total_us" : 20935 } ], "serviço" : "kv", "count" (contagem) : 6 } ] |
A observabilidade do tempo de resposta está ativada por padrão, e já definimos um conjunto de limites para evitar o registro de solicitações saudáveis. Se quiser ultrapassar os limites do seu cluster, você pode até mesmo definir limites menores manualmente. Você pode ler mais sobre isso aqui.