Spring Data GemFire 自定义分区和性能

问题描述

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

例如:

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

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

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

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

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

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

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

解决方法

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

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

一般来说,我认为在您的区域中使用简单的标量类型作为键几乎总是更可取,例如LongInteger、{{ 1}} 等。大多数搜索应该基于值或值的属性(即对象)而不是键的单个组件(例如 String)。

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

但是在您的情况下实际上需要 PartitionResolver 吗?

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

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

提示:请记住,GemFire Regions 在基本层面上只是一个 Key键值 数据结构。是的,它们是分布式的(在大多数情况下)以及针对 PARTITION Regions 进行分区,但它基本上基于 java.util.Map 和密钥的“哈希”。如果您的整个密钥定义了分区(或路由),则不需要自定义 Map

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

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

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

date

现在,发生在相似日期/时间的所有条目(键/值)都将路由到逻辑分区 Region 中的同一分区(或存储桶)。当然,您可以进一步过滤要分组的日期,或者根据年/月/日或简单的年/月路由键/值对,但是您可以选择。同样,重要的是从自定义 class KeyDatePartitionResolver implements PartitionResolver { public String getName() { return getClass().getName(); } public Object getRoutingObject(EntryOperation<Key,Object> entryOp) { Key key = entryOp.getKey(); return key.getDate(); } } 中的 Object 方法返回的 getRoutingObject(..) 实现了 PartitionResolverequals(:Object) 方法。显然,Java 的 hashCode() 类 (Javadoc) 可以。

关于...

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

嗯,这取决于您的应用程序搜索案例。您的某些值的搜索案例是基于键的组成部分(即 [ java.util.Date,id1,id2 ])的整体还是单独的?

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

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

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

您还必须权衡键/值对的数量与索引是否完全必要之间的利益。如果数据本质上主要是参考性的,数据集相对较小(例如 索引 时更有效。全扫描相当于 RDBMS 中的全表扫描。请记住,索引不是免费的。它们占用空间(内存)和时间(CPU)来维护。

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

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

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

如果您还使用 PARTITION Region 配置了自定义 Functions,我相信它还会将解析器应用于传递给 {{1} } 执行 PartitionResolver 时。

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

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

与往常一样,当提出此类问题时,根据您的 UC(或数据访问模式)、要求、数据集,情况会有很大差异。正确的做法是尝试和测试。

祝你好运!

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...