从多部分主键生成 C* 桶哈希
Generate C* bucket hash from multipart primary key
我将拥有非常宽的 C* tables。为了防止它们变得太宽,我遇到了一个很适合我的策略。它出现在这个视频中。
Bucket Your Partitions Wisely
这种策略的好处是不需要 "look-up-table"(它很快),不好的部分是需要知道桶的最大数量并最终没有使用更多的桶(不可扩展)。我知道我的最大存储桶大小,所以我会试试这个。
通过从 tables 主键计算散列,这可以与其余主键一起用作存储桶部分。
我想出了以下方法来确保(我认为?)特定主键的哈希始终相同。
使用番石榴哈希:
public static String bucket(List<String> primKeyParts, int maxBuckets) {
StringBuilder combinedHashString = new StringBuilder();
primKeyParts.forEach(part ->{
combinedHashString.append(
String.valueOf(
Hashing.consistentHash(Hashing.sha512()
.hashBytes(part.getBytes()), maxBuckets)
)
);
});
return combinedHashString.toString();
}
我使用 sha512 的原因是能够拥有最大字符数为 256(512 位)的字符串,否则结果永远不会相同(根据我的测试看来)。
我远不是哈希大师,因此我要问以下问题。
要求:在不同 nodes/machines 上的不同 JVM 执行之间,对于给定的 Cassandra 主键,结果应该始终相同?
- 我可以依靠提到的方法来完成这项工作吗?
- 是否有更好的散列大字符串的解决方案,以便它们始终对给定字符串产生相同的结果?
- 我是否总是需要从字符串中散列,或者是否有更好的方法对 C* 主键执行此操作并始终产生相同的结果?
拜托,我不想讨论特定的数据建模table,我只想有一个桶策略。
编辑:
进一步阐述并提出了这个,因此字符串的长度可以是任意的。你怎么看这个?
public static int murmur3_128_bucket(int maxBuckets, String... primKeyParts) {
List<HashCode> hashCodes = new ArrayList();
for(String part : primKeyParts) {
hashCodes.add(Hashing.murmur3_128().hashString(part, StandardCharsets.UTF_8));
};
return Hashing.consistentHash(Hashing.combineOrdered(hashCodes), maxBuckets);
}
我目前在生产中使用类似的解决方案。因此,对于您的方法,我将更改为:
public static int bucket(List<String> primKeyParts, int maxBuckets) {
String keyParts = String.join("", primKeyParts);
return Hashing.consistentHash(
Hashing.murmur3_32().hashString(keyParts, Charsets.UTF_8),
maxBuckets);
}
所以差异
- 一次将所有PK部分发送到哈希函数中。
- 我们实际上将最大存储桶设置为代码常量,因为只有当最大存储桶保持不变时才会有一致的散列。
- 我们使用 MurMur3 哈希,因为我们希望它速度快而不是加密强度高。
对于您的直接问题 1) 是的,该方法应该可以完成工作。 2)我认为通过上面的调整你应该设置。 3)假设你需要整个PK?
我不确定您是否需要使用整个主键,因为期望您的主键的分区部分对于很多事情都是相同的,这就是您进行分桶的原因。您可以只散列那些将为您提供用于分区键的良好存储桶的位。在我们的例子中,我们只是对 PK 的一些集群键部分进行哈希处理,以生成我们用作分区键一部分的存储桶 ID。
我将拥有非常宽的 C* tables。为了防止它们变得太宽,我遇到了一个很适合我的策略。它出现在这个视频中。 Bucket Your Partitions Wisely
这种策略的好处是不需要 "look-up-table"(它很快),不好的部分是需要知道桶的最大数量并最终没有使用更多的桶(不可扩展)。我知道我的最大存储桶大小,所以我会试试这个。
通过从 tables 主键计算散列,这可以与其余主键一起用作存储桶部分。
我想出了以下方法来确保(我认为?)特定主键的哈希始终相同。
使用番石榴哈希:
public static String bucket(List<String> primKeyParts, int maxBuckets) {
StringBuilder combinedHashString = new StringBuilder();
primKeyParts.forEach(part ->{
combinedHashString.append(
String.valueOf(
Hashing.consistentHash(Hashing.sha512()
.hashBytes(part.getBytes()), maxBuckets)
)
);
});
return combinedHashString.toString();
}
我使用 sha512 的原因是能够拥有最大字符数为 256(512 位)的字符串,否则结果永远不会相同(根据我的测试看来)。
我远不是哈希大师,因此我要问以下问题。
要求:在不同 nodes/machines 上的不同 JVM 执行之间,对于给定的 Cassandra 主键,结果应该始终相同?
- 我可以依靠提到的方法来完成这项工作吗?
- 是否有更好的散列大字符串的解决方案,以便它们始终对给定字符串产生相同的结果?
- 我是否总是需要从字符串中散列,或者是否有更好的方法对 C* 主键执行此操作并始终产生相同的结果?
拜托,我不想讨论特定的数据建模table,我只想有一个桶策略。
编辑:
进一步阐述并提出了这个,因此字符串的长度可以是任意的。你怎么看这个?
public static int murmur3_128_bucket(int maxBuckets, String... primKeyParts) {
List<HashCode> hashCodes = new ArrayList();
for(String part : primKeyParts) {
hashCodes.add(Hashing.murmur3_128().hashString(part, StandardCharsets.UTF_8));
};
return Hashing.consistentHash(Hashing.combineOrdered(hashCodes), maxBuckets);
}
我目前在生产中使用类似的解决方案。因此,对于您的方法,我将更改为:
public static int bucket(List<String> primKeyParts, int maxBuckets) {
String keyParts = String.join("", primKeyParts);
return Hashing.consistentHash(
Hashing.murmur3_32().hashString(keyParts, Charsets.UTF_8),
maxBuckets);
}
所以差异
- 一次将所有PK部分发送到哈希函数中。
- 我们实际上将最大存储桶设置为代码常量,因为只有当最大存储桶保持不变时才会有一致的散列。
- 我们使用 MurMur3 哈希,因为我们希望它速度快而不是加密强度高。
对于您的直接问题 1) 是的,该方法应该可以完成工作。 2)我认为通过上面的调整你应该设置。 3)假设你需要整个PK?
我不确定您是否需要使用整个主键,因为期望您的主键的分区部分对于很多事情都是相同的,这就是您进行分桶的原因。您可以只散列那些将为您提供用于分区键的良好存储桶的位。在我们的例子中,我们只是对 PK 的一些集群键部分进行哈希处理,以生成我们用作分区键一部分的存储桶 ID。