public static ClickHouseNodes of(String cacheKey, String endpoints, Map<?, ?> options) {
        // TODO discover endpoints from a URL or custom service, for examples:
        // discover://(smb://fs1/ch-list.txt),(smb://fs1/ch-dc.json)
        // discover:com.mycompany.integration.clickhouse.Endpoints
        if (ClickHouseChecker.isNullOrEmpty(cacheKey) || ClickHouseChecker.isNullOrEmpty(endpoints)) {
            throw new IllegalArgumentException("Non-empty cache key and endpoints are required");
        }
        return cache.computeIfAbsent(cacheKey, k -> create(endpoints, options));
    }
Gets or creates list of managed {@link ClickHouseNode} for load balancing
and fail-over. Since the list will be cached in a {@link WeakHashMap}, as
long as you hold strong reference to the {@code cacheKey}, same combination
of {@code endpoints} and {@code options} will be always mapped to the exact
same list.

@param cacheKey  non-empty cache key
@param endpoints non-empty URIs separated by comma
@param options   default options
@return non-null list of nodes
clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseNodes.java