Orientador: Antônio Cláudio Gómez de Sousa Projeto (graduação) UFRJ/POLI/Departamento de Eletrônica e de Computação COPPE, 2013.



Documentos relacionados
Modelo Cascata ou Clássico

IFPE. Disciplina: Sistemas Operacionais. Prof. Anderson Luiz Moreira

Orientação a Objetos

FACULDADE DE ENGENHARIA DE COMPUTAÇÃO. PROJETO FINAL I e II PLANO DE TRABALHO <NOME DO TRABALHO> <Nome do Aluno> <Nome do Orientador>

DATA WAREHOUSE. Introdução

Comparativo de desempenho do Pervasive PSQL v11

2 Diagrama de Caso de Uso

Um Driver NDIS Para Interceptação de Datagramas IP

Wilson Moraes Góes. Novatec

4 O Workflow e a Máquina de Regras

AUTOR: DAVID DE MIRANDA RODRIGUES CONTATO: CURSO FIC DE PROGRAMADOR WEB VERSÃO: 1.0

Especificação do 3º Trabalho

3 Um Framework Orientado a Aspectos para Monitoramento e Análise de Processos de Negócio

Referências internas são os artefatos usados para ajudar na elaboração do PT tais como:

Engenharia de Software III

Noções de. Microsoft SQL Server. Microsoft SQL Server

Capacidade = 512 x 300 x x 2 x 5 = ,72 GB

Módulo 4. Construindo uma solução OLAP

Projeto de Arquitetura

O modelo do computador

Esta dissertação apresentou duas abordagens para integração entre a linguagem Lua e o Common Language Runtime. O objetivo principal da integração foi

O hardware é a parte física do computador, como o processador, memória, placamãe, entre outras. Figura 2.1 Sistema Computacional Hardware

Nome: Login: CA: Cidade: UF CARTÃO RESPOSTA QUESTÃO RESPOSTA QUESTÃO RESPOSTA

04/08/2012 MODELAGEM DE DADOS. PROF. RAFAEL DIAS RIBEIRO, MODELAGEM DE DADOS. Aula 2. Prof. Rafael Dias Ribeiro. M.Sc.

Análise e Desenvolvimento de Sistemas ADS Programação Orientada a Obejeto POO 3º Semestre AULA 03 - INTRODUÇÃO À PROGRAMAÇÃO ORIENTADA A OBJETO (POO)

Sistemas Distribuídos

Estrutura, Processos e Threads

Conceitos de Banco de Dados

Processos Técnicos - Aulas 4 e 5

Sistemas Operacionais

Notas da Aula 15 - Fundamentos de Sistemas Operacionais

Persistência e Banco de Dados em Jogos Digitais

Sistemas Operacionais

IW10. Rev.: 02. Especificações Técnicas

Algoritmos e Programação (Prática) Profa. Andreza Leite andreza.leite@univasf.edu.br

Microsoft Access XP Módulo Um

Sistemas Operacionais

FAÇA FÁCIL: DRIVER IGS PARA COMUNICAÇÃO DE PROTOCOLOS PROPRIETÁRIOS INTRODUÇÃO

Data Warehouse. Debora Marrach Renata Miwa Tsuruda

Prof. Marcos Ribeiro Quinet de Andrade Universidade Federal Fluminense - UFF Pólo Universitário de Rio das Ostras - PURO

Persistência de Dados

Sistemas Operacionais. Prof. André Y. Kusumoto

Manual do Painel Administrativo

Metodologia e Gerenciamento do Projeto na Fábrica de Software v.2

Engenharia de Software

Conteúdo. Disciplina: INF Engenharia de Software. Monalessa Perini Barcellos. Centro Tecnológico. Universidade Federal do Espírito Santo

TRABALHO COM GRANDES MONTAGENS

UML - Unified Modeling Language

Ministério da Educação Secretaria de Educação Profissional e Tecnológica Instituto Federal de Educação, Ciência e Tecnologia do Rio Grande do Sul

Sistema Operacional Correção - Exercício de Revisão

Hardware (Nível 0) Organização. Interface de Máquina (IM) Interface Interna de Microprogramação (IIMP)

PARANÁ GOVERNO DO ESTADO

Display de 7. PdP. Autor: Tiago Lone Nível: Básico Criação: 16/12/2005 Última versão: 18/12/2006. Pesquisa e Desenvolvimento de Produtos

Estrutura de Dados. Introdução a Ponteiros. Prof. Gerson Borges Estrutura de Dados I 1

Prof. Marcelo Machado Cunha

Multiplexador. Permitem que vários equipamentos compartilhem um único canal de comunicação

Importância da normalização para as Micro e Pequenas Empresas 1. Normas só são importantes para as grandes empresas...

Dadas a base e a altura de um triangulo, determinar sua área.

Requisitos de Software

CAPÍTULO 2 CARACTERÍSTICAS DE E/S E PORTA PARALELA

Para construção dos modelos físicos, será estudado o modelo Relacional como originalmente proposto por Codd.

Banco de Dados Aula 1 Introdução a Banco de Dados Introdução Sistema Gerenciador de Banco de Dados

ESTUDO DE CASO WINDOWS VISTA

Construindo portais com Plone

Como instalar uma impressora?

Manual da Turma Virtual: MATERIAIS. Para acessar a turma virtual com o perfil Docente, siga o caminho indicado abaixo:

Trecho retirando do Manual do esocial Versão 1.1

A memória é um recurso fundamental e de extrema importância para a operação de qualquer Sistema Computacional; A memória trata-se de uma grande

Manual do Visualizador NF e KEY BEST

Notas da Aula 17 - Fundamentos de Sistemas Operacionais

PROCESSO DE DESENVOLVIMENTO DE SOFTWARE. Modelos de Processo de Desenvolvimento de Software

Introdução a Java. Hélder Nunes

Desenvolvendo uma Arquitetura de Componentes Orientada a Serviço SCA

Modelagemde Software Orientadaa Objetos com UML

Ao longo do presente capítulo será apresentada uma descrição introdutória da tecnologia FPGA e dos módulos básicos que a constitui.

Disciplina: Unidade III: Prof.: Período:

Introdução ao GED Simone de Abreu

BRAlarmExpert. Software para Gerenciamento de Alarmes. BENEFÍCIOS obtidos com a utilização do BRAlarmExpert:

Impressão de Código de Barras Uma abordagem prática ZEBRA ZPL2

02 - Usando o SiteMaster - Informações importantes

Notas da Aula 4 - Fundamentos de Sistemas Operacionais

Arquitetura de Rede de Computadores

)HUUDPHQWDV &RPSXWDFLRQDLV SDUD 6LPXODomR

CRIANDO BANCOS DE DADOS NO SQL SERVER 2008 R2 COM O SQL SERVER MANAGEMENT STUDIO

ArpPrintServer. Sistema de Gerenciamento de Impressão By Netsource Rev: 02

Manual SAGe Versão 1.2 (a partir da versão )

Introdução a listas - Windows SharePoint Services - Microsoft Office Online

GARANTIA DA QUALIDADE DE SOFTWARE

Arquitetura de Computadores. Tipos de Instruções

Apresentação. Nossa sugestão é que você experimente e não tenha medo de clicar!!!

10 DICAS DE TECNOLOGIA PARA AUMENTAR SUA PRODUTIVIDADE NO TRABALHO

Feature-Driven Development

1) MANUAL DO INTEGRADOR Este documento, destinado aos instaladores do sistema, com informações de configuração.

