如何使用redis生成唯一編號

語言: CN / TW / HK

在系統開發中,保證資料的唯一性是至關重要的一件事,目前開發中常用的方式有使用資料庫的自增序列、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方法

  /// <summary>
/// 迴圈獲取編號
/// </summary>
/// <param name="redisClent">redis客戶端</param>
/// <param name="type">型別</param>
/// <param name="count">嘗試次數</param>
/// <returns></returns>
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上傳序列

   /// <summary>
/// redis上傳序列
/// </summary>
/// <param name="type"></param>
/// <param name="autoInsert">資料庫量不足新增</param>
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

   /// <summary>
/// 獲取編號
/// </summary>
/// <param name="type">型別</param>
/// <returns></returns>
public string GetNumber(ShortNumberType type)
{
using (var redisClent = RedisManager.GetClient())
{
return GetForeachNumbers(redisClent, type);
}
}