Como projetar serviços da Web altamente escaláveis em Java?

15

Estou criando alguns serviços da Web que teriam 2000 usuários simultâneos. Os serviços são oferecidos gratuitamente e, portanto, espera-se obter uma grande base de usuários. No futuro, pode ser necessário ampliar até 50.000 usuários.

Já existem algumas outras questões que abordam o assunto como: link

No entanto, minhas exigências diferem da pergunta acima.

Por exemplo - Meu aplicativo não tem uma interface de usuário, portanto imagens, CSS, javascript não são um problema. É em Java, portanto, sugestões como usar o HipHop para traduzir PHP para código nativo são inúteis.

Por isso, decidi fazer minha pergunta separadamente.

Esta é a configuração do meu projeto -

  1. Serviços Web baseados em descanso usando o Apache CXF
  2. Hibernate 3.0 (com otimizações relevantes como carregamento lento e HQL customizado para ajuste)
  3. Tomcat 6.0
  4. MySQL 5.5

Quais são as melhores práticas a seguir para tornar um aplicativo baseado em Java escalonável?

    
por Kshitiz Sharma 19.06.2012 / 07:56
fonte

3 respostas

8

Eu lidei com a questão no passado, mas ainda sinto que tenho muito a aprender em campo. Eu acho que este é um dos campos mais interessantes que existem no desenvolvimento de software hoje em dia, aqui estão algumas reflexões sobre isso:
O MySQL é um banco de dados justo a menos que você esteja trabalhando com uma enorme quantidade de dados, e nesse caso você pode considerar o banco de dados NoSQL, mas deve examinar cuidadosamente qual é o melhor banco de dados NoSQL para necessidades.

Você deve implementar o cache em seu sistema - tente armazenar o máximo possível de dados somente leitura ou definir algumas estratégias de armazenamento em cache - por exemplo, tivemos um cenário em que era válido para um usuário ver "dados antigos" como desde que a atualização recente ocorreu na última hora.
Eu consideraria o JBoss Cache, ou talvez o Infinispan (que é mais parecido com uma estrutura de dados distribuída) ou outro framework popular de cache por esta.
Além disso, como você mencionou o tomcat, presumo que você trabalhe em algum módulo request-respone. Tente considerar o uso de um cache que existe em um escopo de uma determinada solicitação, isso pode ser um HashMap simples associado ao leia o armazenamento local .
A minha ideia aqui é bastante parecida com cache de primeiro nível no Hibernate .   

Você deve se lembrar que arquivos, transações e outros recursos são caros em termos de mantê-los abertos. Certifique-se de fechar arquivos e transações o mais rápido possível, ou você acabará com bugs que serão reproduzidos em configurações de grande escala

Além disso, você deve entender o que os usuários simultâneos de 2000 - isso significa que 2000 usuários estão acessando seu servidor ao mesmo tempo, ou eles estão usando seu sistema? Distinguir entre casos em que 2000 usuários tentam abrir um soquete para seu servidor, e um caso em que apenas 500 são, e 1500 estão atualmente olhando para resultados, de preenchimento de entrada no lado do cliente.

Você deve considerar o uso de clustering - você terá que lidar com problemas como o balanceamento de carga , a sessão persistente (o que significa o balanceador de carga redirecionará uma solicitação para o mesmo servidor para a mesma sessão) e muito mais.

Se você precisa ter um código de sincronização - escolha cuidadosamente a estratégia de sincronização. Vi alguns sistemas nos quais um bloqueio simples era usado, mas um ReaderWriterLock poderia ter melhorado as coisas, já que a maioria dos acessos era somente leitura.

Considere ter cache e validação do lado do cliente, se possível, tente salvar chamadas para o servidor e enviar apenas diferenças de dados, caso a maior parte da sua resposta para uma solicitação com o mesmo parâmetro não seja alterada. Por exemplo, no oVirt projeto de código aberto que solicitamos para obter estatísticas de uma determinada máquina virtual. alguns dos dados da VM raramente mudam, então enviamos somente MD5 dela, se os dados mudarem o valor MD5 também é alterado, nós executamos uma requisição para obter os dados completos, e não apenas o MD5.

Eu mencionei o hibernate antes - eu recomendaria que você cuidadosamente o considerasse - se você precisar executar muitas gravações e menos leituras, o Hibernate pode não ser o ideal para você, e você deve considerar talvez trabalhar com Spring-JDBC como um wrapper sobre o JDBC.

Indexe seu banco de dados com sabedoria e use um esquema de db correto. Considere o uso de uma camada de procedimentos armazenados, pois eles são pré-compilados e otimizados

Eu gostaria de afirmar que, no passado, eu lidei com um sistema (nó único) no mysql (principalmente somente leitura de acesso) com o jboss 4.2.1 e consegui alcançar 2000 usuários simultâneos (não acessando de uma só vez em termos de abertura 2000 sockets contra o nosso servidor), mas usando / navegando no nosso sistema, usando o JBoss Cache e pré-carregando no cache alguns dos dados mais acessados, ou os dados que percebemos serão "quentes e populares", mas nossa solução foi boa para nossa arquitetura e nossos fluxos, como eu digo nestes casos -
Há mais dicas e truques, mas depende da sua arquitetura e dos fluxos que você precisa ter no seu sistema. Boa sorte!

    
por 22.06.2012 / 08:09
fonte
3