Engenharia de Software. Apostila I >>> Introdução à ES - HEngholmJr

Projeto de Sistemas I

EXEMPLO: Processo para atualização da hora Processo para monitoramento da necessidade de proteção de tela. Figura Exemplo

Faculdades Santa Cruz - Inove. Plano de Aula Base: Livro - Distributed Systems Professor: Jean Louis de Oliveira.

Transcrição:

UNIVERSIDADE FEDERAL DO RIO DE JANEIRO Escola Politécnica Departamento de Eletrônica e de Computação Centro de Tecnologia, bloco H, sala H-217, Cidade Universitária. Rio de Janeiro RJ CEP 21949-900 Este exemplar é de propriedade da Universidade Federal do Rio de Janeiro, que poderá incluí-lo em base de dados, armazenar em computador, microfilmar ou adotar qualquer forma de arquivamento. É permitida a menção, reprodução parcial ou integral e a transmissão entre bibliotecas deste trabalho, sem modificação de seu texto, em qualquer meio que esteja ou venha a ser fixado, para pesquisa acadêmica, comentários e citações, desde que sem finalidade comercial e que seja feita a referência bibliográfica completa. Os conceitos expressos neste trabalho são de responsabilidade do autor e do orientador. 1

Magalhães, Pedro da Silveira Framework de ETL (Extração-Transformação-Carga) utilizando processamento em paralelo por técnica de pipeline / Pedro da Silveira Magalhães Rio de Janeiro: UFRJ/POLI- COPPE, 2013. XI, 42 p.: il.; 29,7 cm. Orientador: Antônio Cláudio Gómez de Sousa Projeto (graduação) UFRJ/POLI/Departamento de Eletrônica e de Computação COPPE, 2013. Referências Bibliográficas: p. 40-42. 1. [Extração]. 2. [Transformação]. 3. [Carga]. 4. [ETL]. I. de Souza, Antônio Cláudio Gómez. II. Universidade Federal do Rio de Janeiro, Poli/COPPE. III. Título. 2

DEDICATÓRIA graduação. Dedico este trabalho a minha família que esteve presente em toda minha 3

AGRADECIMENTO Agradeço ao professor Antônio Cláudio Gomez por ter me orientado durante o Projeto de Graduação. Agradeço também a empresa Stone Age por ter me dado a liberdade de muitas vezes abdicar do trabalho colocando sempre a formação do profissional a frente. 4

RESUMO Projeto de Graduação apresentado à Escola Politécnica/COPPE/UFRJ como parte dos requisitos necessários para a obtenção do grau de Engenheiro de Computação e Informação. FRAMEWORK DE ETL (EXTRAÇÃO-TRANSFORMAÇÃO-CARGA) UTILIZANDO PROCESSAMENTO PARALELO POR TÉCNICA DE PIPELINE. Pedro da Silveira Magalhães Março/2013 Orientador: Antônio Cláudio Gómez de Sousa Curso: Engenharia de Computação e Informação Um ciclo de ETL (extract, transform e load), refere-se a um processo no domínio de banco de dados muito utilizado em sistemas de Data Warehouse. Esse ciclo envolve três etapas distintas: a extração de dados de fontes, transformação dos dados e a carga no sistema alvo. Um ciclo ETL pode ser consideravelmente complexo e problemas podem ocorrer quando esses processos são modelados de maneira incorreta. Na maioria das vezes os dados advindos do sistema transacional são de baixa qualidade, apresentando problemas como: domínio de dados mal definidos, erros de digitação, heterogeneidade das fontes de dados envolvidas, etc. Para lidar com esses desafios e complexidade, as empresas estão cada vez mais investindo em ferramentas de ETL, ao invés de criar seus processos a partir do zero. Ao utilizar um ferramental de apoio, as chances de sucesso aumentam, pois permitem auto documentação, visualização do fluxo de dados, reutilização de componentes, design estruturado e padronizado, desempenho e consequentemente maior produtividade e qualidade. O objetivo do projeto é criar um framework capaz de apoiar o processo de construção/execução de um ciclo ETL entregando os benefícios anteriormente citados. 5

Palavras-Chave: Extração, Transformação, Carga, Data Warehouse, ETL 6

ABSTRACT Undergraduate Project presented to POLI/COPPE/UFRJ as a partial fulfillment of requirements for the degree of Computer and Information Engineer. ETL Framework using parallel processing by pipeline technique. Pedro da Silveira Magalhães March/2013 Advisor: Antônio Cláudio Gómez de Sousa Course: Computer and Information Engineering ETL cycle (extraction, transform and load), refers to a process in the context of database systems widely used in the Data Warehouse. This cycle involves three distinct steps: data sources extraction, data transformation and load on the target system. ETL cycle can be considerably complex and problems may occur when these processes are modeled incorrectly. Most often the data from the transactional system are of low quality, presenting problems as: the data poorly defined, typing errors, heterogeneity of data sources involved, etc.. To deal with these challenges and complexity, companies are increasingly investing in ETL tools instead of creating their processes from scratch. When using supporting tools, the chances of success increase because they allow self documentation, visualization of data flow, component reuse, structured and standardized design, better performance, higher productivity and quality. The project goal is to create a framework able to support the process of building / running ETL cycle delivering the benefits mentioned above. Keywords: extract, transform, Data Warehouse, ETL. 7

SIGLAS ETL: Extract, Transform, Load XML: extensible Markup Language IDE: Integrated Development Enviroment CSV: Comma Separate Value HTML: HyperText Markup Language ODS: Operational Data Store MDM: Master Data Management XSD: XML Schema Definition 8

Sumário Sumário... 9 Capítulo 1: Introdução...10 1.1. Contextualização... 10 1.2. Motivação... 10 1.3. Objetivo... 11 1.4. Metodologia... 12 1.5. Estrutura do documento... 12 Capítulo 2: Ciclo ETL...14 2.1. Introdução... 14 1.6. Extract (Extração)... 14 1.7. Transform (Transformação)... 14 1.8. Load (Carga)... 15 1.9. Exemplo prático Duas Abordagens... 15 Capítulo 3: Extreme DataStream...18 1.10. Introdução... 18 1.11. Fluxo de Dados... 19 1.12. Metadados Layout... 22 1.13. Nós de Processamento... 24 1.14. Arestas... 27 Capítulo 4: Implementação...28 1.15. Visão geral... 28 1.16. Padrões de Projeto... 28 1.17. Diagrama de Classes... 29 1.18. O problema Produtor-Consumidor... 34 1.19. Criando Novos Nós de Processamento... 38 Capítulo 5: Exemplo de Uso Paralelismo...40 1.20. Introdução... 40 1.21. O Problema... 40 1.22. Hardware Utilizado... 40 1.23. Grafos Utilizados... 41 1.24. Resultados... 43 1.25. Conclusões... 45 Capítulo 6: Conclusões e Lições Aprendidas...47 Referências...49 9

