Processamento de Dados Massivos/O desafio de escalabilidade

Escalabilidade e eficiência de aplicações Big Data

editar

Um dos grandes desafios para a construção de aplicações BigData que sejam escaláveis e eficientes é que essas aplicações demandam recursos em três dimensões e as demandas variam drasticamente entre aplicações ou mesmo durante a sua execução. Nesta seção buscamos entender as dimensões, as fontes de degradação de desempenho e como elas podem ser caracterizadas, entendidas e minimizadas.

Distinguimos três tipos de recursos (ou dimensões) que devem ser providos pela plataforma computacional para a execução de aplicações Big Data, as quais são tipicamente paralelas e distribuídas: processamento, comunicação e armazenamento. Processamento se refere à computação propriamente dita que é executada em uma ou mais CPUs. Comunicação se refere à transferência de dados entre CPUs utilizando recursos de redes de comunicação. Armazenamento se refere às operações de preservação de dados de entrada ou computados em disco rígido ou outra tecnologia de armazenamento perene.

Uma perspectiva de caracterização das aplicações é sobre o quanto elas utilizam os recursos de cada uma dessas dimensões. A meta nesse caso é utilizar ao máximo os recursos durante todo o período de execução, o que não é possível para a maioria das aplicações, mas cuja análise e mensuração permite entendê-las melhor. Assim, dada uma dimensão e os recursos disponíveis, podemos mensurar quanto dos recursos será efetivamente utilizado a cada instante do tempo.

Considerando a dimensão de processamento, cada unidade de processamento pode estar, a cada instante do tempo em um de três estados: processamento, ocioso e computação adicional (overhead). Processamento é caracterizado por computação associada à solução do problema original, a qual é normalmente distribuída entre as unidades de processamento. O processador fica ocioso quando não possui processamento a realizar, como consequência de paralelismo insuficiente ou desbalanceamento de carga, ou quando está aguardando dados de ou sincronizando com alguma outra unidade de processamento. A computação adicional é todo o processamento que não é realizado originalmente na aplicação, mas passa a ser realizado em consequência da paralelização. Podemos citar três exemplos de computação adicional. O primeiro exemplo é toda computação associada a primitivas de comunicação e sincronização. O segundo exemplo é computação associada à solução original que é replicada por questões de eficiência, como a inicialização de variáveis locais. O terceiro exemplo é computação adicional realizada para atender requisições de outros processos, como obtenção de dados, em geral realizadas por daemons ou mecanismos semelhantes.

Em termos de comunicação, cada canal de comunicação, representado pela interface de rede, pode estar ocupado ou não. Aqui consideramos que a sua ocupação está associada à aplicação em foco e outras aplicações que porventura estejam utilizando o canal, embora quantificadas, não são relevantes para o entendimento e melhoria do desempenho da aplicação. O tempo de comunicação, isto é, o tempo para envio de uma mensagem entre duas unidades de processamento pode ser dividido entre contenção e tempo de transmissão. O tempo de transmissão depende do volume de dados a ser transmitido, da latência de comunicação entre as unidades de processamento e da banda passante do meio. A contenção depende da configuração instantânea da aplicação e seus fluxos de processamento. É importante ressaltar que o fato do canal estar ocupado pode afetar a utilização de outros componentes, como unidades de processamento ficarem ociosas enquanto contendem por um canal de comunicação.

Em termos de armazenamento, cada dispositivo de armazenamento, por exemplo um disco ou partição de disco, pode estar ocioso ou executando uma operação. A complexidade dos dispositivos de armazenamento os torna bastante difícil de serem quantificados e entendidos plenamente. Em primeiro lugar porque esses dispositivos são extremamente agressivos em termos de replicação (caching e buffering) e carga especulativa (prefetching), o que os torna muito difícil de entender. Mais ainda, a possibilidade de usar dispositivos para memória virtual torna o cenário ainda mais complexo. Podemos avaliar esses dispositivos de forma encapsulada, verificando apenas quando eles estão executando alguma operação ou não, assim como a natureza da operação em termos da porção de código que a invocou e qual a finalidade da invocação (p.ex., leitura, escrita, armazenamento temporário ou permanente).

Em suma, há um primeiro desafio que é a monitorização de aplicações nesse cenário e quantificação dos usos dos vários componentes. O segundo desafio, que pode demandar análises envolvendo mais de um componente e instâncias de um mesmo componente, é explicar o que causou o comportamento observado. Desta forma, uma estratégia de avaliação que será aplicada para o desenvolvimento de aplicações é sempre considerar essas dimensões, mapeadas nos vários componentes de processamento, comunicação e armazenamento, a sua taxa de utilização e a natureza ou finalidade do uso.