概述
设计目标:每秒最大生成10万个ID,ID单调递增且唯一。Reidis可以不需要持久化ID。
要求:集群时钟不能倒退。
总体思路:集群中每个节点预生成生成ID;然后与redis的已经存在的ID做比较。如果大于,则取节点生成的ID;小于的话,取Redis中最大ID自增。
Java代码
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static com.google.common.base.Preconditions.checkArgument;
/**
* 生成递增的唯一序列号, 可以用来生成订单号,例如216081817202494579
*
* 生成规则:
* 业务类型 + redis中最大的序列号
*
* 约定:
* redis中最大的序列号长度为17,包括{6位日期 + 6位时间 + 3位毫秒数 + 2位随机}
*
* 建议:
* 为了容错和服务降级, SeqGenerator生成失败时最好采用UUID替换
*
* Created by juemingzi on 16/8/19.
*/
public class SeqGenerator {
private static final Logger logger = LoggerFactory.getLogger(SeqGenerator.class);
private static final Path filePath = Paths.get(Thread.currentThread().getContextClassLoader().getResource("lua/get_next_seq.lua").getPath());
//线程安全
private static final FastDateFormat seqDateFormat = FastDateFormat.getInstance("yyMMddHHmmssSSS");
private static final RedisExtraService redisExtraService = SpringContext.getBean(RedisExtraService.class);
private final byte[] keyName;
private final byte[] incrby;
private byte[] sha1;
public SeqGenerat