How to use redis to generate serial number redis persistence

How to use redis to generate serial number

Summary

This article describes how to use redis to generate serial numbers. This article is implemented in spring boot. After knowing the principle, other frameworks can be easily implemented.

Principle introduction

This paper mainly uses the incr method of redis to supplement zero. Then the unique serial number is composed of time, random number and prefix.


Here is the structure of the serial number.

At the end of this article, I will briefly introduce the persistence of redis. Prevent redis downtime from causing auto increment reset. As a result, the serial number is repeated.

Flow chart

This implementation is divided into
1. Initializing serial number information into cache
2. Generate serial number

Here is the general flow chart of each

1. Initializing serial number information into cache

2. Generate serial number

code implementation

1. Serial number entity class

Used to store serial number information

@Data
public class YuSnGenCode {
	// The serial number generates the dependent class. The class name will be used as the key of redis 
    private Class entity;
    // prefix
    private String prefix;
    // If the number of self increasing digits does not reach this digit, it will be automatically zeroed
    private Integer num;

    public YuSnGenCode(Class entity, String prefix, Integer num) {
        this.entity = entity;
        this.prefix = prefix;
        this.num = num;
    }
}

2. Initialize serial number into cache

Initializing the serial number after program startup

@Component
@Slf4j
public class YuSnGenStart implements ApplicationRunner {
    @Autowired
    YuSnGenUtil yuSnGenUtil;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("=====Start initializing serial number=====");
        List<YuSnGenCode> yuSnGenCodeList = new ArrayList<>();
        yuSnGenCodeList.add(new YuSnGenCode(Account.class, "AC", 6));
        yuSnGenCodeList.add(new YuSnGenCode(Shop.class, "DP", 6));
        yuSnGenCodeList.add(new YuSnGenCode(Order.class, "OR", 6));
        yuSnGenCodeList.add(new YuSnGenCode(Dispatch.class, "DL", 6));
        yuSnGenCodeList.add(new YuSnGenCode(Refund.class, "RF", 6));
        yuSnGenCodeList.add(new YuSnGenCode(PayLog.class, "PL", 6));
        yuSnGenCodeList.add(new YuSnGenCode(Withdrawal.class, "WR", 6));
        yuSnGenCodeList.add(new YuSnGenCode(Aftermarket.class, "AS", 6));
        yuSnGenCodeList.add(new YuSnGenCode(Coupon.class, "CO", 6));
        yuSnGenCodeList.add(new YuSnGenCode(CouponGen.class, "CG", 10));
        yuSnGenCodeList.add(new YuSnGenCode(Draw.class, "DP", 6));
        yuSnGenUtil.init(yuSnGenCodeList);
        log.info("=====Initialization of serial number completed=====");
    }
}
  public void init(List<YuSnGenCode> yuSnGenCodes) {
        // Serial number initialization into cache
        for (YuSnGenCode yuSnGenCode : yuSnGenCodes) {
            String redisKey = yuSnGenCode.getEntity().getName();
            // Cache key: key: entity class name value: serial number data (prefix, self incrementing digits)
            redisTemplate.opsForValue().set(yuSnGenCode.getEntity().getName(), FastJsonUtils.toJsonStr(yuSnGenCode));
            log.info(yuSnGenCode.getEntity().getName() + "Initialized");

        }
    }

The serial number after initialization is shown in the figure below

3. Generate serial number

   public Optional<String> gen(Class c) {
   // Get the name of the entity class
        String redisKey = c.getName();
        // Determine whether this entity class has been initialized
        if (null != redisTemplate.opsForValue().get(redisKey)) {
        // Get the generation information of serial number from cache
            YuSnGenCode yuSnGenCode = FastJsonUtils.toBean(redisTemplate.opsForValue().get(redisKey).toString(), YuSnGenCode.class);
         // According to the prefix of the serial number, judge whether the serial number has been generated today
            if (redisTemplate.opsForValue().get(yuSnGenCode.getPrefix()) == null) {
            	// If not, create a new cache format (key: or value: 0)
                // Set to expire at 00:00:01 the next morning
                Long todayTime = LocalDate.now().plusDays(1).atTime(0, 0, 0, 1).atOffset(ZoneOffset.ofHours(8)).toEpochSecond();
                Long nowTime = LocalDateTime.now().atOffset(ZoneOffset.ofHours(8)).toEpochSecond();
                Long expireTime = todayTime - nowTime;
                redisTemplate.opsForValue().set(yuSnGenCode.getPrefix(), 0, expireTime*1000, TimeUnit.MILLISECONDS);
            }
            // Carry out auto increment operation
            StringBuffer sn = new StringBuffer();
            // Combined with prefix, time and random number
            sn.append(yuSnGenCode.getPrefix());
            String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
            sn.append(date);
            Long num = redisTemplate.opsForValue().increment(yuSnGenCode.getPrefix());
            sn.append(addZero(String.valueOf(num), yuSnGenCode.getNum()));
            String random = String.valueOf(new Random().nextInt(1000));
            sn.append(random);
            // Generate final serial number return
            return Optional.ofNullable(sn.toString());
        }
        return Optional.ofNullable(null);
    }
 // Automatic zeros
 public String addZero(String numStr, Integer maxNum) {
        int addNum = maxNum - numStr.length();
        StringBuffer rStr = new StringBuffer();
        for (int i = 0; i < addNum; i++) {
            rStr.append("0");
        }
        rStr.append(numStr);
        return rStr.toString();
    }

After the first generation of the serial number, there will be a data in redis with the prefix of the serial number as the key, and then it will be added directly. No need to add

Code testing

General test

   public Response test2() {
        return Response.success(yuSnGenUtil.gen(Order.class).get());
    }

give the result as follows

Concurrent test

Here we use ab for stress concurrency testing
Before the test, our serial number data is 0

Conduct 5000 request 100 concurrent test

There is no problem that the serial number data is 5000 after the request.

redis persistence

Redis persistence means that data can still be recovered after a restart after an unexpected exit of redis. We use redis persistence here to prevent redis from accidentally exiting and restarting, resulting in the reset of serial number data, resulting in the generation of duplicate serial number.

Redis provides different levels of persistence:

RDB

RDB persistence can store your data in a snapshot at a specified time interval

AOF

AOF persistent mode records every write operation to the server. When the server is restarted, these commands will be executed again to recover the original data

We are using AOF this time

According to the tips on the official website. We just need to open appendonly in the redis.config file. In this way, redis will generate the appendonly.aof file. When the server restarts, it will execute these commands again to recover the original data.

Be careful

Because there are three default backup methods for AOF

1. always executes fsync every time a new command is appended to an AOF file: very slow and very secure
2. Every sec fsync once per second: fast enough (similar to using RDB persistence), and only one second of data will be lost in case of failure.
3. no never fsync: hands over the data to the operating system for processing. Faster and less secure options.
And we use the second. It is also the default of AOF. But in this way, the data of 1s may be lost in case of failure, so if the data requirements are very strict, students can use the first method to only modify the appendfsync attribute of redis.config file.

The above is how to use the incr auto increment method of redis to write and generate serial numbers. If you have any questions, please point out in the comment area. Thank you A kind of

Published 6 original articles, won praise 0, visited 110
Private letter follow

Keywords: Redis Spring snapshot less

Added by Parody on Wed, 11 Mar 2020 05:38:01 +0200