Posts de September, 2008

[Tiago Motta] Cópia exclusiva de coleção

Thursday, September 18th, 2008

Por serem de díficil identificação, problemas de concorrência acabam indo pra produção sem sequer serem notado em ambiente de testes e desenvolvimento. Erros acabam ocorrendo de maneira intermitente, causando dores de cabeça e acessos de insanidade nos desenvolvedores. Martin Fowler em seu livro Patterns of Enterprise Application Architecture identifica algumas soluções para evitar problemas de concorrência relativos a integridade de dados. Contudo há um outro problema que não está catalogado neste livro: A concorrência de informações na memória.

Ao guardar objetos em uma coleção que é compartilhada por outras threads, é necessário tomar providências para que não sejam lançadas exceções inesperadas. A medida básica é garantir que os pontos de acesso às coleções compartilhadas devem obter exclusividade sobre seu uso com a diretiva synchronized. Veja abaixo um exemplo de classe que torna o uso de uma lista à prova de erros de concorrência:

public class ListaSegura {    private List lista = new ArrayList();    public void adiciona(Object objeto) {        synchronized (lista) {            lista.add(objeto);        }    }    public void remove(Object objeto) {        synchronized (lista) {            lista.remove(objeto);        }    }    public void listar() {        synchronized (lista) {            for (Object o : lista) {                System.out.println(o);            }        }    }}

É uma solução simples e que resolve em parte o problema. Contudo na maioria das vezes não podemos obter a exclusividade para iterar sobre uma coleção. No caso mostrado acima isso é possível pois estamos apenas imprimindo o objeto. Mas existem alguns casos em que obter essa exclusividade para a iteração nos traria alguns problemas. Esses casos estão descritos abaixo:

1- Alteração da coleção: No caso de você iterar pela coleção para remover ou adicionar algum objeto a ela. A exclusão ou adição ocorreria no meio da iteração e com isso seria lançada uma exceção de concorrência.Um exemplo simples disso são classes que gerenciam cache e precisam periodicamente remover objetos expirados.

2- Iteração prolongada: Quando a coleção possui objetos demais ou o processo executado durante a iteração é lento, tornando o tempo de exclusividade total muito longo. Isso faria com que o restante do sistema que precisasse utilizar essa coleção ficasse muito tempo aguardando pela exclusividade terminar. Um exemplo comum é a execução de métodos que acessem banco de dados dentro da iteração de um objeto exclusivo.

Para resolver esses dois casos identifiquei o padrão de desenvolvimento Cópia Exclusiva de Coleção. A idéia é obter a exclusividade da lista somente para fazer uma cópia dos itens em outra coleção e então poder iterar sobre esta cópia sem muitas preocupações. Abaixo mostro um exemplo de uma classe Armario que possui muitas Coisas. Se alguma coisa for lixo, ela deve ser removida na execução do método removeLixo.

public class Armario {    private List coisas = new LinkedList();    public void removeLixo() {        List copia = lista();        for (Coisa coisa : copia) {            if (coisa.isLixo())                remove(coisa);        }    }        public List lista() {        List copia = null;        synchronized (coisas) {            copia = new ArrayList(coisas.size());            copia.addAll(coisas);        }        return copia;    }    public void adiciona(Coisa coisa) {        synchronized (coisas) {            coisas.add(coisa);        }    }    public void remove(Coisa coisa) {        synchronized (coisas) {            coisas.remove(coisa);        }    }}

Com isso o tempo de exclusividade fica restrito ao tempo da cópia para a outra coleção, que ocorre no método lista. Dessa forma temos uma folga no tempo de iteração total e a possibilidade de rearranjar a coleção, adicionando ou removendo itens a ela. É importante ressaltar que o melhor jeito de evitar o calafrio de receber um java.util.ConcurrentModificationException é evitar a utilização de objetos compartilhados entre threads. Quando isso não é possível, o jeito é utilizar um padrão como Cópia Exclusiva de Coleção.

[Rafael Silva Pereira] Otimizando um Servidor Web para Download Progressivo

Thursday, September 18th, 2008

