我需要从多个线程生成唯一的序列号。我在下面创建了简单的类,它似乎有用,但我不确定我是否可以依赖序列号是唯一的。
此外,如果超过999999,我需要能够将数字重新设置为0.我不希望它在很长一段时间内翻转,因为该方法可能被称为小于100每天一次。我知道系统会在有机会达到999999之前定期关闭以进行维护。
将从BizTalk映射中的xslt转换调用GetSequenceNumber
方法,并且可以在同一时间(在同一BizTalk主机实例中)多次调用该方法。
在我的开发系统上,它似乎正常工作并生成不同的值,即使BizTalk同时多次调用该方法。开发系统只运行一个BizTalk主机实例。
然而,在生产系统上,有两台服务器。我是否认为这种方法不能保证跨服务器的唯一性,因为它们在不同的应用程序域中运行?
我无法使用guid,因为序列号限制为16个字符。
public class HelperMethods
{
private static int sequenceNumber = 0;
public string GetSequenceNumber()
{
string result = null;
int seqNo = Interlocked.Increment(ref sequenceNumber);
result = string.Format("{0:MMddHHmmss}{1:000000}", DateTime.Now, seqNo);
return result;
}
}
我认为我可能能够使用服务器计算机名称并添加一些任意字符,这样即使在一台服务器上生成的序列号与另一台服务器上生成的序列号相同,它仍然会有所不同,但我可以使用它。我不确定它有多独特。像这样:
string seqNumber = (MachineName == "Blah" ? "A" : "B") + GetSequenceNumber();
有没有人对如何创建唯一序列号有任何建议?它不一定非常独特,我只需要碰撞就不太可能了。另外,如果以线程安全的方式达到1000000,如何将数字重置为0?
答案 0 :(得分:3)
这应该可以很好地返回一个包含16个字符的唯一字符串。它基于Guid
是唯一的。由于Guid
在使用Convert.ToBase64String
时转换为24个字符的字符串,因此使用XOR将字节折叠在自身上,以确保唯一性遍布所需的16个字符。
Guid gd = Guid.NewGuid();
byte[] ba = gd.ToByteArray();
ba = ba.Zip(ba.Reverse(), (b0, b1) => (byte)(b0 ^ b1)).ToArray();
string mostLikelyUnique16 = Convert.ToBase64String(ba).Substring(0, 16);
我得到的结果如8QBIi7JpCeHhCWmy
。
不保证唯一性,但我认为它相当不错,特别是考虑到你的要求允许偶尔发生碰撞。
我做了一个简单的测试,产生了100万个没有任何碰撞的值。
答案 1 :(得分:2)
如果事先知道服务器数量并且数量不是很大,那么您可以将最高有效数字分配给“服务器ID”,该服务器ID在每个服务器的配置中设置。因此,例如在10台服务器中,其中一台服务器只能使用范围为3000000-3999999的数字。对于一组100个服务器中的另一个实例,它将是范围4200000-4299999。
主要是在配置中包含告诉服务器的信息。
答案 2 :(得分:1)
这里有几个问题。
BizTalk管道和业务流程在单独的AppDomain中运行,Orchestration AppDomain有时会在业务流程的水合作用之间被拆除。即使,就目前而言,此映射仅在业务流程 xor 中运行,有时可能会将其放在另一个(或另一个主机实例)上,并且您的解决方案将蓬勃发展。当你开始在多服务器环境中运行任何东西时,请忘记它。
BizTalk地图的底线是,它们通常不会以任何使用外部资源的方式不确定。如果你只是想生成一个GUID(这是不确定的),那没关系。如果要在多个映射中生成序列,那不是一个好主意。你将不得不依赖一些外部系统(它实际上应该是外部的,甚至你正在运行的BizTalk appdomain才能真正正常工作 - 例如单例WCF服务或使用SQL Server SEQUENCE
)和这通常是地图中的一个坏主意(特别是一个将在多个系统上并行执行的地图)。
那你能做什么?
SEQUENCE
的SQL(2012+)表中,该表根据您的要求循环,然后按顺序将其拉出来。