47
Um Guia para Testes de Escalabilidade de Serviços Web Diego de Araújo Martinez Camarinha Orientador: Prof. Dr. Fabio Kon Coorientador: Prof. Dr. Paulo Meirelles Coorientador: Paulo Bittencourt Moura (Doutorando) 02 de dezembro de 2013 1

Um Guia para Testes de Escalabilidade de Serviços Webbcc.ime.usp.br/tccs/2013/diego/images/monografia.pdf · Um Guia para Testes de Escalabilidade de Serviços Web Diego de Araújo

Embed Size (px)

Citation preview

Um Guia para Testes de

Escalabilidade de Serviços Web

Diego de Araújo Martinez Camarinha

Orientador: Prof. Dr. Fabio Kon

Coorientador: Prof. Dr. Paulo Meirelles

Coorientador: Paulo Bittencourt Moura (Doutorando)

02 de dezembro de 2013

1

PARTE OBJETIVA

2

1. Introdução

Estamos na era do big data . Por exemplo, 100 horas de vídeo são enviadas para o 1

YouTube por minuto, acumulando mais de 16 anos de vídeo por dia e mais de 6 bilhões de

vídeos são assistidos por mês, praticamente 1 hora para cada pessoa no planeta ; em 2010, 2

em horários de pico do Facebook, por segundo, 13 milhões de consultas eram feitas no

banco de dados, 450 milhões de linhas eram lidas e 3,5 milhões eram modificadas e 38

gigabytes eram transmitidos ; por dia, são feitas 2,1 bilhões de consultas no banco de dados 3

do Twitter e 58 milhões de tweets são feitos, sendo que 43% deles são enviados pelo celular

. Com essa quantidade de dados que é gerada na internet, uma abordagem centralizada no 4

tratamento de requisições tornou­se inviável, pois ela apresenta problemas de escalabilidade

e baixa tolerância a falhas [1]. Por essa razão, a computação em nuvem está se tornando

cada vez mais popular.

Nessa abordagem, computadores interligados através de uma rede compartilham

mémoria e armazenamento para realizar computações mais eficientes. É importante

ressaltar que a computação também pode ser feita em máquinas virtuais, que podem ser

criadas e destruídas conforme a necessidade de processamento. Nesse cenário, de um

lado há uma série de vantagens providas por uma estrutura de computação em nuvem; do

outro, existe a necessidade de uma sofisticada arquitetura para a troca de mensagens entre

os computadores (o que ajuda os sistemas a serem mais flexíveis e, portanto, ajuda a

melhorar a sua escalabilidade) e, além disso, devido à grande quantidade de plataformas em

que clientes podem ser desenvolvidos, esses computadores precisam ser capazes de lidar

com tal heterogeneidade [2].

Uma das soluções que foram propostas é SOA (Service­oriented architecture). SOA

consiste em um modelo arquitetural [3], que visa promover a interoperabilidade (capacidade

de ser desenvolvido utilizando­se múltiplas tecnologias) entre sistemas de software

heterogêneos, diminuindo, assim, o custo e a complexidade decorrentes de sua integração.

É uma abordagem que ajuda os sistemas a se manterem escaláveis e flexíveis enquanto

crescem, que tem como base três elementos [2]:

Serviços web, que, por um lado representam funcionalidades que podem ser parte

1 http://www.mckinsey.com/insights/business_technology/big_data_the_next_frontier_for_innovation2 http://www.youtube.com/yt/press/statistics.html3

http://highscalability.com/blog/2010/11/4/facebook­at­13­million­queries­per­second­recommends­minimiz.html4 http://www.statisticbrain.com/twitter­statistics/

3

de um ou mais processos e, por outro, podem ser implementados por qualquer

tecnologia em qualquer plataforma;

Uma infraestrutura específica, que permite combinar esses serviços de forma

flexível e fácil e,

Políticas e processos, que lidam com o fato de que sistemas distribuídos de larga

escala são heterogêneos, precisam de constante manutenção e possuem diferentes

donos.

Antes, para que um serviço soubesse tratar requisições de diversos clientes

desenvolvidos em plataformas diferentes, precisávamos que ele conseguisse entender e

responder cada tipo de requisição. Isso o tornava complexo, pois precisava de um

tratamento diferente para cada tipo de conexão, inviabilizando sua evolução [2].

Com SOA, é criado um canal único de comunicação, no qual para um cliente

conseguir enviar mensagens a um servidor (ou até mesmo um servidor mandar mensagens

a outro), basta que se conecte ao canal, fornecendo alta interoperabilidade. Dessa forma,

serviços podem receber e enviar mensagens de clientes desenvolvidos em qualquer

plataforma e conectar diferentes sistemas facilmente.

Porém, quando muitos sistemas são conectados uns aos outros, é difícl entender

suas dependências e o seu fluxo de mensagens e, por causa disso, modificar o

funcionamento de um sistema pode causar problemas no funcionamento dos outros.

Quando falta estrutura para lidar com a interoperabilidade, escalar tamanha conectividade

entre os sistemas é uma tarefa custosa, que normalmente adiciona muita complexidade ao

sistema como um todo, prejudicando substancialmente sua manutenibilidade [2]. Portanto,

para que sistemas de larga escala sejam escaláveis, mais que uma infraestrutura de

serviços web interoperável é necessária: é preciso que toda arquitetura, ou seja, todos os

tópicos citados acima, sejam considerados.

Com este trabalho, buscamos entender como serviços web trabalham e, a partir

disso, realizar testes que possam identificar possíveis limitantes, tanto no funcionamento

dos serviços quanto na troca de mensagens que pode existir entre eles, deixando­nos,

assim, em condições de recomendar mudanças arquiteturais que ajudem a promover a

escalabilidade do sistema.

4

2. Motivação

Desde outubro de 2011, contribuo com o Mezuro, um projeto do CCSL (Centro de

Competência em Software Livre) do IME­USP. O Mezuro [4] é uma plataforma para

monitoramento de código fonte que utiliza o Kalibro como ferramenta auxiliar. Esse último é

um serviços web que coleta e analisa métricas de código, utilizando configurações

existentes ou personalizadas, fornecendo, também, uma interpretação padrão para os

resultados obtidos [5].

Com a perspectiva do Mezuro logo entrar em produção e assumindo que existirão

situações em que muitos usuários farão requisições ao Kalibro simultaneamente, tornou­se

necessário um estudo para verificar se, em situações como essa, o tempo de resposta

dessa composição permaneceria inalterado, ou seja, surgiu a necessidade de se criar

testes de escalabilidade para o Kalibro a fim de detectar seus possíveis limitantes e ter um

indicativo para sabermos o quão escalável ele é.

Por não haver consenso sobre quais métricas são relevantes nem sobre o que o

resultado das medições significam, é pertinente investigar uma forma melhor de executar

testes de escalabilidade e interpretar tais resultados.

Nesse contexto, outra motivação é descobrir se existem ferramentas que dão

suporte a testes automatizados de escalabilidade e que também possam auxiliar na

interpretação das informações, de forma que possamos afirmar com maior segurança se

um serviço é escalável, bem como estarmos aptos a propor mudanças estruturais e/ou no

fluxo de processamento das requisições, visando melhorar o desempenho do sistema.

3. Objetivos

No final do estudo feito neste trabalho, pretendemos conseguir definir um guia de

testes de escalabilidade para serviços web em geral, definindo as métricas mais relevantes

que podem ser utilizadas para a avaliação de sua escalabilidade e sugerindo interpretações

e conclusões que podem ser tomadas a partir dos resultados obtidos.

Além disso, o principal objetivo é avaliar se o Kalibro é escalável, sendo capaz de

recomendar e, possivelmente, realizar mudanças em seu código (e/ou arquitetura) de forma

que outra avaliação possa ser feita para verificar se tais mudanças realmente acarretaram

em melhora na escalabilidade do serviço.

5

4. Conceitos e Tecnologias

Nesta seção, vamos descrever alguns conceitos básicos que utilizaremos no

decorrer desta monografia.

4.1 Serviços Web

Serviços web são componentes de software distribuídos que visam a promover a

comunicação interoperável entre os mais diferentes sistemas. Aplicações distribuídas

podem ser desenvolvidas pela composição de serviços web [1]. Do ponto de vista do

usuário final, serviços compostos são visíveis da mesma forma que serviços atômicos e

podem ser integrados em novas composições. A literatura apresenta duas abordagens

principais para a composição de serviços web: orquestrações e coreografias.

Em uma orquestração, um nó central (orquestrador) coordena o fluxo de informação

entre os demais serviços. Apesar da implementação e do gerenciamento dessa abordagem

serem mais simples, sua natureza centralizada é propensa a problemas de escalabilidade e

tolerância a falhas [1]. Como alternativa, coreografias de serviços foram propostas como

uma solução descentralizada e escalável para a composição de serviços [6]. Cada

participante de uma coreografia desempenha um papel que determina seu comportamento

na composição. A interação entre os serviços de uma coreografia dá­se de maneira

colaborativa e a coordenação é descentralizada. Como resultado, coreografias são boas

arquiteturas para fluxos de negócio totalmente descentralizados [7].

Por fim, somando­se a tudo isso, existem quatro padrões que compõem a base de

