取代的乐趣


作者:Daniel Amadei

在 Oracle Coherence 中取代系统属性名称是一种非常简单但很强大的方法,可以让多个节点共存于同一个 JVM 中而不发生冲突

2012 年 4 月发布

Oracle Coherence 提供了一种灵活的方法来更改配置过程中使用的系统属性名称,这可以防止一些可能出现的问题,比如,当您将多个属于不同集群的应用程序部署到同一 Oracle WebLogic Server 实例时可能出现的问题。

假设您有多个应用程序部署到同一 Oracle WebLogic Server 实例。这些应用程序分别属于彼此之间毫不相关的不同的 Coherence 集群。如果您将操作配置文件封装到每个应用程序的 EAR 中,就必须找到一种办法来取代每个集群成员自身所绑定的 IP 地址和端口。(如果您只有一个应用程序,此过程将非常简单:只需添加一个系统属性来取代 IP 地址或主机名,再添加另一个来取代端口,任务就完成了。)

例如:

  • tangosol.coherence.localhost 是用于取代 Coherence 节点自身将绑定的 IP 地址或主机名的默认系统属性名称。
  • tangosol.coherence.localport 是用于取代 Coherence 节点自身将绑定的本地端口的默认系统属性名称。

如果您有多个应用程序运行在同一 JVM 上但分属于不同集群,您会怎么办?(Coherence 节点是“按类加载器限定范围的”,因此,根据加载 Coherence 类的类加载器的不同,您可能在每个 JVM 上有一个节点、每个 EAR 一个节点或者每个 WAR 一个节点。这完全取决于您如何引用 coherence.jar:从应用服务器类加载器、EAR 还是 WAR;这将决定在单一 JVM 上可以有多少个集群节点。)这正是取代系统属性名称的方法发挥作用之处。

问题

我们在实践中探讨一下此问题。假设您有两个应用程序:AppA 和 AppB。AppA 是一个名为 myCluster 的 Coherence 集群的成员,具有以下 Coherence 操作配置:

<?xml version='1.0'?>
<coherence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config"
  xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config coherence-operational-config.xsd">

  <cluster-config>
    <member-identity>
      <cluster-name>myCluster</cluster-name>
    </member-identity>

    <unicast-listener>
      <well-known-addresses>
        <socket-address id="1">
          <address>10.10.10.10</address>
          <port>7777</port>
        </socket-address>
        <socket-address id="2">
          <address>10.10.10.10</address>
          <port>8888</port>
        </socket-address>
        <socket-address id="3">
          <address>10.10.10.10</address>
          <port>9999</port>
        </socket-address>
      </well-known-addresses>
      <address system-property="tangosol.coherence.localhost">10.10.10.10</address>
      <port system-property="tangosol.coherence.localport">8888</port>
      <port-auto-adjust system-property="tangosol.coherence.localport.adjust">true</port-auto-adjust>
    </unicast-listener>
  </cluster-config>
</coherence>

AppB 是另一个应用程序,它是一个名为 myClusterB 的 Coherence 集群的成员,具有以下操作配置:

<?xml version='1.0'?>
<coherence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config"
  xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config coherence-operational-config.xsd">

  <cluster-config>
    <member-identity>
      <cluster-name>myClusterB</cluster-name>
    </member-identity>

    <unicast-listener>
      <well-known-addresses>
        <socket-address id="1">
          <address>10.10.10.10</address>
          <port>5555</port>
        </socket-address>
        <socket-address id="2">
          <address>10.10.10.10</address>
          <port>4444</port>
        </socket-address>
        <socket-address id="3">
          <address>10.10.10.10</address>
          <port>3333</port>
        </socket-address>
      </well-known-addresses>
      <address system-property="tangosol.coherence.localhost">10.10.10.10</address>
      <port system-property="tangosol.coherence.localport">5555</port>
      <port-auto-adjust system-property="tangosol.coherence.localport.adjust">true</port-auto-adjust>
    </unicast-listener>
  </cluster-config>