Capítulo 1: Introdução 1.1. Contextualização Falar que a análise de dados é de suma importância para as empresas é um eufemismo. De fato, nenhum negócio pode sobreviver sem analisar os dados disponíveis. Podemos mostrar situações como: analisar a aceitação de um suco de frutas baseando-se em dados de vendas históricos, verificar sazonalidade de vendas de determinado produto, prever fraudes em cartões de crédito baseando-se no comportamento passado do cliente, encontrar correlações entre eventos (Ex.: temporada de furacões e venda de produtos não perecíveis). Todas essas situações são indicativos suficientes para concluir que a análise de dados está à frente de qualquer negócio. Assim, esta pode ser definida como o processo de inspecionar, higienizar, transformar e modelar os dados com o objetivo de retirar informação, conclusões e ajudar no processo decisório de uma empresa. 1.2. Motivação Atualmente os dados estão presentes em vários meios digitais como bases de dados de transações, posts do Facebook, Twitter, redes de sensores, logs de transações, mensagens de texto, e-mail e etc. Tendo em vista que os dados já estão presentes e na maioria das vezes digitalizados, o grande desafio se dá na disponibilização/processamento/armazenamento desse dado para o usuário final, seja ele outro sistema ou um indivíduo. Essa informação apresenta três tipos de caraterísticas: possuem grandes volumes, da ordem de bilhões de registros, possuem velocidades diferentes (eventos ocorrendo em diferentes janelas de tempo, como taxa de amostragem de um sensor, compras em sites da internet e posts de redes sociais.) e possuem com grande variedade de fontes de dados. Esses 3Vs (volume, variedade e velocidade) descrevem, segundo Gartner, que é a consultoria líder em pesquisa de tecnologia da informação no mundo, o conceito de Big Data. 10

1.3. Objetivo Dado o cenário anteriormente explicitado, temos a convicção que a análise de dados pode ser uma área bem complexa. Ela possui diversas facetas, técnicas, apoiados por diversos nomes, em diferentes negócios. A mineração de dados pode ser entendida como a técnica que foca na modelagem e descoberta de conhecimento para realizar predições. A parte de Inteligência de Negócios cobre a análise de dados utilizando informações do negócio, utilizando consultas agregadas e respondendo a perguntas descritivas do tipo On-line Analytical Processing (OLAP). Por exemplo, quantas escovas de dente foram vendidas entre abril e maio no estado do RJ. A análise preditiva foca na aplicação de modelos para realizar previsões. Por exemplo, baseado em um histórico de transações bancárias, qual a probabilidade de uma determinada transação ser fraudulenta ou não. Todas as análises acima citadas partem do pressuposto de que já foi realizado um prévio tratamento nos dados. Que estes já foram higienizados, estruturados, padronizados e transformados. A esse ciclo damos o nome de Extract, Transform and Load (ETL). O ciclo de ETL envolve a extração dos dados de diversas fontes, a transformação do dado (padronização, higienização, junção de diversas fontes, etc) e a carga no sistema alvo, normalmente um banco de dados. O ciclo de ETL pode envolver uma considerável complexidade, e grandes problemas operacionais podem ocorrer caso seja mal modelado. Por ser um processo de natureza complexa, o ciclo ETL é normalmente apoiado por ferramentas de mercado. Essas ferramentas trazem algumas vantagens em relação ao processo normal, onde o desenvolvedor cria aplicações para realizar a extração/transformação/carga dos dados. São elas: auto documentação (permitem a visualização do fluxo de dados graficamente), reutilização de componentes, design estruturado e padronizado, melhor desempenho (paralelismo) e consequente aumento de produtividade e qualidade do processo. Assim, o objetivo deste projeto é criar um framework capaz de apoiar o processo de construção/execução de um ciclo ETL oferecendo os benefícios anteriormente citados. Esse framework possibilitará a paralelização de processos e utilizará a técnica de pipeline para prover ganhos de desempenho sobre a metodologia tradicional. 11

1.4. Metodologia Para o desenvolvimento do nosso projeto adotamos o modelo de desenvolvimento de software sequencial, conhecido como modelo em cascata. Escolhemos esse modelo, pois partimos de requisitos e fases bem definidas, pois já existem ferramentas parecidas como a que vamos construir. Assim nosso projeto ficou constituído em cinco fases: Levantamento de requisitos, Projeto do Sistema, Construção, Integração. Durante a construção realizamos testes unitários e de integração em componentes críticos do sistema. Ao final, foram realizamos testes de validação para verificar aderência com os requisitos. Como se trata de um framework que deve ser extensível, tentamos criar nossas classes bem desacopladas e com alto grau de coesão. Para isso, fizemos usos de alguns padrões de projeto como: Fábrica Abstrata (Abstract Factory) e Singleton. Por ser extensível, considerá-lo-emos como um framework caixa-cinza, ou seja, já possui componentes e funcionalidades prontas, porém é permitido a partir da extensão e inserção de novas classes, a criação de novos componentes e funcionalidades. Mostraremos como estendê-lo na seção Criando Novos Nós de Processamento Utilizamos a linguagem Object Pascal, que é uma extensão da linguagem Pascal com suporte a Orientação a Objeto, para o desenvolvimento do nosso framework. A IDE utilizada foi a Borland Delphi Enterprise 7. 1.5. Estrutura do documento Esse projeto de final de graduação está dividido em seis capítulos: - Introdução: começamos o capítulo contextualizando e mostrando ao leitor em que área da Engenharia de Computação estamos abordando. Em seguida, descreveremos qual a motivação do projeto e os objetivos que queremos alcançar. Descreveremos as ferramentas e o modelo de ciclo de vida que iremos utilizar. - Ciclo ETL: nesse capítulo situaremos o leito no que se refere a um ciclo ETL. 12

Descreveremos cada uma das etapas do ciclo (Extração/Transformação/Carga) e daremos alguns exemplos. Ao final mostraremos duas abordagens de criação de um ciclo ETL e listaremos suas vantagens e desvantagens. - Extreme DataStream: descreveremos para o leitor o principal componente do framework. Definiremos alguns conceitos pertinentes as projeto como fluxo de dados, metadados, nós de processamento e arestas. Mostraremos como definir esses conceitos em nossa abstração de grafo utilizando uma estrutura XML. - Implementação: mostraremos nesse capítulo artefatos como diagramas de classe, diagrama de sequência. No nível de código fonte mostraremos quais padrões de projeto utilizamos. Definiremos o problema de produtor-consumidor e como ele se adequa em nossa necessidade. Por fim, mostraremos como é possível estender o framework para a criação de novos nós de processamento. - Exemplo de Uso Paralelismo: partiremos para um caso de uso onde mostraremos a capacidade de paralelizar um determinado ciclo ETL, descreveremos o problema e o hardware utilizado. Mostraremos quatro versões de grafos e analisaremos a execução dos mesmo, mostrando os resultado e as conclusões. - Conclusões e Lições Aprendidas: nesse capítulo faremos um apanhado geral sobre o projeto. O que aprendemos, quais pontos altos e baixos, erros e acertos durante o projeto e das ferramentas escolhidas. 13

