[英]Spring Data GemFire custom partition and performance
我们正在使用 Spring Data GemFire 服务器、客户端和定位器。 我们所有的 GemFire PARTITION Regions 都有复杂的键。
例如:
class Key {
String id1;
String id2;
Date date;
}
我们想根据整个密钥创建一个自定义分区。 在getObject()
方法中,我们计划返回一个 | 这 3 个字段的分隔字符串。
这是最佳做法还是有其他方法可以返回 object?
我们还计划创建关键索引,在这种情况下,我们必须分别在Key.id1
和Key.id2
和Key.date
上创建索引,因为我们的搜索将基于关键日期和关键 id1、id2。
这是创建关键索引以提高性能的正确方法吗?
根据 GemFire 文档,我们计划使用 Functions 来提高性能。 在Filter
参数中搜索发生在特定分区
我们是否只需要发送复杂的 object 或我们在getObject
中添加的任何分区逻辑并传入过滤器集?
首先,这个问题与您是否使用Spring Data GemFire (SDG) 启动 GemFire(数据)服务器无关,例如使用Gfsh 。 话虽如此,使用Spring (特别是 SDG)来引导和配置您的服务器、定位器和客户端具有显着优势。 但是,我只是想在这个问题与其他感兴趣的读者有关的地方进行区分。
通过getObject()
方法,我假设您实际上指的是PartitionResolver.getRoutingObject()
? 请参阅Javadoc 。
一般来说,我想说在您的Regions中使用简单的标量类型作为键几乎总是更可取的,例如Long
、 Integer
、 String
等。大多数搜索应该基于值或值的属性(即对象)而不是密钥的单个组件(例如id1
)。
此外,我还要指出,我不同意PartitionResolver
Javadoc项目符号 #1,其中指出“密钥 class 可以实现PartitionResolver
接口以启用自定义分区”。 我认为这是一种天真的方法,原因有很多,其中最重要的是它将您的密钥 class 与 GemFire 耦合。 当需要PartitionResolver
时,您应该始终首选 #2。
但是在您的情况下真的需要PartitionResolver
吗?
由于您的“整个”键定义了“路线”(即Key
类的所有属性 [ id1
、 id2
、 date
]),因此您甚至根本不需要涉及自定义PartitionResolver
。
您只需在您的Key
class 中正确实现Object
equals(:Object)
和hashCode()
方法。
提示:请记住,基本级别的 GemFire区域只是一个
java.util.Map
键值数据结构。 是的,它们是分布式的(在大多数情况下)以及为 PARTITION Regions分区,但它基本上基于Map
和您的密钥的“哈希”。 如果您的整个键定义了分区(或路由),则不需要自定义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中的同一分区(或存储桶)。 当然,您可以进一步过滤要分组的日期,或根据年/月/日或简单的年/月路由键/值对,但您可以选择。 同样,重要的是从自定义PartitionResolver
中的Object
getRoutingObject(..)
方法返回的 Object 实现了equals(:Object)
和hashCode()
方法。 显然,Java 的java.util.Date
class ( Javadoc ) 可以。
关于...
“这是为提高性能而创建关键索引的正确方法吗? ”
好吧,这取决于您的应用程序搜索案例。 您对某些值的搜索案例是集体还是单独基于密钥的组件(即 [ id1
、 id2
、 date
])?
例如,如果您通过组合 [ id1
, date
] 以及 [ id2
, date
] 进行搜索,那么您将使用来自Key
class 的这些字段创建 2 个(KEY)索引。 如果您按所有 3 个字段 [ id1
、 id2
、 date
] 进行搜索,那么您的 (KEY)索引将包括所有 3 个字段。 如果您通过所有 3 个组合进行搜索,那么(通常)需要所有 3 个 KEY索引以获得最佳性能。
本质上,查询谓词表达式中使用的字段或字段组合应该被索引以获得可能更优化的性能。
但也不能保证。 请记住,当值更改(添加、更新、删除等)时,索引需要在某种程度上更新。 因此,存在与索引相关的“维护成本”,您拥有的越多,它的潜在成本就越高。
您还必须权衡键/值对的数量和索引是否有必要之间的好处。 如果数据本质上主要是参考数据,数据集相对较小(例如,可能 < 1000 个条目),那么有时完全扫描在性能上仍然比使用Index时更有效。 全扫描相当于 RDBMS 中的全表扫描。 请记住,索引不是免费的。 它们占用空间(内存)和时间(CPU)来维护。
我还要说,通常最好(再次)使用简单的键并在与键关联的值中保持“可搜索”state。 不过,这归结为设计偏好。 使用(简单)键进行分区/路由。
有关其他(和相关)信息,请参阅: 此处、 此处、 此处和此处。
最后,关于Functions
,过滤器是一组“键”( Javadoc )。 这些键用于查找或路由到逻辑 PARTITION Region中的(存储桶)分区。
如果您还使用 PARTITION Region配置了自定义PartitionResolver
,我相信它也会将解析器应用于在执行Function
时传递给Function
的过滤(或一组键)。
但是,您只是传递整个密钥,在您的情况下,它是Key
class 的一个实例,您可以在其中传递多个实例(因此,“ Set
”),具体取决于您要过滤的密钥。
无论如何,我希望这一切都有意义。
与往常一样,当这类问题或被问到时,它会根据您的 UC(或数据访问模式)、要求、数据集而显着变化。 在这里做的正确的事情是尝试和测试。
祝你好运!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.