跨线程生成唯一的序列号

时间:2017-03-27 22:29:35

标签: c# biztalk

我需要从多个线程生成唯一的序列号。我在下面创建了简单的类,它似乎有用,但我不确定我是否可以依赖序列号是唯一的。

此外,如果超过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?

3 个答案:

答案 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)和这通常是地图中的一个坏主意(特别是一个将在多个系统上并行执行的地图)。

那你能做什么?

  1. 选择另一种识别您的debatched消息的方式。也许是批次ID和个人ID - 也许两者都是GUID(或者至少是从GUID中获得的东西,它仍然足够独特)。
  2. 在批处理或出路前对消息进行排序,通过Ordered Delivery端口 singleton orchestration (实际上是单例队列)。这有一些明显的缺点,但你可以用它来获得一点创意 - 首先映射你的整个批次然后排序,然后debatch;或重做你的debatch过程,以便在消息发布时在消息中构建一个序列;或者将所有内容放入一个带有SEQUENCE的SQL(2012+)表中,该表根据您的要求循环,然后按顺序将其拉出来。
  3. 重新考虑您的要求。什么是终端系统要求这个?你为什么认为你需要在地图上这样做?