Soul source code reading series data synchronization based on Http long polling

In the last article, I learned the execution process of http long polling by tracking the source code. However, I still have some questions. This article is in Official website It has been expanded on the basis of and added some own understanding.

The data synchronization mechanism of zookeeper and websocket is relatively simple, while http synchronization will be relatively complex. Soul draws on the design idea of Apollo and Nacos, extracts its essence, and realizes the http long polling data synchronization function. Note that this is not the traditional ajax long polling!

The http long polling mechanism is shown above. The request logic is that the Soul gateway actively requests the configuration service of Soul admin. There are two kinds of response logic: the configuration modification of the Soul admin end itself and the waiting time of 60s.

After the http request reaches sou admin, it does not respond to the data immediately, but uses servlet3 The asynchronous mechanism of 0 responds to data asynchronously. First, throw the long polling request task LongPollingClient into the blocking queue blogingqueue, start the scheduling task, execute it every 60s, take out the request in the queue and send the corresponding response. If there is no change in configuration information, you also need to respond to the request to let the gateway know that you don't need to wait all the time. Of course, when the gateway requests to configure the service, it also has a timeout of 90s.

class LongPollingClient implements Runnable {
    LongPollingClient(final AsyncContext ac, final String ip, final long timeoutTime) {
        // Omit
    }
    @Override
    public void run() {
        // Join the scheduled task. If there is no configuration change within 60s, execute it after 60s and respond to the http request
        this.asyncTimeoutFuture = scheduler.schedule(() -> {
            // clients is a blocking queue that holds the request information from the soul web
            clients.remove(LongPollingClient.this);
            List<ConfigGroupEnum> changedGroups = HttpLongPollingDataChangedListener.compareMD5((HttpServletRequest) asyncContext.getRequest());
            //Send response
            sendResponse(changedGroups);
        }, timeoutTime, TimeUnit.MILLISECONDS);
        //Put in the blocking queue
        clients.add(this);
    }
}

If the data information of soul admin changes during this period, the long polling requests in the queue will be removed one by one, and the data will be responded to to inform which Group's data has changed (we divide the plug-in, rule, traffic configuration and user configuration data into different groups). After receiving the response information, the gateway only knows which Group has changed its configuration, and needs to request the configuration data of the Group again.

// When the configuration of soul admin changes, the requests in the queue are removed one by one and responded to
class DataChangeTask implements Runnable {
    DataChangeTask(final ConfigGroupEnum groupKey) {
        this.groupKey = groupKey;
    }
    @Override
    public void run() {
        try {
            //Processing requests in the blocking queue one by one
            for (Iterator<LongPollingClient> iter = clients.iterator(); iter.hasNext(); ) {
                LongPollingClient client = iter.next();
                //remove
                iter.remove();
                //response
                client.sendResponse(Collections.singletonList(groupKey));
            }
        } catch (Throwable e) {
            LOGGER.error("data change error.", e);
        }
    }
}

After receiving the http response information, the soul web gateway layer pulls the change information (if there is any change), and then requests the configuration service of soul admin again. This cycle is repeated.

Long polling is reflected in that the request task will be executed all the time.

class HttpLongPollingTask implements Runnable {

    	//Omit other codes

        @Override
        public void run() {
            //Keep cycling
            while (RUNNING.get()) {
                for (int time = 1; time <= retryTimes; time++) {
                    try {
                        doLongPolling(server);
                    } catch (Exception e) {
                        //Keep cycling
                    }
                }
            }
            log.warn("Stop http long polling.");
        }
    }

Polling: the client sends an http request to the server every few seconds. After receiving the request, the server responds directly whether there is data update or not. When the server response is completed, the TCP connection will be closed. This method is very simple and has good compatibility. It can be implemented in this way as long as it supports http protocol. The disadvantage is that it consumes a lot of resources and takes up more memory and bandwidth.

Long polling: after the client sends the request, the server will not return data immediately. The server will block and the request connection will be suspended. It will not return until the server has data update or the connection timeout. The client will send the request again to create a new connection and repeat so as to obtain the latest data. Compared with polling, long polling reduces the number of unnecessary http requests and saves resources.

Keywords: soul

Added by mikemessiah on Tue, 01 Feb 2022 10:41:47 +0200