IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope:Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  WebSphere  >

使用 WebSphere Extended Deployment 的 ObjectGrid 组件进行高度可伸缩的网格式计算和数据处理

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

样例代码

英文原文

英文原文


级别: 中级

Jonathan Marshall (marshalj@uk.ibm.com), 高级 IT 专家, IBM 

2008 年 4 月 23 日

Journal icon 此实践指导演示利用 IBM® WebSphere® Extended Deployment 的组件 ObjectGrid 创建的基础设施如何为网格式计算和数据处理提供优秀的平台。

来自 IBM WebSphere Developer Technical Journal.

引言

IBM WebSphere Extended Deployment 的 ObjectGrid 组件通常被看作是提供一系列服务质量的分布式缓存技术,包括通过缓存分区提供的可伸缩性,通过使用分区复制提供的弹性,以及事务性和安全性。基于这些服务质量创建的基础设施还可以为网格式计算和数据处理提供优秀的平台。

假定您需要存储大量数据。出于可伸缩性方面的原因(如允许非常大的数据集),或仅仅因为弹性,您可能希望让数据分布在多个 JVM 上。在 ObjectGrid 中,利用散列算法将数据划分在多个 JVM 上,从而实现上述目的。如需处理非常大的数据集,计算和处理中开销最大的部分不是计算,而是移动(序列化)数据,以便对数据进行处理。更为高效的方法是在原处(数据所在的位置)执行处理,并且仅返回您想要的任何结果。这称为应用和数据收集。显然,这同样支持并行式计算,从而显著提高性能,这正是 ObjectGrid 允许您通过 DataGrid API 完成的工作。

本文介绍如何设置内存中数据网格,然后以分布式和并行方式跨网格执行计算和数据更新。作为本练习的一部分,您还将学习使用 EntityManager API 存储和检索数据,而不是使用简单的 map API。(本文不会具体讨论此问题,而是作为对 EntityManager API 的主要优势和概念的介绍。)

本文假定您基本了解 ObjectGrid,并了解如何使用简单应用程序配置基础、分布式环境。有关 ObjectGrid 基础概念的出色介绍,请参见参考资料

您可通过购买完整的 WebSphere Extended Deployment 产品获得 ObjectGrid,或购买名为 WebSphere Extended Deployment Data Grid 的组件。它可作为 WebSphere Application Server 或 WebSphere Extended Deployment 的组成部分安装、独立于应用服务器使用,或在任何其他 Java 应用服务器中运行。

要执行本文中描述的步骤,您需要:

  • WebSphere Extended Deployment Data Grid V6.1(请参见参考资料以获得试用版)。
  • 在 JDK 1.4.2 或更高版本中受支持的任何 JVM;本文使用的是 Java SDK 1.5.0。

示例场景

为了达到本次练习的目的,让我们来了解与所有人密切相关的示例主题。工资和涨工资。例如,您的任务是对公司员工的工资执行一些分析,并计算出平均工资。如果公司当年的经营状况良好,您希望为所有员工涨工资。为此,您将创建一个存储库,用于存储有关公司所雇员工的信息。

您将创建一个 ObjectGrid 来存储许多 Employee 对象,每个 Employee 对象包含一名员工的相关信息。假设您需要放在内存中的数据量对于单个 JVM 来说过于庞大,因此将其设置为分布式网格,分散在许多 JVM 中。如图 1 所示。


图 1. Employee ObjectGrid 概览
图 1. Employee ObjectGrid 概览

要从客户端访问所有这些数据并进行处理或保存任何更改,在网络带宽和计算(用于数据序列化)方面将产生非常大的开销。ObjectGrid 可以在称为代理的网格本身的每个分区上执行计算,该代理是一小段代码,在每个分区本地运行。由于每个代理可以直接对数据进行操作,因此可以节省在序列化和数据传输方面的所有开销,从而使您可以从计算并行化中受益。

