Aula 7 - Hands On - Configurando nossa aplicação na AWS com EC2, Elastic Load Balancing e Auto Scaling
O documento apresenta uma introdução sobre sistemas distribuídos na nuvem AWS, incluindo como configurar o ambiente de programação e realizar testes de carga em uma aplicação implantada em uma instância EC2 usando o Apache Benchmark.
Aula 7 - Hands On - Configurando nossa aplicação na AWS com EC2, Elastic Load Balancing e Auto Scaling
1.
Introdução a SistemasDistribuídos
Hands On Configurando nossa
aplicação na AWS com EC2,
Elastic Load Balancing e
AutoScaling
Eduardo de Lucena Falcão
Amazon CloudWatch
25/05/2013 5
Configurando seuAmbiente
● Não é preciso muito, a AWS é 100% virtual:
– Um desktop ou notebook (com acesso a Internet, é claro);
– Um cartão de crédito (pra configurar uma conta AWS);
– Um telefone (para completar o processo de registro).
● Software:
– Java: para utilizar as ferramentas de linha de comando
e/ou como Linguagem de Programação da sua aplicação
(API Java p/ AWS);
– Eclipse (caso realmente for programar em Java).
6.
25/05/2013 6
Conta AWS
●
Sugirofortemente que vocês criem suas próprias contas AWS.
– Possibilita o uso do AWS Management Console;
– Amazon Free Usage Tier por um ano para todos os serviços:
● Por exemplo, é possível utilizar uma instância micro por 750h/mês.
– S3: 5 GB de armazenamento padrão, 20.000 solicitações de Get,
2.000 solicitações de Put, 15 GB de transferência de dados para
fora a cada mês;
– SQS e SimpleDB também oferecem transferências de dados e
espaço grátis no primeiro ano.
● Lembre-se de parar as instâncias quando não estiver mais usando, e
isso lhe fará economizar;
● É possível criar alarmes: Amazon CloudWatch.
7.
25/05/2013 7
Conta AWS
●Para quem não quiser criar a conta:
– Fornecerei um par de chaves para acesso ;)
8.
25/05/2013 8
Eclipse eJVM e AWS sdk
● Opção 1
● $ sudo apt-get update
● $ sudo apt-get install openjdk-6-jdk
● Extrair pasta do eclipse juno em sua
home
– http://www.eclipse.org/downloads/
● Extrair pasta do AWS JDK em sua
home
– http://sdk-for-java.amazonwebservices.com/latest/aws-java-sdk.zip
● Iniciar um projeto Java e adicionar as
bibliotecas da pasta aws-java “libs” e
“thitrd-party” ao nosso classpath
● Opção 2 (mais fácil mas falha às vezes)
● $ sudo apt-get install eclipse
1. Abra "Help" (Ajuda) -> "Install New
Software." ;
2. Digite http://aws.amazon.com/eclipse
na caixa de texto rotulada “Work with”;
3. Selecione “AWS Toolkit for Eclipse” na
lista a seguir;
4. Clique em “Next”.
1. Escolha AWS SDK for Java
5. Next ==> Next...
9.
25/05/2013 9
Primeiro Teste
●Crie um novo Projeto Java;
– Na pasta aws-java-sdk-1.4.3/samples/AwsConsoleApp
● Copie o AWSConsoleApp.java e AwsCredentials.properties
para a pasta src do seu projeto
● Adicione os seguintes jars no buildpath:
– aws-java-sdk-1.4.3/lib/aws-java-sdk-1.4.3.jar
– Todos os jars da pasta third-party
● Peça a AwsCredentials.properties ao professor e atualize;
● Execute AWSConsoleApp.java
25/05/2013 11
Gerenciador dedas Instâncias EC2
● Peça a classe chamada EC2Manager ao professor:
– Nela teremos todos os nossos métodos para
criar/parar/terminar nossa instâncias EC2.
– É uma alternativa a vocês não terem acesso ao AWS
Console Manager.
12.
25/05/2013 12
Criando nossa1ª instância EC2
● Peça seu par de chaves ao professor. (para criar a
instância acoplada à sua chave)
● Execute o método createNewInstance (uma única vez)
– Em seguida: execute getInstancePublicDns, e guarde o
DNS público que o método imprimirá na console.
● Checando se nossa instância está executando:
1.Conectar-se via ssh à mesma;
2.Checar via AWS Management Console.
13.
25/05/2013 13
Conectando àInstância EC2
1.Abra o terminal;
2.Localize sua chave privada (eduardo-falcao.pem);
3.Sua chave não pode estar publicamente visível para o
SSH funcionar:
1.$ chmod 400 eduardo-falcao.pem
4.Conecte-se a sua intância usando o DNS Público dela:
[ec2-54-235-27-45.compute-1.amazonaws.com]
5.
$ ssh -i eduardo-falcao.pem ubuntu@ec2-54-235-27-45.compute-1.amazonaws.com
25/05/2013 19
Implantando aaplicação no EC2
1.Copiar o arquivo .WAR para a instância EC2
$ scp -i eduardo-falcao.pem
/home/eduardo/workspace/Quicksort-Restful.war ubuntu@ec2-50-
16-146-100.compute-1.amazonaws.com:/home/ubuntu
2.Conectar-se à sua instância via ssh
– ssh -i eduardo-falcao.pem ubuntu@ec2-50-16-146-100.compute-
1.amazonaws.com
3.Instalar o tomcat:
$ sudo apt-get update (se ainda não tiver executado antes)
$ sudo apt-get install tomcat7
20.
25/05/2013 20
Configurando oTomcat no EC2
● Configurando as portas do Tomcat: o Tomcat7 roda na porta 8080
por padrão. Mas a porta padrão no Grupo de Segurança do EC2 é
80. Lembre-se de checar isso no Amazon EC2 Management Console.
– $ sudo vim /etc/tomcat7/server.xml
– $ sudo vim /etc/default/tomcat7
– $ sudo service tomcat7 restart
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
URIEncoding="UTF-8"
redirectPort="443" />
AUTHBIND=yes
21.
25/05/2013 21
Deploy doWAR no Tomcat
● $ cd /var/lib/tomcat7/webapps/ROOT/
● $ sudo rm -rf *
● Considerando que ainda estamos na pasta ROOT:
– $ sudo unzip -d . /home/ubuntu/Quicksort-Restful.war
● Checar se o WAR foi implantado via Web browser:
– DNS público: http://ec2-50-16-146-100.compute-1.amazonaws.com/
– Curl (POST):
● curl -X POST -d @intArray.json http://ec2-50-16-146-100.compute-
1.amazonaws.com/requests --header "Content-
Type:application/json"
22.
25/05/2013 22
Testando aaplicação
1º Teste de Carga: Sistema Convencional
Quantas requisições eu consigo atender em 5 minutos?
Hands On - 4
25/05/2013 24
Wrong Way!
●Bash Script com requisições POST.
●
Bloqueante
#!/bin/bash
START=$(date +%s)
for i in {1..5}
do
curl -X POST -d @intArray-
5000.json http://ec2-50-16-146-
100.compute-
1.amazonaws.com/requests --header
"Content-Type:application/json"
done
END=$(date +%s)
DIFF=$(( $END - $START ))
echo "It took $DIFF seconds"
●
Não Bloqueante
#!/bin/bash
START=$(date +%s)
for i in {1..5}
do
curl -X POST -d @intArray-
5000.json http://ec2-50-16-146-
100.compute-
1.amazonaws.com/requests --header
"Content-Type:application/json" &
done
END=$(date +%s)
DIFF=$(( $END - $START ))
echo "It took $DIFF seconds"
25.
25/05/2013 25
Right Way!(Apache Benchmark)
● INSTALAR EM UMA INSTÂNCIA EC2 AWS
● $ sudo apt-get install apache2-utils
● Requisição HTTP/GET de uma página HTML
– Quantidade de requisições: 100
– Nível de concorrência: 10
– URL:
http://ec2-50-16-146-100.compute-1.amazonaws.com/
● ab -n 100 -c 10
http://ec2-50-16-146-100.compute-1.amazonaws.com/
25/05/2013 28
Projetando nossoTeste
● Quicksort
● Quanto ao nível de concorrência?
● Quanto à heterogeneidade da carga?
– Nº de elementos de nosso array:
● Máximo e mínimo;
– Quantidades de requisições?
– Conteúdo das requisições?
● Pior e melhor caso do algoritmo.
● Objetivo: aproximar nosso teste da realidade!
29.
25/05/2013 29
Tipos deTeste
1.Em quanto tempo meu sistema
consegue atender N requisições?
2.Quantas requisições eu consigo
atender em N minutos?
30.
25/05/2013 30
Projetando nossoTeste
● Quicksort – qual a carga real desse sistema? o.O
● Quanto ao nível de concorrência? 100
● Quanto à heterogeneidade da carga?
– Nº de elementos de nosso array:
● Muito pouco: 10;
● Pouco: 100;
● Médio: 1000;
● Alto: 5000;
● Muito alto: 10000;
– Quanto tempo de medição? 20 minutos
– Conteúdo das requisições? (Não abordado)
● Pior e melhor caso do algoritmo.
25/05/2013 32
Exemplo simples
●Array com 10 elementos (Meu PC)
– Time taken for tests: 300.035 seconds
– Complete requests: 1447
– Failed requests: 0
– Requests per second: 4.82 [#/sec] (mean)
– Time per request: 207.350 [ms] (mean, across all concurrent requests)
● Array com 10 elementos (EC2)
– Time taken for tests: 300.034 seconds
– Complete requests: 15461
– Failed requests: 0
– Requests per second: 51.53 [#/sec] (mean)
– Time per request: 19.406 [ms] (mean, across all concurrent requests)
33.
25/05/2013 33
Análise Geraldos Resultados
● Testado a partir de meu PC
● Quando o nosso sistema convencional é submetido a
uma carga variada (de 10 a 10000 elementos por
requisição) fornecida por 50 usuários simultâneos
durante 5 minutos nós temos os seguintes resultados:
– Complete requests: 4449 (1447+1422+1263+209+108 )
– Failed requests: 5
– Requests per second: 2,964 =
(4,82+4,74+4,21+0,69+0,36)/5
– Time per request (ms):
(1447*207.350)+(1422*211.070)+(1263*237.584)+(209*144
7.802)+(108*2786.235) = 1503749.58 / 4449 = 337.997 ms
● Testado a partir de uma instância EC2
● Quando o nosso sistema convencional é
submetido a uma carga variada (de 10 a
10000 elementos por requisição) fornecida
por 50 usuários simultâneos durante 5
minutos nós temos os seguintes resultados:
– Complete requests: 58539
(15461+14758+13196+10536+4588)
– Failed requests: 0
– Requests per second: 39,018 =
(51,53+49,19+43,98+35,10+15,29)/5
– Time per request (ms):
(15461*19.406)+(14758*20.330)+(13196*22.7
38)+(10536*28.487)+(4588*65.399) =
1500306,598 / 58539 = 25.629 ms
34.
25/05/2013 34
Projetando nossoTeste
● Quicksort – qual a carga real desse sistema? o.O
● Quanto ao nível de concorrência? 100
● Quanto à heterogeneidade da carga?
– Nº de elementos de nosso array:
● Muito pouco: 10;
● Pouco: 100;
● Médio: 1000;
● Alto: 5000;
● Muito alto: 10000;
– Quanto tempo de medição? 20 minutos
– Conteúdo das requisições? (Não abordado)
● Pior e melhor caso do algoritmo.
35.
25/05/2013 35
Projetando nossoTeste
#!/bin/bash
#20 minutos array com 10 números, -n 1000000 para que nao pare em 50K requisicoes
ab -t 1200 -n 1000000 -c 20 -p intArray-10.json -T Content-Type:application/json http://ec2-50-16-146-
100.compute-1.amazonaws.com/requests > resposta-arrays-com-tamanho-10.txt &
#20 minutos array com 100 números, -n 1000000 para que nao pare em 50K requisicoes
ab -t 1200 -n 1000000 -c 20 -p intArray-100.json -T Content-Type:application/json http://ec2-50-16-146-
100.compute-1.amazonaws.com/requests > resposta-arrays-com-tamanho-100.txt &
#20 minutos array com 1000 números, -n 1000000 para que nao pare em 50K requisicoes
ab -t 1200 -n 1000000 -c 20 -p intArray-1000.json -T Content-Type:application/json http://ec2-50-16-146-
100.compute-1.amazonaws.com/requests > resposta-arrays-com-tamanho-1000.txt &
#20 minutos array com 5000 números, -n 1000000 para que nao pare em 50K requisicoes
ab -t 1200 -n 1000000 -c 20 -p intArray-5000.json -T Content-Type:application/json http://ec2-50-16-146-
100.compute-1.amazonaws.com/requests > resposta-arrays-com-tamanho-5000.txt &
#20 minutos array com 10000 números, -n 1000000 para que nao pare em 50K requisicoes
ab -t 1200 -n 1000000 -c 20 -p intArray-10000.json -T Content-Type:application/json http://ec2-50-16-146-
100.compute-1.amazonaws.com/requests > resposta-arrays-com-tamanho-10000.txt &
36.
25/05/2013 36
Análise dosResultados
● Array com 10 elementos
– Time taken for tests: 1200.056 seconds
– Complete requests: 70950
– Failed requests: 0
– Requests per second: 59.12 [#/sec] (mean)
– Time per request: 16.914 [ms] (mean, across all concurrent requests)
● Array com 100 elementos
– Time taken for tests: 1200.056 seconds
– Complete requests: 69535
– Failed requests: 0
– Requests per second: 57.94 [#/sec] (mean)
– Time per request: 17.258 [ms] (mean, across all concurrent requests)
37.
25/05/2013 37
Análise dosResultados
● Array com 1000 elementos
– Time taken for tests: 1200.037 seconds
– Complete requests: 74929
– Failed requests: 0
– Requests per second: 62.44 [#/sec] (mean)
– Time per request: 16.016 [ms] (mean, across all concurrent requests)
● Array com 5000 elementos
– Time taken for tests: 1200.157 seconds
– Complete requests: 42301
– Failed requests: 0
– Requests per second: 35.25 [#/sec] (mean)
– Time per request: 28.372 [ms] (mean, across all concurrent requests)
38.
25/05/2013 38
Análise dosResultados
● Array com 10000 elementos
– Time taken for tests: 1200.507 seconds
– Complete requests: 24050
– Failed requests: 0
– Requests per second: 20.03 [#/sec] (mean)
– Time per request: 49.923 [ms] (mean, across all concurrent requests)
39.
25/05/2013 39
Análise Geraldos Resultados
● Testado a partir de uma instância EC2
● Quando o nosso sistema convencional é submetido a uma carga
variada (de 10 a 10000 elementos por requisição) fornecida por 100
usuários simultâneos durante 20 minutos nós temos os seguintes
resultados:
– Complete requests: 281765 (70950+69535+74929+42301+24050)
– Failed requests: 0
– Requests per second: 46,956 = (59,12+57,94+62,44+35,25+20,03)/5
– Time per request (ms):
(70950*16,914)+(69535*17,258)+(74929*16,016)+(42301*28,372)+(24050*4
9,923) = 6000958,316 / 281765 = 21.297 ms
40.
25/05/2013 40
Como otimizaro nosso Sistema
via AWS?
● Utilizando instâncias EC2, com o AutoScale
para escalonar automaticamente, e o Elastic
Load Balancer para fazer um balanceamento
de carga automático entre essas instâncias.
25/05/2013 42
Criando umaImagem
● Se tudo tiver ocorrido perfeitamente até agora, já
podemos criar uma Imagem do nosso Sistema.
● Execute o método registerNewAmi (guarde a imageID)
● Execute o método createNewInstance, usando a nova
imageID como parâmetro
– Em seguida: execute getInstancePublicDns, e guarde o
DNS público que o método imprimirá na console;
– Verifique se sua instância iniciou, tentando acessar os
serviços fornecidos pela mesma.
43.
25/05/2013 43
Elastic LoadBalancing
● Exemplo: criar um ELB com 5 máquinas, sem AutoScale, e rodarei nosso benchmark.
● Passo 1: criar novas instâncias EC2 com nossa AMI previamente gerada.
●
Passo 2: criar um ELB passando como instância os Ids dessas máquinas recém-
criadas, Zonas de Disponibilidade em que o ELB atuará, e seus Listeners.
– Passo 2.1: configure um Listener.
● Listener listener = new Listener("HTTP", 80, 80);
● Parâmetros;
– Protocol: TCP, HTTP, HTTPS;
– Load balancer port – porta na qual o ELB irá receber as requisições.
– Instance port – porta na qual o ELB usará para encaminhar requisições à
outras instâncias.
– createElasticLoadBalancer("elbSimples", listener, new String[] {"i-2edf554f","i-
b62006dd","i-76df5517"}, new String [] {"us-east-1b"});
44.
25/05/2013 44
Elastic LoadBalancer
● Passo 3: configure o HealthCheck;
– Timeout: tempo limite pra receber uma resposta de um
“health check”;
– Interval: tempo entre uma checagem e outra;
– UnhealthyTreshold: número de checagens antes de declarar
uma instância como “Unhealthy”/não saudável;
– HealthyTreshold: número de checagens antes de declarar
uma instância como “Healthy”/saudável;
– Target: parte do sistema em que será checado a saúde.
25/05/2013 46
Elastic LoadBalancer
● Passo 4: requisite o DNS público de seu ELB;
– getLoadBalancerPublicDns("elbSimples")
● Passo 5: checando se nosso ELB está funcionando;
– Entre com o DNS no browser e verifique se o serviço
está sendo fornecido como esperado.
● Agora vamos projetar a nossa 2ª carga de teste!
47.
25/05/2013 47
Testando aaplicação
2º Teste de Carga: Sistema Distribuído Não Escalável
com 5 instâncias
Quantas requisições eu consigo atender em 20 minutos?
Hands On - 6
25/05/2013 49
Projetando nosso2º Teste
● Quicksort – qual a carga real desse sistema? o.O
● Quanto ao nível de concorrência? 100
● Quanto à heterogeneidade da carga?
– Nº de elementos de nosso array:
● Muito pouco: 10;
● Pouco: 100;
● Médio: 1000;
● Alto: 5000;
● Muito alto: 10000;
– Quanto tempo de medição? 20 minutos
– Conteúdo das requisições? (Não abordado)
● Pior e melhor caso do algoritmo.
50.
25/05/2013 50
Projetando nossoTeste
#!/bin/bash
#20 minutos array com 10 números, -n 1000000 para que nao pare em 50K requisicoes
ab -t 1200 -n 1000000 -c 20 -p intArray-10.json -T Content-Type:application/json http://elbsimples-286769172.us-
east-1.elb.amazonaws.com/requests > resposta-arrays-com-tamanho-10.txt &
#20 minutos array com 100 números, -n 1000000 para que nao pare em 50K requisicoes
ab -t 1200 -n 1000000 -c 20 -p intArray-100.json -T Content-Type:application/json http://elbsimples-286769172.us-
east-1.elb.amazonaws.com/requests > resposta-arrays-com-tamanho-100.txt &
#20 minutos array com 1000 números, -n 1000000 para que nao pare em 50K requisicoes
ab -t 1200 -n 1000000 -c 20 -p intArray-1000.json -T Content-Type:application/json http://elbsimples-
286769172.us-east-1.elb.amazonaws.com/requests > resposta-arrays-com-tamanho-1000.txt &
#20 minutos array com 5000 números, -n 1000000 para que nao pare em 50K requisicoes
ab -t 1200 -n 1000000 -c 20 -p intArray-5000.json -T Content-Type:application/json http://elbsimples-
286769172.us-east-1.elb.amazonaws.com/requests > resposta-arrays-com-tamanho-5000.txt &
#20 minutos array com 10000 números, -n 1000000 para que nao pare em 50K requisicoes
ab -t 1200 -n 1000000 -c 20 -p intArray-10000.json -T Content-Type:application/json http://elbsimples-
286769172.us-east-1.elb.amazonaws.com/requests > resposta-arrays-com-tamanho-10000.txt &
51.
25/05/2013 51
Análise dosResultados
● Array com 10 elementos
– Time taken for tests: 1200.045 seconds
– Complete requests: 207013
– Failed requests: 0
– Requests per second: 172.50 [#/sec] (mean)
– Time per request: 5.797 [ms] (mean, across all concurrent requests)
● Array com 100 elementos
– Time taken for tests: 1200.487 seconds
– Complete requests: 195892
– Failed requests: 0
– Requests per second: 163.18 [#/sec] (mean)
– Time per request: 6.128 [ms] (mean, across all concurrent requests)
52.
25/05/2013 52
Análise dosResultados
● Array com 1000 elementos
– Time taken for tests: 1200.271 seconds
– Complete requests: 183052
– Failed requests: 0
– Requests per second: 152.51 [#/sec] (mean)
– Time per request: 6.557 [ms] (mean, across all concurrent requests)
● Array com 5000 elementos
– Time taken for tests: 1200.148 seconds
– Complete requests: 39334
– Failed requests: 0
– Requests per second: 32.77 [#/sec] (mean)
– Time per request: 30.512 [ms] (mean, across all concurrent requests)
53.
25/05/2013 53
Análise dosResultados
● Array com 10000 elementos
– Time taken for tests: 1201.065 seconds
– Complete requests: 28502
– Failed requests: 0
– Requests per second: 23.73 [#/sec] (mean)
– Time per request: 42.140 [ms] (mean, across all concurrent requests)
54.
25/05/2013 54
Análise Geraldos Resultados
● Quando o nosso sistema distribuído com ELB e 5 instâncias EC2 é
submetido a uma carga variada (de 10 a 10000 elementos por
requisição) fornecida por 100 usuários simultâneos durante 20
minutos nós temos os seguintes resultados:
– Complete requests: 653793 (207013+195892+183052+39334+28502)
– Failed requests: 0
– Requests per second: 108,938 =
(172,5+163,18+152,51+32,77+23,73)/5
– Time per request (ms):
(207013*5.797)+(195892*6.128)+(183052*6.557)+(39334*30.512)+(285
02*42.140) = 6001985,789/653793 = 9.18 ms
55.
25/05/2013 55
Comparativo: SistemaConvencional vs
Sistema Distribuído (ELB + 5 EC2)
● Quando o nosso sistema convencional é
submetido a uma carga variada (de 10 a 10000
elementos por requisição) fornecida por 100
usuários simultâneos durante 20 minutos nós
temos os seguintes resultados:
– Complete requests: 281765
(70950+69535+74929+42301+24050)
– Failed requests: 0
– Requests per second: 46,956 =
(59,12+57,94+62,44+35,25+20,03)/5
– Time per request (ms):
(70950*16,914)+(69535*17,258)+(74929*16,016)+(
42301*28,372)+(24050*49,923) = 6000958,316 /
281765 = 21.297 ms
● Quando o nosso sistema distribuído com ELB e 5
instâncias EC2 é submetido a uma carga variada
(de 10 a 10000 elementos por requisição)
fornecida por 100 usuários simultâneos durante
20 minutos nós temos os seguintes resultados:
– Complete requests: 653793
(207013+195892+183052+39334+28502)
– Failed requests: 0
– Requests per second: 108,938 =
(172,5+163,18+152,51+32,77+23,73)/5
– Time per request (ms):
(207013*5.797)+(195892*6.128)+(183052*6.557)+(3
9334*30.512)+(28502*42.140) =
6001985,789/653793 = 9.18 ms
56.
25/05/2013 56
Comparativo: SistemaConvencional vs
Sistema Distribuído (ELB + 5 EC2)
● Quando o nosso sistema convencional é
submetido a uma carga variada (de 10 a 10000
elementos por requisição) fornecida por 100
usuários simultâneos durante 20 minutos nós
temos os seguintes resultados:
● Quando o nosso sistema distribuído com ELB
e 5 instâncias EC2 é submetido a uma carga
variada (de 10 a 10000 elementos por
requisição) fornecida por 100 usuários
simultâneos durante 20 minutos nós temos os
seguintes resultados:
57.
25/05/2013 57
Comparativo: SistemaConvencional vs
Sistema Distribuído (ELB + 5 EC2)
● Quando o nosso sistema convencional é
submetido a uma carga variada (de 10 a 10000
elementos por requisição) fornecida por 100
usuários simultâneos durante 20 minutos nós
temos os seguintes resultados:
● Quando o nosso sistema distribuído com ELB
e 5 instâncias EC2 é submetido a uma carga
variada (de 10 a 10000 elementos por
requisição) fornecida por 100 usuários
simultâneos durante 20 minutos nós temos os
seguintes resultados:
58.
25/05/2013 58
Tipos deTeste
1.Em quanto tempo meu sistema
consegue atender N requisições?
2.Quantas requisições eu consigo atender
em N minutos?
59.
25/05/2013 59
Testando aaplicação
3º Teste de Carga: Sistema Convencional vs Sistema
Distribuído com ELB e 5 instâncias EC2
Em quanto tempo meu sistema consegue atender 5000000
requisições?
Hands On - 7
25/05/2013 61
Projetando nosso3º Teste
● Quicksort – qual a carga real desse sistema? o.O
● Quanto ao nível de concorrência? 100
● Quanto à heterogeneidade da carga?
– Nº de elementos de nosso array:
● Muito pouco: 10;
● Pouco: 100;
● Médio: 1000;
● Alto: 5000;
● Muito alto: 10000;
– Quantidade de requisições? 1000000
– Conteúdo das requisições? (Não abordado)
● Pior e melhor caso do algoritmo.
62.
25/05/2013 62
Testando oSist. Convencional
#!/bin/bash
#100000 requisicoes com array com 10 números
ab -n 100000 -c 20 -p intArray-10.json -T Content-Type:application/json http://ec2-50-16-146-100.compute-
1.amazonaws.com/requests > resposta-arrays-com-tamanho-10.txt &
#100000 requisicoes com array com 100 números
ab -n 100000 -c 20 -p intArray-100.json -T Content-Type:application/json http://ec2-50-16-146-100.compute-
1.amazonaws.com/requests > resposta-arrays-com-tamanho-100.txt &
#100000 requisicoes com array com 1000 números
ab -n 100000 -c 20 -p intArray-1000.json -T Content-Type:application/json http://ec2-50-16-146-100.compute-
1.amazonaws.com/requests > resposta-arrays-com-tamanho-1000.txt &
#100000 requisicoes com array com 5000 números
ab -n 100000 -c 20 -p intArray-5000.json -T Content-Type:application/json http://ec2-50-16-146-100.compute-
1.amazonaws.com/requests > resposta-arrays-com-tamanho-5000.txt &
#100000 requisicoes com array com 10000 números
ab -n 100000 -c 20 -p intArray-10000.json -T Content-Type:application/json http://ec2-50-16-146-100.compute-
1.amazonaws.com/requests > resposta-arrays-com-tamanho-10000.txt &
63.
25/05/2013 63
Testando oSist. Distribuído (ELB
+ 5 EC2)
#!/bin/bash
#100000 requisicoes com array com 10 números
ab -k -n 100000 -c 20 -p intArray-10.json -T Content-Type:application/json http://elbsimples-
286769172.us-east-1.elb.amazonaws.com/requests > resposta-arrays-com-tamanho-10.txt &
#100000 requisicoes com array com 100 números
ab -k -n 100000 -c 20 -p intArray-100.json -T Content-Type:application/json http://elbsimples-
286769172.us-east-1.elb.amazonaws.com/requests > resposta-arrays-com-tamanho-100.txt &
#100000 requisicoes com array com 1000 números
ab -k -n 100000 -c 20 -p intArray-1000.json -T Content-Type:application/json http://elbsimples-
286769172.us-east-1.elb.amazonaws.com/requests > resposta-arrays-com-tamanho-1000.txt &
#100000 requisicoes com array com 5000 números
ab -k -n 100000 -c 20 -p intArray-5000.json -T Content-Type:application/json http://elbsimples-
286769172.us-east-1.elb.amazonaws.com/requests > resposta-arrays-com-tamanho-5000.txt &
#100000 requisicoes com array com 10000 números
ab -k -n 100000 -c 20 -p intArray-10000.json -T Content-Type:application/json http://elbsimples-
286769172.us-east-1.elb.amazonaws.com/requests > resposta-arrays-com-tamanho-10000.txt &
64.
25/05/2013 64
Análise Geraldos Resultados
(ELB + 5 EC2) vs Sist. Convenc.
● Quando o nosso sistema convencional é
submetido a uma carga variada (de 10 a
10000 elementos por requisição)
fornecida por 100 usuários simultâneos
com 500000 requisições nós temos os
seguintes resultados:
– Complete requests: 499999
– Time taken for tests: 3784.8s =
63.08min
(1607.9+1551.9+1582.9+2457.5+3784.8)
– Failed requests: 1 (0+0+1+0+0)
– Requests per second: 51.38 =
(62.19+64.43+63.17+40.69+26.42)/5
– Time per request (ms): 21,964 ms
(16.07+15.52+15.82+24.57+37.84)/5=
109.82/5
● Quando o nosso sistema distribuído com
ELB e 5 instâncias EC2 é submetido a uma
carga variada (de 10 a 10000 elementos por
requisição) fornecida por 100 usuários
simultâneos com 500000 requisições nós
temos os seguintes resultados:
– Complete requests: 499996
– Time taken for tests: 1468.2s = 24.47min
(1466.3+1465.7+1461+1460+1468.2)
– Failed requests: 4 (0+2+1+1+0)
– Requests per second: 59.956 =
(68.20+68.22+68.45+68.49+26.42)/5
– Time per request (ms): 19,272 ms
(14.66+14.65+14.61+14.6+37.84)/5= 96.36/5
65.
25/05/2013 65
Comparativo: SistemaConvencional vs
Sistema Distribuído (ELB + 5 EC2)
● Quando o nosso sistema convencional é
submetido a uma carga variada (de 10 a 10000
elementos por requisição) fornecida por 100
usuários simultâneos com 500000 requisições
nós temos os seguintes resultados:
● Quando o nosso sistema distribuído com ELB
e 5 instâncias EC2 é submetido a uma carga
variada (de 10 a 10000 elementos por
requisição) fornecida por 100 usuários
simultâneos com 500000 requisições nós temos
os seguintes resultados:
66.
25/05/2013 66
Comparativo: SistemaConvencional vs
Sistema Distribuído (ELB + 5 EC2)
● Quando o nosso sistema convencional é
submetido a uma carga variada (de 10 a 10000
elementos por requisição) fornecida por 100
usuários simultâneos com 500000 requisições
nós temos os seguintes resultados:
● Quando o nosso sistema distribuído com ELB
e 5 instâncias EC2 é submetido a uma carga
variada (de 10 a 10000 elementos por
requisição) fornecida por 100 usuários
simultâneos com 500000 requisições nós temos
os seguintes resultados:
67.
25/05/2013 67
Análise Geraldos Resultados Parciais -
(ELB + 5 EC2) vs Sist. Convenc.
● Analisando o teste de quantas requisições os dois
sistemas conseguem atender em 20 minutos (slides 53,
54, 55):
– Conseguimos um speedup de 2,32 na quantidade de
requisições atendidas: de 281765 para 653793;
– Aumentamos a capacidade de atender requisições por segundo
de 46,956 para 108,938 (aumento de 61,982 req/s);
– Conseguimos diminuir 12,117 ms no tempo de processamento
de uma requisição de 21.297 ms para 9.18 ms.
● Resumindo: tornamos o nosso sistema 2,32 x mais rápido.
68.
25/05/2013 68
Análise Geraldos Resultados Parciais -
(ELB + 5 EC2) vs Sist. Convenc.
● Analisando o teste de em quanto tempo os dois sistemas
conseguem atender em 500000 requisições (slides 62,
63 e 64):
– Conseguimos um speedup de 2,57 no tempo de
processamento das requisições: de 63,08 minutos para 24,47
minutos
● Resumindo: tornamos o nosso sistema 2,57 x mais rápido.
69.
25/05/2013 69
Análise Geraldos Resultados Parciais -
(ELB + 5 EC2) vs Sist. Convenc.
● Agora analisemos os gráficos de uso da CPU (20 minutos):
– Ao passo em que uma instância não é suficiente para tal
processamento, é possível também constatar que 5 instância só
seria interessante no início, e talvez três instâncias fossem o
ideal para o processamento durante o restante do processo.
70.
25/05/2013 70
Análise Geraldos Resultados Parciais -
(ELB + 5 EC2) vs Sist. Convenc.
● Agora analisemos os gráficos de uso da CPU (500000 requisições):
– No início, talvez o ideal realmente seja 5 ou 6 instâncias, mas
com o tempo o ideal é que elas diminuíssem para 1 ou 2
instâncias.
71.
25/05/2013 71
Análise Geraldos Resultados
(ELB + 5 EC2) vs Sist. Convenc.
● Quais as vantagens de se ter incorporado o ELB e 5 novas instâncias ao
nosso sistema?
– Mais poder de processamento; Balanceamento de Carga com fácil
implantação; Capacidade de detectar instâncias disfuncionais e desviar
tráfego para instâncias saudáveis, consegue se recuperar
automaticamente de falhas (ainda que aconteçam), ...
● O ELB supriu todas as nossas expectativas?
– Desvantagens: o balanceamento não é ideal para cargas heterogêneas,
não previne o acontecimento de falhas, falta de auto-escalonamento
(proporcionando melhores resultados e melhor controle financeiro); ...
25/05/2013 73
Configurando onosso Sistema
com ELB e Auto Scaling
● Passo 1: crie uma nova instância e com a mesma crie
um novo ELB para o Auto Scaling
Listener listener = new Listener("HTTP", 80, 80);
createElasticLoadBalancer("elbSimples-for-auto-scaling", listener, new String[] {"i-ee9c3b86"},
new String [] {"us-east-1b"});
HealthCheck healthCheck = new HealthCheck();
healthCheck.setInterval(10); //intervalo de Checagem
healthCheck.setHealthyThreshold(2); //qtdade de checagens para declarar uma
healthCheck.setUnhealthyThreshold(2); //instancia como healthy ou unhealthy
healthCheck.setTarget("HTTP:80/requests");//a checagem será feita na url requests
healthCheck.setTimeout(5); //tempo limite pra responder um checkout
configureHealthCheck("elbSimples-for-auto-scaling", healthCheck);
P.s.:Pode remover a instância depois do ELB criado.
74.
25/05/2013 74
Configurando onosso Sistema
com ELB e Auto Scaling
● Passo 2: na classe AutoScalingManager, crie o seu
serviço Auto Scaling
– Passo 2.1: crie seu LaunchConfiguration
CreateLaunchConfigurationRequest launchConfiguration = new CreateLaunchConfigurationRequest();
launchConfiguration.setLaunchConfigurationName("launch-configuration-eduardo-falcao");
launchConfiguration.setImageId("ami-7350391a"); //trocar por sua img pre-configurada
launchConfiguration.setInstanceType("t1.micro");
launchConfiguration.setKeyName("eduardo-falcao"); //trocar por sua chave
ArrayList<String> securityGroupList = new ArrayList <String>();
securityGroupList.add("ISD-Estacio"); //trocar pelo seu SecurityGroup
launchConfiguration.setSecurityGroups(securityGroupList);
autoScaling.createLaunchConfiguration(launchConfiguration);
75.
25/05/2013 75
Configurando onosso Sistema
com ELB e Auto Scaling
● Passo 2: na classe AutoScalingManager, crie o seu
serviço Auto Scaling
– Passo 2.2: crie seu AutoScalingGroup
CreateAutoScalingGroupRequest autoScalingGroup = new CreateAutoScalingGroupRequest();
autoScalingGroup.setLaunchConfigurationName("launch-configuration-eduardo-falcao");
ArrayList<String> loadBalancersList = new ArrayList <String>();
loadBalancersList.add("elbSimples-for-auto-scaling"); //trocar pelo elb que vc criou pro AutoScaling
autoScalingGroup.setLoadBalancerNames(loadBalancersList);
autoScalingGroup.setAutoScalingGroupName("auto-scaling-group-eduardo-falcao");
ArrayList<String> avaiLabilityZonesList = new ArrayList <String>();
avaiLabilityZonesList.add("us-east-1a");
avaiLabilityZonesList.add("us-east-1b");
autoScalingGroup.setAvailabilityZones(avaiLabilityZonesList);
autoScalingGroup.setMaxSize(10);
autoScalingGroup.setMinSize(1);
autoScaling.createAutoScalingGroup(autoScalingGroup);
76.
25/05/2013 76
Configurando onosso Sistema
com ELB e Auto Scaling
● Nosso Auto Scaling já está criado! Por enquanto não
definimos nenhuma política de escalonamento.
● Mas já temos a disponibilidade garantida!
● O ELB tenta equilibrar o nº de máquinas em cada
Zona de Disponibilidade.
...
autoScalingGroup.setMaxSize(10);
autoScalingGroup.setMinSize(1); //o ideal seria 2 para serviços mais importantes
autoScaling.createAutoScalingGroup(autoScalingGroup);
77.
25/05/2013 77
Escalonando nossoSistema sob
Demanda
1.Eventos (proc. de CPU, I/O da rede, ...)
2.Monitoramento (CloudWatch)
3.Triggers
1.Horário (meu escalonamento acontecerá toda noite)
2.Manual (meu escalonamento mínimo é 5)
3.Métricas (quando alcançar 60% de processamento)
4.Políticas de Escalonamento
1.Adicionar/Remover capacidade (adicionar 1 instância EC2)
2.Capacidade exata (10 instâncias EC2)
3.Percentual (50% de minha capacidade atual)
78.
25/05/2013 78
Criando nossa1ª Política de
Escalonamento – Scale Out
● Quando essa política for acionada: o auto scaling irá
aumentar em 1 instância pra atender aquela demanda. E
novas políticas só poderão se ativadas depois de 1
minuto.
PutScalingPolicyRequest scalingOutPolicy = new PutScalingPolicyRequest();
scalingOutPolicy.setAutoScalingGroupName("auto-scaling-group-eduardo-falcao");
scalingOutPolicy.setPolicyName("Scale_Out");
scalingOutPolicy.setAdjustmentType("ChangeInCapacity");
scalingOutPolicy.setScalingAdjustment(1);
scalingOutPolicy.setCooldown(60); //se escalonou, espera esse tempo antes de checar novas políticas
PutScalingPolicyResult scalingOutPolicyResult = autoScaling.putScalingPolicy(scalingOutPolicy);
79.
25/05/2013 79
Criando nosso1º Trigger
My High CPU Alarm
● Esse é o Trigger utilizado para ativar a a política de
escalonamento Scale Out.
PutMetricAlarmRequest myHighCPUAlarm = new PutMetricAlarmRequest();
myHighCPUAlarm.setAlarmName("myHighCPUAlarm");
myHighCPUAlarm.setMetricName("CPUUtilization");
List<Dimension> dimensions = new ArrayList<Dimension>();
Dimension dimension = new Dimension();
dimension.setName("AutoScalingGroupName");
dimension.setValue("auto-scaling-group-eduardo-falcao"); //mudar para seu nome
myHighCPUAlarm.setDimensions(dimensions);
...
80.
25/05/2013 80
Criando nosso1º Trigger
My High CPU Alarm
● Esse é o Trigger utilizado para ativar a a política de
escalonamento Scale Out.
...
myHighCPUAlarm.setNamespace("AWS/EC2");
myHighCPUAlarm.setComparisonOperator(ComparisonOperator.GreaterThanThreshold);
myHighCPUAlarm.setStatistic(Statistic.Average);
myHighCPUAlarm.setUnit(StandardUnit.Percent);
myHighCPUAlarm.setThreshold(60d);
myHighCPUAlarm.setPeriod(60);
myHighCPUAlarm.setEvaluationPeriods(1);
List<String> actions = new ArrayList<String>();
//Identifica que a ação a ser feita é a Política Scaling Out
actions.add(scalingOutPolicyResult.getPolicyARN());
myHighCPUAlarm.setAlarmActions(actions);
cloudWatch.putMetricAlarm(myHighCPUAlarm);
81.
25/05/2013 81
Criando nossa2ª Política de
Escalonamento – Scale In
● Quando essa política for acionada: o auto scaling irá
aumentar em 1 instância pra atender aquela demanda. E
novas políticas só poderão se ativadas depois de 1
minuto.
PutScalingPolicyRequest scalingInPolicy = new PutScalingPolicyRequest();
scalingInPolicy.setAutoScalingGroupName("auto-scaling-group-eduardo-falcao");
scalingInPolicy.setPolicyName("Scale_In");
scalingInPolicy.setAdjustmentType("ChangeInCapacity");
scalingInPolicy.setScalingAdjustment(-1);
scalingInPolicy.setCooldown(60); //se escalonou, espera esse tempo antes de checar novas políticas
PutScalingPolicyResult scalingInPolicyResult = autoScaling.putScalingPolicy(scalingInPolicy);
82.
25/05/2013 82
Criando nosso2º Trigger
My Down CPU Alarm
● Esse é o Trigger utilizado para ativar a a política de
escalonamento Scale In.
PutMetricAlarmRequest myDownCPUAlarm = new PutMetricAlarmRequest();
myDownCPUAlarm.setAlarmName("myDownCPUAlarm");
myDownCPUAlarm.setMetricName("CPUUtilization");
// List<Dimension> dimensions = new ArrayList<Dimension>();
// Dimension dimension = new Dimension();
// dimension.setName("AutoScalingGroupName");
// dimension.setValue("auto-scaling-group-eduardo-falcao");
myDownCPUAlarm.setDimensions(dimensions);
...
83.
25/05/2013 83
Criando nosso2º Trigger
My Down CPU Alarm
● Esse é o Trigger utilizado para ativar a política de
escalonamento Scale In.
...
myDownCPUAlarm.setNamespace("AWS/EC2");
myDownCPUAlarm.setComparisonOperator(ComparisonOperator.LessThanThreshold);
myDownCPUAlarm.setStatistic(Statistic.Average); //média da utilização do CPU naquele tempo
myDownCPUAlarm.setUnit(StandardUnit.Percent);
myDownCPUAlarm.setThreshold(30d);
myDownCPUAlarm.setPeriod(60); //tempo em segundos para verificar o alarme
//quantas vezes consecutivas o alarme precisa ser ativado para executar a ação
myDownCPUAlarm.setEvaluationPeriods(2);
List<String> actions2 = new ArrayList<String>();
//Identifica que a ação a ser feita é a Política Scaling In
actions2.add(scalingInPolicyResult.getPolicyARN());
myDownCPUAlarm.setAlarmActions(actions2);
cloudWatch.putMetricAlarm(myDownCPUAlarm);
84.
25/05/2013 84
Testando oSist. Distribuído
(Auto Scaling)
#!/bin/bash
#100000 requisicoes com array com 10 números
ab -k -n 100000 -c 20 -p intArray-10.json -T Content-Type:application/json http://elbsimples-for-auto-scaling-
1556089577.us-east-1.elb.amazonaws.com/requests > resposta-arrays-com-tamanho-10.txt &
#100000 requisicoes com array com 10 números
ab -k -n 100000 -c 20 -p intArray-100.json -T Content-Type:application/json http://elbsimples-for-auto-scaling-
1556089577.us-east-1.elb.amazonaws.com/requests > resposta-arrays-com-tamanho-100.txt &
#100000 requisicoes com array com 10 números
ab -k -n 100000 -c 20 -p intArray-1000.json -T Content-Type:application/json http://elbsimples-for-auto-scaling-
1556089577.us-east-1.elb.amazonaws.com/requests > resposta-arrays-com-tamanho-1000.txt &
#100000 requisicoes com array com 10 números
ab -k -n 100000 -c 20 -p intArray-5000.json -T Content-Type:application/json http://elbsimples-for-auto-scaling-
1556089577.us-east-1.elb.amazonaws.com/requests > resposta-arrays-com-tamanho-5000.txt &
#100000 requisicoes com array com 10 números
ab -k -n 100000 -c 20 -p intArray-10000.json -T Content-Type:application/json http://elbsimples-for-auto-scaling-
1556089577.us-east-1.elb.amazonaws.com/requests > resposta-arrays-com-tamanho-10000.txt &
85.
25/05/2013 85
Análise Geraldos Resultados
(ELB + 5 EC2) vs Sist. Convenc.
Quando o nosso sistema convencional
é submetido a uma carga variada (de
10 a 10000 elementos por requisição)
fornecida por 100 usuários
simultâneos com 500000 requisições
nós temos os seguintes resultados:
● Complete requests: 499999
● Time taken for tests: 3784.8s =
63.08min
(1607.9+1551.9+1582.9+2457.5+3784.
8)
● Failed requests: 1 (0+0+1+0+0)
● Requests per second: 51.38 =
(62.19+64.43+63.17+40.69+26.42)/5
● Time per request (ms): 21,964 ms
(16.07+15.52+15.82+24.57+37.84)/5=
109.82/5
Quando o nosso sistema distribuído
com ELB e 5 instâncias EC2 é
submetido a uma carga variada (de
10 a 10000 elementos por requisição)
fornecida por 100 usuários
simultâneos com 500000 requisições
nós temos os seguintes resultados:
● Complete requests: 499996
● Time taken for tests: 1468.2s =
24.47min
(1466.3+1465.7+1461+1460+1468.2)
● Failed requests: 4 (0+2+1+1+0)
● Requests per second: 59.956 =
(68.20+68.22+68.45+68.49+26.42)/5
● Time per request (ms): 19,272 ms
(14.66+14.65+14.61+14.6+37.84)/5=
96.36/5
Quando o nosso Sistema com
ELB e Auto Scaling é
submetido a uma carga
variada (de 10 a 10000
elementos por requisição)
fornecida por 100 usuários
simultâneos com 500000
requisições nós temos os
seguintes resultados:
● Complete requests: 49998
● Time taken for tests:
1605.923s = 26,76min
1605.923 = (1090,164;
1091.459; 1592.250;
1577.380; 1605.923)
● Failed requests: 2
● Requests per second: 74,36
=
(91,73+91,62+62,80+63,40+6
2,27)/5
● Time per request (ms):
25/05/2013 87
Analisando oGráfico do Sistema
com ELB e Auto Scaling
● Para esse teste específico é possível perceber que:
– precisamos tomar mais cuidado quando formos criar
mais instâncias;
● Ex.: é evidente que não há necessidade alguma de
criar as 3 últimas instâncias.
– Precisamos de uma política de terminação de
instâncias mais refinada.
● Percebemos que as instâncias cinza e verde
poderiam ter sido terminadas antes de atingir o
nível de processamento 0.
88.
25/05/2013 88
Breves Conclusõese Comparações
● Se por algum momento o Sistema com ELB e 5 EC2 lhe parecer ser
melhor (caso você compare apenas o tempo total do processamento de
todas as requisições), observe os seguintes pontos:
– A capacidade de processar requisições/segundo aumentou em 15
unidades;
– E o tempo por requisição diminuiu 6 ms. Essa diferença pode causar
grande impacto se o sistema recebe milhares de requisições/segundo;
– A configuração do nosso Auto Scaling não está refinada;
– Testes em curto período de tempo não são bons parâmetros;
– Em longos períodos de tempo há uma grande possibilidade dessa
infra (5 EC2) ser sub-utilizada ou insuficiente para nossa demanda. E
isso implica em muito dinheiro desperdiçado/perdido.
89.
25/05/2013 89
Conclusões
● Quandofor aplicar definitivamente o Auto Scaling em seu
sistema, teste-o exaustivamente antes. Podem ser necessários
alguns ajustes nos Triggers e Scaling Policies.
● Ao testar:
– procure executar pela maior quantidade de tempo possível.
Algumas horas podem ser suficientes.
– Varie quantidade de requisições, Carga/Tamanho das
requisições, e número de requisições concorrentes,
procurando sempre se aproximar de um caso de teste real.
Sempre que possível, testar os piores casos possíveis.
25/05/2013 91
Comandos Auxiliares
●Parar o Tomcat7: (quando for testar pelo Eclipse)
– $ sudo /etc/init.d/tomcat7 stop
● Instalar o unzip (necessário p/ o deploy do WAR):
– $ sudo unzip -d . /home/ubuntu/Quicksort-Restful.war