Capítulo 2: Ciclo ETL 2.1. Introdução Um ciclo de ETL (Extract, Transform e Load), refere-se a um processo no domínio de banco de dados muito utilizado para realizar carga em sistemas de Data Warehouse, Operational Data Store (ODS) e Datamarts. Também é vastamente utilizado na área de integração de dados, migração de dados e Master Data Management (MDM). Este ciclo envolve três etapas distintas: extração, transformação e carga. 1.6. Extract (Extração) A primeira parte de um ciclo ETL envolve extrair dados de sistemas fontes. Esses sistemas podem ser bem heterogêneas, com dados em diversos formatos, e devem ser consolidados para realizar a carga no Data Warehouse. Alguns formatos comuns de dados incluem: banco de dados relacionais e arquivos planos, como arquivo CSV, XML, HTML e etc. Outra maneira de realizar o processo de ETL é a utilizando dados online, ou seja, conforme os dados vão chegando através de um fluxo de dados, são tratados, transformados e carregados no sistema alvo. Uma etapa intrínseca à extração se refere a tratar somente dados em formatos esperados e descartar dados de fontes desconhecidos. Ou seja, os dados advindos dos sistemas fonte devem estar em um padrão ou estrutura previamente conhecidos. 1.7. Transform (Transformação) Nessa fase é aplicadas uma série de regras e funções sobre os dados vindos da etapa de extração para transformá-los em entradas para o processo de carga. Alguns processos desta fase são: 1. Ordenação de um arquivo por uma determinada chave. 2. Selecionar somente algumas informações. Por exemplo, se o arquivo fonte tiver três tipos de informações (nome, idade e nacionalidade) e queremos utilizar somente nome e 14

idade. 3. Padronização: como os arquivos podem vir de diversas fontes, podemos ter atributos que representam a mesma informação, mas com dados diferentes. Exemplo: Em um arquivo podemos ter masculino igual à 1 e feminino igual 2 e em outro Masculino igual a M e Feminino igual a F. 4. Derivação de um novo cálculo. Por exemplo, valor_venda = quantidade*preco_unitario. 5. Junção de múltiplas fontes de dados por chaves de junção. Podemos também efetuar duplicação de registros. Podemos agregar registros para formar um dado estatístico. Por exemplo, sumarizar múltiplas linhas de um arquivo de transações para ter o total de vendas por loja, total de vendas por região, etc. 6. Transpor o arquivo original, isto é, linhas viram colunas e colunas viram linhas. 7. Dividir um arquivo CSV em arquivos separados, um para cada coluna 8. Validar e buscar dados em tabelas ou arquivos de referência. 9. Aplicar qualquer tipo de validação simples ou complexa no dado. Por exemplo, validar se um determinado campo apresenta uma data válida. Caso haja alguma exceção poderá haver rejeição parcial ou completa. 1.8. Load (Carga) A fase de carga é o momento em que os dados advindos da etapa anterior são carregados no sistema alvo, que normalmente é um Data Warehouse. Essas cargas, em sua maioria, são realizadas periodicamente (diariamente, semanalmente ou mensalmente). Isso ocorre, porque o DW é usualmente utilizado para guardar informações históricas. Conforme os dados são carregados no sistema, o banco de dados é responsável por tratar as condições de integridade dos dados que estão sendo inseridos, como por exemplo, realizar uma validação de data, disparar uma trigger para atualizar outra tabela, tratar a unicidade de um dado. 1.9. Exemplo prático Duas Abordagens O ciclo de ETL pode envolver uma grande complexidade e problemas podem ocorrer caso este seja mal modelado. Descreveremos sucintamente um exemplo de ciclo ETL e mostraremos duas abordagens para sua construção. Em seguida, mostraremos 15

suas vantagens e desvantagens. Figura 1 - Representação de um ciclo ETL, utilizando um grafo. Acima apresentamos um ciclo ETL, descrito como um grafo. Clientes.txt e Itens.txt: arquivos de entrada do ciclo ETL. Leitor de arquivos: realizar leitura dos arquivos de entrada. Consulta Receita: processo responsável por realizar uma consulta à Receita Federal, utilizando CPF como chave e trazendo o nome da pessoa. Cálculo da Nota Fiscal: A partir dos itens, o processo calcula a nota fiscal. Ordenação: realiza a ordenação dos arquivos, um pela chave fkcliente e outra pela chave pkcliente. Junção: realiza a junção dos arquivos vindos das arestas nove e onze, utilizando as chaves fkcliente e pkcliente. Escritor de Arquivos: realizar a escrita do arquivo final em disco. Arquivo de Saída: arquivo final do processo. Abordagem Monolítica: Nessa abordagem todo o ciclo ETL é criado a partir do zero, e todas as transformações dos dados são realizadas através um único programa, seja ele um executável ou um script. Imagine o ciclo completo ETL descrito acima sendo executado apenas por uma aplicação. Teríamos um total acoplamento, uma baixa coesão e sem possibilidade de reutilização dos componentes (dependendo da modelagem essa reutilização pode ser dá em nível de código fonte apenas). Toda manutenção/evolução seria feita em apenas um componente, o que acarretaria possíveis novos erros de difícil rastreabilidade. 16

Abordagem um módulo por nó de processamento: Nessa abordagem temos um executável/script por nó de processamento, onde um nó X possui como entrada o arquivo A1 e uma saída A2. A saída do nó X será a entrada para o nó Y. Assim o ciclo segue, onde a saída de um nó de processamento é entrada para outro. Nessa abordagem, todos os nós de processamento devem possuir uma maneira de ler/escrever no disco já que esta é à maneira de comunicação entre eles. Para a descrição das vantagens e desvantagens entre as duas abordagens chamaremos a monolítica, de abordagem A, e a outra de abordagem B. Na abordagem A temos a vantagem em relação a B de realizarmos menos E/S no disco. Isso acarreta um ganho de desempenho por não utilizar um dos recursos mais lentos do computador, que é o acesso ao disco físico. Em contrapartida, na abordagem B podemos paralelizar o ciclo ETL, ou seja, utilizar melhor os recursos de CPU em detrimento do E/S. Em um ciclo ETL do tipo CPU bound, onde o maior tempo é gasto utilizando a CPU, o ciclo B tende a possuir um melhor desempenho em relação ao A, pois realiza um melhor uso dos recursos conseguindo paralelizar as tarefas. No exemplo acima, utilizando a abordagem B, poderíamos executar os nós de processamento Leitor de Arquivos, Cálculo da Nota Fiscal e Ordenação por fkcliente concorrentemente com Leitor de Arquivos, Consulta a Receita, Valida Node e Ordenação por pkcliente. Na abordagem A temos baixíssima reutilização apenas em nível de código fonte. Na abordagem B, os nós de processamento são módulos separados e podemos intercambiá-los para criar novos ciclos ETL. Apresentaremos nas próximas seções nossa abordagem para a criação do ciclo ETL, e tentaremos unir o melhor das duas abordagens anteriormente citadas, ou seja, um ganho de produtividade por reutilização de nós de processamento sem perda de desempenho. 17

Capítulo 3: Extreme DataStream 1.10. Introdução Ferramentas de ETL são construídas para poupar esforço (tempo e dinheiro) eliminando, quase em sua totalidade, a escrita de código. Dentre algumas vantagens podemos citar: auto documentação (permitem a visualização do fluxo de dados graficamente), reutilização de componentes, design estruturado e padronizado, melhor desempenho (paralelismo). Nessas ferramentas podemos modelar o ciclo ETL utilizando a abstração de um grafo, onde as arestas representam os dados fluindo de um processo para o outro, e os vértices representam os nós de processamento. Podemos utilizar como exemplo a figura já citada na seção anterior. O objetivo do framework Extreme DataStream é permitir a execução de um fluxo ETL, além de prover uma biblioteca onde novos nós podem ser incorporados ao sistema de maneira simples. Não será desenvolvido nenhum tipo de interface gráfica para a criação do fluxo ETL. Utilizaremos um arquivo XML para a descrição do fluxo em si. Quando falarmos de nós, vértices ou blocos, estaremos nos referindo a nós de processamento, ou seja, estruturas que realizam efetivamente o processo dos dados. Quanto falarmos em arestas, estaremos no referindo ao o fluxo de dados flui através dos nós de processamento, como os nós de processamento são interligados. Conforme visto, nas duas abordagens anteriores, temos vantagens e desvantagens. Abaixo citamos as resumidamente: Abordagem Monolítica (Abordagem A) - Vantagens: Menor quantidade de E/S no disco rígido em relação à abordagem B, acarretando melhor desempenho. - Desvantagens: Baixa reutilização, apenas em nível de código fonte. Abordagem um módulo por nó de processamento (Abordagem B) - Vantagens: Alta reutilização em nível de componentes. Possibilidade de paralelizar o processo. - Desvantagens: Baixo desempenho, pois os nós se comunicam através de 18

