分布式自增序列id的实现(二) ---分布式序号生成器

本文在分布式自增序列的实现(一) ---分布式序号生成器基础上成文,因此直接上解决办法,省去问题的讨论。请先阅读分布式自增序列的实现(一) ---分布式序号生成器

上一篇我们提到使用zookeeper的持久化序列node来自动生成分布式序列id,本文将讨论使用redis的INCR功能实现分布式自增序列的实现。redis是单线程的,它能保证生成的序列是不重复的。

Redis incr功能介绍

官方文档https://redis.io/commands/incr
Increments the number stored at key by one. If the key does not exist, it is set to 0 before performing the operation. An error is returned if the key contains a value of the wrong type or contains a string that can not be represented as integer. This operation is limited to 64 bit signed integers.

Note: this is a string operation because Redis does not have a dedicated integer type. The string stored at the key is interpreted as a base-10 64 bit signed integer to execute the operation.

Redis stores integers in their integer representation, so for string values that actually hold an integer, there is no overhead for storing the string representation of the integer.

The counter pattern is the most obvious thing you can do with Redis atomic increment operations.
可以看到最大的序列是64bit的有符号的整型, 最大值是2的63次方-1, 也就是9,223,372,036,854,775,807,基本上绝大部分项目够用了。从0开始。特别是文档中的这句,"incr可以用作计数器模式,它是原子自增操作。"

具体代码实现

我直接使用的spring-data-redis,程序基于springboot。完整代码在这里,欢迎加星,fork。 本程序启动时会自动连接redis, 请先配置好自己的redis服务器ip和端口等信息.

本示例代码使用了RedisAtomicLong ,请参考官方文档https://docs.spring.io/spring-data/redis/docs/current/api/org/springframework/data/redis/support/atomic/RedisAtomicLong.html 我们主要使用addAndGet方法。

服务层代码

package com.yq.service.impl;

import com.yq.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * Simple to Introduction
 * className: RedisServiceImpl
 *
 * @author EricYang
 * @version 2018/8/4 23:00
 */
@Service
@Slf4j
public class RedisServiceImpl implements RedisService {

    @Autowired
    private StringRedisTemplate template;

    @Autowired
    RedisAtomicLong redisAtomicLong;

    private static final String LONG_KEY = "yqLong";

    @Bean
    public RedisAtomicLong getRedisAtomicLong() {
        RedisAtomicLong counter = new RedisAtomicLong(LONG_KEY, template.getConnectionFactory());
        return counter;
    }

    @Override
    public String get(String key) {
        ValueOperations<String, String> ops = this.template.opsForValue();
        return ops.get(key);
    }

    @Override
    public void set(String key, String value) {
        ValueOperations<String, String> ops = this.template.opsForValue();
        ops.set(key, value);
    }

    @Override
    public String getHash(String key, String hashKey) {
        HashOperations<String, String, String> hashOps = this.template.opsForHash();
        return hashOps.get(key, hashKey);
    }

    @Override
    public void setHash(String key, String hashKey, String value) {
        HashOperations<String, String, String> hashOps = this.template.opsForHash();
        hashOps.put(key, hashKey, value);
    }

    @Override
    public long getRedisSequence() {
        long sequence = 0L;
        try {
            if (redisAtomicLong.get() == 0) {
                redisAtomicLong.getAndSet(0L);
            }
            sequence = redisAtomicLong.incrementAndGet();
        } catch (Exception ex) {
            log.error("Failed to get sequence.", ex);
        }
        return sequence;
    }
}

controller层代码, 供其他服务调用

@RestController
@RequestMapping("/cache")
public class RedisController {
    private Logger logger = LoggerFactory.getLogger(RedisController.class);

   @Autowired
   RedisService redisService;

    @ApiOperation(value = "获取sequence")
    @GetMapping(value = "/sequence", produces = "application/json;charset=UTF-8")
    public long getSequence() {
        long value = redisService.getRedisSequence();
        return value;
    }
    。。。

效果截图

getSequence.png
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • pyspark.sql模块 模块上下文 Spark SQL和DataFrames的重要类: pyspark.sql...
    mpro阅读 9,503评论 0 13
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,860评论 18 139
  • 1 Redis介绍1.1 什么是NoSql为了解决高并发、高可扩展、高可用、大数据存储问题而产生的数据库解决方...
    克鲁德李阅读 5,354评论 0 36
  • 文/赖佳秀 冬姐姐穿着雪白的衣服悄悄地走了,春妹妹来了,她给故乡穿上了五颜六色的新衣,大地美起来了,香起来...
    我爱无花果阅读 641评论 0 0
  • 无意间看到张小娴写的:女人需要三样东西 1.男人 2.爱情 3.安全感 我终于知道所有的痛苦的症结...
    竹筠益阅读 340评论 0 1