No dia 27 do mês passado estive no Congresso SET, da Sociedade Brasileira de Engenharia de Televisão e Telecomunicações, onde apresentei junto com o Marcello Azambuja um artigo sobre Arquiteturas de Distribuição de Vídeos na Internet. Porém, devido ao tempo bastante limitado da apresentação, não pude entrar em detalhes mais específicos de como otimizar as arquiteturas para obter um melhor desempenho. Por isso, resolvi colocar um pouco do que está no artigo aqui no blog, já que nem todo mundo que tem interesse neste assunto estava na apresentação. (O slides podem ser vistos aqui)

Assim, resolvi começar falando especificamente sobre o Download Progressivo, ou seja, como podemos otimizar um Web Server para que ele seja capaz de servir a maior quantidade de usuários possível. No caso de distribuição de vídeos via Progressive Download temos algumas características básicas que devem ser consideradas para otimização:

  • As conexões com o WebServer são persistentes, ou seja, o usuário fica conectado ao servidor por uma quantidade razoável de tempo, até que o conteúdo seja completamente copiado;
  • Dependendo da quantidade de vídeos diferentes podemos ter diversos conteúdos diferentes sendo acessados simultaneamente;
  • Os arquivos de mídia não estão necessariamente nos discos do servidor. Eles podem estar em um repositório central sendo acessados pelo servidor Web através de NFS/CIFS;
  • A quantidade de acessos ao serviço pode aumentar rapidamente, variando de acordo com o conteúdo disponibilizado;

Com estas características já podemos identificar alguns gargalos principais:

  • Tráfego de rede: muitos usuários conectados realizando download irão rapidamente ocupar a banda disponível. Além disso, existe a ocupação de banda pela cópia dos arquivos do repositório central para o servidor;
  • IO (Repositório Central e Disco Local): muitos usuários realizando download significa muito IO de leitura, que é maior a medida que temos mais usuários acessando arquivos diferentes;
  • Memória: quanto mais usuários, mais memória o Apache irá precisar para atendê-los, e quanto mais arquivos, mais memória o kernel irá utilizar para cache;
  • CPU: quanto mais usuários mais processamento para organizar e servir as requisições;

Na verdade, se queremos obter o máximo de uma arquitetura não podemos nos limitar a olhar apenas um componente. O primeiro ponto, e mais simples, consiste em alterar as configurações do Apache, escolher a versão correta (2.X), e compilar uma versão do Web Server que tenha apenas aquilo que é relevante para a distribuição de arquivos, ou seja, devemos evitar incluir na configuração de compilação módulos que não serão utilizados, como mod ssl, por exemplo.

Uma vez compilado cabe a nós decidir qual arquitetura interna de funcionamento possui uma performance maior: se é a multi-process (Apache Prefork) ou a multi-process/multi-thread (Apache Worker).

Basicamente, no prefork, para cada conexão será criado um processo específico para atendê-la, de modo que a quantidade de processos httpd será sempre maior ou igual a quantidade de clientes. Nesta arquitetura, temos uma quantidade inicial que processos que são pré-criados para atender as conexões, sendo que a medida que os clientes se conectam, eles são atendidos por estes processos. No prefork, temos basicamente dois problemas em termos de performance:

  • Memória: cada processo criado ocupa uma porção da memória, de modo que a memória disponível para cache do kernel é cada vez menor, ao ponto que toda ela é preenchida pelos processos httpd, momento onde o servidor começa a fazer swap em disco;
  • Load: a criação de novos processos (fork) gera um overhead no sistema, de modo que quanto maior a taxa de conexão, maior será o overhead no fork para atender as novas conexões;

A outra opção de MPM, o worker, trabalha com o conceito multi-thread, onde as requisições são atendidas por threads e não por processos. Assim, teríamos apenas um ou poucos processos com múltiplas threads em cada um deles, atendendo cada uma das conexões. Com o worker, minimizamos a utlização de memória, já que as threads compartilham a mesma área de memória do processo pai, e reduzimos o overhead na criação de processos. Na verdade, no caso do worker, definimos a quantidade de threads por processo de modo que só realizamos um fork quando este limite é atingido.

