写点什么

使用 redis 生成唯一编号

作者:喵叔
  • 2021 年 11 月 29 日
  • 本文字数:1806 字

    阅读完需:约 6 分钟

在项目开发中,我们需要保证数据的唯一性,就目前开发中常用的方式有使用自增序列、GUID、时间戳以及时间戳加上随机数。生成 ID 的方法有很多,每种适用场景、需求以及性能要求不同。下面我们列出以下较为常用的生成 ID 的方式,并且来讨论以下他们的优缺点。


  1. 利用数据库自带的自增功能设置唯一 id:


  • 优点:可控并且显而易见。

  • 缺点:对于单库单表来说数据库压力大,对于单库多表来说,id 并不是全库唯一。


  1. 利用 GUID:生成 GUID 是长度为 32 的 16 进制字符串,如果转换为 byte 数组则一共有 16 个 byte 元素,也就是说 GUID 是一个 128bit 长的数字。


  • 优点:减轻了数据库的压力。

  • 缺点:对于需要排序来说,我们无法使用 id 排序。


TIP:目前有类似 GUID 的方式,但是大多数都是把时间拼接上去,但是这样就造成了 id 特别长。


  1. 自定义 ID:目前推特使用的是自己开发的全局唯一 ID 生成服务 Snowflake。它是由精确到毫秒的 41 位时间序列和 10 位机器标识以及 12 位的计数顺序号组成的,它的最高位是符号位并且始终为 0。


  • 优点:高性能、低延迟、可以按时间排序。

  • 缺点:需要独立开发和部署。


  1. Redis 生成 id:对于大型系统来说,我们可以使用 Redis 来生成 ID,主要是依赖于 redis 是单线程的,因此可以用来生成全局唯一 ID。要实现这个功能我们可以用 redis 的原子操作 INCR 和 INCRBY 来实现。下面我们就来看一下如何使用 redis 生成唯一 ID,主要思想是利用 redis 单线程特性以保证操作的原子性,这样读写同一 key 时不会出现不同的数据。代码如下:


  • 首先我们先利用 DequeueItemFromList 方法循环获取编号 GetForeachNumbers,


 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 上传序列


  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;}
复制代码


  • 最后获取编号


public string GetNumber(ShortNumberType type){  using (var redisClent = RedisManager.GetClient())  {    return GetForeachNumbers(redisClent, type);  }}
复制代码


发布于: 3 小时前阅读数: 6
用户头像

喵叔

关注

还未添加个人签名 2020.01.14 加入

还未添加个人简介

评论

发布
暂无评论
使用redis生成唯一编号