Multi-core Parallelization in Clojure - a Case Study
Java para sistemas de missão critica: mito ou realidade?
1. JUSTJAVA’2006
SUCESU-SP – Sociedade de Usuários de Informática e
Telecomunicações São Paulo
Conferencista : Alberione Braz da Silva e Marcelo Martins
Pires
2. Conferencista
Alberione Braz da Silva
Consultor de Negócios e Sistemas para América Latina pela
Telefonica Internacional S/A.
Mestre em Sistemas de Computação pela Pontifícia Universidade
Católica de Campinas e Engenheiro de Minas pela Universidade
Federal de Pernambuco
Marcelo Martins Pires
Consultor de Sistema para Brasil e América Latina da Telefonica.
Especialista Soluções J2EE pela FIAP, Especialista em Orientação a
Objetos pela Unicamp e Tecnólogo em Processamento de Dados pela
FATEC
2
4. Agenda
• Premissas Envolvidas
• Arquitetura Sugerida por Fornecedores e a arquitetura utilizada
• Influência da Arquitetura no desenvolvimento de um sistema de missão
crítica
– Fluxo do processamento
– Custo computacional
– Uso de I/O através do DMA (Direct Memory Access)
• Codificação
– Ordenação/Organização de arquivos
– Persistência de dados utilizando o BerkeleyDB
– Framework Spring
– Melhores praticas para programação
• Demonstração dos resultados
• Conclusão
• Propostas
• Perguntas
4
5. Premissas Envolvidas
As principais premissas eram utilização do java como
linguagem de programação e com máxima portabilidade,
outras foram:
• Processamento de 500 milhões de CDRs/dia.
• Processamento on-line quase em tempo real (~3min).
• Redução de custo proposto com infra-estrutura.
• Redução de custo com aquisição de Software e
manutenção sem utilização de OpenSource.
5
6. Arquitetura Sugerida por Fornecedores e a arquitetura utilizada
De modo geral a arquitetura proposta pelo fornecedor de
infra-estrtura para o sistema CORE foi de um equipamento
multiprocessado com 12 CPUs de 1.2GHz, com 24 Gbytes
de memória, com storage de 100Gbyte RAID-5 e com
banco de dados.
A arquitetura utilizada para o sistema CORE foi de um
equipamento multiprocessado com 6 CPUs de 1.2GHz
com 12 Gbytes de memória, com storage de 500Gbyte
RAID 0+1 (utilizado 150 Gbytes hoje).
6
7. Influência da Arquitetura no desenvolvimento de um sistema de
missão crítica - Fluxo do processamento (4 etapas lógicas)
Gerenciador de
Processos de normaliza-
ção, consolidação e
X Indica a seqüência dos semáforos recuperação de receita
4
3
2 Aplicação de
2 algoritmos
1
Consolidação
Agregação
Agregação
Normalização
Agregação
Normalização
Validação Agregação
Normalização
Agregação
Normalização Arqs.
Agregação
Normalização de
Agregação
Normalização alertas
Agregação
Normalização
Agregação
Normalização
Agregação
Normalização
Normalização
Arqs. CDRs Normalizadas consolidadas
Arqs. do BMP
Arqs. Validos e distribuídos por Tecnologia Arqs. CDRs Normalizados sem consolidação
7
8. Influência da Arquitetura no desenvolvimento de um sistema de
missão crítica – Custo Computacional (Relação entre CPUs,
Threads, memória e desempenho)
Normalmente, quando fala-se em Threads os desenvolvedores atem-
se na forma de disponibilizá-la e não em sua relações CPUs e
Memória, que esta relacionado diretamente com custo
computacional. Como se segue: CPUs
Para promover este ganho realizou-se as seguintes Ganho de 6 CPUs
ações:
•Fixou-se na JVM em 6 GBytes a memória mínima e
máxima utilizada, com isto, evita-se o overhead de
gerenciamento pela própria JVM.
•Usou-se a característica do gerenciamento de Ganho de 12 GBytes
Threads do ambiente, ou seja, uso-se cinco threads
executando em paralelo (relação direta com a
quantidade de CPUs) e cinco em slice.
Memória
Threads
8
9. Influência da Arquitetura no desenvolvimento de um sistema de
missão crítica – Uso de I/O através do DMA (Direct Memory
Access)
A características dos sistemas voltados a missão critica são grandes
volumes e grande quantidade de acesso as unidades de
armazenamento ou comunicação para tratamento das informação.
Para promover este ganho realizou-se as seguintes
ações:
•Usou-se o DMA
•Usou-se o pacote NIO que permite a utilização do
DMA através da JVM
9
10. Codificação – Ordenação/Organização de arquivos
Organização ordenada por nome de arquivo
...
...
Consolidação das CDR das 9 horas da manhã
Localização dos elementos, do arquivo consolidado, através da implementação de
Busca binária.
Ex: Localizando o elemento 88
00 11 22 33 44 55 66 77 88 99 100
00 11 22 33 44 55 66 77 88 99 100
00 11 22 33 44 55 66 77 88 99 100 10
11. Codificação – Persistência de dados utilizando o BerkeleyDB
Soluções de baixo custo
Trata-se de um banco de dados embutido na aplicação
Famoso por sua robusteza, performance e escalabilidade
Utilizado em soluções de missão crítica
Pode ser usado em aplicações que necessitem de storages concorrentes de alta
performance
Não é um servidor de banco de dados, não pode ser considerado como um SGBD
relacional ou orientado a objetos
Não possui uma linguagem de consulta como o SQL
O Berkeley DB suporta transações ACID, Undo e Redo (write-ahead logging),
recuperação de falhas com checkpoints, utiliza bloqueio para o controle de
concorrência (two-phase locking) e detecta deadlocks.
11
12. Codificação – Framework Spring
O módulo Spring Core representa as
Spring ORM Spring Web principais funcionalidades do Spring, no qual o
Spring AOP Hibernate Support
JDO Support
Web Utilities principal elemento é o BeanFactory.
Spring DAO Spring Context Trata-se de uma implementação do padrão
Spring MVC JDBC Support JDBC Support Factory, responsável em remover a
DAO Support DAO Support
programação de Singletons e permitindo o
baixo acoplamento entre a configuração e a
Spring Core
Bean Container
especificação de dependências, de sua lógica
de programação.
<bean id=quot;axeAdapterManagerquot; class=quot;br.com.telefonica.sacc.core.adapter.controller.
DefaultAdapterManagerquot; singleton=quot;falsequot;>
<property name=quot;brokerquot; ref=quot;axeBrokerquot; />
<property name=quot;parserquot; ref=quot;axeParserquot; />
<property name=quot;agregatorquot; ref=quot;connectorAgregatorManagerquot; />
<property name=quot;persistencequot; ref=quot;persistenceManagerquot; />
</bean>
package br.com.telefonica.sacc.core.adapter.controller;
public class DefaultAdapterManager implements AdapterManager, BrokerListener {
private CDRBroker broker;
private CDRParser parser;
private AgregatorManager agregator;
private PersistenceManager persistenceManager; 12
13. Codificação – Melhores práticas para programação
A forma de codificação e a própria lógica implementada pode afetar bastante
o desempenho, pois cada segundo perdido é multiplicado pelo volume de
informações a serem tratadas.
• Utilizar Classes e Métodos que usam a DMA como estrutura de acesso a
Acesso a arquivos (ex.:java.nio)
arquivos de • Utilizar Classes com menor nível de hierarquia no Diagrama Classes de
dados e referência
parâmetros • Utilizar arrays de bytes ou caracteres para efetuar a leitura, transformação
e/ou gravação
• Evitar a criação de instancias dentro fluxo crítico do processo
• Evitar Alocação de objetos dentro fluxo crítico do processo
• Reduzir processamento no processo de Garbage Collection
• Reciclar instancias
• Compartilhar instancias
Estruturas de
classes e • Evitar a concatenação de caracteres ou strings com o uso do sinal “+”
objetos • Utilizar o metodo append da classe StringBuilder (não é thread safe) ao invés
da concatenação de Strings
• Evitar o excesso de extensão de classes
• Evitar o redimensionamento de arrays, vetores e strings dentro do fluxo crítico
do processo
• Evitar o uso de string em todo fluxo processamento crítico
13
14. Codificação – Melhores práticas para programação
• Utilizar preferencialmente, em operações binárias, o comando condicional
switch/case
• Utilizar o conjunto de condicionais IF sempre do melhor caso condicional para
o pior caso.
public void fazerAlgo (String codigo){
if (codigo.equals(“mais comum”)){
//...
} else if (codigo.equals(“segunda mais comum”)){
//...
} else if (codigo.equals(“terceira mais comum”)){
//...
}
}
Estruturas
Condicionais • Substituir alguns testes por Exception Handling
• Ao invés de executar testes custosos como instanceog e teste de valor nulo
(null) utilize Exception Handling
Mais lento:
if (foo != null && foo.isHappy()){
// ...
}
Mais rápido:
try{
if ( foo.isHappy()){
//...
}
}
catch(NullPointerException ex) {}
14
15. Codificação – Melhores práticas para programação
• Utilizar sempre que possível o comando FOR nas estruturas de laço/repetição
• Declarações podem ficar fora da estrutura de laço
mais lento:
for (int i = 0; i < policy.getVehicleCount(); i++){
IAddress address = company.getAddress();
//...
}
mais rápido:
int count = policy.getVehicleCount();
IAddress address = null;
for (int i = 0; i < count; i++){
address = company.getAddress(); //...
}
Otimizando • Executar teste condicionais fora do laço sempre que possível
Estrutura de mais lento:
repetição for (int i = 0; i > max; i++){
if (codido.equals(“vermelho”)) { //do X }
else { //do Y }
}
mais rápido:
if (codigo.equals(“vermelho”)){
for (int i = 0; i > max; i++){
// do X
}
} else{
for (int i = 0; i > max; i++){
// do Y
}
} 15
16. Codificação – Melhores práticas para programação
• De preferência pelo uso de Arrays a Collections
• Acessar um elemento em uma Array é de dois a três vezes mais
rápido em relação a Collection como um ArrayList
• Caso o tamanho seja conhecido e fixado e os elementos podendo
Manipulando ser indexados por por valores inteiros, a utilização de um array trará
Arrays e um ganho de desempenho significativo
Coleções • Porém o ganho de desempenho só poderá ser significativo caso
exista operações com grande número de repetições
• Na criação de Maps Utilize objetos Inteiros como chaves (Keys)
• O método hashCode e equals serão executados de com uma
melhor desempenho
• Caso no costrutor da classe contenha uma inicialização/associação de
valores a um campo (propriedade) da classe, a inicialização dessa mesmo
campo em sua declaração é desnecessário/inapropriado
public class Node{
private String name = “Qualquer coisaquot;;
Inicialização //...
dos campos }
nos Melhor prática:
construtores public class Node{
private String name;
public Node (String name){
this.name = name;
}
} 16
17. Codificação – Melhores práticas para programação
• Utilizar a leitura de um texto qualquer atraves de array de bytes, não
utilizando String, e efetuar a conversao atraves da multiplicacao dos valores
pelo multiplo de 10
De 2 a 3 vezes mais Rápido! Mais lento!
public static long toLong(byte[] public static long toLongDefault(
number){ String numero)
long valor = 0; {
long mult = 1; return Long.parseLong(numero);
for (int i = number.length-1; i >= }
0; i--)
Conversões
{
de String para
if (number[i] > 0x2F &&
tipos
number[i] < 0x3A)
primitivos
{
valor += (number[i] - 0x30) *
mult;
mult *= 10;
}
}
return valor;
}
• No Quadro a esquerda, podemos omitir a linha referente a verificação de
valores numéricos, incluindo um bloco try/catch, melhorando o desempenho e
tornando a função de 3 a 4 vezes mais rápida que a solução padrão.
17
18. Demonstração dos resultados
Os principais pontos que afetem o desempenho são: o tamanho dos arquivos
tratados, ocorrência de erro na checagem devido a forma de implementação
e processo de “Posto em marcha”.
Fatores que afetam o desempenho para Thread 5
“Posto em marcha” Erro de checagem Tamanho do arquivo
30
25
Adminsional
20
15
10
5
0
1 11 21 31 41 51 61 71 81 91 101 111 121 131 141
Arquivo
MB/Seg CDRs/Seg
18
19. Conclusão
Atualmente pode-se aplicar a linguagem java para o
desenvolvimento de qualquer tipo de sistema, inclusive de
missão crítica e/ou de grandes volumes. Mantendo-se, a
portabilidade, escalabilidade e interoperabilidade que a
linguagem java e a JVM proporciona.
Com isto, pode-se sugerir a quebra do paradigma que a
linguagem java e a JVM são lentas.
19
20. Propostas
Como atingiu-se as metas de desempenho ficaram
algumas questões pendentes de estudo, que podem ser
avaliadas. Que são:
• Quando afeta o desempenho a utilização do spring?
• A classe no nível com menor extensão é melhor para
o desempenho?
20