A escolha entre prefork ou worker deve ser realizada caso a caso, ou seja, dependendo da situação de uso e da configuração de hardware uma escolha poderá ser melhor que a outra. No caso específico de servidores para utilização em distribuição de vídeos em Progressive Download, a escolha do MPM Worker é recomendada, com o objetivo de reduzir a ocupação de memória pelo servidor Web, deixando-a livre para que o kernel possa utilizá-la para cache de conteúdo, reduzindo o IO no disco e conseqüentemente o tempo de resposta da requisição. Uma configuração interessante seria neste caso seria forçar a criação de todos os processos filho (children) e suas threads no momento que o servidor Web for iniciado, reduzindo assim o overhead de controle de threads.

Além de configurar o MPM, o Apache permite diversas outras configurações capazes de aumentar o desempenho do mesmo, como a possibilidade de desabilitar Hostname Lookups e DNS resolving, e outras que podem ser encontradas na documentação do Apache.

Entretanto, quando falamos de arquiteturas de distribuição de vídeo que recebem grandes volumes de acesso, devemos nos preocupar um pouco mais em como otimizar o processo de distribuição. Uma das maneiras mais eficientes de aumentar a capacidade de uma infra-estrutura de Download Progressivo consiste em realizar um processo de cache intensivo. Ter uma estratégia de cache de conteúdo é fundamental quando falamos de alta performance com um grande volume de acessos. Quando temos um volume muito grande, temos também diversos requests ao mesmo conteúdo. Processar todo o request para cada cliente consistiria em repetir as mesmas operações diversas vezes, sem aproveitar para um request os dados processados por outro. Assim, fica claro que podemos otimizar este processamento, simplesmente aproveitando aquilo que serve para mais de uma requisição.

Em situações onde temos uma arquitetura onde o Apache funciona como uma espécie de “proxy” entre o usuário e um repositório central de vídeos, essa necessidade é ainda mais latente, uma vez que não faz sentido obter um mesmo arquivo diversas vezes neste repositório para servir para os clientes a cada request semelhante. Uma vez copiado do storage para o Apache, para servir uma requisição, o arquivo pode ser mantido no servidor Web para as requisições posteriores realizadas ao mesmo vídeo. Com essa abordagem, reduzimos a carga no storage e o tráfego de rede e de operações de cópia.

Para realizar o cache de conteúdo existem diversas alternativas, como o Squid e o mod_cache. O mod_cache, por estar integrado ao Apache e por ser bastante conhecido e utilizado, além de apresentar uma ótima performance, é uma excelente opção para cache em arquiteturas de distribuição em Download Progressivo.

O mod_cache permite duas abordagens principais de cache: disco ou memória. O mod_disk_cache é o módulo responsável pelo cache em disco, e funciona da seguinte forma: ao receber um request, o mod_disk_cache verifica se o conteúdo solicitado já está no cache em disco. Se estiver, o módulo valida se o conteúdo não está expirado e serve o mesmo a partir do cache, sem que a requisição seja passada aos demais módulos do Apache. Caso, não esteja cacheado, o request passa pelo path normal de atendimento ao request, sendo que, ao finalizar o processamento, o mod_cache escreve a resposta no cache antes de servir a mesma. Assim, ele cria dois arquivos em disco: o .data, com o conteúdo do request, e o .header com os headers da resposta. O nome dos arquivos criados é criado a partir de um hash, para evitar que o conteúdo seja sobre-escrito.

O mod_mem_cache, é o módulo responsável pelo cache em memória, e funciona de forma semelhante ao mod_disk_cache, porém armazenando o conteúdo em memória.

A escolha de um dos módulos para utilização em um servidor de Download Progressivo também depende da configuração do hardware. Entretanto, em servidores que rodam em Linux, o uso do mod_disk_cache é recomendada, uma vez que o gerenciamento do cache em memória feito pelo kernel é bastante eficiente.

Com um web server bem otimizado e configurado, e com uma estratégia de cache eficiente, temos uma arquitetura de distribuição muito mais robusta e capaz de atender um volume até 70% maior que o volume que atenderíamos utilizando apenas um servidor com as configurações “default”, o que reduz de forma significativa os custos de investimento para expansão da capacidade, tornando esta uma opção bastante interessante para distribuição de vídeos na internet.

[Bruno Mentges de Carvalho] Criando um Product Backlog, parte 1

Sunday, September 14th, 2008

Recentemente um dos nossos clientes internos na globo.com pediu para que nós os ajudássemos a elaborar um product backlog para uma nova versão de seu produto. Eu representando o lado técnico, um product owner, um arquiteto da informação e um designer fomos escolhidos para tal atividade.

