[Este blog foi distribuído pelo site http://nitschinger.at/].

Para todos os usuários do nosso Java SDK, preparamos algumas adições interessantes para você. Esta postagem os aborda em detalhes e mostra como você pode se tornar mais produtivo

Observe que esta publicação do blog pressupõe que você esteja executando a versão 1.2.1, pois houve algumas pequenas alterações entre a 1.2.0 e a 1.2.1 que afetam, por exemplo, o suporte a ouvintes e a coleta de métricas.

Distribuição central do Maven

Da versão 1.2.0 em diante, o Java SDK é distribuído diretamente do Maven Central. Isso significa que você não precisa mais incluir o repositório do Couchbase. O código maven a seguir é suficiente para começar (observe que o groupId foi alterado):

<dependências>
<dependência>
<groupId>com.couchbase.client>
<artifactId>cliente couchbase>
<versão>1.2.1>
>
>

Isso também carregará automaticamente a dependência mais recente do spymemcached (para a versão 1.2.0, é a 2.10.0). Antes de nos aprofundarmos no que mudou, aqui são as notas de versão para uma referência rápida.

Suporte ao ouvinte

Até agora, havia duas maneiras de obter o resultado de uma solicitação assíncrona. Ou bloqueando o thread atual da seguinte forma:
// fazer uma operação assíncrona (retorna imediatamente)
OperaçãoFuturo<Booleano> setFuture = cliente.definir("chave", "valor");

// bloquear o thread atual
Booleano resultado = setFuture.obter();

Ou para fazer um loop nos métodos futuros sem bloqueio. Isso é especialmente útil se você estiver lidando com uma lista de futuros.
Lista<OperaçãoFuturo<Booleano>> futuros = novo ArrayList<OperaçãoFuturo<Booleano>>();
para (int i = 0; i < 100; i++) {
futuros.adicionar(cliente.definir("chave-" + i, "valor"));
}

enquanto (!futuros.isEmpty()) {
Iterador<OperaçãoFuturo<Booleano>> iter = futuros.iterador();
enquanto (iter.hasNext()) {
OperaçãoFuturo<Booleano> futuro = iter.próxima();
se (futuro.isDone()) {
iter.remover();
}
}
}

Agora, desde a versão 1.2.0, há uma nova maneira de lidar com as respostas: adicionar ouvintes. A ideia é fornecer um retorno de chamada para o futuro que será executado assim que a operação for concluída. Um exemplo simples é mostrado aqui:
OperaçãoFuturo<Booleano> setFuture = cliente.definir("chave", "valor");
setFuture.addListener(novo Listador de conclusão de operação (OperationCompletionListener)() {
@Override
público vazio onComplete(OperaçãoFuturo<?> futuro) lançamentos Exceção {
Sistema.fora.println(futuro.obter());
}
});
Observe que o .get() no futuro não bloqueará mais porque o resultado já foi calculado. Tudo o que você colocar no método de retorno de chamada será executado de forma assíncrona no pool de threads. Para ver como essa abordagem é flexível, vamos reescrever o exemplo acima esperando até que os 100 futuros sejam concluídos.
final Trava CountDownLatch = novo CountDownLatch(100);
para (int i = 0; i < 100; i++) {
OperaçãoFuturo<Booleano> futuro = cliente.definir("chave-" + i, "valor");
futuro.addListener(novo Listador de conclusão de operação (OperationCompletionListener)() {
@Override
público vazio onComplete(OperaçãoFuturo<?> futuro) lançamentos Exceção {
trava.countDown();
}
});
}
trava.aguardar();
Aqui estamos usando um CountDownLatch que espera no thread atual desde que tenha sido contado cem vezes. Exatamente o que precisamos em nossa situação, mas o código é muito mais fácil de ler. E o mais importante é que ele é muito mais flexível, pois outras coisas podem ser feitas, como disparar uma nova solicitação, consultar um serviço da Web ou calcular um resultado.
Também é possível substituir o padrão ExecutorService com uma implementação personalizada. Isso pode ser necessário se o comportamento padrão (basicamente um cachedThreadPool com limite superior) não atender às suas necessidades. Além disso, você deve usar essa abordagem se criar um monte de Cliente Couchbase para que você possa compartilhar o mesmo serviço em todas elas.
// Criar o Builder
Construtor do CouchbaseConnectionFactoryBuilder = novo CouchbaseConnectionFactoryBuilder();

// Criar um pool de threads de 5 threads fixos
Serviço ExecutorService = Executores.newFixedThreadPool(5);

// Definir no construtor
construtor.setListenerExecutorService(serviço);

// Criar a instância
Cliente CouchbaseClient = novo Cliente Couchbase(construtor.buildCouchbaseConnection());

Recursos aprimorados de criação de perfil

Obter insights sobre um aplicativo em execução é sempre difícil, por isso nos propusemos a facilitar esse processo para você. Incorporamos uma biblioteca chamada metrics que cria perfis, dependendo do nível de configuração escolhido.
Antes de poder usá-lo, você precisa adicionar essa dependência opcional:
<dependência>
<groupId>com.codahale.metrics>
<artifactId>núcleo de métricas>
<versão>3.0.1>
>
No construtor, há um método que permite que você ative o criador de perfil:
Construtor do CouchbaseConnectionFactoryBuilder = novo CouchbaseConnectionFactoryBuilder();
// ativar a coleta de métricas
construtor.setEnableMetrics(MetricType.DESEMPENHO);
Se você observar o MetricType você pode ver que há três tipos de valores que podem ser escolhidos: OFF (que mantém a coleta de métricas desativada), PERFORMANCE (que coleta apenas métricas relevantes para o desempenho) e DEBUG (que coleta todos os tipos de métricas, inclusive as de desempenho). Embora a biblioteca de métricas seja bastante eficiente, lembre-se de que a coleta de métricas consome alguns recursos do seu aplicativo.
Por padrão, as informações de métricas serão impressas no console a cada 30 segundos. Você pode executar o código de teste a seguir em seu IDE e ver como fica:
Construtor do CouchbaseConnectionFactoryBuilder = novo CouchbaseConnectionFactoryBuilder();
construtor.setEnableMetrics(MetricType.DESEMPENHO);

CouchbaseConnectionFactory cf =
construtor.buildCouchbaseConnection(Matrizes.asList(novo URI(“http://127.0.0.1:8091/pools”)), "default", “”);
Cliente CouchbaseClient = novo Cliente Couchbase(cf);

enquanto(verdadeiro) {
cliente.definir("foo", "bar");
Tópico.dormir(100);
}

Agora aguarde 30 segundos e verá um resultado como este no console:
10/8/13 12:04:14 PM ============================================================

- Histogramas ----------------------

[Média de bytes lidos do sistema operacional por leitura

contagem = 893

min = 24

max = 24

média = 24,00

stddev = 0,00

mediana = 24,00

75% <= 24,00

95% <= 24,00

98% <= 24,00

99% <= 24,00

99,9% <= 24,00

[Média de bytes gravados no sistema operacional por gravação

contagem = 893

min = 38

max = 38

média = 38,00

stddev = 0,00

mediana = 38,00

75% <= 38,00

95% <= 38,00

98% <= 38,00

99% <= 38,00

99,9% <= 38,00

[MEM] Tempo médio no fio para operações (µs)

contagem = 893

min = 179

max = 1730

média = 263,80

desvio padrão = 75,43

mediana = 251,00

75% <= 280,00

95% <= 351,90

98% <= 425,36

99% <= 559,70

99.9% <= 1730.00

- Metros ------------------------

Taxa de solicitação [MEM]: Todos

contagem = 893

taxa média = 9,92 eventos/segundo

Taxa de 1 minuto = 9,85 eventos/segundo

Taxa de 5 minutos = 9,68 eventos/segundo

Taxa de 15 minutos = 9,63 eventos/segundo

[MEM] Taxa de resposta: Todas (falha + sucesso + nova tentativa)

contagem = 893

taxa média = 9,92 eventos/segundo

Taxa de 1 minuto = 9,85 eventos/segundo

Taxa de 5 minutos = 9,68 eventos/segundo

Taxa de 15 minutos = 9,63 eventos/segundo

Não entrarei em detalhes sobre todas essas métricas nesta postagem do blog; consulte a documentação para obter uma visão mais completa. Mais uma coisa que quero mostrar a você é que a biblioteca de métricas também pode expor essas métricas por meio do JMX. Tudo o que você precisa fazer é definir uma propriedade do sistema que altere o modo de saída: net.spy.metrics.reporter.type=jmx. Outras configurações possíveis são csv e slf4j. Se você escolher um registrador que imprime informações em um determinado intervalo, poderá alterá-lo definindo net.spy.metrics.reporter.interval para algo diferente de 30.
Portanto, se você colocar a linha System.setProperty("net.spy.metrics.reporter.type", "jmx"); Antes do código mostrado acima, você pode abrir (por exemplo) o jConsole e alternar para a guia MBeans do aplicativo. Você verá um métricas subseção exposta que contém as mesmas métricas que apareceriam nos registros.

CAS com vencimento

Antes da versão 1.2.0, não era possível, em um único comando, fazer um cas atualizar e definir uma nova expiração ao mesmo tempo. Você teve que fazer uma segunda toque que não era eficiente nem atômica. Agora, a API expõe uma nova cas() que permite que você passe o tempo de expiração ao mesmo tempo. É fácil de usar:
cliente.cas("chave", cas, newExpiration, value);
As variações assíncronas também foram expostas desde a versão 1.2.1.

Inicialização por meio de propriedades

Uma coisa que é útil se os endereços IP do cluster mudarem com frequência é que agora você pode inicializar um Cliente Couchbase com base nas propriedades do sistema. Aqui está um exemplo:
Sistema.setProperty("cbclient.nodes", "http://127.0.0.1:8091/pools");
Sistema.setProperty("cbclient.bucket", "default");
Sistema.setProperty("cbclient.password", "");

Construtor do CouchbaseConnectionFactoryBuilder = novo CouchbaseConnectionFactoryBuilder();
CouchbaseConnectionFactory cf = construtor.buildCouchbaseConnection();
Cliente CouchbaseClient = novo Cliente Couchbase(cf);

É claro que você pode definir essas propriedades no contêiner do aplicativo ou durante a inicialização, portanto, é muito flexível e não está diretamente vinculado ao seu código. Observe que, se você esquecer de definir uma dessas propriedades, o código o avisará da seguinte forma:
Exceção na thread "main" java.lang.IllegalArgumentException: Propriedade do sistema cbclient.nodes não definida ou vazia
at com.couchbase.client.CouchbaseConnectionFactory.(CouchbaseConnectionFactory.java:160)
at com.couchbase.client.CouchbaseConnectionFactoryBuilder$2.(CouchbaseConnectionFactoryBuilder.java:318)
at com.couchbase.client.CouchbaseConnectionFactoryBuilder.buildCouchbaseConnection(CouchbaseConnectionFactoryBuilder.java:318)
em Main.main(Main.java:33)
em sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
em sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
em java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

Outras alterações

Além dos aprimoramentos mostrados acima, a versão inclui, como sempre, várias correções de bugs menores. O intervalo de pesquisa padrão para ReplicarPara e PersistTo foi reduzido para 10ms para levar em conta as alterações de desempenho que foram incluídas na versão 2.2 do Couchbase Sever. Além disso, o cliente agora usa o Mecanismo de autenticação CRAM-MD5` automaticamente se o servidor for compatível com ele (desde a versão 2.2 também).
Esses novos recursos incríveis devem ser motivo suficiente para fazer o upgrade agora mesmo! Se algo não funcionar como esperado, entre em contato com o suporte ao cliente ou abra um tíquete aqui.

Autor

Postado por Michael Nitschinger

Michael Nitschinger trabalha como engenheiro de software principal na Couchbase. Ele é o arquiteto e mantenedor do Couchbase Java SDK, um dos primeiros drivers de banco de dados totalmente reativos na JVM. Ele também é o autor e mantenedor do Couchbase Spark Connector. Michael participa ativamente da comunidade de código aberto e contribui para vários outros projetos, como RxJava e Netty.

Um comentário

  1. [...] Postagem do blog da semana: O que há de novo no Couchbase Java SDK 1.2 [...]

Deixar uma resposta