如何使用redis生成唯一编号
概述
在系统开发中,保证数据的唯一性是至关重要的一件事,目前开发中常用的方式有使用数据库的自增序列、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);
            }
        }
