Mastering Apollo’s HTTP Long Polling: A Deep Dive into Distributed Config Centers
This article explores Apollo’s distributed configuration center, focusing on its core architecture and the implementation of HTTP Long Polling, including code examples, timeout considerations, and strategies to ensure reliable message delivery across multiple client nodes.
Introduction
Today’s topic is Apollo, a distributed configuration center. For those unfamiliar with configuration centers, you can look them up.
Common configuration centers include:
Apollo: open‑source from Ctrip with standardized permission and workflow governance.
Nacos: Alibaba’s open‑source project with rich features, also supporting DNS and RPC service discovery.
Spring Cloud Config: part of the Spring Cloud ecosystem, seamlessly integrates with Spring Cloud.
Apollo enjoys high popularity in China’s developer community, with over 100 k stars on GitHub and many production cases.
In this article we focus on the core and interesting technical points of Apollo.
Overall Architecture
The overall design of most configuration centers follows a similar pattern. The usage flow is:
User modifies and publishes configuration in the configuration center.
The configuration center notifies Apollo clients of the update.
Apollo client pulls the latest configuration, updates its local cache, and notifies the application.
HTTP Long Polling
Apollo uses HTTP Long Polling to notify applications of configuration changes. The client sends an HTTP request that the server holds until new data arrives or a timeout occurs, effectively turning a single request into a push‑style notification.
Compared with WebSocket, long polling is simpler to implement on the client side and incurs less overhead for infrequent configuration changes.
Implementation with Spring’s DeferredResult
Spring provides
DeferredResultto implement server‑side long polling. Apollo’s source code uses this class to keep the request thread free while waiting for changes.
Key points:
A global
deferredResultMapstores pending long‑polling requests, keyed by namespace.
The
/listenendpoint creates a
DeferredResultwith a timeout (default 10 s) and registers it in the map.
The
/publishendpoint sets the result for all pending requests of the same namespace, waking them up.
<code>private final Multimap<String, DeferredResult<String>> deferredResultMap = HashMultimap.create();
private long DEFAULT_LONG_POLLING_TIMEOUT = 10 * 1000;
@GetMapping("/listen")
public DeferredResult<String> pollNotification(@RequestParam("namespace") String namespace) {
DeferredResult<String> result = new DeferredResult<>(DEFAULT_LONG_POLLING_TIMEOUT, "timeout");
result.onTimeout(() -> log.info("timeout"));
result.onCompletion(() -> {
log.info("completion");
deferredResultMap.remove(namespace, result);
});
deferredResultMap.put(namespace, result);
return result;
}
@GetMapping("/publish")
public Object publishConfig(@RequestParam("namespace") String namespace,
@RequestParam("context") String context) {
if (deferredResultMap.containsKey(namespace)) {
for (DeferredResult<String> dr : deferredResultMap.get(namespace)) {
dr.setResult(context);
}
}
return "success";
}
</code>Timeout Settings
Although the server controls the timeout, gateways (e.g., Nginx) may impose their own limits (default 60 s). Ensure your timeout does not exceed the gateway’s limit.
Ensuring No Message Loss
If a client node loses network connectivity during a long‑polling request, it may miss a configuration change. Apollo records every change in the database with an auto‑increment
notificationId. Each poll returns the latest
notificationId, and the client sends the last received id on the next request, allowing the server to deliver missed updates.
The server builds the long‑polling URL with the previous
notificationId(method
assembleLongPollRefreshUrl) and updates the id after each successful response.
<code>private void doLongPollingRefresh(String appId, String cluster,
String dataCenter, String secret) {
// omitted for brevity
// 1. Randomly select a config service
// 2. Assemble URL with notificationId
// 3. Send HTTP request and process response
// 4. Update notificationId and notify listeners
}
</code>Conclusion
This article presented Apollo’s core technique—HTTP Long Polling—for delivering configuration updates, discussed timeout considerations, and explained how Apollo guarantees reliable delivery even when network interruptions occur.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.