Repository navigation
Metrics instrumentation across all DataStoreTypes (ZK, HTTP, DROVE) - #108
jitendradhawan wants to merge 43 commits into
Conversation
…ng instead of a list
…r-fix [Fix] Collision Check concurrency handling
…nanoseconds-fix [Fix] Prevent duplicate IDs by switching to monotonic clock (nanoTime)
… metrics recording
…ceRegistryUpdaterMetricsIntegrationTest
…date log messages for clarity
ToOnlyGaurav
left a comment
There was a problem hiding this comment.
Please go through comments
- Let's call metric_id to be something meaningful like upstream_id or dataSourceId etc.
| @SuperBuilder | ||
| public abstract class AbstractRangerHubClient<T, R extends ServiceRegistry<T>, D extends Deserializer<T>> implements RangerHubClient<T,R> { | ||
|
|
||
| private final String metricId; |
There was a problem hiding this comment.
Let's keep it generic name closer to functional. Keeping non-functional attribute with functional group looks a bit off
There was a problem hiding this comment.
renamed to upstreamId
|
|
||
| // Wait for initial update and a brief period for metric recording to complete | ||
| awaitRefresh(registry); | ||
| sleep(100); // Allow time for MetricRecorder call after updateNodes |
There was a problem hiding this comment.
Possible to use any synchronisation mechanism which gives better guarantees than sleep. Most of the time these tests fails if we have slow environments.
There was a problem hiding this comment.
Using awaitility now instead of sleep to check periodically with few ms wait
| List<ServiceNode<T>> nodes = new ArrayList<>(children.size()); | ||
| log.debug("Found {} nodes for [{}]", children.size(), serviceName); | ||
| if(children.isEmpty()){ | ||
| MetricRecorder.recordNullOrEmptyListNodeResponse(DataStoreType.ZK, metricId); |
There was a problem hiding this comment.
Can we have wrapper method for these two.
There was a problem hiding this comment.
extracted new method recordNullOrEmptyResponse to encapsulate both methods
| public static final String STALE_DATA_RETAINED = "staleDataRetained"; | ||
| public static final String ZK_READ = "zkRead"; | ||
|
|
||
| private static MetricRegistry metricRegistry = new MetricRegistry(); |
There was a problem hiding this comment.
new MetricRegistry(); is of no use.
|
|
||
| public static void recordNodeDataSinkUpdateStatus(DataStoreType dataStoreType, String metricId, String status) { | ||
| if (metricRegistry != null) { | ||
| metricRegistry.meter(MetricRegistry.name(PACKAGE_PREFIX, DATA_SOURCE, dataStoreType.name(), |
There was a problem hiding this comment.
Looks a bit confusion when read with line#110
There was a problem hiding this comment.
Resolved by using DATA_STORE_TYPE, dataStoreType.name(), DATA_SOURCE, upstreamId in all MetricRecorder methods
| ? oldV | ||
| : newV)) | ||
| .values(); | ||
| MetricRecorder.recordServiceNodesReturned(service.getServiceName(), serviceNodes.size()); |
There was a problem hiding this comment.
If we are getting these from upstreams, how we will figure out which upstream is returning wrong value?
There was a problem hiding this comment.
Now we're pushing node count also which are fetched from any upstream in ServiceRegistryUpdater
| dataLock.lock(); | ||
| try { | ||
| long resolvedTime = resolution.convert(timeInMillis, TimeUnit.MILLISECONDS); | ||
| long resolvedTime = resolution.convert( |
There was a problem hiding this comment.
Didn't get the need of doing this?
| } | ||
|
|
||
| public boolean check(long timeInMillis, int location) { | ||
| public long checkAndGetTime(int location) { |
There was a problem hiding this comment.
This method looks overloaded from the response perspective.
| * Checks collisions between ids in given period | ||
| */ | ||
| @Slf4j | ||
| public class CollisionChecker { |
| val serviceRegistrationResponse = registerService(service.getServiceName(), httpUrl, requestBody).orElse(null); | ||
| if(null == serviceRegistrationResponse || !serviceRegistrationResponse.valid()){ | ||
| log.warn("Http call to {} returned a failure response {}", httpUrl, serviceRegistrationResponse); | ||
| MetricRecorder.recordNullOrEmptyRegisterServiceResponse(DataStoreType.HTTP, metricId, service.getServiceName()); |
There was a problem hiding this comment.
let's shrink these two methods to one.
Don't want metrics related code to be surfaced more.
There was a problem hiding this comment.
extracted to recordNullOrEmptyRegisterServiceResponse
…or improved clarity
…s; simplify metric recording
|
- MatchingShardSelector: remove unused Collectors import (S1128) - HealthcheckStatus: suppress S115 - renaming healthy/unhealthy breaks 145 call sites - ServiceDiscoveryBundle: suppress S1172 on overridable protected methods - param required by subclasses - Domain: rename field 'domain' -> 'domainName' to avoid S1700 (field same name as class) - Id: rename field 'id' -> 'idValue' to avoid S1700; add @JsonProperty to preserve JSON serialization - IdGeneratorBase: replace RuntimeException with IllegalStateException (S112) - RangerDroveUtils: add explanatory comments to intentional no-op SSL methods (S1186/S4830); upgrade SSLContext from 'SSL' to 'TLSv1.2' (S4423); remove unused type param <T> (S2326); remove commented-out code block (S125) - RangerHubServerBundle: remove explicit type param from buildDroveClient call - HttpApiCommunicator: add comment to empty close() method (S1186) - PathBuilder: make REGISTERED_SERVICES_PATH static final (S1104/S1444/S3008)
…r suppressions - Domain.java: revert domainName->domain rename; add @SuppressWarnings(java:S1700) on class - Id.java: revert idValue->id rename and @JsonProperty; add @SuppressWarnings(java:S1700) on class - RangerDroveUtils.java: revert TLSv1.2->SSL; add @SuppressWarnings(java:S4423) on SSLContext line
…ery-dw5-bundle ServiceDiscoveryBundle
- Bump all Maven modules to 2.0.0-RC7 - Document metrics instrumentation and fixes - Call out breaking API and configuration migrations
Cap node-count reservoirs and remove unbounded service zombie metrics.\nMove standalone metric initialization behind configurable bundle lifecycle.
Replace inventory node-count histograms with latest-value gauges to reduce retained samples and update overhead. Keep service response histograms bounded.
|



Summary
Adds Dropwizard metrics instrumentation across Ranger's ZooKeeper, HTTP, and Drove discovery paths. Metrics now cover upstream availability, remote calls, parsing/serialization, registry refreshes, stale-data retention, health checks, provider updates, and node/service counts.
This change also introduces stable upstream IDs for metric attribution, wires metrics through Dropwizard bundles, adds backend-focused integration tests, and prepares release
2.0.0-RC7.Why
Ranger previously exposed limited visibility into discovery failures and data quality. Operators could not reliably distinguish upstream outages, malformed responses, stale-node retention, zombie filtering, or registry refresh latency.
These metrics make those states observable and separate them by datastore type and configured upstream.
What Changed
Metrics foundation
MetricRecorder, backed by DropwizardMetricRegistryand safe no-op behavior before initialization.DataStoreType(ZK,HTTP,DROVE) and upstream ID dimensions.io.appform.ranger.UniformReservoirhistograms for API response counts.ServiceDiscoveryConfiguration.builder()callers must explicitly set.metricsEnabled(true).Instrumented flows
Representative metric hierarchy:
Data flow
Bundle and configuration wiring
MetricRegistry.id.metricsEnabledconfiguration and server-bundle enablement hooks.zkServiceDiscovery.MetricRecorderis process-global. Disabling one bundle skips initialization but does not clear a registry initialized by another bundle.Breaking Changes / Migration
idzookeepers: [...]zookeeper: "connection-string"and addidwithUpstreamId(...)APINodeDataSource/NodeDataSinkgetUpstreamId()andgetDataStoreType().upstreamId(...), includingSimpleRangerZKClient.builder()DEFAULT_NAMESPACE/DEFAULT_HOSTfrom discovery-coreHTTP upstream migration
Each entry under
httpClientConfigsnow requires a non-blankid. Use a unique, stable value for correct metric attribution. Other HTTP client fields remain unchanged. The ID is propagated to the HTTP hub client and appears in metric names as<upstreamId>.Add an ID to every configured endpoint when multiple HTTP clients exist:
Programmatic configuration must also set the ID:
Direct callers of the generated all-arguments constructor must pass
idas its new first argument. Prefer the builder to avoid positional migration mistakes.Resulting metrics use the configured value, for example:
Drove upstream migration
Each
DroveUpstreamConfignow requires a non-blankid. Use a unique, stable value for correct metric attribution. Add it to YAML and programmatic builders:Direct
DroveOkHttpTransportcallers must change(okHttpClient)to(upstreamId, okHttpClient). Remove explicit generic type witnesses fromRangerDroveUtils.buildDroveClient(...), which is no longer generic.ZooKeeper upstream migration
Each Ranger Hub ZooKeeper upstream now requires a non-blank
id. Configuration changes from pluralzookeepers(List<String>) to singularzookeeper(String). A ZooKeeper ensemble remains one comma-separated connection string; configure separate upstream entries when connecting to multiple independent ensembles.Multiple independent ensembles now require separate entries:
Programmatic hub configuration must call
setId(...)andsetZookeeper(...)instead ofsetZookeepers(...). Direct ZooKeeper clients, finder/provider builders, factories, data sources, and sinks must also receive and propagateupstreamId.Resulting metrics use the configured value, for example:
Upstream IDs become metric-name segments. Validation enforces non-blank values but not uniqueness or metric-safe characters; choose unique, stable, low-cardinality IDs.
Programmatic extension migration
Custom implementations and direct callers must update these signatures:
dataSource(Service)dataSource(String upstreamId, Service)dataSink(Service)dataSink(String upstreamId, Service)getDefaultDataSource()getDefaultDataSource(String upstreamId)upstreamIdupstreamIdBehavioral Notes
isActive()is observed, not current-state gauges or transition counters.Optional.empty()records neither refresh success/failure nor stale retention.unknownFailuremetrics can overlap because handled failures are rethrown as communication exceptions.KeeperExceptions are classified as empty responses; broader read failures usezkRead.*.unknownFailure.Operational Considerations
Dependency Impact
ranger-coregains production dependency on Dropwizard Metrics.ranger-httpgains production dependency onjavax.validation-apiforHttpClientConfig.idvalidation.ranger-zookeepergains WireMock as test dependency.Testing
ranger-core,ranger-http,ranger-drove, andranger-zookeeper.PingCheckMonitorTestexternal network dependency with local WireMock.Suggested verification:
Reviewer Guide
Recommended review order:
MetricRecordermetric taxonomy, registry lifecycle, and cardinality behavior.ServiceRegistryUpdater,HealthChecker, andFinderUtilsinstrumentation semantics.metricsEnabledbehavior.Please pay particular attention to:
HttpCommunicator.healthy()instead of always reporting active.Additional Changes
2.0.0-RC6to2.0.0-RC7and documented migration inCHANGELOG.md.IllegalStateException, and added Sonar suppressions in ID model classes.List.of(...).