如何用Java设计高度可扩展的Web服务?


15

我正在创建一些具有2000个并发用户的Web服务。该服务是免费提供的,因此有望获得大量用户。将来可能需要扩展到50,000个用户。

已经有一些其他问题可以解决此问题,例如 -/programming/2567254/building-highly-scalable-web-services

但是,我的要求与上述问题有所不同。

例如-我的应用程序没有用户界面,因此图像,CSS,javascript不是问题。它是用Java编写的,因此使用HipHop将PHP转换为本地代码的建议毫无用处。

因此,我决定单独询问我的问题。

这是我的项目设置-

  1. 使用Apache CXF的基于Rest的Web服务
  2. Hibernate 3.0(具有相关的优化功能,例如延迟加载和自定义HQL以进行优化)
  3. Tomcat 6.0
  4. MySQL 5.5

为了使基于Java的应用程序可扩展,应遵循哪些最佳实践?


如果要公开REST服务,则使用类似Varnish的反向代理将有很大帮助。数据需要多新鲜?您确定需要一个关系数据库吗?您可以对数据进行分区吗?通过您所描述的技术堆栈,我将专注于确保尽可能少的请求实际到达您的端点。您是否打算使用Hazel cast / Gigaspaces等解决方案在内存中进行此操作?
ebaxt 2012年

@ebaxt谢谢您的建议。Gigaspaces似乎是开源的。但是榛树演员看起来很有趣。
Kshitiz Sharma

1
@ebaxt“您确定需要一个关系数据库吗?” 采用nosql会对应用程序体系结构产生巨大的变化。我们正在努力将复杂性降至最低。成本虽然不是我们的考虑因素。因此,我们将坚持使用关系方法。
Kshitiz Sharma

1
您可以使用Postgres,MySQL或其他任何方式。您的基础架构是什么?可以使用磁盘阵列吗?服务器托管在同一位置吗?您可以将群集与心跳等连接吗?您可以将它们放在同一子网中吗?
edze 2012年

1
我也是程序员。但是,如果您的关系数据库成为瓶颈,那么您最终会遇到这个问题。市场上有一些数据库在某些情况下比其他数据库性能更好。但是,他们用不同的默认事务隔离级别和乐观并发VS悲观并发等
edze

Answers:


8

我过去处理过这个问题,但仍然觉得我在该领域有很多东西要学习。我发现这是当今软件开发中最有趣的领域之一,对此有一些想法:
MySQL 足够公平,除非您要处理大量数据,在这种情况下,您可以考虑使用NoSQL数据库,但是您应该仔细检查什么是最适合您的 NoSQL数据库。

您应该在系统上实现缓存-尝试尽可能多地缓存只读数据,或者定义一些缓存策略-例如,我们有一个场景,在这种情况下,用户可以看到“旧数据”只要最近的更新发生在最后一个小时。
我会考虑使用JBoss Cache,或者使用Infinispan(更像是分布式数据结构)或其他流行的缓存框架。
此外,正如您提到的tomcat一样,我假设您在某些请求-响应模块中工作。尝试考虑使用给定请求范围内存在的缓存,它甚至可以是与线程本地存储关联的简单HashMap 。
我的想法非常类似于Hibernate的一级缓存

您应该记住,文件,事务和其他资源在保持打开状态方面很昂贵。确保尽快关闭文件和事务,否则最终会出现在大规模设置中会重现的错误

此外,您必须了解2000个并发用户-这是否意味着2000个用户同时访问您的服务器,或者他们正在使用您的系统?区分2000个用户尝试打开服务器套接字的情况与当前只有500个用户(目前有1500个用户正在查看结果)和填充客户端输入的情况之间的区别。

您应该考虑使用群集-您将不得不处理诸如负载平衡,粘性会话(这意味着负载平衡器会将请求重定向到同一会话的同一服务器)之类的问题。

如果需要同步代码,请仔细选择同步策略。我看到一些使用简单锁的系统,但是使用了ReaderWriterLock可能会有所改善,因为大多数访问都是只读的。

如果可能,请考虑进行客户端缓存和验证,并尝试保存对服务器的调用,并仅发送数据差异,以防您对具有相同参数的请求的大多数响应都没有变化。
例如,在oVirt开源项目中,我们要求获取给定虚拟机的统计信息。VM的某些数据很少更改,因此我们仅发送其中的MD5,如果数据更改了,则MD5值也更改了,我们执行请求以获取完整数据,而不仅仅是MD5。

我之前提到过hibernate-我建议您仔细考虑使用它-如果您需要执行大量写入操作,而读取次数较少,那么Hibernate可能不适合您,因此您应该考虑使用Spring-JDBC作为包装JDBC。

明智地索引数据库,并使用正确的数据库方案。考虑使用存储过程的层,因为它们已经过预编译和优化了,

我想声明一下,我过去使用jboss 4.2.1处理了mysql(主要是只读访问)上的系统(单节点),并成功达到2000个并发使用者
(不是针对服务器打开2000个套接字,而是一次访问),而是使用/浏览我们的系统,使用JBoss Cache并将一些访问量最大的数据预加载到缓存中,或者我们意识到的数据将“很流行” “但是我们的解决方案对我们的体系结构和流程 非常有用,
因此,正如我在这种情况下所说的-
还有更多技巧和窍门,但这实际上取决于您的体系结构以及系统中需要的流程。祝好运!