Product backlog é um documento de alto nível do projeto. Nele é contido todas as features, wish-lists, etc. que o cliente deseja para o sistema descritas de uma maneira bem abrangente e na linguagem do cliente, que chamamos de “histórias”. Cada história contém também uma estimativa de complexidade e o valor de negócio da mesma para o cliente, para facilitar na priorização.

Um exemplo de uma história é o seguinte: “Para poder ter uma experiência melhor assistindo um vídeo, eu como usuário gostaria de poder assistir o vídeo em tela cheia“.

A primeira etapa foi marcar uma reunião com os envolvidos para ouvir deles o que eles tem hoje, o que os atrapalha, e o que eles querem para resolver seus problemas. Do ponto de vista técnico, que é o que vos apresento, o maior desafio é se ater ao “O QUÊ” ao invés do “COMO”. Ouvir o que eles querem fazer, o que eles precisam, o que os atrapalha, etc. Por vezes me peguei com vontade de perguntar se queriam isso dessa ou daquela forma, e precisei me conter para não tirar o foco da reunião.

Depois dessa reunião nós tivemos uma visão mais clara da necessidade de nossos futuros clientes e resolvemos reunir o time e conversar a respeito, visto que serão eles (e eu) que iremos desenvolver o produto. Essa reunião foi muito produtiva pois levantou diversos pontos que ainda precisavam ser trabalhados.

Já aí temos alguns pontos desse nosso processo:

1. Se reunir com o time do cliente e o cliente e ouvir deles os “o quês
2. Se reunir com o seu time e discutir os pontos levantados
3. Marcar uma reunião com o cliente e o time do cliente para dar este primeiro feedback.

Como podemos ver, a presença do cliente é fundamental. E esse ciclo de reuniões já produz um primeiro feedback. Tivemos uma nova reunião para passar o feedback e atacar os pontos levantados. Tudo isso foi feito em menos de uma semana, o que é o mote das práticas ágeis: ciclos curtos de feedback.

A partir destes 3 pontos já é possível rascunhar um primeiro product backlog. E, como seguimos o scrum e práticas ágeis, isso não é nenhum problema, pois o product backlog é aberto e modificável.

Essa foi a parte 1 do processo de criação do product backlog. Em breve estarei escrevendo o próximo da série, enquanto avançamos com a criação product backlog.

[Bruno Mentges de Carvalho] Criando um Product Backlog, parte 1

Sunday, September 14th, 2008

Recentemente um dos nossos clientes internos na globo.com pediu para que nós os ajudássemos a elaborar um product backlog para uma nova versão de seu produto. Eu representando o lado técnico, um product owner, um arquiteto da informação e um designer fomos escolhidos para tal atividade.

Product backlog é um documento de alto nível do projeto. Nele é contido todas as features, wish-lists, etc. que o cliente deseja para o sistema descritas de uma maneira bem abrangente e na linguagem do cliente, que chamamos de “histórias”. Cada história contém também uma estimativa de complexidade e o valor de negócio da mesma para o cliente, para facilitar na priorização.

Um exemplo de uma história é o seguinte: “Para poder ter uma experiência melhor assistindo um vídeo, eu como usuário gostaria de poder assistir o vídeo em tela cheia“.

A primeira etapa foi marcar uma reunião com os envolvidos para ouvir deles o que eles tem hoje, o que os atrapalha, e o que eles querem para resolver seus problemas. Do ponto de vista técnico, que é o que vos apresento, o maior desafio é se ater ao “O QUÊ” ao invés do “COMO”. Ouvir o que eles querem fazer, o que eles precisam, o que os atrapalha, etc. Por vezes me peguei com vontade de perguntar se queriam isso dessa ou daquela forma, e precisei me conter para não tirar o foco da reunião.

Depois dessa reunião nós tivemos uma visão mais clara da necessidade de nossos futuros clientes e resolvemos reunir o time e conversar a respeito, visto que serão eles (e eu) que iremos desenvolver o produto. Essa reunião foi muito produtiva pois levantou diversos pontos que ainda precisavam ser trabalhados.

Já aí temos alguns pontos desse nosso processo:

