A unique serial number generation scheme

Encountered several scenarios that need to produce unique keys

1: Warehousing system, all kinds of order numbers in the warehouse need to be unique and have certain business significance

  Requirements: AAAA20151212000000001 AAAA is the in-cabin service code, the middle 8 digits are the corresponding year, month, and day, and the last 8 digits are the unique key guarantee.    

2: E-commerce order system, the order number needs to be unique

  Requirements: 28710080047686 The last four digits are the buyer's ID (for sub-database and sub-table), and the front data is the unique key guarantee bit.

3: The unique key requirements for registered user ID and comment ID in the chat app system.

  Requirement: etx32s user ID unique value

Among the three requirements, a key value that can guarantee the uniqueness of the serial number is required. In distributed systems, there are many solutions to ensure unique key values. For example: simple and rude DB self-increment sequence, MD5 (basically unique), and in scenario 1, the distributed lock made by tair (Ali middleware) used at that time guarantees self-increment and uniqueness. This time I introduce a design scheme of sequence generation middleware products.

 

Overall program:



 

 

ps:

 Overall plan idea:

 The application cluster obtains an id each time and caches it locally. Every time you use it, get it locally. When the local id segment is used up, make another remote call to update.

 On the server side, DB is the master-slave configuration, and MHA is used for abnormal master-slave switching.

 Capacity Analysis:

 Cluster 10wqps, 500 servers. The single-machine id segment is set to 1w length, the request pressure on the server side is less than 1qps, the server side has no pressure, and most of them are obtained locally, without rpc consumption.   

 

 example:

 1: Client initialization

    //Initialize the client Util

    public static IdGenerator instance(String... password) {

        IdGenerator ig = generators.get(key);

        if (ig == null) {

            synchronized(generators) {

                ig = generators.get(key);

                if (ig == null) {

                    ig = new IdRangeIncrementGenerator(tmpPassword, idRangeDispatcher);

                    generators.putIfAbsent(key, ig);

                }

            }

        }

        return ig;

    }

    //Initialize client serialization segment and local Queue

    public IdRangeIncrementGenerator(final String schema, final String table, final String password,

                                     IdRangeDispatcher dispatcher) throws NoSuchGeneratorException {

        super(dispatcher);

        checkArgument(isNotBlank(password), "The password is blank");

        this.password = password;

        //Get idRange asynchronously

        backThread = new Thread(new Runnable() {

            @Override

            public void run() {

                while (!Thread.currentThread().isInterrupted()) {

                    try {

                        IdRange idRange = retryNext(password);//Call the server and go to the DB to get the Id

                        backQueue.put(new IdRangeRound(idRange));

                    } catch (InterruptedException ie) {

                        logger.error("interrupted.");

                        Thread.currentThread().interrupt();

                        break;

                    } catch (Throwable e) {

                        logger.error("backThread retryNext() error", e);

                    }

                }

            }

        });

        backThread.setName("Raptor-IdGenerator-backThread");

        backThread.setDaemon(true);

        backThread.start();

        IdRangeRound idRange = reload(idRangeRound);

        String msg = "Can't get idRange by password[" + password + "]";

        checkNotNull (idRange, msg);

    }

 

2 The client obtains the Id segment and uses it

//Get directly from the local method

@Override

    public long next(int num) throws NoMoreIdException {

    checkArgument(num > 0, "The num[" + num + "] must be > 0 ");

        long[] ids = new long[num];

        for (int i = 0; i < num; i++) {

       long id;

       IdRangeRound is = idRangeRound;

       while ((id = ir.next(1)) == -1) {

       //When the local id segment is not enough, re-remotely obtain and update the id segment

           go = reload(go);

       }

            ids[i] = id;

        }

        return ids;

    }

    / / Block thread update, re-acquire the Id side

    private synchronized IdRangeRound reload(IdRangeRound ir) {

        if (ir != idRangeRound) {

            return idRangeRound;

        }

        try {

            return idRangeRound = backQueue.take();

        } catch (InterruptedException e) {

            throw new RuntimeException(e);

        }

    }

 

3 Server-side DB disaster recovery solution: MHA

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326918487&siteId=291194637
Recommended