arquivos, ou seja, o arquivo gerado por um nó é entrada para o próximo nó. Em nosso framework, tentaremos unir o melhor das duas abordagens, ou seja, um alto desempenho com possibilidade de paralelismo, sem a necessidade de criação de arquivos intermediários entre os processos e reutilização em nível de componentes. Para não haver necessidade da criação de arquivos intermediários, utilizaremos a memória RAM da máquina, ou seja, cada nó de processamento será uma unidade autônoma provendo/consumindo dados de um buffer. Em alguns nós poderá haver a necessidade de criação de arquivos temporários, como por exemplo, uma ordenação de um arquivo que não cabe fisicamente na memória. Fica claramente evidenciado que temos um problema clássico de produtor-consumidor, que será abordado nas próximas seções. Resolvendo esse problema, estaremos retirando a única desvantagem da abordagem B, e permanecendo com todas as suas vantagens. Claro que, neste momento, não estamos levando em consideração o tempo gasto na sincronização entre os processos/threads. O desenvolvedor do ciclo ETL deverá descrever seu grafo utilizando um arquivo XML, em um formato específico, que será descrito na próxima seção. Não é intuito desse Projeto de Graduação, criar uma ferramenta de apoio para a criação desse grafo. 1.11. Fluxo de Dados Para descrever nosso grafo do ciclo ETL utilizaremos um documento em formato XML. Para garantirmos que esse documento esteja corretamente formatado, a ferramenta utilizará um XML Schema. Um arquivo que contenha as definições da linguagem XML Schema é chamado de XML Schema Definition (XSD), o qual descreve a estrutura de um documento XML. Essa linguagem foi amplamente utilizada no desenvolvimento da nota fiscal eletrônica brasileira. Abaixo demonstramos o conteúdo do XSD. Explicaremos em detalhes cada uma das seções desse documento nas próximas seções. <?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/xmlschema" elementformdefault="qualified" attributeformdefault="unqualified"> <xs:element name="etlmanager" type="etl_manager_type"></xs:element> 19

<xs:complextype name="etl_manager_type"> <xs:sequence> <xs:element name="metadatas" type="metadata_list"/> <xs:element name="phases" type="phase_list"/> </xs:sequence> </xs:complextype> <xs:complextype name="metadata_list"> <xs:sequence> <xs:element name="metadata" type="metadata_type" minoccurs="1" maxoccurs="unbounded" /> </xs:sequence> </xs:complextype> <xs:complextype name="metadata_type"> <xs:sequence> <xs:element name="field" type="field_type" minoccurs="1" maxoccurs="unbounded"/> </xs:sequence> <xs:attribute name="id" type="xs:string" use="required"/> <xs:attribute name="memory" type="xs:integer" use="required"/> </xs:complextype> <xs:complextype name="field_type"> <xs:simplecontent> <xs:extension base="xs:string"> <xs:attribute name="type" type="field_enum" use="required"/> <xs:attribute name="size" type="xs:integer" use="required"/> <xs:attribute name="initialpos" type="xs:integer" use="required"/> </xs:extension> </xs:simplecontent> </xs:complextype> <xs:simpletype name="field_enum"> <xs:restriction base="xs:string"> <xs:enumeration value="string"/> <xs:enumeration value="integer"/> <xs:enumeration value="byte"/> <xs:enumeration value="longint"/> 20

</xs:restriction> </xs:simpletype> <xs:complextype name="phase_list"> <xs:sequence> <xs:element name="phase" type="phase_type" minoccurs="1" maxoccurs="unbounded" /> </xs:sequence> </xs:complextype> <xs:complextype name="phase_type"> <xs:sequence> <xs:element name="edges" type="edge_list"/> <xs:element name="processes" type="process_list"/> </xs:sequence> <xs:attribute name="id" type="xs:integer" use="required"/> </xs:complextype> <xs:complextype name="edge_list"> <xs:sequence> <xs:element name="edge" type="edge_type" minoccurs="1" maxoccurs="unbounded" /> </xs:sequence> </xs:complextype> <xs:complextype name="process_list"> <xs:sequence> <xs:element name="process" type="process_type" minoccurs="1" maxoccurs="unbounded" /> </xs:sequence> </xs:complextype> <xs:complextype name="process_type"> <xs:sequence> <xs:any maxoccurs="unbounded" processcontents="skip"/> </xs:sequence> <xs:attribute name="id" type="xs:string" use="required"/> <xs:attribute name="type" type="xs:string" use="required"/> </xs:complextype> <xs:complextype name="edge_type"> 21

<xs:attribute name="fromprocess" type="xs:string" use="required"/> <xs:attribute name="fromport" type="xs:integer" use="required"/> <xs:attribute name="toprocess" type="xs:string" use="required"/> <xs:attribute name="toport" type="xs:integer" use="required"/> <xs:attribute name="metadata" type="xs:string" use="required"/> </xs:complextype> </xs:schema> 1.12. Metadados Layout Metadados são dados sobre outros dados. No nosso contexto, os metadados farão a descrição dos dados que trafegam entre as arestas do nosso ciclo ETL. Esses metadados serão sempre formatados como registros de tamanho fixo. Em um registro de tamanho fixo, um campo sempre começa e termina no mesmo lugar em todos os registros. Por exemplo: Pedro da Silveira Magalhaes 01000022421030RJ Jose Carlos da Silva 00900033920103SP Renata Souza 00080010103242MG Luis Felipe 00150000123242BA O conjunto de dados acima representa um arquivo onde seus registros possuem tamanho fixo. Nome Posição Inicial = 1 Posição Final = 30 Renda Posição Inicial = 30 Posição Final= 36 CEP Posição Inicial = 36 Posição Final = 44 UF Posição Inicial = 44 Posição Final = 46 Para o caso citado acima, o registro possui um tamanho de 46 bytes. Não são necessários delimitadores, pois todos os campos possuem tamanho fixo. Abaixo, descrevemos o XSD para a sessão de declaração de metadados: <xs:complextype name="metadata_type"> <xs:sequence> 22

<xs:element name="field" type="field_type" minoccurs="1" maxoccurs="unbounded"/> </xs:sequence> <xs:attribute name="id" type="xs:string" use="required"/> <xs:attribute name="memory" type="xs:integer" use="required"/> </xs:complextype> <xs:complextype name="field_type"> <xs:simplecontent> <xs:extension base="xs:string"> <xs:attribute name="type" type="field_enum" use="required"/> <xs:attribute name="size" type="xs:integer" use="required"/> <xs:attribute name="initialpos" type="xs:integer" use="required"/> </xs:extension> </xs:simplecontent> </xs:complextype> <xs:simpletype name="field_enum"> <xs:restriction base="xs:string"> <xs:enumeration value="string"/> <xs:enumeration value="integer"/> <xs:enumeration value="byte"/> <xs:enumeration value="longint"/> </xs:restriction> </xs:simpletype> Na seção metadata devemos definir um ID único para nosso metadado. Quando um dado flui de um nó para outro, esta informação deverá ser armazenada na aresta que interliga esses dois nós. O dado permanece na aresta, alocado na memória RAM do computador, e o tamanho do buffer de alocação é configurado através da tag memory. Em outros termos, a tag memory define o tamanho máximo da fila no problema produtor-consumidor. Destacamos uma seção apenas para descrever o processo de produtor-consumidor. Na seção field descrevemos informações sobre o campo do registro de 23