1. Se reunir com o time do cliente e o cliente e ouvir deles os “o quês
2. Se reunir com o seu time e discutir os pontos levantados
3. Marcar uma reunião com o cliente e o time do cliente para dar este primeiro feedback.

Como podemos ver, a presença do cliente é fundamental. E esse ciclo de reuniões já produz um primeiro feedback. Tivemos uma nova reunião para passar o feedback e atacar os pontos levantados. Tudo isso foi feito em menos de uma semana, o que é o mote das práticas ágeis: ciclos curtos de feedback.

A partir destes 3 pontos já é possível rascunhar um primeiro product backlog. E, como seguimos o scrum e práticas ágeis, isso não é nenhum problema, pois o product backlog é aberto e modificável.

Essa foi a parte 1 do processo de criação do product backlog. Em breve estarei escrevendo o próximo da série, enquanto avançamos com a criação product backlog.

[Christiane Melcher] Mudando o template

Friday, September 12th, 2008

Esse blog foi criado há séculos e nada até agora…

Dessa vez sai!!

Aguardem post de inauguração. Amazônia,  claro :)

bjs,

Chris

[Christiane Melcher] Mudando o template

Friday, September 12th, 2008

Esse blog foi criado há séculos e nada até agora…

Dessa vez sai!!

Aguardem post de inauguração. Amazônia,  claro :)

bjs,

Chris

[Cainã Nunes] II designers – Do Design Gráfico ao Design Digital

Monday, September 8th, 2008

Hello World.

Escrevo este post de estréia para comunicar que estarei participando do II designers na próxima terça-feira, dia 16/09.

Abaixo o release do evento:

II designers

O II designers – VII Festival de Design é um evento acadêmico que acontece entre os dias 15 e 18 de setembro de 2008, no auditório do ICH da Universidade Federal de Pelotas. O evento é organizado pelo PET – Artes Visuais da UFPEL e conta com patrocínio master da agência Conrad Caine Media Applications, da Alemanha, patrocínio da agência Insight Design, de Pelotas, e do apoio da Editora Rosari e dos Hotéis Manta.

Com a temática “do Design Gráfico ao Design Gigital”, o designers promove a discussão de aspectos entre as duas áreas, por meio do diálogo com profissionais renomados no mercado. O evento contará com palestras, oficinas e exposições, além do tradicional Festival de Design, que descobre novos talentos locais, e o Festival de Cinema, organizado pelo curso de Cinema e Animação da UFPEL.

O designers valoriza o design gaúcho e enfatiza a qualidade dos profissionais da área atuantes no Rio Grande do Sul. Por isso, o evento foi batizado com este nome, que faz uma alusão ao seu propósito ao mesmo tempo em que referencia o público gaúcho. Todos os palestrantes convidados são nascidos no Estado e possuem um trabalho relevante na área. Entre eles: Cainã Nunes, da globo.com; Marcos Nähr, da DELL; Prof. Dr. Luis Vidal Negreiros, da Uniritter; Pablo de La Rocha, da agência w3Haus; e Isabela Rodrigues, da agência Santa Motion.

Para mais detalhes sobre o evento, basta acessar o site www.ufpel.edu.br/iad/designers. As inscrições estão sendo realizadas no IAD/UFPel, ao valor de R$ 15,00 (com direito a uma oficina), desde 8 de setembro, podendo ser efetuadas também nos dias do evento. As vagas são limitadas. O IAD fica na rua Alberto Rosa, 62.

[Guilherme Cirne] Comando do ubiquity para busca no Globo Vídeos

Monday, September 8th, 2008

Está no ar um comando do ubiquity para busca no Globo Vídeos.

Para instalá-lo, primeiro é preciso ter o Firefox 3 com a extensão do ubiquity instalada. Depois, basta entrar na home do Globo Vídeos. Uma barra aparecerá no topo perguntando se você quer instalar o comando. É só selecionar a opção para instalar e depois confirmar na página de aviso que aparecerá.

Para usá-lo, é só invocar o ubiquity e digitar globovideos [palavra(s) a serem buscada(s)]. Uma nova aba será aberta com o resultado da busca no Globo Vídeos.

Esse tipo de comando é apenas o começo do que se pretende fazer com o ubiquity no futuro. Certamente é um conceito inovador que promete bastante.