Khi xử lý cập nhật cấu hình, Apollo sử dụng cơ chế polling dài để đảm bảo ứng dụng luôn nhận được thay đổi mới nhất. Dưới đây là phân tích chi tiết về triển khai kỹ thuật.
@RestController
@RequestMapping("/notifications/v2")
public class NotificationControllerV2 implements ReleaseMessageListener {
private static final Logger logger = LoggerFactory.getLogger(NotificationControllerV2.class);
private final Multimap pendingRequests =
Multimaps.synchronizedSetMultimap(TreeMultimap.create(String.CASE_INSENSITIVE_ORDER, Ordering.natural()));
private static final Type changeRequestsType =
new TypeToken>() { }.getType();
}
Trong lớp này, thuộc tính pendingRequests đóng vai trò trung tâm, quản lý ánh xạ giữa khóa cấu hình và các kết quả trễ. Mỗi yêu cầu từ client được lưu trữ dưới dạng PollingResultHolder để xử lý sau khi có cập nhật.
@GetMapping
public DeferredResult>> pollConfigUpdates(
@RequestParam("appId") String appIdentifier,
@RequestParam("cluster") String environment,
@RequestParam("changes") String changeRequestsStr,
@RequestParam(value = "dc", required = false) String dataCenter,
@RequestParam(value = "ip", required = false) String clientAddress) {
// Xử lý logic...
}
Các tham số quan trọng bao gồm:
- appIdentifier: Mã định danh ứng dụng
- environment: Môi trường cấu hình (cluster)
- changeRequestsStr: Chuỗi thay đổi cấu hình dưới dạng JSON
- dataCenter: Trung tâm dữ liệu (tùy chọn)
- clientAddress: Địa chỉ IP client (dùng cho ghi log)
Sau khi phân tích chuỗi changeRequestsStr bằng Gson:
List changeRequests =
gson.fromJson(changeRequestsStr, changeRequestsType);
if (CollectionUtils.isEmpty(changeRequests)) {
throw new InvalidRequestException("Invalid change format");
}
Hệ thống lọc thông tin thay đổi:
Map validChanges =
validateChangeRequests(appIdentifier, changeRequests);
Tiếp theo, tạo đối tượng PollingResultHolder với thời gian chờ 60 giây:
PollingResultHolder holder = new PollingResultHolder(60000);
Set namespaces = Sets.newHashSet();
Map clientNotifications = Maps.newHashMap();
for (Map.Entry entry : validChanges.entrySet()) {
String namespace = entry.getKey();
ConfigChangeNotification change = entry.getValue();
namespaces.add(namespace);
clientNotifications.put(namespace, change.getNotificationId());
// Xử lý chuẩn hóa tên namespace
}
Sau đó, tạo danh sách khóa cần theo dõi:
Multimap monitoredKeys =
keyMonitor.assembleMonitoredKeys(appIdentifier, environment, namespaces, dataCenter);
Set allKeys = Sets.newHashSet(monitoredKeys.values());
Kiểm tra cập nhật mới nhất:
List latestChanges =
releaseService.getLatestChanges(allKeys);
List newUpdates =
generateConfigNotifications(namespaces, clientNotifications, monitoredKeys, latestChanges);
Cuối cùng, trả về kết quả cho client:
holder.onTimeout(() -> logTimeoutKeys(allKeys));
holder.onCompletion(() -> {
for (String key : allKeys) {
pendingRequests.remove(key, holder);
}
});
for (String key : allKeys) {
pendingRequests.put(key, holder);
}