tamanho fixo. Para isso temos os seguintes atributos: - type: representa um tipo enumerado que define o tipo de dado no campo. Pode ser string, integer, byte ou um longint. Apesar de termos listados todos esses tipos de campos, somente está implementado na solução o campo do tipo string. - initialpos: define onde o campo começa dentro do registro de tamanho fixo. - size: define o tamanho do campo. Destacamos abaixo um exemplo de um metadado definido: <metadata id="metadata0" memory="40000"> <field type="string" size="2" initialpos="0">valor</field> <field type="string" size="2" initialpos="2">crlf</field> </metadata> 1.13. Nós de Processamento São as estruturas que efetivamente realizam o trabalho sobre os dados. O intuito do projeto não é prover os mais variados tipos de transformações sobre os dados, e sim uma maneira simples para o desenvolvedor criar os seus próprios nós de processamento. A criação de nós bem coesos e flexíveis garante ao desenvolvedor do fluxo de ETL uma maior reutilização dos blocos já criados. Alguns exemplos de nós de processamento são: - nó capaz de realizar a ordenação de um arquivo a partir de uma chave. - nó capaz de retirar a duplicidade de registros, utilizando a escolha de uma chave única. - nó capaz de realizar a junção de dois fluxos de dados utilizando uma chave de junção. - nó capaz de filtrar os registros de um fluxo de dados utilizando uma expressão lógica / matemática. Os nós de processamento possuem como entrada fluxos de dados. Esses fluxos de dados pode se originar de qualquer recurso do sistema, seja um disco físico, a própria memória RAM ou uma interface de rede, bastando para isso criar nós específicos. Abaixo descrevemos o XSD somente da seção de criação de nós de processamento. <xs:complextype name="process_list"> <xs:sequence> <xs:element name="process" type="process_type" minoccurs="1" 24

maxoccurs="unbounded" /> </xs:sequence> </xs:complextype> <xs:complextype name="process_type"> <xs:sequence> <xs:any maxoccurs="unbounded" processcontents="skip"/> </xs:sequence> <xs:attribute name="id" type="xs:string" use="required"/> <xs:attribute name="type" type="xs:string" use="required"/> </xs:complextype> Na seção process definimos um nó de processamento que fará parte do nosso ciclo ETL. Esses nós devem conter sempre o atributo id e o atributo type. O id define unicamente um processo dentro do ciclo, enquanto o type define o tipo do processo. Para executar nossos exemplos criamos apenas três tipos de processos, que são eles FileReader, FileWriter e Factorial. - FileReader Nó responsável pela leitura de um arquivo texto de tamanho fixo. Exemplo: <process id="filereader0" type="filereader"> <recordsize>4</recordsize> <filepath>d:\projetos\factorial.txt</filepath> </process> O tamanho do registro do arquivo é indicado pela tag recordsize. O caminho do arquivo é indicado pela tag filepath. Esse leitor possui a capacidade de ler partes segmentadas do arquivo de entrada, dependendo da quantidade de arestas de saída ligadas a ele. Considere o trecho de ciclo ETL abaixo, onde o FileReader aparece lendo como entrada o arquivo Numeros.txt e ligado a três processos que são responsáveis por realizar um cálculo de score. 25

Figura 2 - Exemplo de Utilização do FileReader para realizar paralelismo Assim o nó FileReader se comportará da seguinte maneira: ele entregará blocos de registros aos nós conectados a ele, utilizando uma política de round-robin. Dessa maneira, conseguiremos paralelizar o cálculo do score, onde cada um dos nós CalculaScore executará sua tarefa em um processador. Mais a frente mostraremos um exemplo prático e os resultados obtidos com esse paralelismo. - FileWritter Nó responsável pela escrita dos dados em disco. Análogo ao FileReader, esse escritor de arquivos possui a capacidade de receber N fluxos de dados, ou seja, podemos conectar quantas arestas quisermos em um nó do tipo FileWriter. Cada uma dessas arestas será conectada a uma porta diferente. Assim o FileWriter lerá cada fluxo de dados utilizando um política de round-roubin e escrevendo o resultado em arquivo físico, diretamente no disco rígido. Exemplo: <process id="filewriter0" type="filewriter"> <filepath>d:\factorial_out.txt</filepath> </process> O caminho do arquivo de saída, o qual será efetivamente gravado em disco, é indicado pela tag filepath. - Factorial Nó responsável pelo cálculo do fatorial de um número. Esse nó, por ser muito específico, provavelmente não apresenta nenhuma utilização prática. Ele foi apenas criado para demostrar a capacidade da ferramenta de realizar tarefas em paralelo. Exemplo: 26

<process id="factorial1" type="factorial"> <factorialfield>valor</factorialfield> </process> A tag factorialfield indica qual campo deverá ser calculado o fatorial. 1.14. Arestas Quando ligamos um nó de processamento a outro, criamos uma aresta. Os dados que trafegam de um nó pra outro ficam temporariamente armazenados na aresta, em um buffer na memória RAM da máquina. Abaixo descrevemos o XSD somente da seção de criação de nós de processamento. <xs:complextype name="edge_type"> <xs:atribute name="fromprocess" type="xs:string" use="required"/> <xs:attribute name="fromport" type="xs:integer" use="required"/> <xs:attribute name="toprocess" type="xs:string" use="required"/> <xs:attribute name="toport" type="xs:integer" use="required"/> <xs:attribute name="metadata" type="xs:string" use="required"/> </xs:complextype> A tag fromprocess e fromport indica de qual nó/porta parte a aresta. A tag toprocess e toport indica em qual nó/porta a aresta chega. Assim para definir uma aresta, ou seja, de onde ela parte até onde ela chega, devemos defini-la com duas tuplas: (fromprocess, fromport) e (toprocess e toport). A tag metadata indica o formato dos dados que trafegam na aresta. Abaixo segue um exemplo de definição de duas arestas. <edges> <edge fromprocess="filereader0" fromport="0" toprocess="factorial1" toport="0" metadata="metadata0"/> <edge fromprocess="factorial1" fromport="0" toprocess="filewriter0" toport="0" metadata="metadata1"/> </edges> 27