Boa pergunta. Provavelmente difícil dizer qual é a melhor abordagem, mas vou tentar da minha experiência.

A melhor maneira de escalar o aplicativo da Web baseado em Java é escrevê-lo como sem estado quanto possível (se possível). Isso permite que você dimensione horizontalmente o aplicativo, onde você pode adicionar servidores do tomcat se houver mais usuários simultâneos.

No entanto, como você observou, pode haver problemas com as conexões com o banco de dados. Mas a pergunta que eu tenho é: como você está pegando os dados? É gerado pelo usuário ou você recebe os dados de terceiros? Isto é muito importante porque, se você está dando um serviço ao seu usuário com os dados agregados de aplicativos de terceiros (digamos FB, Twitter etc), então o que você pode seguir é gravar no banco de dados mestre e replicar os dados para os bancos de dados escravos. que são alocados para cada instância do tomcat. Então cada servidor tomcat pode obter do seu próprio banco de dados escravo.

 Are there faster alternatives to Mysql?

Você pode usar o cluster MySQL que possui armazenamento de dados na memória. Mas cuidado com o fato de que o aplicativo pode precisar de algumas alterações. O sql joins não é bem suportado no cluster MySQL, embora na versão mais recente existam melhorias para o mesmo. Se o custo não for um fator, você pode experimentar o Oracle.

A solução de armazenamento em cache definitivamente melhorará o desempenho. Mas tudo depende da arquitetura de todo o aplicativo. Você deve estar bem ciente de quando enviar dados para o cache, quando fazê-lo sujo (remover do cache).

Com relação à distribuição da carga no ambiente de vários servidores, sugiro usar o balanceador de carga do que usar o Apache para balanceamento de carga.

    
por 19.06.2012 / 08:49
fonte
2

Atualmente, estou configurando um sistema semelhante (em nível profissional) e esse é o design que escolhi:

  • Dois balanceadores de carga Nginx (ambos ativos, ambos com failover para o outro, balanceados com round robin de DNS)
  • Dois bancos de dados MySQL no modo de replicação mestre principal
  • Duas instâncias do Tomcat como um cluster do tomcat
  • Duas instâncias do Memcached para armazenamento em cache e compartilhamento de estado de sessão para o cluster do Tomcat

Isso alcançará uma solução escalável, de alta disponibilidade e redundante.

Os balanceadores de carga (em hardware decente) carregam facilmente uma linha saturada de 1gbit cada. Este também é um ótimo local para descarregamento de SSL.

Você pode salvar suas informações da sessão no memcached. No caso de uma instância do tomcat falhar, outra instância do tomcat poderá recuperar informações relevantes da sessão e os clientes não perceberão nada. Não se esqueça de combinar isso com sessões pegajosas também. (Para manter o tráfego de rede baixo)

O armazenamento em cluster do Tomcat também tem a opção de compartilhar informações da sessão entre o cluster em tempo real, sem usar o memcached. Embora eu ache que o desempenho, usando o Memcached, será melhor.

Se você precisar de mais energia em qualquer um desses aplicativos:

  • Nginx: adicione mais balancetes de carga, embora eu não ache que esse será o gargalo em breve.
  • Tomcat: você pode aumentar facilmente o tamanho do cluster do Tomcat ou adicionar mais clusters
  • MySQL: Adicione alguns escravos somente leitura ou aumente o tamanho do cluster (dependendo do seu aplicativo, mas desde que você escreveu um aplicativo baseado em REST, isso não deve ser um problema)
  • Memcached: adicione mais nós, Memcached dimensiona muito bem, acredito.

Eu não sei como seu aplicativo é criado e quais são os grandes recursos hogs, mas se você ver uma alta carga de banco de dados (durante seus loadtests!), adicionar um cache entre o aplicativo e o banco de dados certamente pode melhorar muito o desempenho . Mas não esqueça que nem tudo é cachable, se suas consultas são sempre diferentes, o cache não vai ajudar (muito)

Meu conselho seria fazer o download do VMware Workbench (ou software de virtualização similair) e tentar criar uma configuração simples. Sem loadbalancing ou clustering, apenas o básico e trabalhe a partir daí. Um a um, adicione mais recursos (balanceamento, armazenamento em cache, armazenamento em cluster, etc.) e certifique-se de fazer alguma pesquisa sobre cada tópico, para que você saiba que você fez a escolha certa.

Se você continuar executando os mesmos testes de desempenho durante esse processo, poderá ver por si mesmo se usar X é melhor do que usar Y em sua configuração ou qual impacto terá, etc.

No final, uma configuração como essa realmente depende dos requisitos de seu aplicativo e de seus clientes, tudo pode ser feito de várias maneiras, cada um com seus próprios pontos strongs e fracos.

Mais alguma pergunta?

Boa sorte!

Wesley

    
por 25.06.2012 / 18:47
fonte