</coherence>

当我们只启动一个包含这两个应用程序的 Oracle WebLogic Server 实例时,该实例会正常启动,因为每个节点的端口不同。但如果在同一台计算机上使用相同操作配置文件运行多个服务器实例(或者两个配置使用同一端口),则必须取代端口和主机名以避免冲突。

类似地,假设有两个 WebLogic Server 实例运行在同一台计算机上。每个实例托管 AppA 和 AppB。通过系统属性取代主机名及/或端口而不是指定 4 个不同的 XML 文件(该计算机中运行的每个 Coherence 节点一个)将很有用,对不对?我们来试试看会发生什么情况。

如果我们使用 Oracle Enterprise Pack for Eclipse (OEPE) 启动 WebLogic Server 实例,可以指定 JAVA_OPTIONS 环境变量,如图 1 所示。访问此屏幕:

  1. 在 OEPE 中双击服务器名
  2. 单击 Open launch configuration 链接
  3. 访问 Environment 选项卡。

 override-coherence-f1

图 1 通过 OEPE IDE 指定系统属性

(在 OEPE 之外,可以在用于启动 WebLogic Server 实例的脚本中指定这些属性。)

指定属性之后,启动服务器时 AppA 的 Coherence 节点将正常启动,因为它在其 WKA (well-known-addresses) 列表中具有端口 9999。(根据 Oracle Coherence 文档,WKA 定义为:“WKA 特性是一种允许集群成员使用单播而不是多播发现和加入集群的机制。WKA 最常用于多播网络在环境中不需要或不可用时,或环境未经相应配置以支持多播时。如果启用 WKA,将禁用所有集群多播通信。”)但在同一 JVM 上运行的另一节点却没有这么幸运。由于两者均依赖于同一系统属性名称,两个 Coherence 节点都会采纳它并将其端口取代为同一个!AppB Coherence 操作配置在其 WKA 列表中没有端口 9999,因此我们遇到麻烦了。(即使它在 WKA 列表中指定了这种端口,我们还是会遇到同样甚至是更糟糕的麻烦,因为结果可能是不同集群的节点试图通信。)

如下所示,AppB 节点尝试启动,但没有已知服务器在运行。同样,可以看到,服务器使用的端口变为 10001,因为 9999 已被运行在一个完全不同的集群中的 AppA 节点使用。

2011-12-18 21:08:42.648/48.473 Oracle Coherence GE 3.7.1.1 <Warning> (thread=Cluster, member=n/a): This Member(Id=0, Timestamp=2011-12-18 21:08:12.166, Address=10.10.10.10:10001, MachineId=43245, Location=site:,machine:DAMADEI-BR,process:5484, Role=WeblogicServer) has been attempting to join the cluster using WKA list [/10.10.10.10:3333, /10.10.10.10:4444, /10.10.10.10:5555] for 30 seconds without success; this could indicate a mis-configured WKA, or it may simply be the result of a busy cluster or active failover. 

解决方案

此问题的一个可行的(也许是最好的)解决方案是利用更改 Coherence 用于取代 XML 配置的系统属性的名称的功能。与许多以固定方式使用系统属性名称的产品不同,Coherence 允许您将系统属性名称更改为您喜欢的任意名称。例如,通过在 Coherence 的操作配置 XML 中指定以下元素:

<address system-property="appA.coherence.localhost">10.10.10.10</address>

……我们要做两件事情:首先,指定 Coherence 应绑定的 IP 地址(或主机名);其次,通过指定的 system-property 属性更改系统属性名称,这样 Coherence 将尝试找到该属性名称以取代此绑定值。

这样做,我们可以取代系统属性名称以取代 Coherence 将绑定的 IP/主机名和端口,因而我们将能够为在同一 JVM 上运行的每个应用程序指定不同的属性。