本练习将演示如何创建两个代理来执行以下操作:

  1. 执行计算(计算平均值)
  2. 对所有数据执行更新(按百分比增加每位员工的工资)。

在图 1 中,ObjectGrid 提供的基础结构代码以紫色显示,您将通过本练习提供的代码以白色显示:

  • 数据:Employee Java™ 对象,下面将进行介绍。
  • 代理:实际执行在原处 计算的代码。
  • 客户机代码:使用 Agent Manager API 控制代理。

最后,以此为例,清单 1 显示了 Employee Java 对象。显示了要存储在 ObjectGrid 中的四个信息字段,加上一些帮助说明如何使用这些字段的注释。例如,@Id 标记了 Employee 对象的键字段。


清单 1. Employee 对象
                
@Entity
public class Employee {
  @Id String ssn;
  String firstName;
  String surname;
  int salary;
}





回页首


创建网格并使用 EntityManager API 执行数据访问

在本部分中,您将创建分布式 ObjectGrid,并介绍如何使用 EntityManager API 在网格中存储和读取 Employee 对象。

A. 创建 ObjectGrid

  1. 描述 ObjectGrid

    首先创建您将用到的 ObjectGrid。清单 2 显示了定义文件。这就像获取和定义您的备份 map 那样简单,这是存储对象的位置。定义文件描述了两项内容:

    • 要存储的 Java 对象(这里是 Employee 对象)。
    • 实体元数据描述文件,用于描述 Java 对象的属性。

    此描述符也可以描述各种事务、访问和插件设置。



    清单 2. ObjectGrid 定义 XML 文件
                            
    lt;?xml version="1.0" encoding="UTF-8"?>
    <objectGridConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://ibm.com/ws/objectgrid/config ../objectGrid.xsd"
    	xmlns="http://ibm.com/ws/objectgrid/config">
    
    	<objectGrids>
    	    	<objectGrid name="EmployeeStoreObjectGrid" 
    		entityMetadataXMLFile="entity.xml">
    			<backingMap name="Employee"/>
    
    		</objectGrid>
    	</objectGrids>
    
    </objectGridConfig>

  2. 描述实体

    将使用 EntityManager API 来存储和查询您在 ObjectGrid 中的 Employee 对象。使用 EntityManager API 在 ObjectGrid 中存储 Java 对象不需要编写您自己的代码,即可将数据存储和检索到 Java 对象中。(这种方法好比 JPA 持久性方法。)之前,您必须编写代码在 Java map 中存放和获取对象,但是,现在 EntityManager API 都可以代劳。您只需描述应用程序中要存储的 Java 对象。这些描述可通过代码中的注释或 XML 描述符文件(实体模式描述符)提供。

    • 使用注释

      Employee 对象(清单 1)精确而简单,并且只使用了两处注释:

      • @Entity:指定 Java 对象为实体。
      • @Id:指定 Java 变量作为主键。

      可以提供其他注释来描述与其他对象和其他行为之间的关系,但是以上注释足以实现我们的目的。

    • 使用实体模式描述符

      如果您恰好在使用本地 ObjectGrid(即该 ObjectGrid 与应用程序在同一进程中),那么您不必提供实体模式描述符,而只需依赖于注释。您将以编程方式注册要使用的实体。但是,在分布式环境中,您需要告知 ObjectGrid 所期望的实体。这会注册您希望在 ObjectGrid 中使用 Employee 对象。

      清单 3 显示了采用最简单形式的描述符,其中包含所需的最少信息。提供了三部分信息:

      • 实体的名称
      • 实体的类名
      • Employee 实体作为模式根元素。这仅仅是为了告知 ObjectGrid 在复杂的对象图中,Employee 对象是父对象或根对象。


      清单 3. Employee 对象的实体模式描述符
                                      
      <?xml version="1.0" encoding="UTF-8"?>
      <entity-mappings xmlns="http://ibm.com/ws/projector/config/emd"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        	 xsi:schemaLocation="http://ibm.com/ws/projector/config/emd ./emd.xsd">
      
          <entity class-name="com.ibm.websphere.samples.datagrid.Employee" 
      name="Employee" schemaRoot="true"/>
      
      </entity-mappings>

      描述符也可以提供与注释相同的有关实体的元数据信息,如主键字段,以及对象之间的任何映射。使这些描述与 Java 代码分离可能非常有用,但这取决于个人喜好。

      (schemaRoot 属性在分布式 ObjectGrid 中是强制的,以使网格了解要散列哪个对象,以便确定要放置该对象的分区。考虑存储超过一个相关 Java 对象的图时,这一点得到了更直观的体现。由于 ObjectGrid 只支持单阶段提交事务,因此任何更新都只能在单个分区内执行。这要求所有相关对象都存储在同一分区内。因此,schemaRoot 是图的根对象。)

  3. 描述部署环境

    您已描述了 ObjectGrid 和要在其中放置的内容。现在必须决定它的运行方式。例如:

    • 您需要多少个分区?
    • 您需要多少个副本?它们是同步还是异步的?

    考虑到本文的目的,您将不创建副本,因为不需要故障转移功能。(但是,如果您希望加入故障转移功能,那么只需简单地更改配置。)

    对于本例,您希望有五个分区。(这可以是能演示在网格的各个分区上执行的计算的任意数字。)清单 4 显示了您将使用的部署策略。



    清单 4. ObjectGrid 部署策略文件
                            
    <?xml version="1.0" encoding="UTF-8"?>
    <deploymentPolicy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://ibm.com/ws/objectgrid/deploymentPolicy
       ../deploymentPolicy.xsd"
    	xmlns="http://ibm.com/ws/objectgrid/deploymentPolicy">
    
    	<objectgridDeployment objectgridName="EmployeeStoreObjectGrid">
     	   	<mapSet name="EMPLOYEE_MAPSET" numberOfPartitions="5" 
    		minSyncReplicas="0" maxSyncReplicas="0" maxAsyncReplicas="0>
             		<map ref="Employee" />
         	  	</mapSet>
    	</objectgridDeployment>
    
    </deploymentPolicy>

    该部署策略相当直观。作为概览:上述 map 集是一组包含共同的集群和复制标准集的 map。在此场景中,您只有一个 map,因此它在 map 集中是单独的。

    (实际上,需要对分区数目进行一定的考虑。您需要考虑可能需要的数据量和存储数据所需的服务器数量。分区数目应至少等于服务器的总数,但最好应为服务器总数的 2 到 3 倍。这为故障转移时分配分区提供了很大的灵活性(可以很好地分配故障转移分区),也为添加新功能提供了很大的灵活性(新服务器可以承载经过良好分配的负载)。


图 2. 完全配置的 ObjectGrid
图 2. 完全配置的 ObjectGrid

您现已完成对 ObjectGrid 的描述,如图 2 所示。您已完成以下操作:

  • 已配置 ObjectGrid 名称。
  • 已描述要存储在 ObjectGrid 中的实体。
  • 已配置 ObjectGrid 可以使用的分区数。

现在已经准备好开始为网格填充数据并在网格上执行计算。

B. 使用 EntityManager API 填充网格

在使用 ObjectGrid 之前,需要使用 Catalog 服务器的引导地址以典型方式连接到 ObjectGrid。然后,在您的客户机应用程序中,可以执行一系列更新和检索操作。

  1. 使用 EntityManager API 添加数据

    让我们花一点时间了解 EntityManager API 的主要概念。如清单 5 所示,此操作基本上包含五个步骤:

    1. 获取一个 ObjectGrid 会话,与您对任何 map 函数执行的操作一样。
    2. 从会话中获取 EntityManager。
    3. 在 EntityManager 中启动事务范围。
    4. 创建 Java 实体(在本例中,是包含一些数据的单个 Employee 对象)并使用 EntityManager 保持对象。
    5. 在您已完成创建和编辑 Java 对象时提交事务。


    清单 5. 使用 EntityManager API 存储数据
                            
    Session session = objectGrid.getSession();
    EntityManager em = session.getEntityManager();
    
    em.getTransaction().begin();
    Employee e = new Employee();
    e.firstName = "Jonathan";
    e.surname = "Marshall";
    e.ssn = "1234";
    e.salary = 100000;
    
    em.persist(e);
    em.getTransaction().commit();

    EntityManager API 的一个实际好处在于,一旦对象保持在 ObjectGrid 中,在事务范围内对该对象所做的任何更改都会在事务结束时自动在 ObjectGrid 中更新。

    本文提供的示例代码中,将遍历 ObjectGrid 并向其添加五个 Employee 对象,这样您就可以看到放在不同分区中的对象。

  2. 使用 EntityManager API 读取数据

    为了从 ObjectGrid 中读取数据,您将再次使用 EntityManager API 来获取事务和访问数据。检索对象的最简单选择是使用 find 方法,例如:

    em.find(Employee.class, "1234");

    这将基于由 @Id 注释指定的 Java 对象的键字段执行查找。使用 EntityManager API 也可以对网格执行查询以检索大量对象。这有点类似于 SQL 和 JPA 中的查询实体。

    查询 ObjectGrid(清单 6):

    1. 获取 ObjectGrid 会话。
    2. 从会话中获取 EntityManager。
    3. 在 EntityManager 中启动事务范围。
    4. 使用 EntityManager 执行查询。
    5. 遍历结果(尽管本例中只有 1 个结果)。
    6. 在您已完成读取和编辑 Java 对象时,提交事务。


    清单 6. 使用 EntityManager API 查询数据
                            
    Session session = objectGrid.getSession();
    EntityManager em = session.getEntityManager();
    
    em.getTransaction().begin();
    
    String queryString = "select e from Employee e where e.ssn = '1234'";
    Query query = em.createQuery(queryString);
    Iterator<Employee> results = query.getResultIterator();
    
    while (results.hasNext()) {
    	Employee e = results.next();
    	System.out.println(e.firstName);
    	System.out.println(e.surname);
    	System.out.println(e.ssn);
    	System.out.println(e.salary);
    }
    
    em.getTransaction().commit();

    在事务最后提交之前,对象都处于“托管”状态。也就是说,对 Java 对象所做的任何更改都在事务提交时被 ObjectGrid 拾取和存储。(对于分布式 ObjectGrid 的情况,如在本例中,更改将保存在 ObjectGrid 客户端的 Near Cache 中。)在事务之外,Java 对象不再连接到 ObjectGrid,因此不会保存任何更改。它们现在处于“已断开”状态。

    有趣的是,清单 6 显示的查询代码只适用于单个分区 ObjectGrid。这是因为 ObjectGrid 只支持单阶段提交事务(比两阶段提交要快得多),因此一次查询只能跨越单个分区。要执行跨网格查询,必须在每个分区上执行查询。可以从 PartitionManager 获得分区数,还可以使用如下内容选择要查询的分区:

    query.setPartition(i)

    如清单 7 所示。



    清单 7. 跨多个分区执行查询
                            
    BackingMap bm = objectGrid.getMap("Employee");
    PartitionManager pm = bm.getPartitionManager();
    int numPartitions = pm.getNumOfPartitions();
    
    for (int i = 0; i < numPartitions; ++i) {
    	em.getTransaction().begin();
    
    	Query query = em.createQuery("select e from Employee e");
    	query.setPartition(i);
    	Iterator<Employee> results = query.getResultIterator();
    		
    	//use the results
    
    	em.getTransaction().commit();
    }

    您现已拥有分布式 ObjectGrid,以及使用 EntityManager API 读取和写入数据的能力。这为要执行的网格操作提供了基础。





回页首


在网格上执行计算和更新

您现在就可以使用 ObjectGrid 功能在 ObjectGrid 分区上执行在原处 计算和更新。此功能的基础是创建和运行代理。

代理是提供的一段应用程序逻辑,与 ObjectGrid 中的数据搭配。您定义的每个代理将存在于每个分区中。代理是通过在 ObjectGrid 客户机中调用 Agent Manager 并行执行的(图 1)。在代理中,可以对网格数据执行任何计算或操作。

分布式 ObjectGrid 需要了解要运行的代理代码。因此,每个服务器的 Java 类路径需要包括代理 Java 类,以便进行服务器端处理。

有两种类型的网格代理,它们之间的显著差异在于它们可以向客户机返回的信息:

  • MapGridAgent 从分区返回结果的映射。例如,MapGridAgent 对于检索数据子集并且针对每个结果执行一些计算可能非常有用。
  • ReduceGridAgent 从每个分区返回单个结果。例如,ReduceGridAgent 对于计算出某个分区的最低值和最高值可能非常有用。

A. 在网格上执行计算

让我们返回我们的场景:您希望能计算出全体员工的平均工资。为了实现此目的,您需要让每个分区计算:

  • 该分区中员工的总工资。
  • 该分区中的员工数目。

然后将此信息传回客户机,以计算跨网格的平均工资:

计算

计算是在每个分区(数据所在的位置)上并行执行的。当分区上的计算完成时,将值传回客户机,然后客户机可以执行简单的聚合计算。

您将使用 ReduceGridAgent 执行该计算。这是从每个分区“返回一个结果”的代理。让我们简单地看一下如清单 8 所示的接口,您需要为您的代理实现该接口。


清单 8. ReduceGridAgent 接口
                
public interface ReduceGridAgent {
	
	/**
	 * Provides the logic to be run on each partition.    
	 * @return Object containing the result of the processing
	 */
	public Object reduce(Session s, ObjectMap map);
	
	/**
	 * Provides the logic to be run on each partition.
	 * In this case, the entries for the partition are constrained 
	 * further by the entity keys in the collection    
	 * @return Object containing the result of the processing
	 */
	public Object reduce(Session s, ObjectMap map, Collection keys);

	/**
	 * Run once for the whole grid. 
	 * It is run after the reduce methods have been run.  
	 * @param A Collection of Java Objects, which is the results from
	 * each reduce method.  
	 */
	public Object reduceResults(Collection results);

}

您将提供以下方法的实现:

  • reduce() 用于计算某个分区的平均工资;它在服务器端的每个分区上执行。
  • reduceResults() 用于聚合从各个分区返回的平均值;它在客户机上运行。

在本练习中,您不会用到第二个 reduce 方法,但是该方法背后隐藏着一种想法,正如该方法提供的键集所指出的,您可以对分区的子集执行操作。例如,在本场景中,您可以计算数据子集(例如经理)的平均工资。

有关该接口在分布式基础设施中的情况,请参见图 3。


图 3. 平均工资网格代理概览
图 3. 平均工资网格代理概览

最后,除实现 ReduceGridAgent 接口之外,您的代理还需要实现 EntityAgentMixin 接口。在存储实体时尤其必要,并且只需要实现 getClassForEntity() 方法,该方法返回您正在处理的实体的 Java 类类型。

  1. Reduce 代理代码

    请参见清单 9,了解将在每个分区上运行的 reduce 代理代码(图 3)。其逻辑非常直观:

    1. 查询分区上的所有员工。
    2. 遍历这些员工,计算分区上的员工总数和总工资。


    清单 9. 平均工资 reduce 代理代码
                            
    public Object reduce(Session s, ObjectMap map) {
    	EntityManager em = s.getEntityManager();
    	Query q = em.createQuery("select e from Employee e");
    	Iterator<Employee> employees = q.getResultIterator();
    	int sum = 0;
    	int count = 0;
    	while (employees.hasNext()) {
    		Employee e = employees.next();
    		sum += e.salary;
    		count++;
    	}
    	WeightedSalary partitionTotal = new WeightedSalary();
    	partitionTotal.employeeCount = count;
    	partitionTotal.salaryTotal = sum;
    	return partitionTotal;
    }

  2. 聚合来自整个网格的数据

    要组合来自整个网格的结果,您只需遍历各个分区所提供的结果。计算整个网格的工资总额,然后除以网格中的员工总数(清单 10).此代码在客户端运行。



    清单 10. 平均工资 reduce 代理聚合代码
                            
    public Object reduceResults(Collection results) {
    	System.out.println("Calculate salary total across the grid");
    	Iterator<WeightedSalary> salaries = results.iterator();
    	int sum = 0;
    	int count = 0;
    	while (salaries.hasNext()) {
    		WeightedSalary sc = (WeightedSalary) salaries.next();
    		sum += sc.salaryTotal;
    		count += sc.employeeCount;
    	}
    	return sum / count;
    }

    您已定义了代理,现在只需从您的应用程序代码中启动它(如清单 11 所示):

    1. 您拥有 ObjectGrid 中的 Employee ObjectMap 的句柄。通过此句柄,您可以获取 AgentManager,它提供了请求网格执行您的代理代码的方法。
    2. 为您刚刚描述的代理创建一个实例。
    3. 将代理传递给 AgentManager 上的 callReduceAgent 方法,并使用所返回的结果。在本例中,返回一个包含整个网格上的平均工资的整数。


    清单 11. 平均工资 reduce 代理客户机代码
                            
    AgentManager amgr = map.getAgentManager();
    AverageSalaryReduceAgent agent = new AverageSalaryReduceAgent();
    
    Integer aveSalary = (Integer) amgr.callReduceAgent(agent);

    正如您所看到的,这非常简单,您很快就可以看到此方法在操作网格数据方面的强大功能。在这个简单的示例中,演示了图 3 中所描述的解决方案的各个方面如何整合在一起:

    • 客户机发起调用(从主程序)。
    • 代理方法在每个分区上运行(在 reduce 代理代码中)。
    • 再次对客户机执行聚合(也是在 reduce 代理代码中)。

B. 在网格上执行更新

您刚刚使用了 reduction 代理提供来自网格的“答案”。DataGrid API 提供的另一种类型的代理是 MapGridAgent。此代理同样支持将工作推送到 ObjectGrid 分区上,从而对分区上的所有数据或其子集执行操作。其区别在于,MapGridAgent 的设计旨在返回基于 map 的结果。这允许您对感兴趣的分区中的每个对象执行一项操作,并向客户机返回结果集。

在这种情况下,您实际上要执行的操作更简单,并使用 MapGridAgent 在 ObjectGrid 上执行更新。这可以通过 ReduceGridAgent 或 MapGridAgent 来完成,因为各自支持对给定分区的完全访问权限,以进行更新。此处使用后者仅仅是出于演示目的。

让我们简单地介绍一下 MapGridAgent 接口。它比 ReduceGridAgent 略为简单,因为 MapGridAgent 只包含两个方法,每个方法都在服务器上运行(清单 12)。


清单 12. 增加工资 map 代理代码
                
public interface MapGridAgent {
	
	/**
	 * Process a single entity in the partition we are working within 
	 * as designated by the key parameter passed to the method.  
	 * @return Object containing processed data 
	 */
	public Object process(Session s, ObjectMap map, Object key);
	
	/**
	 * Select all or some of the entities for this partition  
	 * @return Map containing results for client
	 */
	public Map processAllEntries(Session s, ObjectMap map);

}

在此查看和管理员工工资的场景中,假定公司正在全公司范围内提高 10% 的工资。这是要对 ObjectGrid 中的所有数据执行的非常简单的操作。图 4 直观地显示了此处执行的顺序:

  1. 从客户机发出对代理管理器的调用。
  2. 这会在每个代理上调用 processAllEntries 方法。
  3. processAllEntries 方法查询获得该分区中的所有 Employee 对象。
  4. 为每个 Employee 对象执行 process 方法,更新分区内的 Employee 工资。

图 4. MapGridAgent 概览
图 4. MapGridAgent 概览

因此,两种方法在 MapGridAgent 接口上都得到了实现(清单 13):

  • processAllEntries 方法允许您选择分区中的所有实体,然后通过 process 方法对每个实体执行操作。
  • process 方法只需更新由 key 参数指定的 Employee 对象的工资。由于 Employee 对象是托管实体,因此更新某个对象也会自动在网格分区中更新该对象。
  • 还需要向此代理传递一个参数,以确定为给定员工增加工资的百分比。此参数在对象构造函数上传递,以强制设置该参数。

在本例中,您不需要响应,因此使用了空的 Hash map。


清单 13. 增加工资 map 代理客户机代码
                
public class IncreaseSalaryMapAgent implements MapGridAgent, EntityAgentMixin {
	private float increasePercentage;
	
	public IncreaseSalaryMapAgent(float increasePercentage){
		super();
		this.increasePercentage = increasePercentage;
	}

	public Map processAllEntries(Session s, ObjectMap map) {
		EntityManager em = s.getEntityManager();
		Query q = em.createQuery("select p from Employee p");
		Iterator iter = q.getResultIterator();
		while (iter.hasNext()) {
			Employee p = (Employee) iter.next();
			process(s,map,p);
		}
		return new HashMap(); //just empty hashmap
	}

	public Object process(Session s, ObjectMap map, Object key) {
		Employee p = (Employee)key;
		p.salary *= 1 + increasePercentage;
		return p;
	}

	public Class getClassForEntity() {
		return Employee.class;
	}

}

代理跨网格执行,其方式与 ReduceGridAgent 完全相同。您可以在清单 14 中看到此结果。同样,您获取指向 AgentManager 的句柄以调用 map 代理。这一次传递的是 IncreaseSalaryMapAgent,已使用要向网格中的工资数据执行的百分比增长对其进行了初始化。


清单 14. 来自演示应用程序的示例输出
                
AgentManager amgr = map.getAgentManager();
IncreaseSalaryMapAgent agent = new IncreaseSalaryMapAgent(increase);

Map m = amgr.callMapAgent(agent);

这是启动代理的最简单方法。但是,也可以采用与 reduction 代理相同的方法扩展该方法,将一组实体键传递给 callMapAgent 方法进行处理。这会绕过代理中的 processAllEntries 方法,从而为相应分区上的特定实体直接调用 process 方法。

现在您已完成分布式应用程序和网格代理的设计,并且已准备好进行测试。





回页首


运行演示应用程序

  1. 准备 ObjectGrid

    基于您在前面定义的配置,启动 ObjectGrid。(如果您没有 ObjectGrid 的副本,请参见参考资料以获得试用版。)下载本文包含的演示应用程序。这里将使用的重要目录包括:

    • DEMO_HOME:引用您解压缩演示应用程序的位置。
    • JAVA_HOME:Java SDK 的位置(必须设置为环境变量)。
    • OG_HOME:ObjectGrid V6.1 的位置。
  2. 启动 Catalog 服务器

    现在可以从 ObjectGrid bin 目录中启动 Catalog 服务器和两个 ObjectGrid 服务器。从 OG_HOME/bin 运行:

    startOgServer.bat/.sh catalogServer –listenerHost localhost

  3. 启动 ObjectGrid 服务器

    下面的启动脚本假定所有 ObjectGrid 服务器都将在相同的硬件上运行。因此,它们不需要参数来通知其 Catalog 服务器的位置。

    从 OG_HOME/bin 运行(每个命令在一行上):

    startOgServer.bat/.sh server1
    	-objectgridFile <DEMO_HOME>/META-INF/ObjectGrid_Definition.xml
    	-deploymentPolicyFile <DEMO_HOME>/META-INF/ObjectGrid_Deployment.xml 
    	-jvmArgs -cp <DEMO_HOME>
    
    startOgServer.bat/.sh server2 
    	-objectgridFile <DEMO_HOME>/META-INF/ObjectGrid_Definition.xml 
    	-deploymentPolicyFile <DEMO_HOME>/META-INF/ObjectGrid_Deployment.xml 
    	-jvmArgs -cp <DEMO_HOME>

    您可以只使用一个 ObjectGrid 服务器来运行此演示,但是使用两个或更多的 ObjectGrid 服务器有助于了解所发生情况的分布式特性。请随意启动更多具有不同名称的服务器。

    等待每个 ObjectGrid 服务器启动,通过以下消息确认:

    CWOBJ1001I: ObjectGrid Server server1 is ready to process requests.

    将在日志目录中创建 ObjectGrid 服务器的日志,该目录位于您启动服务器的目录。在运行客户机应用程序的同时观察 server1 和 server2 的 SystemOut.log 的内容将非常有趣。

  4. 运行客户机应用程序

    从 DEMO_HOME 目录使用以下命令启动客户机代码(全部在一行上):

    java -cp <OG_HOME>/lib/ogclient.jar;. com.ibm.websphere.samples.datagrid.SalaryApp



    清单 14. 来自演示应用程序的示例输出
                            
    Populating grid with Employee entities
    Calculate salary average across the grid
    Average salary across grid: 44000
    Processing salary increase across grid
    Calculate salary average across the grid
    Average salary across grid: 48400
    Reading from partition: 0
    	Jonathan
    	Marshall
    	0
    	110000
    Reading from partition: 1
    	Alan
    	Chambers
    	1
    	55000
    Reading from partition: 2
    	Matt
    	Perrins
    	2
    	22000
    Reading from partition: 3
    	Joe
    	Bloggs
    	3
    	22000
    Reading from partition: 4
    	Fred
    	Smith
    	4
    	33000

    此输出显示:

    • 运行两个代理的结果:
      • 在运行工资增加代理之前显示平均工资。
      • 运行工资增加代理。
      • 平均工资实际上增加了 10%。
    • 单个员工记录的打印输出存储在您的 ObjectGrid 中。每个员工的工资再次增加了 10%,并且从不同的分区读取各个 Employee 对象,从而显示了查询的分布式特性。

    如果看一下 server1 和 server2 的 SystemOut.log 文件,您会看到五条类似如下所示的消息:

    [10/10/07 14:04:10:046 BST] 
    21722172 SystemOut O Calculating salary total for partition: 0
    [10/10/07 14:04:10:468 BST] 
    40d840d8 SystemOut O Processing salary increase for partition: 0

    此日志输出是由代理在运行时生成的,因此您会看到代理从五个不同的位置运行了五次。客户机可以运行许多次,随着网格中的工资数据不断增长,每一次都会显示更高的平均工资。





回页首


结束语

分享这篇文章……

digg 提交到 Digg
del.icio.us 发布到 del.icio.us
Slashdot Slashdot 一下!

本文演示了 ObjectGrid 的两个强大的功能领域:使用 EntityManager API 在 ObjectGrid 中保存 Java 对象,以及使用 DataGrid API 执行网格计算和更新。

使用这些工具,可以方便地建立分布式数据网格的基本基础设施并执行网格计算。本文提供的简单示例演示了如何使用 ObjectGrid 支持有可能异常困难的复杂场景。而且,此方法有可能带来显著的性能提升,同时不需要大量的硬件基础设施。





回页首


致谢

我要感谢 Alan Chambers、Billy Newport 和 Chris Johnson 对本文的审阅和提供的重要反馈。






回页首


下载

描述名字大小下载方法
Code sampleObjectGrid-computation-demo.zip16 KBHTTP
关于下载方法的信息


参考资料

学习

获得产品和技术

讨论


关于作者

Jonathan Marshall 是英国 IBM WebSphere Technical Sales 的一名高级 IT 专家。他担任 WebSphere Application Server 和相关产品的技术顾问已有六年时间,最近专注于 IBM 的流程集成产品。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?







回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款