我同意除了存储过程,不要使用存储过程。您可以使用并发的哈希图和原子值来确保线程安全
NimChimpsky 2012年

3

好问题。可能很难说出哪种方法是最好的,但是会根据我的经验尝试。

扩展基于Java的Web应用程序的最佳方法是尽可能地使其无状态(如果可以的话)。这允许您水平扩展应用程序,如果有更多并发用户,则可以在其中添加tomcat服务器。

但是,正如您所指出的,数据库连接可能存在问题。但是我的问题是,您如何获取数据?是用户生成的还是您从第三方获取数据?这点非常重要,因为如果您使用第三方应用程序(例如FB,Twitter等)聚合的数据为用户提供服务,那么您可以遵循的是写入主数据库并将数据复制到从数据库中分配给每个tomcat实例。然后,每个tomcat服务器都可以从其自己的从数据库中获取。

 Are there faster alternatives to Mysql?

您可以使用具有内存数据存储的MySQL群集。但请注意,应用程序可能需要进行一些更改。在sql joins没有得到很好的支持在MySQL集群虽然在最新的版本有对同样的改进。如果成本不是影响因素,则可以尝试使用Oracle。

缓存解决方案肯定会提高性能。但是,这一切都取决于整个应用程序的体系结构。您应该清楚何时将数据推送到缓存,何时将其清空(从缓存中删除)。

关于在多服务器环境中分配负载,我建议您使用负载平衡器,而不是使用Apache进行负载平衡。


“我建议您使用负载平衡器,而不是使用Apache进行负载平衡。”如果不是Apache,您会建议哪种方法/软件?
Kshitiz Sharma

我基本上是在建议负载平衡器硬件,您的网络管理员应该可以配置它。这当然会增加项目成本。该负载平衡器将拥有自己的IP(也称为虚拟IP),基本上,您将把该IP分配给您的域。当请求到达时,它将以循环(也可用其他算法)的方式将其路由到所有连接的服务器。如果没有可选的硬件,则可以使用apache来实现此目的,但是我宁愿使用硬件,因为您不需要仅出于此目的而调整apache。

我们正在使用带有httpd的专用服务器来执行相同的操作。硬件不是问题。
Kshitiz Sharma

如果我没记错的话,可以使用httpd和mod_cluster。在检查httpd和mod_cluster

@zaske-您可能是正确的,硬件负载平衡器可能是一个过大的杀伤力。但是,如果需要扩展,可以通过添加更多服务器来轻松实现。

2

我目前正在建立一个类似的系统(专业水平),这是我选择的设计:

  • 两个Nginx负载平衡器(均处于活动状态,两个都进行故障转移,并与DNS循环平衡)
  • 两个MySQL数据库处于master master复制模式
  • 两个Tomcat实例作为tomcat集群
  • 两个Memcached实例,用于Tomcat集群的缓存和会话状态共享

这将实现冗余,高可用性,可扩展的解决方案。

负载均衡器(在适当的硬件上)将轻松地对每个饱和的1gbit线路进行负载均衡。这也是SSL卸载的好地方。

您可以将会话信息保存在memcached中。如果一个tomcat实例失败,另一个tomcat实例可以检索相关的会话信息,并且客户端不会注意到任何事情。不要忘记将其与粘性会话结合使用。(以减少网络流量)

Tomcat群集还具有一个选项,可以在群集之间实时共享会话信息,而无需使用memcached。尽管我认为性能是明智的,但使用Memcached会更好。

如果您需要在以下任何一种应用中使用更多功能:

  • Nginx:添加更多的负载均衡器,尽管我认为这不会很快成为瓶颈。
  • Tomcat:您可以轻松增加Tomcat群集的大小或添加更多群集
  • Mysql:添加一些只读从属服务器或增加群集大小(取决于您的应用程序,但是由于您编写了基于REST的应用程序,因此这应该不是问题)
  • Memcached:添加更多节点,我相信Memcached可很好地扩展。

我不知道您的应用程序是如何构建的,资源消耗是多少,但是如果您发现数据库负载很高(在负载测试期间!),则在应用程序和数据库之间添加缓存肯定可以大大提高性能。但是请不要忘记,并非所有内容都是可行的,如果您的查询始终不同,那么缓存将无济于事(很多)

我的建议是下载VMware Workbench(或similair虚拟化软件)并尝试创建简单的设置。无需负载平衡或群集,仅需基础知识并从那里开始工作。一个接一个地添加更多功能(平衡,缓存,群集等),并确保对每个主题进行一些研究,因此您会知道选择正确的。

如果在此过程中继续运行相同的性能测试,则可以亲自了解在设置中使用X是否比使用Y更好,或者缓存将产生什么影响等。

最后,这样的设置实际上取决于您的应用程序及其客户端的需求,所有的事情都可以通过各种方式来完成,每种方式都有自己的优点和缺点。

还有其他问题吗?

祝好运!

卫斯理



您是否将框架用于缓存层,或者仅对SQL查询使用一堆手动哈希?
djechlin
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.