首页 > 解决方案 > Spring Data GemFire 自定义分区和性能

问题描述

我们正在使用 Spring Data GemFire 服务器、客户端和定位器。我们所有的 GemFire PARTITION Regions 都有复杂的键。

例如:

class Key { 
  String id1;
  String id2;
  Date date;
}

我们想根据整个密钥创建一个自定义分区。在getObject()我们计划返回的方法中 | 这 3 个字段的分隔字符串。

这是最佳实践还是有其他方法可以返回对象?

我们还计划创建关键索引,在这种情况下,我们必须单独创建索引,并且Key.id1我们的搜索将基于关键日期和关键 id1、id2。Key.id2Key.date

这是创建关键索引以提高性能的正确方法吗?

根据 GemFire 文档,我们计划使用 Functions 来提高性能。在Filter搜索发生在特定分区的参数中

我们是否只需要发送复杂对象或我们getObject在过滤器集中添加的任何分区逻辑?

标签: javagemfiregeodespring-data-gemfire

解决方案


首先,这个问题与您是否使用Spring Data GemFire (SDG) 启动 GemFire(数据)服务器无关,例如使用Gfsh。话虽如此,使用Spring尤其是 SDG 来引导和配置服务器、定位器和客户端具有显着优势。但是,我只是想在这个问题与其他感兴趣的读者有关的地方进行区分。

通过getObject()方法,我假设您实际上指的是PartitionResolver.getRoutingObject()?请参阅Javadoc

一般来说,我想说在您的Regions中使用简单的标量类型作为键几乎总是更可取的,例如Long, Integer,String等。大多数搜索应该基于值或值的属性(即对象)而不是比密钥的单个组件(例如id1)。

此外,我还要指出,我不同意PartitionResolver Javadoc项目符号 #1,其中指出“关键类可以实现PartitionResolver接口以启用自定义分区”。我认为这是一种幼稚的方法,原因有很多,其中最重要的是它将您的关键类与 GemFire 结合起来。当需要 a 时,您应该始终首选 #2 PartitionResolver

但是PartitionResolver在您的情况下真的需要 a 吗?

由于您的“整个”键定义了“路线”(即类的所有属性 [ id1, id2, date] Key),因此您甚至根本不需要涉及自定义PartitionResolver

您只需要在您的类中正确实现Object equals(:Object)hashCode()方法即可。Key

提示:请记住,GemFire区域java.util.Map在基本的基础级别上只是一个键值数据结构。是的,它们是分布式的(在大多数情况下)以及为 PARTITION Regions分区,但它基本上基于 aMap和密钥的“散列”。如果您的整个键定义了分区(或路由),则不需要自定义PartitionResolver

提示:此外,PARTITION 区域是一个逻辑区域,它被划分为 113 个存储桶(默认情况下,暂时忽略主存储区和次存储区),这些存储桶分布在集群中的(数据托管)服务器上,从而使区域在物理上当然,假设您的服务器是不同机器上的单独进程,那么分散。这就是构成“逻辑”区域的原因,因为对于您的应用程序来说,它只是 1 个整体数据结构。反正。

PartitionResolver如果键的一部分用于确定分区(或路由)或键/值对,您将实现自定义。如果您想在同一物理位置(即集群中的服务器/进程和机器)将某些键/值对组合在一起,这很有用。

例如,假设您想根据date您的键对相似的键/值对进行分组。然后...

class KeyDatePartitionResolver implements PartitionResolver { 

  public String getName() {
    return getClass().getName();
  }

  public Object getRoutingObject(EntryOperation<Key, Object> entryOp) {
    Key key = entryOp.getKey();
    return key.getDate();
  }
}

现在,发生在相似日期/时间的所有条目(键/值)都将被路由到逻辑 PARTITION Region中的同一分区(或存储桶) 。当然,您可以进一步过滤要分组的日期,或根据年/月/日或简单的年/月路由键/值对,但您可以选择。同样,重要的是从您的自定义方法中Object返回的方法实现了and方法。显然,Java 的类 ( Javadoc ) 可以。getRoutingObject(..)PartitionResolverequals(:Object)hashCode()java.util.Date

关于...

这是为提高性能而创建关键索引的正确方法吗?

好吧,这取决于您的应用程序搜索案例。id1您是基于键的组件(即 [ 、id2date] )集体还是单独搜索某些值?

例如,如果您通过组合 [ id1, date] 以及 [ id2, ] 进行搜索,那么您将使用类中的这些字段date创建 2 个(KEY)索引Key。如果您按所有 3 个字段 [ id1, id2, date] 进行搜索,那么您的 (KEY)索引将包括所有 3 个字段。如果您通过所有 3 个组合进行搜索,那么(通常)需要所有 3 个 KEY索引以获得最佳性能。

本质上,查询谓词表达式中使用的字段或字段组合应该被索引以获得可能更优化的性能。

但也不能保证。请记住,当值更改(添加、更新、删除等)时,索引需要在某种程度上更新。因此,存在与索引相关的“维护成本” ,您拥有的越多,它的潜在成本就越高。

您还必须权衡键/值对的数量和索引是否有必要之间的好处。如果数据本质上主要是参考数据,数据集相对较小(例如,可能 < 1000 个条目),那么有时完全扫描在性能上仍然比使用Index时更有效。全扫描相当于 RDBMS 中的全表扫描。请记住,索引不是免费的。它们占用空间(内存)和时间(CPU)来维护。

我还要说,通常最好(再次)使用简单的键并在与键关联的值中保持“可搜索”状态。不过,这归结为设计偏好。使用(简单)键进行分区/路由。

有关其他(和相关)信息,请参阅:此处此处此处此处

最后,关于Functions,过滤器是一组“键”(Javadoc)。这些键用于查找或路由到逻辑 PARTITION Region中的(存储桶)分区。

如果您还PartitionResolver使用 PARTITION Region配置了自定义,我相信它也会将解析器应用于传递给执行Function时的过滤(或一组键) Function

但是,您只是传递整个密钥,在您的情况下是您的Key类的一个实例,您可以在其中传递多个实例(因此,“ Set”),具体取决于您要过滤的密钥。

无论如何,我希望这一切都有意义。

与往常一样,当这类问题或被问到时,它会根据您的 UC(或数据访问模式)、要求、数据集而显着变化。在这里做的正确的事情是尝试和测试。

祝你好运!


推荐阅读