Introduction

Snowflake is a service used to generate unique IDs for objects within Twitter (Tweets, Direct Messages, Users, Collections, Lists etc.). These IDs are unique 64-bit unsigned integers, which are based on time, instead of being sequential. The full ID is composed of a timestamp, a worker number, and a sequence number.
By default, 64-bit unsigned integers will generate an Id whose length is 19, but sometimes it may be too long, some customers need an Id whose length is 16.
In this article, I will show how can we adapt to generate an Id whose length is 16.

How to Do This?

The full ID is composed of a 41 bit timestamp, 10 bit worker number, and 12 bit sequence number.
We can reduce the bit count of those components to finish this work.
Here is a sample that we can follow.
  1. public class IdGenerator
  2. {
  3. public const long Twepoch = 1288834974000L;
  4. // change from 5 to 3
  5. private const int WorkerIdBits = 3;
  6. // change from 5 to 2
  7. private const int DatacenterIdBits = 2;
  8. // change from 12 to 8
  9. private const int SequenceBits = 8;
  10. private const long MaxWorkerId = -1L ^ (-1L << WorkerIdBits);
  11. private const long MaxDatacenterId = -1L ^ (-1L << DatacenterIdBits);
  12. private const long SequenceMask = -1L ^ (-1L << SequenceBits);
  13. private const int WorkerIdShift = SequenceBits;
  14. private const int DatacenterIdShift = SequenceBits + WorkerIdBits;
  15. public const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits;
  16. private long _sequence = 0L;
  17. private long _lastTimestamp = -1L;
  18. public long WorkerId { get; protected set; }
  19. public long DatacenterId { get; protected set; }
  20. public long Sequence
  21. {
  22. get { return _sequence; }
  23. internal set { _sequence = value; }
  24. }
  25. public IdGenerator(long workerId, long datacenterId, long sequence = 0L)
  26. {
  27. if (workerId > MaxWorkerId || workerId < 0)
  28. {
  29. throw new ArgumentException($"worker Id must greater than or equal 0 and less than or equal {MaxWorkerId}");
  30. }
  31. if (datacenterId > MaxDatacenterId || datacenterId < 0)
  32. {
  33. throw new ArgumentException($"datacenter Id must greater than or equal 0 and less than or equal {MaxDatacenterId}");
  34. }
  35. WorkerId = workerId;
  36. DatacenterId = datacenterId;
  37. _sequence = sequence;
  38. }
  39. private readonly object _lock = new object();
  40. public long NextId()
  41. {
  42. lock (_lock)
  43. {
  44. var timestamp = TimeGen();
  45. if (timestamp < _lastTimestamp)
  46. {
  47. throw new Exception($"timestamp error");
  48. }
  49. if (_lastTimestamp == timestamp)
  50. {
  51. _sequence = (_sequence + 1) & SequenceMask;
  52. if (_sequence == 0)
  53. {
  54. timestamp = TilNextMillis(_lastTimestamp);
  55. }
  56. }
  57. else
  58. {
  59. _sequence = 0;
  60. }
  61. _lastTimestamp = timestamp;
  62. return ((timestamp - Twepoch) << TimestampLeftShift) | (DatacenterId << DatacenterIdShift) | (WorkerId << WorkerIdShift) | _sequence;
  63. }
  64. }
  65. private long TilNextMillis(long lastTimestamp)
  66. {
  67. var timestamp = TimeGen();
  68. while (timestamp <= lastTimestamp)
  69. {
  70. timestamp = TimeGen();
  71. }
  72. return timestamp;
  73. }
  74. private long TimeGen()
  75. {
  76. return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  77. }
  78. }
As you can see, the above code reduces the bit count of worker number and sequence number.
The next step is to use this IdGenerator.
  1. static void Main(string[] args)
  2. {
  3. // keep the generator singleton
  4. var generator = new IdGenerator(0, 0);
  5. System.Threading.Tasks.Parallel.For(0, 20, x =>
  6. {
  7. Console.WriteLine(generator.NextId().ToString());
  8. });
  9. Console.WriteLine("Hello World!");
  10. Console.ReadKey();
  11. }
Here is the result of it.
NOTE
We should keep the generator qas a singleton, it means that we should only create the generator once. If not, it may generate some duplicate Ids.

Summary

This article showed you a simple solution of how to generate a snowflake id whose length is 16.
By the way, you can adjust the bit count to adapt your work.
I hope this will help you!