我有一个状态服务,其中有一系列分区键来自
-9223372036854775808至9223372036854775807(UniformInt64Partition)。
在调用服务时如何生成足够的分区密钥,以改善工作负载在所有分区之间的分配?
谢谢你
答案 0 :(得分:1)
对于如此大范围的分区键,最好的方法是在字段或字段集合的顶部使用hashing algorithm来生成键(编号),并尽可能减少冲突。
假设您要存储客户信息,例如,“约翰·史密斯”中客户名称的哈希值可能会生成32的哈希值,因为与“约翰·史密斯”名称相同的任何用户都会生成相同的哈希值,如果它不经常使用,那将不是问题,因为32不是id,并且可以重复使用,具有相同的哈希值,它们将存储在同一分区中。
如果您确实希望尽可能地分配这些值,则可以使用另一个字段来区分“约翰·史密斯”和“约翰·史密斯”,例如生日,并且除非两个生日都在同一日期,否则您会发现每个值都不同。
在您的情况下,因为范围非常大,所以必须使用哈希算法对这些值进行哈希处理以适合-9223372036854775808至9223372036854775807的范围。
您需要那么多钥匙吗?
如果您的系统不希望有很高的分区数量,那么一种简单的管理方法是使用自然数,该自然数可以紧密反映所选散列函数提供的键范围,因此您可以决定选择一个更好的性能,或更低的碰撞,或两者兼而有之。
答案 1 :(得分:0)
如果您已经使用GUID作为标识数据的键,这并不难。要知道的关键是,尽管GUID(实际上)是全局唯一的,但它甚至不接近在整个范围内均匀分布。我使用SHA1散列算法对GUID进行散列,因为尽管GUID为shortcomings as a cryptographic algorithm,但它在生成均匀分布的散列方面做得很好,而又不需要过多的服务器(在计算和RAM方面)。 附带说明一下,从GUID过渡到long会造成数据丢失(GUID等效于128位整数)。由于目标是在分区之间分布数据,所以这没关系。实际上,您可以使用比Int64小的范围,但是如果您已经有GUID,那为什么要麻烦。
有关从GUID创建分区键的扩展方法,请参见前面的代码。我的实现代码将其折叠为两行,但我在下面进行了细分,以便对其进行注释。
public static ServicePartitionKey ToPartitionKey(this Guid id)
{
// Hash algorithms need byte arrays, so we're converting the Guid here
byte[] guidBytes = id.ToByteArray();
// SHA1 is light weight and good at creating distribution across the range.
// Do not use for encryption!
SHA1CryptoServiceProvider hasher = new SHA1CryptoServiceProvider();
// Hash the Guid's bytes.
byte[] hashedBytes = hasher.ComputeHash(guidBytes);
// Now that our data is repeatibly but distributed evenly, we make it a long
long guidAsLong = BitConverter.ToInt64(hashedBytes, 0);
// return the partition key
return new ServicePartitionKey(guidAsLong);
}