21

集群/分发 Java 服务器应用程序的最佳方法是什么?我正在寻找一种允许您通过添加更多应用程序服务器和更多数据库服务器来水平扩展的方法。

  • 您建议使用哪些技术(软件工程技术或特定技术)来解决此类问题?
  • 您使用哪些技术来设计持久层以扩展到许多读取器/写入器 扩展应用程序事务并扩展对共享数据的访问(最好的方法是消除共享数据;您可以应用哪些技术来消除共享数据)。
  • 根据您的事务是读取还是写入繁重,似乎需要不同的方法,但我觉得您是否可以优化“写入”繁重的应用程序,该应用程序对于“读取”也很有效

“最佳”解决方案将允许您为单个节点编写 Java 应用程序,并希望“隐藏”访问/锁定共享数据的大部分细节。

在分布式环境中,最困难的问题总是归结为让多个事务访问共享数据。似乎有两种常见的并发事务方法。

  1. 显式锁(极易出错且在分布式系统中跨多个节点协调缓慢)
  2. 软件事务内存(STM) AKA 乐观并发,如果事务发现共享状态已更改(并且事务可以稍后重试),则在提交期间回滚事务。哪种方法可以更好地扩展,分布式系统中的权衡是什么?

我一直在研究扩展解决方案(以及提供如何扩展示例的一般应用程序),例如:

  1. Terracotta - 通过使用 Java 的并发锁定机制(同步,ReentrantReadWriteLocks)扩展 Java 内存模型以包含分布式共享内存,从而提供“透明”缩放。
  2. Google App Engine Java - 允许您编写 Java(或 python)应用程序,这些应用程序将分布在“云”服务器中,您可以在其中分发处理事务的服务器,并使用 BigTable 存储持久数据(不确定访问共享的事务的方式数据或句柄锁争用能够有效地扩展)
  3. Darkstar MMO 服务器- Darkstar 是 Sun 的开源 MMO(大型多人在线)游戏服务器,它们以线程事务方式扩展事务,允许给定事务仅运行一定数量并提交,如果需要很长时间,它将回滚(有点像软件事务内存)。他们一直在研究支持多节点服务器设置以进行扩展。
  4. Hibernate 的乐观锁定- 如果您使用 Hibernate,您可以使用他们的乐观并发支持来支持软件事务内存类型行为
  5. Apache CouchDB应该自然地“扩展”到网格配置中的许多读写器数据库。(有没有一个很好的例子来说明如何管理锁定数据或确保事务隔离?):
  6. JCache - 通过将结果缓存到您可以在 Google appengine 中使用来访问 memcached 并缓存其他经常读取的数据的常见查询,来扩展“读取”繁重的应用程序。

Terracotta 似乎是最完整的解决方案,因为您可以“轻松”修改现有服务器应用程序以支持缩放(在定义 @Root 对象和 @AutoLockRead/Write 方法之后)。问题是要真正从分布式应用程序中获得最大的性能,分布式系统的优化并不是事后才想到的,你必须在设计它时知道对象访问可能会被网络 I/O 阻塞。

为了正确扩展,它似乎总是归结为分区数据和负载平衡事务,以便给定的“执行单元”(cpu 核心 -> 线程 -> 分布式应用程序节点 -> 数据库主节点)

似乎要通过集群使任何应用程序正确扩展,您需要能够根据数据访问读取/写入对事务进行分区。人们提出了哪些解决方案来分发他们的应用程序数据(Oracle、Google BigTable、MySQL、数据仓库),以及通常如何管理分区数据(许多写入主机,具有更多读取数据库等)。

在扩展您的数据持久层方面,哪种类型的配置在将您的数据分区到许多读者/许多作者方面表现最好(通常我会根据给定用户(或通常是您的任何核心实体)对我的数据进行分区“根”对象实体)由单个主数据库拥有)

4

6 回答 6

3

以为我找到了一个很棒的 Java 集群/分布式平台,想重新打开这个-

结帐http://www.hazelcast.com

我运行了测试程序,它非常酷,非常轻巧且易于使用。它会自动检测对等配置中的集群成员。机会是无限的。

于 2010-05-20T15:57:07.107 回答
2
于 2009-10-23T23:54:11.067 回答
2

感谢您在一个地方很好地总结了所有可能性。

但是这里缺少一种技术。它是 MapReduce-Hadoop。如果可以将问题融入 MapReduce 范式,它可能是最广泛可用的解决方案。我还想知道 Actor 框架模式(JetLang、Kilim 等)是否可以扩展到集群。

于 2009-10-23T22:59:33.963 回答
1