因此,如果为 AppA 指定以下 XML,那么,仔细查看 address 和 port 元素上的 system-property 属性,我们将取代这两个元素上的系统属性名称:

<?xml version='1.0'?>
<coherence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config"
  xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config coherence-operational-config.xsd">

  <cluster-config>
    <member-identity>
      <cluster-name>myCluster</cluster-name>
    </member-identity>

    <unicast-listener>
      <well-known-addresses>
        <socket-address id="1">
          <address>10.10.10.10</address>
          <port>7777</port>
        </socket-address>
        <socket-address id="2">
          <address>10.10.10.10</address>
          <port>8888</port>
        </socket-address>
        <socket-address id="3">
          <address>10.10.10.10</address>
          <port>9999</port>
        </socket-address>
      </well-known-addresses>
      <address system-property="appA.coherence.localhost">10.10.10.10</address>
      <port system-property="appA.coherence.localport">8888</port>
      <port-auto-adjust system-property="appA.coherence.localport.adjust">true</port-auto-adjust>
    </unicast-listener>
  </cluster-config>
</coherence>

如果指定系统属性 –DappA.coherence.localport=9999,此节点将绑定到端口 9999 而不是如操作配置 XML 中所指定的 8888。指定 tangosol.coherence.localport 对此 Coherence 节点无效。(显然,它将影响在同一 JVM 上运行的使用默认系统属性名称的其他节点。)我们已经取代了它!

由于我们只有两个节点运行在同一 JVM 上,所以同时取代 AppB 的配置是一个好主意,如下所示:

<?xml version='1.0'?>
<coherence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config"
  xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config coherence-operational-config.xsd">

  <cluster-config>
    <member-identity>
      <cluster-name>myClusterB</cluster-name>
    </member-identity>

    <unicast-listener>
      <well-known-addresses>
        <socket-address id="1">
          <address>10.10.10.10</address>
          <port>5555</port>
        </socket-address>
        <socket-address id="2">
          <address>10.10.10.10</address>
          <port>4444</port>
        </socket-address>
        <socket-address id="3">
          <address>10.10.10.10</address>
          <port>3333</port>
        </socket-address>
      </well-known-addresses>
      <address system-property="appB.coherence.localhost">10.10.10.10</address>
      <port system-property="appB.coherence.localport">5555</port>
      <port-auto-adjust system-property="appB.coherence.localport.adjust">true</port-auto-adjust>
    </unicast-listener>
  </cluster-config>
</coherence>

现在,启动服务器并指定属性(如图 2 所示)将使 AppB 上的节点在端口 3333 启动,AppA 上的节点在端口 9999 启动。

 override-coherence-f2

图 2 为 AppA 和 B 上的 Coherence 节点指定不同属性

可以通过查看启动日志来对此进行确认:

AppA 节点日志片段:

ThisMember=Member(Id=1, Timestamp=2012-01-03 22:19:52.987, Address=10.10.10.10:9999, MachineId=43245, Location=site:,machine:DAMADEI-BR,process:7008, Role=WeblogicServer)

同一 JVM 上的 AppB 节点日志片段:

ThisMember=Member(Id=1, Timestamp=2012-01-03 22:19:58.267, Address=10.10.10.10:3333, MachineId=43245, Location=site:,machine:DAMADEI-BR,process:7008, Role=WeblogicServer)

总结

取代系统属性名称是一种非常简单但很强大的方法,可以让多个节点共存于同一个 JVM 中而不发生冲突,利用这种方法,您可以避免编写多个 XML 配置文件,同时仍然可以对每个节点的 Coherence 设置进行细粒度的控制。


Daniel Amadei 是巴西 Oracle Consulting 的首席顾问,专攻 SOA 和集成技术。近年来他一直从事 SOA 方面的工作,并且自 1999 年就开始使用 Java 技术。在认证资格方面,他是 Oracle SOA 基础实践者、Oracle SOA 架构师认证专家和 Sun 认证企业架构师 (SCEA)。