Comment concevoir des services Web hautement évolutifs en Java?


15

Je crée des services Web qui auraient 2000 utilisateurs simultanés. Les services sont offerts gratuitement et devraient donc bénéficier d'une large base d'utilisateurs. À l'avenir, il sera peut-être nécessaire de faire évoluer jusqu'à 50 000 utilisateurs.

Il y a déjà quelques autres questions qui traitent du problème comme - /programming/2567254/building-highly-scalable-web-services

Cependant, mes exigences diffèrent de la question ci-dessus.

Par exemple - Mon application n'a pas d'interface utilisateur, donc les images, CSS, javascript ne sont pas un problème. Il est en Java, donc des suggestions comme utiliser HipHop pour traduire PHP en code natif sont inutiles.

J'ai donc décidé de poser ma question séparément.

Ceci est la configuration de mon projet -

  1. Services Web reposant sur Apache CXF
  2. Hibernate 3.0 (avec des optimisations pertinentes comme le chargement paresseux et HQL personnalisé pour l'optimisation)
  3. Tomcat 6.0
  4. MySql 5.5

Quelles sont les meilleures pratiques à respecter pour rendre une application basée sur Java évolutive?


Si vous exposez un service REST, l'utilisation d'un proxy inverse comme Varnish serait très utile. Quelle doit être la fraîcheur des données? Êtes-vous sûr d'avoir besoin d'une base de données relationnelle? Pourriez-vous partitionner les données? Avec la pile technologique que vous décrivez, je me concentrerais à m'assurer que le moins de demandes possibles atteignent réellement votre point de terminaison. Avez-vous envisagé de le faire en mémoire avec des solutions telles que Hazel cast / Gigaspaces, etc.?
ebaxt

@ebaxt merci pour vos suggestions. Gigaspaces semble être open source. Mais le casting de Hazel semble intéressant.
Kshitiz Sharma

1
@ebaxt "Êtes-vous sûr d'avoir besoin d'une base de données relationnelle?" L'adoption de nosql entraînerait des changements radicaux dans l'architecture de l'application. Nous essayons de garder la complexité au minimum. Le coût n'est cependant pas un facteur pour nous. Nous allons donc nous en tenir à l'approche relationnelle.
Kshitiz Sharma

1
Vous pouvez utiliser Postgres, MySQL ou quoi que ce soit. Qu'en est-il de votre infrastructure? Pouvez-vous utiliser des baies de disques? Les serveurs sont-ils hébergés au même endroit? Pouvez-vous connecter votre cluster avec Heartbeat, etc.? Pouvez-vous les mettre dans le même sous-réseau?
edze

1
Je suis aussi programmeur. Mais si votre base de données relationnelle est le goulot d'étranglement, vous aurez tendance à vous retrouver avec ces questions. Il existe des bases de données sur le marché, certaines fonctionnent mieux que d'autres dans certaines situations. Mais ils utilisent différents niveaux d'isolation de transaction par défaut et concurrence optimiste vs concurrence pessimiste, etc.
edze

Réponses:


8

J'ai traité la question dans le passé, mais je sens toujours que j'ai beaucoup à apprendre sur le terrain. Je trouve que c'est l'un des domaines les plus intéressants du développement logiciel de nos jours, voici quelques réflexions à ce sujet:
MySQL est une base de données assez juste , sauf si vous travaillez avec une énorme quantité de données, et dans ce cas, vous pourriez envisager NoSQL mais vous devez examiner attentivement quelle est la meilleure base de données NoSQL pour vos besoins.

Vous devez implémenter la mise en cache sur votre système - essayez de mettre en cache autant de données en lecture seule que possible, ou définir des stratégies de mise en cache - par exemple, nous avions un scénario dans lequel il était valide pour un utilisateur de voir les "anciennes données" comme tant que la récente mise à jour a eu lieu au cours de la dernière heure.
Je considérerais JBoss Cache, ou peut-être Infinispan (qui ressemble plus à une structure de données distribuée) ou un autre cadre de mise en cache populaire pour cela.
De plus, comme vous l'avez mentionné tomcat, je suppose que vous travaillez dans un module de demande-réponse. Essayez d'envisager d'utiliser un cache qui existe dans la portée d'une demande donnée, cela peut même être un simple HashMap associé au stockage local du thread .
Mon idée ici ressemble assez au cache de premier niveau chez Hibernate .

N'oubliez pas que les fichiers, les transactions et les autres ressources coûtent cher pour les garder ouverts. Assurez-vous de fermer les fichiers et les transactions dès que possible, sinon vous vous retrouverez avec des bogues qui se reproduiront sur des configurations à grande échelle

De plus, vous devez comprendre ce que 2000 utilisateurs simultanés - cela signifie-t-il que 2000 utilisateurs accèdent à votre serveur en même temps ou utilisent-ils votre système? Faites la distinction entre les cas où 2 000 utilisateurs tentent d'ouvrir un socket sur votre serveur et un cas où seulement 500, et 1 500 sont actuellement à la recherche de résultats, remplissent l'entrée côté client.

Vous devriez envisager d'utiliser le clustering - vous devrez faire face à des problèmes tels que l'équilibrage de charge , la session persistante (ce qui signifie que l'équilibreur de charge redirigera une demande vers le même serveur pour la même session) et plus encore.

Si vous avez besoin d'un code de synchronisation - choisissez soigneusement la stratégie de synchronisation. J'ai vu certains systèmes dans lesquels un simple verrou était utilisé, mais un ReaderWriterLockaurait pu améliorer les choses, car la plupart des accès étaient en lecture seule.

Envisagez si possible la mise en cache et la validation côté client, essayez d'enregistrer les appels vers le serveur et d'envoyer uniquement les différences de données, au cas où la plupart de votre réponse à une demande avec le même paramètre ne changerait pas.
Par exemple, chez oVirt open source project, nous demandons à obtenir des statistiques sur une machine virtuelle donnée. certaines des données de la VM changent rarement, nous n'en envoyons donc que MD5, si les données changent, la valeur MD5 est également modifiée, nous effectuons une demande pour obtenir les données complètes, et pas seulement le MD5.

J'ai déjà mentionné hibernate - je vous recommanderais de bien réfléchir à son utilisation - si vous avez besoin d'effectuer beaucoup d'écritures et moins de lectures, Hibernate pourrait ne pas être idéal pour vous, et vous devriez peut-être envisager de travailler avec Spring-JDBC comme wrapper. JDBC.

Indexez votre base de données judicieusement et utilisez un schéma de base de données correct. Pensez à utiliser une couche de procédures stockées car elles sont précompilées et optimisées.Je

voudrais dire que par le passé, j'ai traité un système (nœud unique) sur mysql (principalement en lecture seule) avec jboss 4.2.1 et j'ai réussi à atteindre 2000 simultanément utilisateurs
(n'accédant pas à la fois en termes d'ouverture de 2000 sockets sur notre serveur), mais en utilisant / parcourant notre système, en utilisant JBoss Cache et en préchargeant dans le cache certaines des données les plus consultées, ou les données que nous avons réalisées vont être "chaudes et populaires" "mais notre solution était bonne pour notre architecture et nos flux,
donc comme je le dis dans ces cas -
il y a plus de trucs et astuces, mais cela dépend vraiment de votre architecture et des flux dont vous avez besoin dans votre système. Bonne chance!


J'accepte sauf pour les proc stockés, n'utilisez pas les proc stockés. Et vous pouvez utiliser une table de hachage et des valeurs atomiques simultanées pour rendre threadsafe
NimChimpsky

3

Bonne question. Difficile probablement de dire quelle est la meilleure approche, mais j'essaierai d'après mon expérience.

La meilleure façon de mettre à l'échelle l'application Web basée sur Java est de l'écrire le plus possible sans état (si vous le pouvez). Cela vous permet de mettre à l'échelle horizontalement l'application, où vous pouvez ajouter des serveurs tomcat s'il y a plus d'utilisateurs simultanés.

Cependant, comme vous l'avez noté, il peut y avoir un problème avec les connexions à la base de données. Mais la question que j'ai est, comment obtenez-vous les données? Est-ce généré par l'utilisateur ou vous obtenez les données d'un tiers? Ceci est très important car, si vous offrez un service à votre utilisateur avec les données agrégées à partir d'une application tierce (par exemple FB, Twitter, etc.), alors ce que vous pouvez suivre, c'est écrire dans la base de données maître et répliquer les données dans des bases de données esclaves qui sont alloués à chaque instance de tomcat. Ensuite, chaque serveur tomcat peut obtenir à partir de sa propre base de données esclave.

 Are there faster alternatives to Mysql?

Vous pouvez opter pour le cluster MySQL qui a une banque de données en mémoire. Mais gardez à l'esprit que l'application peut nécessiter quelques modifications. Ils sql joinsne sont pas bien pris en charge dans le cluster MySQL bien que dans la dernière version il y ait des améliorations pour le même. Si le coût n'est pas un facteur, vous pouvez essayer Oracle.

La solution de mise en cache améliorera certainement les performances. Mais alors, tout dépend de l'architecture de l'ensemble de l'application. Vous devez bien savoir quand envoyer des données dans le cache, quand les rendre sales (supprimer du cache).

Concernant la distribution de la charge dans un environnement multi-serveur, je vous suggère d'utiliser l'équilibreur de charge plutôt que d'utiliser Apache pour l'équilibrage de charge.


"Je vous suggère d'utiliser l'équilibreur de charge plutôt que d'utiliser Apache pour l'équilibrage de charge" Quelle approche / logiciel suggéreriez-vous sinon Apache?
Kshitiz Sharma

Je recommandais essentiellement du matériel d'équilibrage de charge, que votre administrateur réseau devrait être en mesure de configurer. Bien sûr, cela a un coût supplémentaire pour le projet. Cet équilibreur de charge aura sa propre IP (également appelée IP virtuelle) et, fondamentalement, vous assignerez cette IP à votre domaine. Lorsque la demande arrive, cela l'achemine vers tous les serveurs connectés de manière circulaire (également d'autres algorithmes disponibles). Vous pouvez utiliser apache à cette fin si le matériel n'est pas une option, mais je préférerais le matériel car vous n'avez pas besoin de régler apache uniquement à cette fin.

Nous utilisons un serveur dédié avec httpd pour faire la même chose. Le matériel n'est pas un problème.
Kshitiz Sharma

Vous pouvez utiliser httpd et mod_cluster, si je me souviens bien. Je considérerais attentivement avant d'aller à la solution "overkill" du matériel LB, avant de vérifier httpd et mod_cluster

@zaske - Vous avez probablement raison de dire que l'équilibreur de charge matérielle est peut-être exagéré. Mais au cas où vous auriez besoin d'évoluer, c'est facile à faire en ajoutant plus de serveurs.

2

Je suis en train de mettre en place un système similaire (au niveau professionnel) et c'est le design que j'ai choisi:

  • Deux équilibreurs de charge Nginx (tous deux actifs, les deux basculent pour l'autre, équilibrés avec un round robin DNS)
  • Deux bases de données MySQL en mode de réplication maître-maître
  • Deux instances Tomcat en tant que cluster Tomcat
  • Deux instances Memcached pour la mise en cache et le partage d'état de session pour le cluster Tomcat

Cela permettra d'obtenir une solution redondante, haute disponibilité et évolutive.

Les équilibreurs de charge (sur un matériel décent) équilibreront facilement une ligne saturée de 1 Gbit chacun. C'est également un excellent endroit pour le déchargement SSL.

Vous pouvez enregistrer vos informations de session dans memcached. En cas d'échec d'une instance de tomcat, une autre instance de tomcat peut récupérer les informations de session pertinentes et les clients ne remarqueront rien. N'oubliez pas de combiner cela avec des séances collantes aussi. (Pour limiter le trafic réseau)

Le clustering Tomcat a également une option pour partager les informations de session avec le cluster en temps réel, sans utiliser memcached. Bien que je pense en termes de performances, l'utilisation de Memcached sera meilleure.

Si vous avez besoin de plus de puissance dans l'une de ces applications:

  • Nginx: Ajoutez plus d'équilibreurs de charge, même si je ne pense pas que ce sera le goulot d'étranglement très bientôt.
  • Tomcat: vous pouvez facilement augmenter la taille du cluster Tomcat ou ajouter plus de clusters
  • Mysql: Ajoutez des esclaves en lecture seule ou augmentez la taille du cluster (selon votre application, mais puisque vous avez écrit une application basée sur REST, cela ne devrait pas poser de problème)
  • Memcached: Ajoutez plus de nœuds, Memcached évolue assez bien je crois.

Je ne sais pas comment votre application est construite et quelles sont les grosses ressources de porcs, mais si vous voyez une charge de base de données élevée (pendant vos tests de charge!), L'ajout d'un cache entre l'application et la base de données pourrait certainement améliorer considérablement les performances. Mais n'oubliez pas que tout n'est pas cachable, si vos requêtes sont toujours différentes, la mise en cache n'aidera pas (beaucoup)

Mon conseil serait de télécharger VMware Workbench (ou un logiciel de virtualisation similaire) et d'essayer de créer une configuration simple. Pas d'équilibrage de charge ou de clustering, juste les bases et travaillez à partir de là. Un par un, ajoutez plus de fonctionnalités (équilibrage, mise en cache, mise en cluster, etc.) et assurez-vous de faire des recherches sur chaque sujet, afin que vous sachiez que vous avez fait le bon choix.

Si vous continuez à exécuter les mêmes tests de performances au cours de ce processus, vous pouvez voir par vous-même si l'utilisation de X est meilleure que l'utilisation de Y dans votre configuration, ou quel impact la mise en cache aura, etc.

En fin de compte, une configuration comme celle-ci dépend vraiment des exigences de votre application et de ses clients, tout peut être fait de différentes manières, chacune avec ses propres forces et faiblesses.

Autres questions?

Bonne chance!

Wesley



Utilisez-vous un cadre pour la couche de mise en cache, ou juste un tas de hachages manuels sur les requêtes SQL?
djechlin
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.