Furion 框架实现高并发自增单号生成 (不使用数据库自增主键)
在 Furion 框架中,可以使用 Snowflake 算法来生成全局唯一的自增单号。Snowflake 算法是 Twitter 开源的分布式 ID 生成算法,通过组合时间戳、机器 ID 和序列号来保证生成的 ID 在分布式环境中不重复。
下面是在 Furion 框架中实现获取自增单号的方法的示例代码:
using System;
using Furion.DependencyInjection;
namespace YourNamespace
{
public interface IIdGenerator
{
long GenerateId();
}
[SkipScan] // 在 Furion 框架中注册为单例服务,跳过扫描
public class SnowflakeIdGenerator : IIdGenerator
{
private readonly object _lock = new object();
private long _lastTimestamp = -1;
private long _sequence = 0;
private const long Twepoch = 1288834974657L; // 起始时间戳,可以根据实际情况调整
private const int WorkerIdBits = 5; // 机器 ID 所占的位数
private const int DatacenterIdBits = 5; // 数据中心 ID 所占的位数
private const int SequenceBits = 12; // 序列号所占的位数
private readonly long _maxWorkerId = -1L ^ (-1L << WorkerIdBits); // 机器 ID 的最大值
private readonly long _maxDatacenterId = -1L ^ (-1L << DatacenterIdBits); // 数据中心 ID 的最大值
private readonly long _workerId; // 机器 ID
private readonly long _datacenterId; // 数据中心 ID
public SnowflakeIdGenerator()
{
_workerId = GetWorkerId();
_datacenterId = GetDatacenterId();
}
public long GenerateId()
{
lock (_lock)
{
var timestamp = GetCurrentTimestamp();
if (timestamp < _lastTimestamp)
{
throw new Exception('Clock moved backwards. Refusing to generate id.');
}
if (timestamp == _lastTimestamp)
{
_sequence = (_sequence + 1) & SequenceMask;
if (_sequence == 0)
{
timestamp = TilNextMillis(_lastTimestamp);
}
}
else
{
_sequence = 0;
}
_lastTimestamp = timestamp;
var id = ((timestamp - Twepoch) << TimestampLeftShift)
| (_datacenterId << DatacenterIdShift)
| (_workerId << WorkerIdShift)
| _sequence;
return id;
}
}
private long TilNextMillis(long lastTimestamp)
{
var timestamp = GetCurrentTimestamp();
while (timestamp <= lastTimestamp)
{
timestamp = GetCurrentTimestamp();
}
return timestamp;
}
private long GetCurrentTimestamp()
{
return DateTimeOffset.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;
}
private long GetWorkerId()
{
// 在实际应用中,可以根据机器的特定标识来获取 workerId
// 这里只是简单示范,使用一个随机数模拟
var random = new Random();
var workerId = random.Next((int)_maxWorkerId);
return workerId;
}
private long GetDatacenterId()
{
// 在实际应用中,可以根据数据中心的特定标识来获取 datacenterId
// 这里只是简单示范,使用一个随机数模拟
var random = new Random();
var datacenterId = random.Next((int)_maxDatacenterId);
return datacenterId;
}
private const long TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits;
private const long DatacenterIdShift = SequenceBits + WorkerIdBits;
private const long WorkerIdShift = SequenceBits;
private const long SequenceMask = -1L ^ (-1L << SequenceBits);
}
}
上述代码中,SnowflakeIdGenerator 类实现了 IIdGenerator 接口,在每次调用 GenerateId 方法时,根据当前时间戳、机器 ID 和序列号生成一个全局唯一的自增单号。为了确保生成的 ID 在分布式环境中不重复,需要根据实际情况设置合适的机器 ID 和数据中心 ID。
在高并发场景下,为了保证线程安全,使用 lock 关键字对关键代码块进行加锁。同时,在生成 ID 时,如果当前时间戳小于上次生成 ID 的时间戳,则抛出异常,避免出现重复单号。
注意:上述代码中的机器 ID 和数据中心 ID 的获取方式只是简单示范,实际应用中需要根据具体的环境和需求来确定。
原文地址: https://www.cveoy.top/t/topic/qet9 著作权归作者所有。请勿转载和采集!