serviços web (http://www.w3schools.com):

Extensible Markup Language (XML): é uma linguagem desenvolvida para

transportar e armazenar dados;

Web Services Description Language (WSDL): é um documento XML usado para

descrever e localizar serviços web contendo, também, informações sobre as

operações que podem ser realizadas e as entradas e saídas esperadas. É através

de um WSDL que um cliente faz requisições e recebe as respostas de um serviço

web.

XML Schema Definition (XSD): seu propósito é definir os blocos de construção

válidos de um documento XML: os elementos e atributos que serão aceitos no

6

documento, bem como seus tipos de dados, podendo também definir valores

padrões ou fixos e quais elementos são elementos filhos, incluindo sua ordem e

quantidade.

Simple Object Access Protocol (SOAP): é um protocolo de comunicação entre

aplicações baseado em XML que define um formato para a estrutura das mensagens

trocadas entre cliente e servidor.

Dessa forma, para que qualquer cliente possa acessar um serviço e pedir

informações ou o processamento de requisições, basta que ele conheça o endereço WSDL

do servidor, que seja capaz de encapsular as mensagens enviadas utilizando o SOAP e que

saiba entender as mensagens que serão recebidas.

4.2 Testes de escalabilidade de serviços web

A crescente utilização de serviços web para o desenvolvimento de aplicações

distribuídas aliada com o uso cada vez maior da internet para a realização de tarefas diárias

como, por exemplo, a compra de itens em alguma loja virtual, impõe a necessidade de que o

serviço se comporte de maneira estável e que saiba lidar com grandes quantidades de

requisições feitas por clientes, mantendo o tempo de resposta baixo. Por isso, muito se

discute sobre a importância de se conseguir calcular e determinar se um serviço ou uma

composição de serviços web é escalável, detectar os limitantes da aplicação e melhorar sua

arquitetura e implementação.

Atualmente, testes automatizados são essenciais para o desenvolvimento de

qualquer sistema computacional: eles detectam rapidamente defeitos, ajudam no controle

de qualidade do código e fornecem uma documentação simples das funcionalidades do

sistema [8]. Porém, apesar de existirem muitas ferramentas que auxiliam a criação de

testes de unidade, integração e aceitação, ainda não existem ferramentas que tornem fácil a

escrita testes automatizados de escalabilidade de um sistema, nem um consenso sobre

quais métricas são relevantes para serem coletadas e analisadas. Por essa razão e pela

importância do sistema ser escalável, muitas pessoas simplesmente testam a

escalabilidade de seus sistemas manualmente, às vezes incluindo alguns scripts pessoais

que automatizam parte do processo [9].

Embora escalabilidade esteja sendo amplamente estudada, muitos pesquisadores

ainda usam definições vagas que definem escalabilidade simplesmente como a relação

7

entre o número de requisições recebidas em um intervalo de tempo e seu desempenho [10].

Além disso, outro problema é que essas definições limitam escalabilidade a uma relação

linear entre estes dois parâmetros. Segundo Duboc [11], escalabilidade é a habilidade de um

sistema satisfazer objetivos de qualidade em níveis que são aceitáveis por seus investidores

quando as características do seu domínio de aplicação e design variam em intervalos

operacionais. Outra definição é que uma aplicação é escalável se atinge o mesmo

desempenho quando a capacidade da infraestrutura aumenta na mesma proporção que o

tamanho do problema [12] e, para Law [13], uma aplicação é escalável se melhorias na

capacidade de execução necessitam de melhorias diretamente proporcionais na capacidade

arquitetural. É importante ressaltar que quando consideramos escalabilidade em sistemas

de computador, não apenas o software deve ser levado em consideração, mas também a

infraestrutura onde ele está rodando [14].

Apesar de dar boa intuição sobre o conceito de escalabilidade, essas definições não

a quantificam precisamente: uma maneira melhor para avaliar a escalabilidade de um

sistema seria considerando métricas de escalabilidade. Dentre a grande quantidade de

métricas existentes, as que usaremos para avaliar a escalabilidade de um serviço serão

listadas e explicadas a seguir:

Speedup: diz respeito ao ganho relativo de desempenho quando mais recursos são

adicionados no sistema, mantendo fixa a carga de requisições recebidas;

Degradação: mede o desempenho que é perdido para uma dada configuração de

sistema, conforme a carga de requisições recebidas vai crescendo e,

Comparação de performance agregada: consiste em comparar a performance

agregada de um sistema quando diferentes cargas de requisições são recebidas,

normalmente enquanto os recursos também são escalados.

4.3 Outras Tecnologias

Nesta subseção, mostraremos alguns dos arcabouços relacionados a testes de

escalabilidade, dentre eles o que utilizaremos neste trabalho, o Scalability Explorer.

4.3.1 Escalabilidade de algoritmos e sistemas

STAS (Scalability Testing and Analyzing System) [15] é um sistema que fornece

8

análises de escalabilidade de algoritmos e sistemas. No STAS, a primeira coisa que se faz é

rodar um módulo de medição de velocidade que coleta a capacidade de computação do

sistema. Uma componente que faz uma pré­análise, então, pega o código fonte do sistema

e realiza uma análise da carga de requisições recebidas, baseada em ações de usuário.

Depois disso, conjuntos de nós são construídos baseados na capacidade de computação,

dobrando­as a cada iteração, para cada conjunto. Enquanto o STAS roda os testes, também

coleta e armazena os tempos de execução. Finalmente, o arcabouço calcula a métrica de

escalabilidade isospeed­e para verificar se o sistema é escalável. Essa métrica considera a

capacidade de computação dos nós e o tempo de execução, comparando duas

configurações, o que resulta em uma razão de escalabilidade, onde 1 significa que o

sistema é completamente escalável. Esse arcabouço pode ser utilizado para analisar a

escalabilidade de sistemas paralelos em C/C++. Entretanto, ele tem algumas limitações em

como os testes são realizados já que somente permite que o número de nós seja escalado

através de uma proporção fixa, além de analisar os resultados utilizando apenas a métrica

isospeed­e que, apesar de ser uma generalização de uma métrica antiga para considerar

ambientes heterogêneos, ainda só é apropriada para sistemas homogêneos.

4.3.2 Escalabilidade baseada em vazão, desempenho e recursos

Jogalekar e Woodside [16], [17] apresentam um arcabouço de escalabilidade que

introduz uma métrica baseada em vazão, desempenho e uso de recursos. Assim como a

isospeed­e, essa métrica fornece uma razão relacionando duas configurações. O principal

aspecto ruim deste tipo de métrica é que, na prática, é muito difícil atingir o valor 1, que é

considerado como escalabilidade total, o que torna comum tomar um intervalo arbitrário para

decidir se um sistema é escalável. Além disso, como essas métricas só funcionam para um

par de configurações, elas podem atestar que o sistema é escalável quando se compara

configurações vizinhas, mas fornecem valores ruis para configurações mais distantes. Isto

significa que, para um sistema com degradação linear, a escolha das configurações usadas

para a avaliação de escalabilidade influencia na análise.

4.3.3 Scalability Explorer

Finalmente, o Scalability Explorer [18] é um arcabouço escrito em Java, desenvolvido

9

no contexto do projeto CHOReOS (http://www.choreos.eu) para ser flexível e permitir ao

usuário escrever testes de escalabilidade significativos utilizando poucas linhas de código.

Ele faz parte do Rehearsal [1], outro arcabouço escrito em Java, cuja finalidade é incentivar

o uso de Desenvolvimento guiado por testes (Test­Driven Development, TDD) no

desenvolvimento de serviços web, dando suporte à geração dinâmica de clientes para

serviços web através de um endereço que aponta para a sua interface, à criação

interceptadores de mensagens que facilitam a escrita de testes de integração do sistema, à

emulação de serviços permitindo que operações de serviços reais possam ser simuladas e

à abstração de coreografias através de seu mapeamento em objetos Java.

No Scalability Explorer, a avaliação de cada operação de um serviço consiste em um

experimento. Cada experimento é dividido em iterações e, em cada uma delas, são feitas

sucessivas requisições ao serviço. O número de iterações e a quantidade de requisições

por iteração é definida pelo usuário. Além disso, o usuário também define a frequência inicial

de requisições e a forma (linear, quadrática ou exponencial) com que a frequência vai variar

de uma iteração para outra, bem como também define a distribuição (uniforme, Poisson ou

Normal) dos intervalos de tempo entre uma requisição e a próxima. É possível também

escolher que os intervalos não obedeçam a nenhuma distribuição específica, enviando uma

requisição sempre que possível. O Scalability Explorer dá suporte a testes de speedup,

degradação e performance agregada. Utilizando um analisador de performance relativa,

dependendo se escolhemos realizar um experimento de carga ou de arquitetura, calculamos

as métricas de degradação e speedup, respectivamente. Para a performance agregada, é

utilizado um analisador que gera um gráfico com o valor agregado de uma métrica de

desempenho. Funções de agregação como média aritmética ou percentil podem ser

integradas a esse analisador.

Além desses, o Scalability Explorer também fornece um outro analisador estatístico

para determinar se um sistema é escalável. O procedimento chamado de Análise de

Variância (ANOVA) trata da variação das médias e é utilizado para testar se não existe

variação nas médias de diversas populações. Porém, para assegurar que o teste é

confiável, o tamanho da amostra precisa ser grande o suficiente. É por essa razão que o

arcabouço implementa mais dois analisadores: um para fazer a estimativa do tamanho da

amostra e outro para realizar a análise de variância. Este último analisador, então, dirá que o

sistema é escalável se manteve performance equivalente em todas as iterações do

experimento.

10

5. Estudo de caso: Kalibro

O Kalibro é um serviço web para configuração, interpretação e monitoramento de

métricas de código­fonte [4]. Ele é o componente principal do Mezuro [5], rede social técnica

que tem como objetivo central disseminar o uso e a compreensão de métricas de

código­fonte. A figura 1 mostra sua tela inicial e resultados do processamento de um

repositório de código­fonte.

Figura 1: Mezuro.

O Kalibro é um sistema robusto, que está sendo desenvolvido e aprimorado já há

quatro anos. Ele contém mais de 200 classes, o que significa que muito tempo deste

trabalho foi dedicado à compreensão de sua arquitetura e do fluxo de dados de suas

operações. Esse sistema também possui ótima cobertura de testes, com mais de 1100

testes, somando­se testes de unidade, integração e aceitação. Portanto, qualquer alteração

necessária pode ser feita com garantias de que, se todos os testes continuam a ser

executados sem erros, as funcionalidades do sistema continuam funcionando como antes.

Após estudar seu funcionamento e arquitetura, identificamos as principais

funcionalidades do Kalibro:

Download de repositórios de código­fonte dos seguintes controladores de versão:

Subversion, Git, Mercurial, Baazar e CVS. Além disso, também é possível carregar

11

arquivos locais, comprimidos ou não, através de seu caminho absoluto no próprio

sistema de arquivos;

Utilização dos seguintes coletores de métricas de código­fonte: Analizo (para

métricas de códigos escritos em C, C++ e Java), Checkstyle (para métricas de

códigos escritos em Java) e CVSAnaly (para métricas de códigos escritos em

python).

Criação de configurações, ou seja, conjuntos pré­definidos de métricas relacionadas

que serão utilizadas na avaliação dos projetos. O Kalibro possui uma configuração

padrão para códigos escritos em Java;

Criação de intervalos associados a uma métrica e ao valor obtido após ela ter sido

calculada;

Criação de grupos de leitura que associam cores e rótulos para cada intervalo

criado, com a finalidade de melhorar a interpretação dos resultados;

Criação de métricas compostas, através de JavaScript, baseadas nas métricas já

fornecidas pelos coletores;

Cálculo de resultados estatísticos para módulos com granularidades maiores. Por

exemplo a média de linhas de código das classes dentro de determinado pacote e,

Cálculo de uma nota do código­fonte de cada módulo de um projeto, baseado em

pesos pré­definidos das métricas e intervalos.

5.1 Infraestrutura de testes

Como já citado acima, a infraestrutura onde o serviço web está rodando tem grande

influência em sua escalabilidade, porém, ter a infraestrutura necessária para realizar testes

de escalabilidade normalmente é caro.

Os primeiros testes escritos para o Kalibro, somente para verificar o funcionamento

do Scalability Explorer, foram realizados na minha própria máquina. Apesar de poder

identificar os primeiros problemas com os testes, eles foram pouco significativos, pois não

simulavam o atraso da rede, além de o serviço estar rodando junto com os próprios testes.

O ideal seria conseguir um ambiente isolado, no sentido de que o único processo

que exigisse mais recursos do computador fosse somente o Kalibro.

12

5.1.1 OpenStack e ClusterSSH

Para simular um ambiente desse tipo e para poder manipular a quantidade máxima

de recursos que o serviço utilizaria, optamos por utilizar a "nuvem" (na verdade, existia

apenas um computador) CHOReOS_sandbox do CCSL, valendo­se de seus recursos para

criar máquinas virtuais de diversos tamanhos.

A ferramenta usada para a criação das máquinas virtuais e seu gerenciamento foi o

OpenStack (http://www.openstack.org/), um sistema operacional de nuvem, capaz de

gerenciar grandes quantidades de recursos. Apesar de possuir um dashboard que

possibilitava a fácil criação de máquinas virtuais, que fornecia algumas opções de sistemas

operacionais para serem automaticamente instalados e que monitorava o estado de cada

máquina, permitindo que elas pudessem ser suspendidas, retomadas, reiniciadas e

deletadas de forma simples, o OpenStack apresentou diversos problemas. Todas essas

operações demoravam tempo considerável para serem executadas. Além disso, o

OpenStack se mostrou instável em muitas situações como, por exemplo, quando máquinas

virtuais eram criadas com o mesmo sistema operacional e mesma quantidade de recursos,

terminando a tarefa em alguns casos com sucesso e em outros não, ou porque o acesso

por ssh à máquina não era permitido ou porque a máquina não conseguia fazer o download

de pacotes necessários para a instalação do serviço.

Outro problema foi a pequena quantidade de configurações possíveis para as

máquinas virtuais: só era permitida a escolha dentre um conjunto pré­definido e não era

permitida a criação de uma nova configuração que fizesse mais sentido no contexto dos

testes que seriam realizados. Por causa disso, criamos máquinas virtuais com 4 tipos de

configurações diferentes. A tabela 1 mostra as configurações das máquinas virtuais

criadas:

Tamanho no de VCPUs RAM (GB) HD (GB)

Médio 2 4 40

Grande 4 8 80

XGrande 8 16 160

XXGrande 12 24 6

Tabela 1: Configuração das máquinas virtuais.

13

As máquinas virtuais foram criadas de forma a que dobrassem a quantidade de

recursos, pois isso facilitaria a execução dos testes de speedup e de performance

agregada, como veremos adiante. Porém, as configurações disponíveis no OpenStack não

permitiam que a proporção fosse mantida entre as máquinas XGrande e o XXGrande. Todas

as VCPUs (Virtual Central Process Unit) eram Intel Xeon E5645, 2.4GHz. A quantidade de

disco rídigo não era prioridade pois o Kalibro e suas dependências não ocupavam muito

espaço, eram poucos os dados armazenados na própria máquina virtual e o banco de

dados ficou armazenado no meu computador pessoal. Por isso a pequena quantidade de

disco rígido da máquina XXGrande não prejudicou os testes. O sistema operacional

instalado em todas as máquinas virtuais foi o Ubuntu Server, versão 12.04. É importante

ressaltar que foram criadas máquinas com configurações menores, porém os testes de

operações do Kalibro que exigiam mais capacidade de processamento e que criavam

muitas threads ficavam muito prejudicadas ou não terminavam.

Por fim, não existia a alternativa de que um script para a configuração do banco de

dados, instalação do Kalibro e suas dependências fosse executado automaticamente logo

após a instalação do sistema operacional, o que significa que tudo teve que ser feito

manualmente para cada máquina criada.

Para os três primeiros problemas citados não houve muito o que fazer mas, depois

que as máquinas foram criadas com êxito, não havia mais a necessidade de se preocupar

com eles. Já para o último problema, uma solução conveniente foi encontrada: o

ClusterSSH (http://linux.die.net/man/1/cssh). Esse programa é capaz de controlar, via

conexões ssh, diversos terminais utilizando apenas um console. Ele permite enviar

comandos simultâneos a todos os terminais, portanto, sempre que alterações em mais de

uma máquina virtual eram necessárias, elas passaram a ser feitas de forma rápida e

prática. A figura 2 mostra o ClusterSSH sendo usado para controlar, através de seu console

no canto superior direito, quatro máquinas virtuais simultaneamente.

14

Figura 2: ClusterSSH.

5.1.2 Estrutura dos testes

A organização das classes de testes foi feita da seguinte forma: para cada endpoint

do Kalibro e para cada tipo de métrica (degradação, speedup e performance agregada)

existe um pacote. Além desses, há um pacote de suporte que contém classes que

controlam o funcionamento de alguns testes. Cada classe pertencente a um pacote de

endpoint representa uma das operações fornecidas por ele. Enquanto que cada classe

pertencente a um pacote de tipo de métrica possui classes que a calcularão para cada um

dos endpoints do Kalibro.

O Scalability Explorer encapsula um experimento na classe Experiment. Essa classe

possui um método que tem que ser sobrescrito para fazer a chamada da operação que será

analisada. Existem ainda outros métodos que podem ser sobrescritos que estão

relacionados com a preparação e encerramento dos testes.

Para mudar o comportamento de cada um desses métodos e para poder executar

os testes de todas as operações de um mesmo endpoint em um único arquivo, todas as

classes que representam operações do Kalibro extendem da classe Strategy, pertencente

ao pacote de suporte. Essa é uma classe abstrata que, além de definir qual é o cliente que

fará as requisições para o serviço, também define um conjunto de métodos que podem ser

15

implementados pelas suas classes filhas. Ela é uma implementação do padrão de projeto

strategy, no qual uma família de algoritmos é definida (as operações dos endpoints), mas

qual algoritmo será utilizado é definido em tempo de execução. As classes que representam

operações utilizam os métodos disponibilizados pela Strategy para preparar o ambiente para

os testes antes e depois de um experimento, de uma iteração ou de uma requisição. A

figura 3 mostra o diagrama de classes no qual a implementação da da classe Strategy foi

baseada.

Figura 3: Padrão de projeto strategy.

Para fazer requisições ao serviço, utilizamos a emulação de clientes disponibilizada

pelo Rehearsal [1]. Algumas vezes, uma operação precisa que objetos sejam passados

como parâmetro. No Rehearsal, cada um desses objetos é encapsulado em um Item. Para

descobrir qual é o esqueleto dos itens necessários para invocar as operações do Kalibro,

utilizamos o Item Explorer [4] que, a partir de um arquivo WSDL válido, gera o esqueleto de

um item que é passado na requisição e para o item que é retornado da requisição. A figura

4 mostra o esqueleto do item requerido como parâmetro e do item que é enviado de

resposta pela operação hasProcessingBefore do Kalibro.

16

Figura 4: Item Explorer.

Todas as classes que representam um tipo de teste a ser executado extendem da

classe Experiment do próprio Scalability Explorer. São nessas classes que definimos os

parâmetros de um experimento: número de iterações, número de requisições por iteração e

seu valor inicial, aumento da frequência de requisições de uma iteração para a outra e qual o

tipo de métrica queremos coletar. Para testes de degradação, utilizamos a estratégia

WorkloadScaling do próprio Scalability Explorer: nessa estratégia, o arcabouço aumenta a

frequência de requisições por minuto de uma iteração. Para testes de speedup utilizamos a

CapacityScaling: nessa estratégia, o parâmetro de aumento é passado para um Deployer

que saberá lidar com esse aumento de capacidade do sistema. Esse Deployer precisa ser

implementado. No nosso caso, criamos a classe KalibroDeployer, que é responsável por

controlar qual máquina virtual será usada em cada iteração. Para os testes de performance

agregada combinamos as duas estratégias para que tanto a carga quanto a capacidade do

sistema aumentassem de iteração em iteração.

17

5.2 Testes de escalabilidade do Kalibro

O Kalibro disponibiliza 50 operações, divididas em 11 endpoints. Para testar esse

serviço inteiramente, foram necessários, portanto, rodar 150 testes de escalabilidade

diferentes.

Os parâmetros numéricos usados nos testes, tais como o aumento na frequência

das requisições, variam de uma operação para a outra, e foram definidos de forma a tentar

gerar uma fila de requisições no serviço, ou seja, o intervalo de tempo entre o envio de uma

requisição e outra para o Kalibro foi configurado para ser menor do que o tempo que o

Kalibro demora para responder a uma requisição. O número de requisições por iteração

também difere em algumas operações: nas operações que exigem mais processamento, os

testes demoravam muito tempo para acabar e, por isso, esse número é menor. Os

resultados de cada teste são salvos em um arquivo no formato XML passado como

parâmetro para o analisador.

Para calcular um tipo de métrica para todas as operações de um endpoint, basta

executar a classe correspondente no pacote da métrica desejada. Já para calcular um tipo

de métrica para uma operação ou um conjunto de operações específico de um endpoint,

basta comentar as chamadas de experimento para as outras que não interessam.

Além disso, todos os testes medem a latência de cada operação, ou seja, o tempo

acumulado desde a chamada da operação, atraso da rede tanto na requisição quanto na

sua resposta e o tempo que o serviço precisa para processar a operação. A latência é

utilizada para o cálculo das métricas de escalabilidade. Os dados mostrados nos gráficos a

seguir são a média da latência de uma operação, em cada iteração do experimento.

Na maior parte dos testes executados, as operações apresentavam latência baixa. O

aumento de carga e o aumento da capacidade da infraestrutura não impactavam

significativamente no tempo de resposta. Isso mostra que, para a maior parte das

operações, o sistema é dificilmente estressado. Ainda assim, três operações com tempo de

resposta alto foram encontradas. Dentre elas, uma era facilmente sobrecarregada com

carga relativamente baixa: a operação de processamento de repositório.

Nos exemplos das próximas seções, destacamos essa operação pois, além de ser

a requisição mais demorada, é a principal operação do Kalibro e possui uma particularidade:

ela é executada paralelamente em threads. O serviço recebe a requisição e responde para

o cliente que começará o processamento, porém, todo ele é feito em background. A

consequência disso é que o Scalability Explorer somente consegue medir o tempo que o

serviço leva para estar pronto para processar um repositório. O processamento em

18

background também é dividido. O Kalibro possui diferentes estados que indicam qual é a

fase do processamento que o serviço está. O tempo que o Kalibro leva para terminar o

processamento em cada estado é armazenado no banco de dados. Porém, a coleta de

métricas e a análise dos resultados também é feita em paralelo. O segundo processo

analisa os resultados sob demanda, conforme o processo de coleta o entrega resultados.

Portanto, os testes não podiam acabar até que o serviço escrevesse no banco de

dados que o processamento estava pronto. Depois disso, consultas ao banco de dados

foram feitas, e uma boa aproximação do tempo total do processamento em background da

requisição foi obtida somando­se o tempo de todos os estados, com exceção do estado de

coleta.

Nos gráficos que seguem, a Resposta do Servidor é a média do tempo que leva

para que o Scabalability Explorer envie uma requisição e receba a resposta do Kalibro, que

significa que o processamento do repositório irá começar. O Processamento em Background é a média do tempo que o Kalibro leva para processar de fato o repositório. O

Total é a soma dos dois tempos anteriores.Nos testes, para a operação de processamento de repositório utilizamos os grupos

de leitura e configuração padrões do Kalibro. Essa operação também exige que um objeto

da classe Project exista e que um objeto da classe Repository esteja associado a ele.Como um objeto da classe Project permite que vários objetos da classe Repository

sejam associados a ele, somente precisávamos de uma instância dessa classe durante

todo o experimento. Já um objeto da classe Repository só pode estar associado a um

repositório de código­fonte. Por essa razão, uma nova instância dessa classe precisava ser

criada antes de cada requisição.

Para que todas as depêndencias fossem satisfeitas, sobrescrevemos o método

beforeExperiment da classe Strategy para que a instância de Project fosse criada antes do

experimento começar e persistisse durante todo o teste; sobrescrevemos o método

beforeRequest para que uma nova instância de Repository fosse criada e associada a um

projeto e a um repositório de código­fonte antes de cada requisição; sobrescrevemos,

também, o método afterRequest para que cada requisição enviada esperasse o seu

processamento em background acabar, pois assim poderíamos coletar esse tempo

diretamente do banco de dados e, para fazer a requisição e coletar o tempo de resposta do

servidor, sobrescrevemos o método request.

O Item Explorer foi utilizado para a identificação dos esqueletos dos itens passados

como parâmetro nas requisições de criação de objetos das classes Project e Repository e

na requisição que verifica o término de um processamento. O repositório de código­fonte

19

utilizado nos testes foi o Qt­Calculator .5

Finalmente, os gráficos são acompanhados pela tabela de intervalos de confiança

dos seus resultados. Como a amostra foi pequena, para calculá­los usamos a distribuição

t­student [19].

5.2.1 Teste de Degradação

Os testes de degradação consistem em manter uma configuração de recursos fixa e

aumentar a carga de requisições de uma iteração para a outra. O tamanho de máquina

virtual escolhido para realizar esses testes foi o Grande.

Os parâmetros utilizados para a realização desses testes foram: 7 requisições por

iteração, 4 iterações, 2 requisições por minuto de valor inicial e aumento linear na carga de 2

requisições por iteração.

Segundo o gráfico da figura 5, conforme o número de requisições por minuto

aumenta, o tempo de resposta também cresce. Isso pode indicar que existe um problema

no fluxo de dados do programa.

A tabela 2 mostra os intervalos de confiança de cada valor coletado em sua

respectiva iteração para o teste de degradação do processamento de repositório.

Figura 5: Teste de degradação do processamento de repositório.

5 http://sourceforge.net/p/qt­calculator/code/HEAD/tree/

20

Requisições por Minuto

Resposta do servidor Processamento em background

2 (26254, 27196) ­ (27196, 28137) (37381, 37939) ­ (37939, 38496)

4 (27495, 29894) ­ (29894, 32293) (38914, 41798) ­ (41798, 44681)

6 (29114, 38084) ­ (38084, 47053) (45406, 54391) ­ (54391, 63376)

8 (34113, 39969) ­ (39969, 45824) (53609, 59236) ­ (59236, 64863)

Tabela 2: Intervalos de confiança para os testes de degradação.

5.2.2 Teste de Speedup

Os testes de speedup consistem em manter a carga de requisições fixa, e aumentar

a capacidade de processamento da infraestrutura de iteração em iteração.

Primeiramente, fizemos os testes com 3 requisições por minuto. Porém, a diferença

de tempo entre as máquinas de tamanho Médio e Grande era muito grande. As outras duas

tinham desempenho similar à Grande. Isso foi um indício de que a carga era grande o

suficiente para sobrecarregar a máquina de tamanho Médio, mas não para sobrecarregar as

outras.

Por essa razão, refizemos os testes com 15 requisições por minuto. Nessa

situação, a máquina de tamanho Médio parava de responder. Isso porque o Kalibro limita o

número de threads que podem estar rodando ao mesmo tempo. Esse número é 10 vezes o

número de processadores da máquina. A máquina de tamanho Médio somente possui 2

VCPUs, e, portanto, quando muitas requisições chegavam simultaneamente, ela

ultrapassava o limite e os testes não acabavam. Esse problema de o sistema parar de

responder ao receber uma carga alta foi reportado para os responsáveis pelo projeto.

Além disso, foram feitas 3 iterações com 10 requisições cada.

A tabela 3 mostra os intervalos de confiança de cada valor coletado em sua

respectiva iteração para o teste de speedup do processamento de repositório.

21

Figura 6: Teste de speedup do processamento de repositório.

Tamanho Resposta do servidor Processamento em background

Grande (46690, 56576) ­ (56576, 66462) (75566, 84311) ­ (84311, 93056)

XGrande (30867, 34100) ­ (34100, 37334) (48874, 52864) ­ (52864, 56853)

XXGrande (31439, 34081) ­ (34081, 36722) (49510, 54173) ­ (54173, 58836)

Tabela 3: Intervalos de confiança para os testes de speedup.

Segundo o gráfico da figura 6, há uma grande diferença no tempo de resposta entre

as máquina Grande e XGrande, porém, essa diferença é bem menor entre as máquinas

XGrande e XXGrande. Isso pode indicar que, a partir do tamanho XGrande, aumentar a

capacidade da máquina não acarreta em melhorias no tempo de resposta. É importante

ressaltar que esse resultado é específico para essa carga, porém acreditamos que 15

requisições por minuto já seja uma carga alta de requisições para o sistema.

5.2.3 Teste de Performance Agregada

Os testes de performance agregada consistem em, a cada iteração, aumentar

22

proporcionalmente a carga de requisições e a capacidade da infraestrutura. Começamos

com a máquina virtual de tamanho Médio e aumentamos até o tamanho XXGrande.

Os testes foram executados em 4 iterações, com 10 requisições cada. A carga

inicial foi de 2 requisições por minuto com aumento exponencial de 2 requisições por

iteração. Isso foi feito para conseguimos manter a proporção entre a carga e a capacidade

das máquinas virtuais.

Figura 7: Teste de performance agregada do processamento de repositório.

Requisições por Minuto

Resposta do servidor Processamento em background

2 (30545, 34005) ­ (34005, 37464) (46055, 50029) ­ (50029, 54002)

4 (30222, 33600) ­ (33600, 36977) (42265, 46299) ­ (46299, 50334)

8 (29091, 31017) ­ (31017, 32943) (40529, 43342) ­ (43342, 46154)

16 (31268, 34351) ­ (34351, 37434) (50040, 55282) ­ (55282, 60524)

Tabela 4: Intervalos de confiança para os testes de performance agregada.

O gŕafico da figura 7 mostra que, conforme aumentamos proporcionalmente a carga

de requisições e a capacidade da infraestrutura, o tempo de resposta melhora um pouco. O

23

aumento no tempo na última iteração pode ser explicado pelo fato de que a proporção não

pode ser mantida, já que a capacidade da máquina de tamanho XXGrande não é o dobro da

capacidade da máquina de tamanho XGrande.

A tabela 4 mostra os intervalos de confiança de cada valor coletado em sua

respectiva iteração para o teste de performance agregada do processamento de repositório.

6. Propostas de Solução

Depois de identificar a operação de processamento de repositório como a mais

problemática do Kalibro, sugerimos duas soluções visando melhorar sua escalabilidade. A

primeira altera a arquitetura do serviço, pois os testes de speedup mostraram que aumentar

a capacidade da infraestrutura não implica em grande ganho de desempenho. A segunda

altera o fluxo de dados do processamento de repositório, pois os testes de degradação

mostraram que o desempenho da operação piora conforme a carga de requisições

aumenta.

6.1 Balanceamento de Carga

A arquitetura do Kalibro funciona da seguinte maneira: o cliente faz uma requisição

para o serviço e esse possui todas as operações possíveis do sistema. Dessa forma, a

requisição é tratada na própria máquina que a recebe.

A solução de balanceamento de carga consiste em replicar o Kalibro em várias

máquinas virtuais e adicionar um balanceador. A ideia é que os serviços replicados sejam

cadastrados no balanceador e, quando um cliente faz uma requisição, essa primeiramente é

direcionada ao balanceador e esse trata de distribuir as requisições entre os serviços

cadastrados. A política de distribuição de requisições implementada foi a de round­robin.

Essa política consiste em distribuir as requisições de forma circular, sem se preocupar com

prioridades de execução. O que acontece na prática é que os serviços cadastrados entram

em uma fila no balanceador. Quando ele recebe uma requisição, ela é repassada para o

primeiro serviço na fila, que então é retirado do início e colocado no final da fila.

A figura 8 mostra a arquitetura do Kalibro. Na esquerda a arquitetura sem

balanceamento e na direita com balanceamento de carga.

Depois de implementar o balanceamento de carga, refizemos os testes da operação

24

de processamento de repositório para verificar se as mudanças acarretaram em melhor

escalabilidade do Kalibro.

Figura 8: Arquitetura do Kalibro. Sem balanceamento e com balanceamento de carga,

respectivamente.

Para replicar o serviço, escolhemos criar mais quatro máquinas virtuais do tamanho

Grande. Utilizamos uma máquina do tamanho Médio para ser o balanceador, já que esse

não exige grande capacidade de processamento.

Não foram realizados os testes de degradação. Isso porque para mantermos a

capacidade de processamento fixa, teríamos manter a estrutura de um balanceador e cinco

serviços cadastrados, por exemplo. Como o fluxo de dados não mudou, a tendência é que o

tempo de resposta fique estável no começo, mas conforme o número de requisições

aumentar, o gráfico apresentará o mesmo comportamento que apresentou para os testes

de degradação na arquitetura sem o balanceamento de carga.

Nos testes de speedup e performance agregada, a diferença é que não aumentamos

o tamanho da máquina virtual de uma iteração para a outra. Ao invés disso, adicionamos

uma máquina virtual de mesmo tamanho. Para isso, implementamos a classe

BalancerDeployer no pacote de suporte. Essa classe implementa métodos que cadastram

novos serviços no balanceador a cada nova iteração.

25

6.1.1 Testes de Speedup com Balanceamento de Carga

Como nos testes de speedup com balanceamento de carga do processamento de

repositório somente utilizamos a máquina virtual de tamanho Médio para realizar o papel de

balanceador, fixamos a carga em 10 requisições por minuto para cada iteração.

Configuramos os testes para que fossem feitas 5 iterações, com 10 requisições em cada

uma. Começamos com 1 máquina virtual cadastrada. A cada iteração, uma nova máquina

virtual era cadastrada no sistema.

Figura 9: Teste de speedup com balanceamento de carga do processamento de repositório.

A tabela 5 mostra os intervalos de confiança de cada valor coletado em suarespectiva iteração para o teste de speedup do processamento de repositório com

balanceamento de carga.

26

Número de máquinas Resposta do servidor Processamento em background

1 (41963, 55205) ­ (55205, 68446) (65154, 77293) ­ (77293, 89431)

2 (28569, 30839) ­ (30839, 33108) (40687, 43035) ­ (43035, 45382)

3 (27878, 28491) ­ (28491, 29102) (38745, 39545) ­ (39545, 40344)

4 (28307, 28729) ­ (28729, 29150) (40661, 42515) ­ (42515, 44369)

5 (27727, 28501) ­ (28501, 29274) (38810, 39696) ­ (39696, 40581)

Tabela 5: Intervalos de confiança para o teste de speedup com balanceamento de carga.

Analisando o gráfico da figura 9, pode­se notar que pelo fato da carga ser maior,

uma única máquina virtual de tamanho Grande apresenta desempenho mais baixo do que

nos testes de speedup anteriores.

Percebemos também que o desempenho fica praticamente constante a partir de três

máquinas virtuais cadastradas. Isso quer dizer que três pode ser o número ideal de

máquinas rodando ao mesmo tempo para que o sistema mantenha o tempo de resposta

estabilizado. É importante ressaltar que esse resultado diz respeito a essa carga em

específico. Se aumentarmos a carga, o aumento de capacidade passa a fazer sentido.

Por fim, mesmo depois de estabilizado, o tempo de resposta sempre foi um pouco

mais alto em comparação aos tempos dos testes de speedup anteriores. Isso se deve ao

fato de que com o balanceamento de carga, existe um tempo adicional para a troca de

mensagens entre balanceador e serviços cadastrados.

6.1.2 Teste de Performance Agregada com Balanceamento de Carga

Os testes de performance agregada com balanceamento de carga foram

praticamente iguais aos testes desse mesmo tipo com a arquitetura antiga. A diferença é

que nos testes novos não houve o problema de manter a proporcionalidade nos tamanhos

das máquinas virtuais, já que neles manter a proporção de uma iteração para a outra

simplesmente significava cadastrar mais uma máquina virtual, de mesmo tamanho, no

balanceador.

Os testes foram realizados em 5 iterações, enviando 10 requisições em cada.

27

Começamos com 1 máquina virtual cadastrada. A cada nova iteração uma nova máquina

virtual era cadastrada no sistema. A carga inicial foi de 2 requisições por minuto com

aumento linear de 2 requisições por iteração. Dessa forma, a proporção entre carga e

capacidade das máquinas virtuais foi mantida.

Figura 10: Teste de performance agregada com balanceamento de carga do processamento de

repositório.

Requisições porminuto

Resposta do servidor Processamento em background

2 (26792, 27335) ­ (27335, 27878) (37551, 37983) ­ (37983, 38415)

4 (27121, 27545) ­ (27545, 27969) (37888, 38243) ­ (38243, 38597)

6 (26924, 28145) ­ (28145, 29363) (38484, 39625) ­ (39625, 40766)

8 (27861, 28436) ­ (28436, 29190) (39073, 40012) ­ (40012, 40952)

10 (27794, 28772) ­ (28772, 29750) (39178, 40089) ­ (40089, 41000)

Tabela 6: Intervalos de confiança para o teste de performance agregada com balanceamento de carga

do processamento de repositório.

28

O gráfico da figura 10 mostra que o sistema fica praticamente estabilizado conforme

aumentamos a carga e cadastramos mais máquinas no balanceador. Isso é um indicativo

de que o sistema possui boa escalabilidade.

A tabela 6 mostra os intervalos de confiança de cada valor coletado em sua

respectiva iteração para o teste de performance agregada do processamento de repositório

com balanceamento de carga.

6.2 Mudança no Fluxo de Dados

Quando o Kalibro recebia a requisição de processamento de repositório do cliente do

Mezuro, ele criava uma thread separada para tratá­la. Essa thread validava a configuração

que era passada e gerava o conjunto de observadores daquele repositório. Os

observadores eram usuários do Mezuro que cadastravam seus e­mails no repositório. Eles

recebiam uma notificação quando o repositório terminasse de ser processado.

Depois disso, outra thread era criada para executar o processamento de fato. Ao

mesmo tempo, uma resposta era enviada para o Mezuro, indicando que o processamento

havia começado.

A partir disso, o processamento era dividido em quatro estados:

LOADING, download do repositório e preparação dos diretórios e banco de dados

para armazenar os resultados do processamento;

COLLECTING, coleta das métricas que pertencem à configuração utilizada. Isso

envolve fazer uma chamada para os respectivos coletores;

ANALYZING, análise dos resultados obtidos na fase de coleta, ou seja, cálculo de

métricas compostas, de resultados estatísticos para os módulos com granularidade

maior e da nota específica de um módulo tinha sido iniciado. Também encaixa cada

resultado em um intervalo da configuração. Esse estado é executado paralelamente

ao estado de coleta e,

BUILDING, montagem da árvore de resultados.

Na árvore de resultados montada, a raíz é o módulo com granularidade

SOFTWARE. Nela podem ser encontrados os resultados e a nota do sistema como um

todo. Os outros nós tem granularidade PACKAGE e possuem os resultados e notas dos

pacotes do sistema. Já as folhas tem granularidade CLASS e disponibilizam os resultados e

29

nota de uma classe específica.

No término do processamento, o serviço ainda enviava um e­mail para todos os

observadores cadastrados, avisando que se a tarefa terminou com sucesso ou não.

No novo fluxo de dados, o Kalibro recebe uma requisição de processamento de

repositório do cliente do Mezuro, cria uma thread que lidará com essa requisição e

imediatamente responde ao cliente, indicando que o processamento começou.

A partir disso, dividimos o processamento em mais estados, sendo que os estados

de LOADING e COLLECTING não mudaram seu funcionamento:

PREPARING, verificação da configuração que quer ser utilizada, preparação do

ambiente para a execução da tarefa. Por exemplo, criação dos objetos necessários

tanto para o processamento quanto para a conexão com o banco de dados;

ANALYZING, somente recebe os resultados da fase de coleta e os encaixa nos

intervalos cadastrados na configuração. Esse estado continua sendo executado

paralelamente ao estado de coleta;

BUILDING, continua montando a árvore de resultados, porém sem ter os valores

dos resultados estatísticos e das notas dos módulos;

AGGREGATING, realiza o cálculo dos resultados estatísticos de cada módulo do

repositório e atualiza a árvore e,

CALCULATING, calcula as notas de cada módulo do repositório, baseado nos

pesos das métricas definidos na configuração. Também atualiza a árvore.

A árvore de resultados continua sendo montada da mesma forma.

É importante notar que o serviço não dá mais suporte a observadores. Isso significa

que também não envia e­mails ao término do processamento. Decidimos que uma

notificação não precisava ser somente por e­mail. Por isso, agora o servidor que possui o

Kalibro rodando pode editar o arquivo de configuração para que um comando seja executado

ao final do processamento. Esse comando poder ser um script bash ou um comando que

envie os resultados do processamento para alguma url acessível pelo cliente.

A figura 11 mostra o fluxo de dados da operação de processamento de repositório.

Na esquerda é exibido o fluxo antigo e na direita o fluxo novo.

Com a nova implementação do fluxo de dados, testamos novamente a operação de

processamento de repositório. Coletamos as métricas de degradação, speedup e

performance agregada e os resultados obtidos são mostrados abaixo.

Nos gráficos exibidos, não apresentamos a linha de tempo total, ou seja, a linha com

30

a soma do tempo de resposta do servidor com o tempo de processamento em background,

pois a linha gerada ficaria muito próxima da linha correspondente ao processamento em

background, deixando os gráficos confusos ao invés de mais informativos. Pela diferença

ser tão pequena, podemos considerar que o tempo total de processamento da operação é

igual ao tempo de processamento em background.

Além disso, pelos valores da resposta do servidor serem muito pequenos,

preferimos não adicionar nas tabelas os seus intervalos de confiança, já que alguns dos

intervalos obtidos aceitavam valores negativos, o que não faz sentido no contexto da

medição de latência de uma operação.

Figura 11: Fluxo de dados do Kalibro. Antes e depois.

6.2.1 Teste de Degradação com o Novo Fluxo de Dados

Os parâmetros utilizados para a realização desses testes foram: 7 requisições por

iteração, 4 iterações, 2 requisições por minuto de valor inicial e aumento linear na carga de 2

requisições por iteração. O tamanho de máquina virtual usado foi o Grande.

Segundo o gráfico da figura 12, a degradação da operação é praticamente igual à

degradação do fluxo antigo. A diferença é que o tempo total de processamento da requisição

aumentou. Isso pode ser explicado pelo fato que o novo fluxo de dados cria mais objetos

31

(usados para identificar cada um de seus estados), o que implica em maior troca de

mensagens entre eles. Por existirem mais estados, mais conexões com o banco de dados

são feitas para que os tempos que eles levaram para terminar sejam armazenados.

Porém, o tempo de resposta do servidor diminuiu consideravelmente e não foi

afetado pelo aumento de carga das requisições.

Figura 12: Teste de degradação com o novo fluxo de dados para o processamento de repositório.

Requisições por minuto Processamento em background

2 (81288, 82283) ­ (82283, 83278)

4 (90518, 93366) ­ (93366, 96214)

6 (110824, 112314) ­ (112314, 113804)

8 (121397, 122281) ­ (122281,123165)

Tabela 7: Intervalos de confiança para o teste de degradação com o novo fluxo de dados.

A tabela 7 mostra os intervalos de confiança de cada valor coletado em sua

respectiva iteração para o teste de degradação do processamento de repositório com o

novo fluxo de dados.

32

6.2.2 Teste de Speedup com o Novo Fluxo de Dados

Nesse novo teste de speedup, configuramos os testes para que fossem feitas 3

iterações com 10 requisições cada. Fixamos a carga em 15 requisições por minuto. Pelas

mesmas razões do teste de speedup anterior, começamos com o tamanho de máquina

virtual Grande e aumentamos a capacidade da infraestrutura até o tamanho XXGrande.

Ao analisar o gráfico da figura 13, percebemos que o comportamento do tempo de

resposta do processamento em background foi diferente do teste com o fluxo antigo. O

sistema apresentou uma certa instabilidade pois, ao aumentarmos a capacidade da

infraestrutura, o tempo de processamento aumentou significativamente, ao invés de diminuir

ou permanecer próximo do tempo de resposta da iteração anterior.

Mais uma vez, o tempo total de processamento foi maior. Pelo tempo de resposta do

servidor ser muito rápido, não é possível perceber a diferença que o aumento na capacidade

das máquinas virtuais proporciona.

Figura 13: Teste de speedup para o processamento de repositório com o novo fluxo de dados.

A tabela 8 mostra os intervalos de confiança de cada valor coletado em sua

33

respectiva iteração para o teste de speedup do processamento de repositório com o novo

fluxo de dados.

Tamanho das máquinas Processamento em background

Grande (163577, 165120) ­ (165120, 166662)

XGrande (98621, 99551) ­ (99551, 100481)

XXGrande (116315, 117393) ­ (117393, 118470)

Tabela 8: Intervalos de confiança para o teste de speedup com o novo fluxo de dados.

6.2.3 Teste de Performance Agregada com o Novo Fluxo de Dados

Os testes foram executados em 4 iterações, com 10 requisições cada. A carga

inicial foi de 2 requisições por minuto com aumento exponencial de 2 requisições por

iteração. Isso foi feito para conseguimos manter a proporção entre a carga e a capacidade

das máquinas virtuais. Começamos com a máquina virtual de tamanho Médio e a cada

iteração aumentamos a capacidade da máquina virtual até o tamanho XXGrande.

A tabela 9 mostra os intervalos de confiança de cada valor coletado em sua

respectiva iteração para o teste de performance agregada do processamento de repositório

com o novo fluxo de dados.

Figura 14: Teste de performance agregada para o processamento de repositório com o novo fluxo dedados.

34

Requisições por minuto Processamento em background

2 (106032, 119495) ­ (119495, 132957)

4 (101990, 109147) ­ (109147, 116303)

8 (88796, 90803) ­ (90803, 92809)

16 (115928, 118196) ­ (118196, 120464)

Tabela 9: Intervalos de confiança para o teste de performance agregada com o novo fluxo de dados.

O gráfico da figura 14 confirma que realmente o tempo de resposta do servidor se

mantém estabilizado e muito inferior em comparação ao tempo com o fluxo de dados

anterior e que o tempo total de processamento é mais alto do que antes. O tempo de

processamento em background mostrou novamente crescimento quando passamos de

máquina virtual de tamanho XGrande para a de tamanho XXGrande. Isso ocorre em virtude

da desproporcionalidade entre a capacidade de processamento e a carga de requisições

nas duas iterações, como aconteceu no teste com o fluxo de dados antigo.

7. Análise dos Resultados

Com todos os testes feitos e resultados coletados, chegamos às seguintes

conclusões sobre as duas soluções apresentadas.

7.1 Análise do Balanceamento de Carga

A análise da implementação do serviço com balanceamento de carga nos mostra

que essa solução de fato melhorou a escalabilidade do Kalibro. O teste de performance

agregada nos mostra que o sistema manteve o desempenho estável à medida que a carga

de requisições aumenta proporcionalmente à capacidade de processamento da

infraestrutura. Os testes de speedup mostram que ter um sistema de balanceamento de

carga com três serviços cadastrados pode ser o ideal para o processamento da operação

de processamento de repositório.

35

Essa arquitetura pode ser ainda mais eficiente se melhorarmos a distribuição de

carga feita pelo balanceador. Apesar de ser simples de implementar, a política de

round­robin não é a mais indicada para esse tipo de distribuição. Isso se deve ao fato de que

essa política pode enviar mais requisições a um serviço que já esteja sobrecarregado. Se

houver um atraso maior na rede devido a perda de pacotes ou se o Kalibro já estiver

utilizando muito processamento da máquina, exigindo que ela troque de estado muitas

vezes, aumentando o tempo de resposta, a política de round­robin pode enviar mais

requisições a esse serviço, "estressando­o" ainda mais.

Uma solução melhor seria implementar uma política que leve em consideração o uso

do processador e memória RAM das máquinas cadastradas antes de decidir para qual delas

enviará a requisição. Escolhendo a máquina que está com "menos trabalho", ou seja, aquela

que está usando menos a capacidade de seu processador e memória RAM, evitamos que

máquinas sejam mais sobrecarregadas.

Essa solução, apesar de resolver os problemas da política de round­robin, assume

que sempre haverá pelo menos uma máquina subutilizada toda vez que o balanceador

precisar repassar uma requisição. Porém, isso não impede que todas as máquinas estejam

sobrecarregadas em algum momento. Por exemplo, se o balanceador tiver uma fila

suficientemente grande de requisições a serem distribuídas, pode ser que todas as

máquinas cadastradas fiquem sobrecarregadas antes do balanceador terminar a

distribuição.

Para solucionar esse tipo de problema, podemos sofisticar mais ainda o

balanceamento de carga utilizando a elasticidade da nuvem. A elasticidade da nuvem

permite que o balanceador crie e delete novas instâncias de máquinas virtuais quando for

necessário. Vamos considerar o caso em que o balanceador precisa repassar requisições,

mas todas as máquinas cadastradas estão sobrecarregadas. Nessa situação, o

balanceador pode criar dinamicamente uma nova máquina virtual com o serviço rodando e

enviar a requisição para ela. Isso é útil em horários de pico de requisições para manter o

desempenho do sistema estabilizado. Da mesma forma, se o balanceador perceber que

existem máquinas virtuais subutilizadas, ele pode deletá­las.

Enfim, apesar do balanceamento de carga com conjunto fixo de máquinas virtuais

ser mais escalável do que a arquitetura anterior, combinando­se uma política de

balanceamento mais sofisticada com a elasticidade da nuvem, podemos criar uma

arquitetura ainda melhor.

As desvantagens desse sistema se encontram na complexidade adicionada no

balanceador e no fato que esse é um sistema caro financeiramente, ou seja, a máquina que

36

efetuará o balanceamento de carga precisará de algoritmos mais sofisticados para

implementar a nova política e para a criação e deleção dinâmica de máquinas virtuais, o que

pode aumentar ainda mais o tempo total de processamento da requisição. Além disso, criar

máquinas virtuais é algo que custa muito dinheiro, o que pode tornar essa solução inviável.

7.2 Análise do Novo Fluxo de Dados

A análise da escalabilidade do Kalibro utilizando o novo fluxo de dados nos mostra

que a implementação feita não acarretou em melhoras de escalabilidade no serviço, em

comparação ao fluxo antigo. Embora o tempo de resposta do Kalibro ao cliente tenha ficado

extremamente rápido, o tempo total do processamento de uma requisição aumentou. De um

modo geral, tanto os testes de degradação quanto os de speedup e performance agregada

mostram que o tempo de resposta do servidor não é afetado nem pelo aumento de carga

das requisições nem pelo aumento na capacidade da infraestrutura das máquinas virtuais.

Já o processamento em background apresentou o mesmo comportamento em comparação

aos testes com o fluxo antigo, o que indica que a escalabilidade do sistema não melhorou.

Porém, apesar da desvantagem de o sistema levar mais tempo para finalizar o

processamento da operação, o novo fluxo de dados possui algumas vantagens em relação

ao fluxo anterior.

Primeiramente, a divisão do processamento em background da operação em mais

estados e o armazenamento do tempo levado para que eles terminem de ser executados no

banco de dados traz benefícios relacionados ao rastreamento de trechos ineficientes do

processamento e à detecção mais precisa de erros. Em outras palavras, com esses dados

armazenados no banco de dados, é possível identificar quais são os estados que ficam

mais tempo em execução. Com essa informação, podemos estudar o funcionamento dos

estados mais problemáticos, podendo sugerir melhorias nos algoritmos ou até mesmo

propondo algoritmos novos. Além disso, se ocorrer algum erro durante o processamento, o

maior número de estados é de grande ajuda para se descobrir em qual parte dele o erro

ocorreu.

Em segundo lugar, o fato de o tempo de resposta do Kalibro para o cliente ser tão

rápido traz benefícios para a aplicação que está fazendo o papel de cliente. No caso do

Mezuro, quando uma requisição de processamento de repositório é feita, a aplicação espera

a resposta do servidor para carregar a próxima página que expõe os resultados do

processamento. Como os testes de escalabilidade mostraram, esse tempo tende a crescer

37

se o serviço recebe muitas requisições desse tipo ao mesmo tempo. Essa demora é

inconveniente do ponto de vista do usuário, pois existe pouco feedback.

Com o novo fluxo de dados, esse tempo de resposta é extremamente rápido, o que

possibilita que o Mezuro carregue a próxima página imediatamente após a requisição ser

feita ao Kalibro. Além disso, o Mezuro mantém o usuário informado qual o estado atual do

processamento. Como a nova implementação possui mais divisões na operação que

anteriormente, o Mezuro pode dar mais feedback ao usuário sobre o estado de

processamento atual.

8. Um Guia para Testes de Escalabilidade de Serviços Web

Com os resultados obtidos, também foi possível montar um guia para testes de

escalabilidade de serviços web:

Escolha as métricas que serão calculadas. Recomendamos calcular as métricas de

degradação, speedup e performance agregada. Com a primeira se avaliará o

desempenho do programa. Com a segunda se avaliará o desempenho da

infraestrutura. Com a última se avaliará o desempenho conjunto da infraestrutura e

do programa. Dessa forma, uma avaliação completa do sistema será obtida;

Escolha um arcabouço para poder realizar testes automatizados de escalabilidade,

que dê suporte ao cálculo das métricas escolhidas;

Prepare o ambiente de testes. Se possível, crie máquinas virtuais de diversos

tamanhos e em computadores diferentes do computador que rodará os testes.

Dessa forma os atrasos da rede também serão considerados;

Use ferramentas que facilitem o trabalho. O OpenStack para gerenciamento de

recursos de um sistema em nuvem, o ClusterSSH para a manipulação simultânea

de diversas máquinas virtuais e o Item Explorer para a descoberta do esqueleto de

objetos que são necessários como parâmetro dos testes são exemplos disso;

Ajuste os parâmetros que controlam o número de requisições que serão enviadas,

quantas serão enviadas por minuto e o aumento na carga de uma iteração para a

outra de forma que o serviço precise enfileirar requisições. Eles podem ser

encontrados experimentalmente. Com isso o comportamento do sistema em

horários de pico é verificado. Os parâmetros variam de uma operação para a outra;

Depois de rodar os testes e coletar as métricas para todas as operações,

38

identifique aquelas que perdem desempenho com cargas altas (teste de

degradação) ou que não ganham desempenho com aumento na capacidade da

infraestrutura (teste de speedup) ou que não apresenta desempenho estabilizado

quando se aumenta a carga e a capacidade da infraestrutura proporcionalmente

(teste de performance agregada). Elas não são escaláveis;

Se o problema for na degradação, estude e altere o processamento dos dados, ou

seja, reconsidere os algoritmos;

Se o problema for no speedup, estude e altere a arquitetura do sistema, ou seja,

reconsidere a troca de mensagens e as estruturas de dados e,

Finalmente, depois de implementadas as soluções, refaça os testes para os três

tipos de métricas e analise os resultados para verificar se as mudanças acarretaram

efetivamente em melhora de escalabilidade.

9. Conclusão

Após termos estudado o funcionamento do Kalibro e feito os testes de degradação,

speedup e performance agregada de todas as 50 operações desse serviço, identificamos

três que eram problemáticas. Dentre elas, escolhemos estudar a operação de

processamento de repositório, por essa ser a principal funcionalidade do serviço.

Foi necessário um estudo mais aprofundado dessa operação, pois ela envolve a

criação de muitas threads e muitas trocas de mensagens são realizadas. Quando

entendemos o funcionamento da arquitetura e do fluxo de dados, implementamos duas

soluções para tentar melhorar a escalabilidade do Kalibro.

A primeira foi o balanceamento de carga, que provou efetivamente melhorar a

escalabilidade do sistema sendo particularmente útil em horários de picos de requisições,

mas que pode ser inviável devido ao seu alto custo financeiro.

A segunda foi alterar o fluxo de dados do sistema, que não melhorou a escalabilidade

do sistema, mas que diminuiu consideravelmente o tempo de resposta do serviço ao cliente,

o que possibilita maior feedback ao usuário sobre o estado de processamento da

requisição.

Segundo as análises, a melhor solução seria combinar o balanceamento de carga

com o novo fluxo de dados, pois dessa forma, apesar do tempo total de processamento da

requisição aumentar, o sistema seria escalável e daria feedback mais rápido ao usuário.

Por fim, um guia para testes de escalabilidade de serviços web foi elaborado com o

39

objetivo de facilitar a avaliação de escalabilidade de um serviço, no qual recomendamos o

cálculo de três métricas, assim como o uso de ferramentas que auxiliam o gerenciamento

de máquinas virtuais e procedimentos para a realização dos testes, análise dos resultados e

desenvolvimento de soluções para os problemas de escalabilidade encontrados.

40

PARTE SUBJETIVA

41

1. Desafios encontrados

O maior desafio encontrado no desenvolvimento deste trabalho foi trabalhar com o

código legado do Kalibro, um sistema com mais de 200 classes que, apesar de possuir uma

ótima cobertura de testes, utiliza o mínimo possível de bibliotecas que já possuam

funcionalidades que o sistema implementou. Por exemplo, boa parte da estrutura de

asserções dos testes de unidade é implementada pelo próprio Kalibro.

Por conta disso, tornou­se difícil entender o funcionamento do sistema e depois de 1

ano o estudando, não me surpreendo quando navego pelos diretórios do projeto e me

deparo com uma classe que não me lembro de já ter visto um dia.

Essa complexidade também atrasou a implementação das duas soluções citadas na

parte objetiva, pois fazer uma simples alteração no código acarretava em alterar diversas

outras partes.

Somado­se à dificuldade de entender o sistema, está o fato de que eu nunca tinha

ouvido falar em escalabilidade durante a graduação. Sobre serviços web a primeira vez foi

quando eu já havia começado o trabalho. A curva de aprendizado desses dois tópicos é

grande e estudar o suficiente sobre eles para poder desenvolver corretamente o trabalho

tomou bastante tempo.

Por fim, foi um grande desafio aprender a utilizar todas as ferramentas que me

auxiliaram no desenvolvimento deste trabalho. Precisei entender o funcionamento do

Scalability Explorer, de algumas partes do Rehearsal (como a emulação de clientes e o Item

Explorer), do OpenStack e do ClusterSSH.

2. Frustrações

A maior frustração do trabalho foi não ter conseguido complementar o guia de testes

com observações e recomendações sobre testes de escalabilidade nas duas abordagens

de composições de serviços web, ou seja, orquestrações e coreografias.

Além disso, o problema encontrado no Kalibro relativo ao limite de criação de threads

impediu que a amostra para os testes fosse maior e que fosse possível usar máquinas

virtuais de tamanhos menores.

42

3. Disciplinas mais relevantes para o trabalho

A seguir, listo as disciplinas de computação que considero terem sido fundamentais

para o desenvolvimento deste trabalho:

Laboratório de Programação Extrema. Nessa disciplina, aprendi e apliquei

conceitos de métodos ágeis. Eles são a base de todo o planejamento que fiz para o

trabalho e que faço para a minha própria vida pessoal. Além disso, utilizo as práticas

de desenvolvimento de software que aprendi para escrever código de melhor

qualidade;

Programação para Redes de Computadores me apresentou os principais

conceitos sobre o funcionamento da Internet. Nela aprendi melhor sobre conceitos de

sistemas distribuídos;

Programação Concorrente. Disciplina que apresentou conceitos de concorrência

fundamentais para o entendimento do Scalability Explorer (que faz as requisições em

paralelo) e da operação de processamento de repositório do Kalibro;

Laboratório de Bancos de Dados foi importante como complemento prático da

matéria Sistemas de Bancos de Dados. Na primeira disciplina aprendi muito sobre

o PostgreSQL, usado no trabalho. Na segunda aprendi aspectos técnicos de bancos

de dados que me ajudaram na compreensão do banco de dados do Kalibro;

Laboratório de Programação I e II. A primeira vez que tive que desenvolver um

projeto grande e em equipe foi em Laboratório de Programação I. Isso foi

importantíssimo para aprender a trabalhar em equipe e, principalmente, a mudar o

desenvolvimento apenas de pequenos exercícios programa para um sistema mais

complexo. Laboratório de Programação II proporcionou o primeiro contato com Java

e com o paradigma de orientação a objetos e,

Engenharia de Software. Nessa disciplina, aprendi principalmente sobre padrões

de projeto, que me ajudaram a escrever os testes de escalabilidade e a entender

algumas partes do Kalibro.

Além das disciplinas de computação, considero todas as disciplinas de álgebra,

cálculo e estatística do curso como de vital importância para a minha formação. Posso não

lembrar de toda a matéria, mas elas com certeza desenvolvem significativamente o

raciocínio lógico, importantíssimo para a área.

43

4. Próximos passos

Muito ainda pode ser feito para a complementação do guia de testes e para melhorar

a escalabilidade do Kalibro.

Primeiro, um estudo aprofundado sobre composições de serviços web pode ser feito

para entender o funcionamento desses tipos de sistema. A partir disso, pode­se selecionar

serviços reais e avaliar sua escalabilidade através de testes automatizados. Se houver

problemas, soluções podem ser implementadas e reavaliadas. Com os resultados obtidos,

o guia de testes de escalabilidade pode ser estendido para abranger também composições

de serviços web.

Segundo, as novas implementações feitas para o Kalibro também podem ser

estendidas e melhoradas.

No caso do balanceamento de carga, é possível implementar outras políticas de

distribuição que sejam mais eficientes do que o round­robin, otimizando o uso dos recursos

das máquinas virtuais cadastradas no sistema. Além disso, para economizar recursos e

energia, é possível usar a elasticidade da nuvem. Para isso, será necessário pesquisar

ferramentas que controlem a criação e deleção de máquinas virtuais automaticamente

quando mais recursos forem necessários e quando houverem máquinas subutilizadas,

respectivamente.

No caso do novo fluxo de dados, um estudo maior sobre o porquê o tempo de

processamento em background agora demora mais para terminar pode ser feito. Com a

criação de mais estados de execução, essa tarefa é facilitada. Uma vez que o estado mais

demorado for identificado, alterações no código podem ser feitas para otimizá­lo. A partir

disso, novos testes podem ser feitos para se avaliar o impacto das mudanças no tempo de

processamento e na própria escalabilidade do serviço.

44

5. Agradecimentos

Gostaria de agradecer, principalmente, ao Paulo Bittencourt Moura, que foi muito

solícito em me ajudar sempre que precisei. Sem ele esse trabalho não teria sido realizado.

Agradeço também ao meu orientador Prof. Fabio Kon, que apesar de nem estar no Brasil,

revisou tudo o que pedi, com críticas e sugestões que definitivamente contribuíram para

melhorar a qualidade do trabalho. Sou grato também ao Prof. Paulo Meirelles, que mesmo

assumindo cargo de professor na UnB, sempre esteve a disposição para responder dúvidas

e auxiliar no direcionamento do trabalho.

Por fim, gostaria de agradecer a toda a equipe do Mezuro. Eles sempre me apoiaram

e me deram força para continuar com o trabalho. Em especial, sou grato ao Rafael Manzo e

ao Carlos Morais pelas dicas e ideias de implementação no código do Kalibro e por me

ajudarem sempre que tive dúvidas (não foram poucas) sobre código.

45

Referências bibliográficas

[1] Besson, F. M. Rehearsal: Um arcabouço para teste automatizado de coreografias de

serviços web. 2012. 130 f. Dissertação (Mestrado) ­ Instituto de Matemática e Estatística,

Universidade de São Paulo, São Paulo, 2012.

[2] Nicolai M. Josuttis. SOA in practice. O'Reilly Media, 1st edição, August 2007.

[3] Eben Hewitt. Java Soa Cookbook. O'Reilly Media, 1st edição, March 2009.

[4] Meirelles, P.; Morais, C; Martins, R. M.; Kon, F.; Santos, C.; Maldonado, J. C.. "Mezuro

Plataform: Source Code Tracking Network", Sessão de Ferramentas do III Congresso

Brasileiro de Software: Teoria e Prática, 2012.

[5] Filho, C. M. de O.; Kon, F.. "Kalibro: Interpretação de métricas de código­fonte".

Dissertação de mestrado, Instituto de Matemática e Estatística, Univesidade de São Paulo,

2013.

[6] Felipe Pontes Guimaraes, Eduardo Hideo Kuroda e Daniel Macedo Batista. Performance

Evaluation of Choreographies and Orchestrations with a New Simulator for Service

Compositions. Em The International Workshop on Computer­Aided Modeling Analysis and

Design of Communication Links and Networks, CAMAD. IEEE, 2012.

[7] Adam Barker, Paolo Besana, David Robertson e Jon B. Weissman. The benets of service

choreography for data­intensive computing. Em Proceedings of the 7th international

workshop on Challenges of large applications in distributed environments, CLADE '09,

páginas 1­10, New York, NY, USA, 2009. ACM.

[8] Bernardo, P. C.; Kon, F.. "A Importância dos Testes Automatizados: Controle ágil, rápido

e confiável de qualidade", Engenharia de Software Magazine, pp. 54­57, 2008.

[9] M. Andreolini, M. Colajanni and M. Pietri, “A scalable architecture for real­time monitoring

of large information systems,” in IEEE Second Symposium on Network Cloud Computing

and Applications, 2012.

46

[10] W.­T. Tsai, Y. Huang, X. Bai, and J. Gao, “Scalable Architectures for SaaS,” IEEE 15th

International Symposium on Object/Component/Service­Oriented Real­Time Distributed

Computing Workshops, pp. 112–117, Apr. 2012.

[11] L. Duboc, E. Letier, and D. S. Rosenblum, “Death, Taxes, & Scalability,” IEEE Software,

vol. 27, no. 4, pp. 20–21, Jul. 2010.

[12] M. Quinn. Parallel Computing: Theory and Practice. McGraw­Hill, 2nd edição, 1994.

[13] D.R. Law. Scalable means more than more: a unifying definition of simulation scalability.

In Simulation Conference Proceedings, 1998. Winter, volume 1, pages 781 –788 vol.1. doi:

10.1109/WSC.1998.745064.

[14] D. Jayasinghe, G. Swint, S. Malkowski, J. Li, Q. Wang, J. Park, and C. Pu, “Expertus: A

generator approach to automate performance testing in IaaS clouds,” in IEEE 5th

International Conference on Cloud Computing (CLOUD), june 2012, pp. 115 –122.

[15] Y. Chen and X.­H. Sun, “Stas: A scalability testing and analysis system,” in Cluster

Computing, 2006 IEEE International Conference on, sept. 2006, pp. 1 –10.

[16] P. Jogalekar and M. Woodside, “Evaluating the scalability of distributed systems,” IEEE

Transactions on Parallel and Distributed Systems, vol. 11, no. 6, pp. 589 –603, jun 2000.

[17] P. Jogalekar and M. Woodside, “Evaluating the scalability of distributed systems,” in

System Sciences, 1998., Proceedings of the Thirty­First Hawaii International Conference on,

vol. 7, jan 1998, pp. 524 –531 vol.7.

[18] Moura, P.; Kon, F.. "Automated Scalability Testing of Software as a Service", 8th

International Workshop on Automation of Software Test, 2013.

[19] Wilton de O. Bussab e Pedro A. Morettin. Estatística Básica. Editora Saraiva, sexta

edição, 2010.

47