Capítulo 4: Implementação 1.15. Visão geral Para modelar nosso framework partimos dos conceitos chaves como: porta, processo, aresta e fases. Modelamos seus relacionamos através de um modelo conceitual que em seguida deu entrada no nosso diagrama de classes. Utilizamos o diagrama de sequência apenas para descrever o problema de Produtor-Consumidor. Utilizando o diagrama de classes, fica claro como deve ser feita a extensão do código para a criação de novos componentes. Na seção Criando Novos Nós de Processamento será mostrado como estender o framework para a criação de novos componentes. 1.16. Padrões de Projeto Descreve uma solução geral que pode ser utilizada para um problema recorrente no desenvolvimento de software orientado a objetos. Assim os padrões de projeto definem relações e interações entre as classes/objetos em um nível de abstração mais alto. Os padrões de projeto têm como objetivo facilitar as reutilizações de soluções e estabelecer um vocabulário comum facilitando documentação e o entendimento do código gerado. Em nossa implementação utilizamos dois padrões de projeto: * Factory (Fábrica) Objetivo - Criar um objeto sem expor a lógica de instanciação ao cliente - Criação de um novo objeto através de uma interface comum Utilização - Cliente necessita de um produto, mas ao invés de criá-lo diretamente, ele pede à fábrica por um novo produto, provendo a informação sobre o tipo de objeto que ele precisa. 28

- A fábrica instancia um novo produto concreto e retorna ao cliente o objeto recentemente criado. - O cliente utiliza o objeto como um produto abstrato sem se preocupar com sua implementação concreta. Vantagem - Conseguir adicionar um novo produto sem alterar a interface de criação, alterando apenas a fábrica. Existem certas implementações de fábrica que permite a inclusão de novos tipos concretos sem alterar a fábrica. * Singleton Às vezes é importante termos apenas uma instância da classe. Usualmente singletons são utilizadas para centralizar o gerenciamento de recursos internos ou externos provendo um ponto global de acesso. Objetivo - Garantir que apenas uma instância da classe será criada - Prover um ponto de acesso global ao objeto Figura 3 - Modelo de classes do padrão Singleton Utilização O padrão Singleton define a operação getinstance, a qual expõe uma única instância a ser acessada pelos clientes. O método getinstance é responsável por criar uma única instância da classe caso ela ainda não tenha sido criado e retorná-la. 1.17. Diagrama de Classes 29

Figura 4 - Diagrama de Classes (Visão de Processos) A classe TProcessFactory, juntamente com a classe abstrata TProcess, representa a implementação do padrão de projeto Fábrica. Esta Fábrica (TProcessFactory) é responsável pela criação dos nós de processamento do sistema. Cada nó de processamento é executado em threads separadas, por isso a classe TProcess é filha da classe Thread. Para criação de um novo nó devemos passar a sua descrição representada pela classe TProcessDescription. Cada processo possui uma lista de portas de saídas e entradas, representadas respectivamente, pelas classes TInputCollection e TOutputCollection. Estas duas classes utilizam outra Fábrica (TPortFactory) que é responsável pela criação da porta de comunicação. 30

Figura 5 - Diagrama de Classes (Visão Comunicação entre Processos) A classe TPortFactory juntamente com a classe TPortDescription implementa novamente o padrão Fábrica. Essa fábrica é responsável pela criação tanto de portas de saída (classe abstrata TOutput) como portas de entrada (classe abstrata TInput). 31

As classes TFixedRecordOutput e TFixedRecordInput representam as portas de saída e entrada respectivamente, que tratam os registros de tamanho fixo. Essas duas classes utilizam a classe TDataPacket (sua dependência se dá pela classe TPort que é pai das classes TInput e TOutput e possuí um atributo do tipo TDataPacket) que abstrai um ResultSet (um conjunto de registros). Esta classe é onde os dados são armazenados para posterior escrita deles no buffer de transferência. Figura 6 - Diagrama de Classes (Visão Comunicação entre Processos - Classes Abstratas) A classe TEdge abstrai a aresta que liga duas portas de nós de processamento. Nessa classe se encontra o buffer responsável pelo armazenamento do TDataPacket. O método Write da classe TOutput escreve dados para a classe TDataPacket. Assim que o buffer do TDatapacket está cheio, ele é escrito no TBuffer, utilizando o método Write. A parte de leitura é análoga. Na seção Diagrama de Sequência descreveremos essa interação. 32

Figura 7 - Diagrama de Classes (Visão Metadados) A estrutura de classes acima é responsável pela leitura do XML que define o grafo. Temos como classe raiz, a classe TETLGraphXML que é implementada utilizando o padrão de projeto Singleton. Tomamos essa decisão por precisar de um ponto único de acesso à abstração do grafo. 33

Figura 8 - Diagrama de Classes (Visão Controlador do Grafo) A classe TGraphManager é interface para gerenciamento da execução do grafo. Ao criarmos a TPhase, criaremos todos os processes dessa fase. Para isso, utilizei novamente o padrão de projeto fábrica, representado pelas classes TProcessFactory e TProcess. A classe TPhase possui o método Launch(), que quando chamado executa a fase do grafo. Cada processo e fase é executado em threads separada. Além destas threads, temos a classe TWacthDogThread que verifica de tempos em tempos o estado de execução dos processos. 1.18. O problema Produtor-Consumidor O problema de produtor-consumidor é um exemplo clássico de sincronização. Ele estabelece os processos concorrentes que compartilham uma área de escrita/leitura. 34

O produtor é responsável por gerar os dados que serão disponibilizados na área de leitura/escrita. Concorrentemente, o consumidor estará lendo e removendo os dados dessa área. O problema é ter certeza que o produtor não tentará adicionar dados na área de leitura/escrita quando estiver cheia,e que o consumidor não tentará remover dados quando a área estiver vazia. Assim, quando temos a área de escrita/leitura cheia o produtor deve esperar até que haja espaço. O mesmo ocorre para o consumidor que deve esperar até que exista alguma informação na área para ser consumida. Assim que o produtor coloca dados na área de leitura/escrita ele avisa o consumidor, para ele iniciar o processamento. Quando o consumidor retira dados da área ele avisa ao produtor. Essa solução é atingida através de uma comunicação entre processos, que pode ser implementada utilizando recursos do sistema operacional como semáforos e mutexes. Abaixo mostramos uma solução retirada do Wikipédia, que é a mesma que utilizaremos ao abordar o problema em nosso projeto. Ela utiliza o recurso de semáforos para realizar a sincronização entre processos. semaphore fillcount = 0; // itens produzidos semaphore emptycount = BUFFER_SIZE; // espaço remanescente procedure producer() { while (true) { item = produceitem(); down(emptycount); putitemintobuffer(item); up(fillcount); } } procedure consumer() { while (true) { down(fillcount); item = removeitemfrombuffer(); up(emptycount); consumeitem(item); } } No contexto de nossa aplicação nos deparamos com o problema de produtor 35

consumidor no momento de trafegar os dados entres os nós de processamento. Para ilustramos o problema do produtor-consumidor no contexto de nossa aplicação utilizamos o diagrama de sequências abaixo: Figura 9 - Diagrama de sequência mostrando o problema do Produtor-Consumidor A classe TOutput é responsável pela escrita dos dados, utilizando a chamada ao método Write da classe TEdge. A classe TEdge escreve no buffer, realizando a tratativa do problema produtor-consumidor. Ela verifica se possui espaço no buffer pelo o semáforo EmptyCount. Caso haja espaço, ela realiza a escrita e notifica o outro semáforo FillCount que os dados podem ser consumidos. Caso não haja ela dorme e espera o outro processo acordá-la. 36

