如何使用redis生成唯一编号

DotNetCore实战

共 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(typetrue))
                    {
                        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);
            }
        }


浏览 93
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报