如何使用redis生成唯一编号
共 1939字,需浏览 4分钟
·
2021-11-30 17:25
概述
在系统开发中,保证数据的唯一性是至关重要的一件事,目前开发中常用的方式有使用数据库的自增序列、UUID生成唯一编号、时间戳或者时间戳+随机数等。
生成ID的方法有很多,来适应不同的场景、需求以及性能要求。
常见方式
常见方式有:
1、利用数据库递增,全数据库唯一。
优点:明显,可控。
缺点:单库单表,数据库压力大。
2、UUID, 生成的是length=32的16进制格式的字符串,如果回退为byte数组共16个byte元素,即UUID是一个128bit长的数字,一般用16进制表示。
优点:对数据库压力减轻了。
缺点:但是排序怎么办?
此外还有UUID的变种,增加一个时间拼接,但是会造成id非常长。
3、twitter在把存储系统从MySQL迁移到Cassandra的过程中由于Cassandra没有顺序ID生成机制,于是自己开发了一套全局唯一ID生成服务:Snowflake。
1 41位的时间序列(精确到毫秒,41位的长度可以使用69年) 2 10位的机器标识(10位的长度最多支持部署1024个节点) 3 12位的计数顺序号(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号) 最高位是符号位,始终为0。
优点:高性能,低延迟;独立的应用;按时间有序。
缺点:需要独立的开发和部署。
4、Redis生成ID
当使用数据库来生成ID性能不够要求的时候,我们可以尝试使用Redis来生成ID。这主要依赖于Redis是单线程的,所以也可以用生成全局唯一的ID。可以用Redis的原子操作INCR和INCRBY来实现。
Redis生成
今天介绍下如何使用redis生成唯一的序列号,其实主要思想还是利用redis单线程的特性,可以保证操作的原子性,使读写同一个key时不会出现不同的数据。
循环获取编号 GetForeachNumbers ,利用DequeueItemFromList方法
///
/// 循环获取编号
///
/// "redisClent">redis客户端
/// "type">类型
/// "count">尝试次数
///
private string GetForeachNumbers(IRedisClient redisClent, ShortNumberType type, int count = 5)
{
var number = string.Empty;
var key = string.Format(CacheKeys.ComShortNumberList, type);
for (var i = 0; i < count; i++)
{
number = redisClent.DequeueItemFromList(key);
if (string.IsNullOrWhiteSpace(number) || string.IsNullOrEmpty(number))
{
if (!RedisUpload(type, true))
{
Thread.Sleep(500);
}
}
else
{
break;
}
}
return number;
}
redis上传序列
///
/// redis上传序列
///
/// "type">
/// "autoInsert">数据库量不足添加
public bool RedisUpload(ShortNumberType type, bool autoInsert)
{
var result = false;
var key = string.Format(CacheKeys.ComShortNumberList, type);
using (var redisClent = RedisManager.GetClient())
{
if (redisClent.GetListCount(key) <= RedisMinCount)
{
var lockKey = "comShortNumber" + type;
string token;
if (RedisManager.Lock(lockKey, out token, 1500))
{
try
{
var list = GetListForRedis(type);
//存储量不足,自动新增
if (list.Count < RedisUploadCount && autoInsert && AutoInsertList(type))
{
list = GetListForRedis(type);
}
if (list.Any())
{
var ids = list.Select(x => x.Id).ToList();
var numbers = list.Select(x => x.Number).ToList();
UpdateListByStatu(ids, ShortNumberStatus.handleIng);
redisClent.AddRangeToList(key, numbers.OrderByDescending(x => x).ToList());
UpdateListByStatu(ids, ShortNumberStatus.Finished);
}
}
finally
{
RedisManager.DelLock(lockKey, token);
}
result = true;
}
}
else
result = true;
}
return result;
}
获取编号 GetNumber
///
/// 获取编号
///
/// "type">类型
///
public string GetNumber(ShortNumberType type)
{
using (var redisClent = RedisManager.GetClient())
{
return GetForeachNumbers(redisClent, type);
}
}