A classe TInput é responsável pela leitura dos dados, utilizando a chamada ao método Read da classe TEdge. Ela verifica se possui algum dados no buffer, verificando o semáforo FillCount. Caso haja dados para serem consumidos, ela realiza a leitura do dado. Caso não haja, ela dorme e espera o outro processo acordá-la. Abaixo colocamos dois trechos de código, um do método Write e outro do método Read da classe TEdge, em linguagem pascal. procedure TEdge.Write(Content: PAnsiChar; Size: integer); begin //espera ter uma unidade disponivel no semaforo WaitForSingleObject(EmptyCount, INFINITE); //move informações para o buffer ponteiro por pt Move(Size, pt^, SizeOf(Integer)); pt := pt + SizeOf(Integer); Move(Content^, pt^, Size); pt := FBuffer; //incrementa o semaforo com uma unidade ReleaseSemaphore(FillCount, 1, nil); end; function TEdge.Read(var Content: PAnsiChar; var Size: integer): boolean; begin EOF := true; WaitForSingleObject(FillCount, INFINITE); //lê o tamanho dos dados do buffer Move(pt^, Size, SizeOf(Integer)); pt := pt + SizeOf(Integer); if (Size <> -1) then begin Move(pt^, FContent^, Size); Content := FContent; EOF := false; end; //reseta ponteiro pt := FBuffer; ReleaseSemaphore(EmptyCount, 1, nil); end; 37

1.19. Criando Novos Nós de Processamento Um dos objetivos do framework é a possibilidade de estendê-lo e criar novos componentes (novos nós de processamento). Para isso montamos nossa estrutura de classes de modo que esta tarefa fosse bem simples, bastando para isso realizar a extensão de classes do framework. Para a criação de novos nós de processamento devemos estender a classe TProcess e inserir um novo tipo de nó na fábrica TProcessFactory. As informações sobre o nó, ou seja, os metadados do nó estão disponíveis através da propriedade FXMLNode herdada da classe TProcess. Para acessar as portas de entrada e saída utilizamos as propriedades FInputCollection do tipo TInputCollection e FOutputCollection do tipo TOutputCollection, que são herdadas da classe TProcess. Abaixo colocamos trechos de código mostrando a inclusão do nó Fatorial type TFactorial = class(tprocess)... public procedure Run(); override; procedure TFactorial.Run;... begin while (InputPort.Read(Value)) do //le dados da porta de entrada begin move(value^, FNumberStr[1], 2); //valor a ser calculado FactorialStr := IntToStr(GetFatorial(StrToInt(FNumberStr)));... OutStr := FOutNumber + #13#10; OutPutPort.Write(Pansichar(OutStr)); //valor fatorial end InputPort.Close(); //fecha porta de entrada OutPutPort.Close(); //fecha a porta de saída end; type TProcessFactory = class... 38

class function TProcessFactory.GetProcess(ProcessDesc: TProcessDescription): TProcess; begin... if (ProcessDesc.ProcessType = 'Factorial') then begin Result := TFactorial.Create(ProcessDesc.PhaseID, ProcessDesc.ProcessID); Exit; end; end; 39

Capítulo 5: Exemplo de Uso Paralelismo 1.20. Introdução O objeto desta seção é demonstrar a utilização do framework para a execução de um processo ETL. Para demonstrar a capacidade de realizar paralelismo utilizaremos quatro tipos de grafo. Todos os grafos possuem a mesma saída, porém utilizam níveis de paralelismo diferentes. Mostraremos o ganho em paralelizar o ciclo ETL através desses exemplos. 1.21. O Problema O problema que trataremos é bastante simples e capaz de ser paralelizado. Ele consiste em calcular o fatorial de uma lista de números. Para aumentar a utilização de CPU, ao invés de calcular apenas uma vez o fatorial do número, realizaremos esse procedimento 10 vezes. - Entrada do problema (lista de números): Um arquivo texto, com 35.126.784 números inteiros, variando de 1 a 10, separador por CR+LF. Esse arquivo possui um total de 140.507.136 bytes, ou seja, 35.126.784 * 4 bytes (2 bytes representando os números e mais 2 bytes de CR+LF). - Saída Um arquivo texto, com 35.126.784 números inteiros, variando de 1 a 3.628.800, separados por CF+LF. Esse arquivo possui um total de 316.141.056 bytes, ou seja. 35.126.784 * 9 bytes (7 bytes representando o resultado do fatorial e mais 2 bytes de CR+LF). 1.22. Hardware Utilizado O objetivo do exemplo de uso é demonstrar o paralelismo e o ganho de desempenho no ciclo ETL. Nosso ciclo possui a característica de ser CPU Bound. Dado isso necessitamos descrever o processador e sua quantidade de núcleos. O processador utilizado será o Core i3 da família de processadores Intel, destinado a Desktops x86-64. Ele possui o recurso de Hyper-Threading que lhe 40

possibilita simular a existência de um maior número de núcleos, fazendo com que o seu desempenho aumente. Mais especificamente este processador possuí dois núcleos de processamento físico e dois virtuais, ou seja, ele possuí dois núcleos de processamento físico e simula mais dois. A tecnologia Hyper-Threading é uma tecnologia usada em processadores que realizam a simulação de mais dois núcleos. Essa técnica é utilizada para oferecer uma maior eficiência na utilização de recursos do processador. Segundo a Intel, o uso dessa tecnologia oferece um aumento de desempenho de até 30%. Abaixo mostramos uma imagem da janela do Gerenciador de Tarefas do Windows, demonstrando a presença de quatro núcleos de processamento: Figura 10 - Gerenciador de Tarefas do Windows. Como podemos ver o computador utilizado possui quatro processadores. 1.23. Grafos Utilizados Executaremos quatro grafos em nosso exemplo. O primeiro deles possuirá 41

apenas um nó de cálculo de fatorial, o segundo dois, e assim sucessivamente. Para exemplificar o grafo segue abaixo uma figura do grafo com um nó de processamento e outro com quatro nós de processamento. Figura 11 - Representação do grafo com apenas um nó de cálculo de fatorial <edges> <edge fromprocess="filereader0" fromport="0" toprocess="factorial1" toport="0" metadata="metadata0"/> <edge fromprocess="factorial1" fromport="0" toprocess="filewriter0" toport="0" metadata="metadata1"/> </edges> Acima apresentamos a listagem de arestas do grafo com um nó de processamento de fatorial. Figura 12 - Representação do grafo com quatro nós de cálculo de fatorial 42

<edges> <edge fromprocess="filereader0" fromport="0" toprocess="factorial1" toport="0" metadata="metadata0"/> <edge fromprocess="filereader0" fromport="1" toprocess="factorial2" toport="0" metadata="metadata0"/> <edge fromprocess="filereader0" fromport="2" toprocess="factorial3" toport="0" metadata="metadata0"/> <edge fromprocess="filereader0" fromport="3" toprocess="factorial4" toport="0" metadata="metadata0"/> <edge fromprocess="factorial1" fromport="0" toprocess="filewriter0" toport="0" metadata="metadata1"/> <edge fromprocess="factorial2" fromport="0" toprocess="filewriter0" toport="1" metadata="metadata1"/> <edge fromprocess="factorial3" fromport="0" toprocess="filewriter0" toport="2" metadata="metadata1"/> <edge fromprocess="factorial4" fromport="0" toprocess="filewriter0" toport="3" metadata="metadata1"/> </edges> Acima apresentamos um XML de exemplo com um grafo com quatro nós de processamento do cálculo do fatorial. 1.24. Resultados Realizamos a medição da execução dos grafos utilizando o aplicativo do Windows Monitor de Desempenho (perfmon.exe). - Execução do Grafo com um nó de Fatorial Consumo de CPU médio: 25,13% Tempo total: 135.532 milissegundos Figura 13 - Uso de CPU x Tempo um processador 43