Postagem de convidado: Eric Lambert
O cliente Java Spymemcached é o principal cliente Java usado por aplicativos baseados em Java que precisam se valer dos servidores Memcached. O motivo pelo qual o Spy se tornou tão popular na comunidade Java é que ele foi altamente otimizado e oferece excelente desempenho, mas, ao mesmo tempo, faz isso sem sobrecarregar o usuário com complexidade indevida.
Para os casos mais comuns, os usuários precisam simplesmente usar o seguinte "modelo List servers = new ArrayList(); servers.add(new InetSocketAddress("192.168.0.9",11211); MemcachedClient client = new MemcachedClient(new BinaryConnectionFactory();, servers);
Nesse momento, eles estão prontos para começar a realizar operações de detonação em seu cluster de servidores Memcached. Embora o Spy ofereça uma interface muito simples e fácil de usar, ele não faz isso às custas da flexibilidade necessária para ajustar o sistema. Por baixo da capa, o Spy oferece muitas maneiras de ajustar o sistema. Neste blog, vou me aprofundar em alguns dos botões e interruptores que o Spy oferece. Espero que, ao fazer isso, eu o ajude a entender melhor como o Spy se comporta e como você pode ajustá-lo para melhor atender às suas necessidades quando o comportamento pronto para uso não for suficiente. Mas antes de entrar nos detalhes, quero começar com um tutorial muito simples, direto e um tanto ingênuo do Spymemcached e usá-lo para ilustrar um ponto bastante significativo.
Digamos que eu esteja avaliando o Spymemcached pela primeira vez e queira entender o desempenho do meu sistema ao fazer uma série de definições, obtenções e exclusões. Para isso, posso criar um programa simples que primeiro defina uma série de entradas no cache, depois recupere cada uma dessas entradas e, por fim, exclua cada uma dessas entradas. Posso instrumentar o código para fazer isso de forma que ele rastreie o tempo total necessário para fazer todas as definições, obtenções e exclusões. O código para isso poderia se parecer com o seguinte // executar conjuntos long start = System.nanoTime(); for (int i = 0; i < numberOfOps; i++) { client.set(KEY_PREFIX + i, 3600, PAY_LOAD).get(); } long end = System.nanoTime(); long setTime = end - start; // executar obtenções start = System.nanoTime(); for (int i = 0; i < numberOfOps; i++) { client.get(KEY_PREFIX + i); } end = System.nanoTime(); long getTime = end - start; // executar exclusões start = System.nanoTime(); for (int i = 0; i < numberOfOps; i++) { client.delete(KEY_PREFIX + i).get(); } end = System.nanoTime(); long delTime = end - start; System.out.println(numberOfOps + " Set: " + setTime / nanosPerSec + " Média: " + setTime / numberOfOps); System.out.println(numberOfOps + " Get: " + getTime / nanosPerSec + " Average: " + getTime / numberOfOps); System.out.println(numberOfOps + " Delete: " + delTime / nanosPerSec + " Média: " + delTime / numberOfOps);
Como mencionei anteriormente, esse é um caso de uso bastante ingênuo e irrealista. No entanto, esse exemplo rudimentar tem uma lição importante a nos ensinar.
Vamos ver o que acontece quando executamos esse teste usando valores diferentes para o numberOfOps
. Se definirmos numberOfOps
para 10.000, nosso desempenho pode ser parecido com o seguinte: 10000 Set: 3.008377 Average: 300837 10000 Get: 1.730886 Average: 173088 10000 Delete: 1.172679 Average: 117267
Agora, vamos aumentar um pouco a aposta e ver o que acontece quando aumentamos o numberOfOperations (número de operações)
por um fator de 10 e o defina como 100.000: 100000 Conjunto: 10.710224 Average: 107102 100000 Get: 9.992544 Média: 99925 100000 Excluir: 9.876984 Média: 98769
O interessante é que, apesar de termos aumentado a carga de trabalho, o tempo médio que cada operação levou para ser concluída ficou significativamente menor. Vemos uma redução de quase 66% na latência das operações de conjunto e de quase 40% na latência das operações de obtenção e uma redução de 15% na latência das exclusões. Agora vamos ver o que acontece quando lançamos 1.000.000 de operações no teste. 1000000 Conjunto: 106.15172 Average: 106151 1000000 Get: 101.086393 Average: 101086 1000000 Delete: 99.747647 Média: 99747
Como podemos ver, o desempenho em 1.000.000 de operações se parece muito mais com o desempenho em 100.000 operações do que o desempenho em 100.000 operações se parece com o desempenho que vemos em 10.000 operações.
Vamos deixar de lado, por enquanto, o que de fato é a causa dessa discrepância e nos concentrar na lição mais importante aqui. Ou seja, quando estamos tentando entender o comportamento e o desempenho de um sistema, os atributos e pontos de dados que usamos ao testar o sistema são fundamentais. Devemos derivar esses valores empiricamente sempre que possível ou baseá-los em uma restrição ou suposição explicitamente declarada. Se eu estivesse realmente usando o teste acima para entender o comportamento do meu sistema baseado no Spymemcached, o simples uso do cenário de 10.000 operações não teria resultado na compreensão do desempenho máximo do sistema. Se eu tivesse executado apenas os cenários de 100.000 ou 1.000.000 de operações, teria deixado passar o fato de que o sistema parece precisar de algum tempo de aquecimento. Mas, ao explorar um pouco para ver quais são os valores interessantes para esse teste simples e ingênuo, aprendemos algumas lições importantes sobre o nosso sistema.
Falo isso porque, com muita frequência, vejo discussões sobre o desempenho e o comportamento de um sistema que usam o que parecem ser valores e suposições arbitrários. E quando vejo isso, fico me perguntando por que o autor escolheu um determinado valor. Se for um valor significativo, sua importância deve ser explicada. Se for um valor arbitrário, devemos ter cuidado com os resultados e as conclusões apresentadas. (Observe que, para fins de registro, os valores registrados acima foram obtidos usando o Spymemcached 2.5 em execução contra o memcached 1.4.4, com o cliente e o servidor em execução no mesmo host).
Alguns >br ;<.
A propósito, parece que este blog está vulnerável a cross site scripting.
<script>alert(\’!\’)</script>