尽管 Oracle Coherence 和许多其他建议的解决方案都非常适合共享数据,但您只引用了锁定和 STM 作为在分布式环境中管理状态突变的方法;这些通常都是扩展状态管理的非常糟糕的方法。在另一个网站上,我最近发布了以下关于如何实现(例如)序列计数器的内容:

如果您正在查看计数器,那么使用 Coherence EntryProcessor 之类的东西将轻松实现“一次且仅一次”的行为,并且对于任意数量的单调递增序列的 HA;这是整个实现:

public class SequenceCounterProcessor
        extends AbstractProcessor
    {
    public Object process(InvocableMap.Entry entry)
        {
        long l = entry.isPresent() ? (Long) entry.getValue() + 1 : 0;
        entry.setValue(l);
        return l;
        }
    }

是的。而已。自动无缝 HA、动态横向扩展弹性、一次性行为等。完成。

EntryProcessor 是我们在 2005 年引入的一种分布式闭包。

顺便说一句,在 Java 8(尚未发布)中,Lambda 项目在语言和标准库中引入了官方闭包支持。

基本上,这个想法是将闭包传递到分布式环境中数据“所有者”的位置。Coherence 通过使用动态分区来动态管理数据所有权,允许分布式系统在正在运行的各种机器和节点之间对数据进行负载平衡。事实上,默认情况下,所有这些都是 100% 自动化的,所以你永远不会真正告诉它把数据放在哪里,或者有多少数据去哪里。此外,在其他节点和其他物理服务器上管理数据的二级(可能还有三级等)副本,以在进程失败或服务器死亡的情况下提供高可用性。同样,这些备份副本的管理默认是完全自动和完全同步的,这意味着系统默认是 100% HA(即没有配置)。

当闭包到达数据所有者时,它在事务工作空间中执行,如果操作成功完成,则将其运送到备份以进行安全保存。数据突变(例如操作的结果)只有在备份成功后才对系统的其余部分可见。

对上述内容的一些优化包括添加 ExternalizableLite 和 PortableObject 接口以优化序列化,并通过直接追求数据的“网络就绪”形式来避免盒装长的序列化:

public Object process(InvocableMap.Entry entry)
    {
    try
        {
        BinaryEntry binentry = (BinaryEntry) entry;
        long l = entry.isPresent() ? binentry.getBinaryValue()
                .getBufferInput().readLong() + 1 : 0L;
        BinaryWriteBuffer buf = new BinaryWriteBuffer(8);
        buf.getBufferOutput().writeLong(l);
        binentry.updateBinaryValue(buf.toBinary());
        return l;
        }
    catch (IOException e)
        {
        throw new RuntimeException(e);
        }
    }

既然它是无状态的,为什么不准备一个单例实例呢?

public static final SequenceCounterProcessor INSTANCE =
        new SequenceCounterProcessor();

从网络上的任何地方使用它就像一行代码一样简单:

long l = (Long) sequences.invoke(x, SequenceCounterProcessor.INSTANCE);

其中“x”是标识您要使用的特定序列计数器的任何对象或名称。有关详细信息,请参阅 Coherence 知识库,网址为:http ://coherence.oracle.com/

Oracle Coherence 是一个分布式系统。每当您启动一个 Coherence 节点时,它都会与其他已经在运行的 Coherence 节点连接,并动态形成一个弹性集群。该集群以分区、高可用性 (HA) 和事务一致的方式托管数据,并托管以“一次且仅一次”的方式对该数据进行操作的操作(就像我在上面展示的那样)。

此外,除了能够从任何 Coherence 节点透明地调用任何逻辑或访问任何数据之外,您还可以从网络上的任何进程透明地调用任何逻辑或访问任何数据(需经过身份验证)和授权,当然)。因此,此代码可以从任何 Coherence 集群节点或任何(Java / C / C++ / C# / .NET)客户端运行:

为了全面披露,我在 Oracle 工作。这篇文章中表达的观点和观点是我自己的,并不一定反映我雇主的观点或观点。

于 2013-08-11T22:14:02.430 回答
1

不要忘记 Erlang 的Mnesia

Mnesia 为您提供了您在普通数据库中习惯的事务之类的东西,但提供了实时操作和容错。另外,您可以在不停机的情况下重新配置。缺点是它是一个内存驻留数据库,因此您必须对非常大的表进行分段。最大的表大小为 4Gb。

于 2009-10-23T23:07:07.527 回答
0

也许这些幻灯片会有所帮助。根据我们的经验,我推荐 Oracle (Tangosol) Coherence 和 GigaSpaces 作为最强大的数据和处理分发框架。根据问题的确切性质,其中之一可能会发光。兵马俑也相当适用于一些问题。

于 2009-12-11T19:39:17.537 回答