Configurando um aplicativo Rails 2.3.x no EC2 para fácil escalabilidade

3

Estou executando uma pilha simples de trilhos em uma única máquina dedicada. Estamos atingindo nossa capacidade total e não temos absolutamente nenhuma configuração para dimensionamento, apenas um aplicativo em uma máquina. Fiz algumas pesquisas e criei uma pilha potencial para escalabilidade. Eu não sou um administrador profissional, mas tenho alguns pensamentos sobre o que devemos fazer com o EC2. Ainda não tenho certeza sobre o compartilhamento do sistema de arquivos, que é onde minha principal pergunta é. Primeiro, eis o que estou lidando.

Pilha atual:

  • rails 2.3.11
  • postgresql
  • passageiro + nginx
  • delayed_job
  • esfinge + thinking_sphinx
  • imagemagick (processamento de imagem pesada)
  • jaxer (vai explicar)

O que nosso aplicativo faz:

Nosso aplicativo faz muitos uploads de imagens e processamento de imagens pesadas com o ImageMagick. Ele também fala com o jaxer para longas conversões de tela para imagem. Tudo isso está atrasado. Gostaríamos de ter certeza de que essas coisas podem ser especialmente dimensionadas. Então, estamos falando de necessidades de armazenamento de arquivos em rápido crescimento e processamento intenso de imagens em tarefas em segundo plano.

Minhas decisões até agora:

  • use gema de borracha para ajuda na implantação / administração
  • mude de delayed_job para redis / resque para facilitar o desacoplamento de trabalhadores (cliente / servidor), várias filas e interface web sinatra
  • têm funções como app, db, web, redis, resque, com tudo em uma única instância ec2 no início, mas logo dividem o material de redis / resque em uma instância separada e, potencialmente, mais daquelas

Perguntas:

A principal questão real é: o que acontece com todos os arquivos? Se eu decidir dividir a função do aplicativo em várias instâncias, como obtenho um acesso ao sistema de arquivos compartilhado?

Além disso, seria ótimo ouvir alguns pensamentos sobre minha configuração em geral.

    
por Max Chernyak 04.07.2011 / 22:10

1 resposta

9

Assim, a maior parte do que você tem lá é bastante simples de escalar. PgSQL em sua própria máquina para aliviar uma pilha de I / CPU / disco IO / consumo de memória como um primeiro passo. Esfinge em seu próprio mundinho também. Definitivamente, mude para o resque para permitir um escalonamento horizontal fácil de seus funcionários.

Mas os arquivos ... sim, os arquivos são difíceis. Eles são sempre difíceis. E suas opções são perigosamente finas.

Algumas pessoas recomendam a rota do sistema de arquivos em cluster, o superaglomerado mágico (GFS2 / OCFS2) ou a opção um pouco mais pobre de algo como GlusterFS. Eu executei muitos sistemas (1000+) usando o GFS, e nunca, nunca faço isso novamente. (Pode até não rodar na rede do EC2, na verdade). O GFS2 / OCFS2 é uma confusão de partes móveis, sub-documentadas, supercomplicadas e propensas a modos de falha confusos que apenas causam problemas de tempo de inatividade. Ele também não vale nada, especialmente em um ambiente pesado de gravação - ele simplesmente cai, derrubando todo o seu cluster e levando de 10 a 30 minutos de trabalho em nível de guru para colocá-lo em funcionamento novamente. Evite isso e sua vida é muito mais fácil. Eu nunca corri o GlusterFS, mas isso é porque eu nunca fiquei particularmente impressionado com isso. Qualquer coisa que você possa fazer com isso, geralmente há uma maneira melhor de fazer isso de qualquer maneira.

A melhor opção, na minha opinião, é o venerável servidor NFS. Uma máquina com um grande (ou não tão grande) volume EBS e um daemon NFS rodando, e todo mundo monta isso. Tem gotchas (não é realmente um sistema de arquivos POSIX, então não o trate como tal), mas para simples operação "lá, eu consertei" para 99% dos casos de uso, não é ruim . No mínimo, pode ser um paliativo enquanto você trabalha em uma solução melhor, que é ...

Use seu conhecimento do seu aplicativo para classificar seu armazenamento. Essa é a abordagem que eu fiz mais recentemente (escalando o Github) e funcionou lindamente. Basicamente, em vez de tratar o armazenamento de arquivos como um sistema de arquivos, você o trata como um serviço - fornece uma API inteligente para usar as partes do seu aplicativo para fazer o que você precisa fazer . No seu caso, você pode precisar apenas armazenar e recuperar imagens para IDs pré-alocados (a PK para sua tabela de "imagens" no banco de dados, por exemplo). Isso não precisa de um sistema de arquivos POSIX inteiro, ele só precisa de alguns métodos HTTP super otimizados (os POSTs precisam ser manipulados dinamicamente, mas se você for realmente inteligente, você pode fazer com que os GETs venham disco direto como arquivos estáticos). Inferno, você provavelmente está servindo essas imagens diretamente para os clientes, então corte o intermediário e torne esse servidor seu servidor de ativos publicamente acessível enquanto você está nisso.

O fluxo de trabalho pode ser algo como:

  • O servidor frontend recebe a imagem
    1. envia para o servidor de arquivos
    2. Adiciona trabalho para processar imagens
    3. (Alternativamente, o POST para o servidor de arquivos faz com que ele reconheça a necessidade de um trabalho de pós-processamento e cria o trabalho sozinho)
  • O trabalhador obtém trabalho de processamento de imagem
    1. Recupera a imagem do servidor de arquivos
    2. Processos de imagem
    3. envia a imagem processada de volta ao servidor de arquivos
  • A página da web precisa incluir imagem na página da web
    1. Grava URL para o servidor de imagens em HTML
    2. o navegador da Web acessa e obtém imagem diretamente

Você não precisa necessariamente usar HTTP POST para colocar as imagens no servidor - o Github, por exemplo, fala com seus servidores de arquivos usando o Git-over-SSH, que funciona bem para eles. A chave, no entanto, é colocar mais cuidado em onde o trabalho deve ser feito e evitar o uso desnecessário de recursos escassos (rede IO para uma solicitação do servidor NFS), trocando por um conjunto mais restrito de opções de uso ("Você só pode solicitar arquivos inteiros atomicamente! ") que funcionam para o seu aplicativo.

Finalmente, você terá que considerar o fator de escalabilidade. Se você está usando um transporte inteligente, no entanto, é fácil - adicione a lógica (pequena quantidade) necessária para determinar com qual servidor de arquivos você precisa falar em cada lugar que fala com o servidor de arquivos, e você basicamente tem escalabilidade infinita . Na sua situação, você pode perceber que seu primeiro servidor de arquivos estará cheio em, digamos, 750.000 imagens. Portanto, sua regra é "Fale com o servidor de arquivos com hostname fs#{image_id / 750_000} ", que não é difícil de codificar em todos os lugares.

Eu costumava me divertir com essa parte do meu trabalho ...

    
por 05.07.2011 / 01:31