Support build Service/Instance Hierarchy and query. (#11698)

This commit is contained in:
Wan Kai 2023-12-27 10:02:31 +08:00 committed by GitHub
parent 9ba0ad2991
commit ce5d6a4ffb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1746 additions and 6 deletions

View File

@ -59,6 +59,7 @@
<include>endpoint-name-grouping.yml</include>
<include>metadata-service-mapping.yaml</include>
<include>trace-sampling-policy-settings.yml</include>
<include>hierarchy-definition.yml</include>
<include>oal/*.oal</include>
<include>fetcher-prom-rules/*.yaml</include>
<include>envoy-metrics-rules/**</include>

View File

@ -12,6 +12,7 @@
service metadata.
* Set up the length of source and dest IDs in relation entities of service, instance, endpoint, and process to 250(was
200).
* Support build Service/Instance Hierarchy and query.
#### UI

View File

@ -105,7 +105,7 @@ extend type Query {
# Query the service hierarchy, based on the given service. Will recursively return all related layers services in the hierarchy.
getServiceHierarchy(serviceId: ID!, layer: String!): ServiceHierarchy!
# Query the instance hierarchy, based on the given instance. Will return all direct related layers instances in the hierarchy, no recursive.
getInstanceHierarchy(instanceId: ID!): InstanceHierarchy!
getInstanceHierarchy(instanceId: ID!, layer: String!): InstanceHierarchy!
}
```
New fields are going to be added to the `topology.graphqls`.

View File

@ -27,7 +27,9 @@ import org.apache.skywalking.oap.server.core.command.CommandService;
import org.apache.skywalking.oap.server.core.config.ConfigService;
import org.apache.skywalking.oap.server.core.config.DownSamplingConfigService;
import org.apache.skywalking.oap.server.core.config.IComponentLibraryCatalogService;
import org.apache.skywalking.oap.server.core.config.HierarchyDefinitionService;
import org.apache.skywalking.oap.server.core.config.NamingControl;
import org.apache.skywalking.oap.server.core.hierarchy.HierarchyService;
import org.apache.skywalking.oap.server.core.management.ui.menu.UIMenuManagementService;
import org.apache.skywalking.oap.server.core.management.ui.template.UITemplateManagementService;
import org.apache.skywalking.oap.server.core.oal.rt.OALEngineLoaderService;
@ -41,6 +43,7 @@ import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
import org.apache.skywalking.oap.server.core.query.AlarmQueryService;
import org.apache.skywalking.oap.server.core.query.BrowserLogQueryService;
import org.apache.skywalking.oap.server.core.query.EventQueryService;
import org.apache.skywalking.oap.server.core.query.HierarchyQueryService;
import org.apache.skywalking.oap.server.core.query.LogQueryService;
import org.apache.skywalking.oap.server.core.query.MetadataQueryService;
import org.apache.skywalking.oap.server.core.query.MetricsMetadataQueryService;
@ -81,6 +84,7 @@ public class CoreModule extends ModuleDefine {
classes.add(DownSamplingConfigService.class);
classes.add(NamingControl.class);
classes.add(IComponentLibraryCatalogService.class);
classes.add(HierarchyDefinitionService.class);
classes.add(IWorkerInstanceGetter.class);
classes.add(IWorkerInstanceSetter.class);
@ -98,7 +102,7 @@ public class CoreModule extends ModuleDefine {
addEBPFProfilingService(classes);
classes.add(CommandService.class);
classes.add(HierarchyService.class);
return classes.toArray(new Class[]{});
}
@ -138,6 +142,7 @@ public class CoreModule extends ModuleDefine {
classes.add(EventQueryService.class);
classes.add(TagAutoCompleteQueryService.class);
classes.add(RecordQueryService.class);
classes.add(HierarchyQueryService.class);
}
private void addServerInterface(List<Class> classes) {

View File

@ -223,6 +223,14 @@ public class CoreModuleConfig extends ModuleConfig {
@Getter
private int serviceCacheRefreshInterval = 10;
/**
* If disable the hierarchy, the service and instance hierarchy relation will not be built.
* And the query of hierarchy will return empty result.
*/
@Setter
@Getter
private boolean enableHierarchy = true;
public CoreModuleConfig() {
this.downsampling = new ArrayList<>();
}

View File

@ -44,11 +44,13 @@ import org.apache.skywalking.oap.server.core.command.CommandService;
import org.apache.skywalking.oap.server.core.config.ComponentLibraryCatalogService;
import org.apache.skywalking.oap.server.core.config.ConfigService;
import org.apache.skywalking.oap.server.core.config.DownSamplingConfigService;
import org.apache.skywalking.oap.server.core.config.HierarchyDefinitionService;
import org.apache.skywalking.oap.server.core.config.IComponentLibraryCatalogService;
import org.apache.skywalking.oap.server.core.config.NamingControl;
import org.apache.skywalking.oap.server.core.config.group.EndpointNameGrouping;
import org.apache.skywalking.oap.server.core.config.group.EndpointNameGroupingRuleWatcher;
import org.apache.skywalking.oap.server.core.config.group.openapi.EndpointNameGroupingRule4OpenapiWatcher;
import org.apache.skywalking.oap.server.core.hierarchy.HierarchyService;
import org.apache.skywalking.oap.server.core.logging.LoggingConfigWatcher;
import org.apache.skywalking.oap.server.core.management.ui.menu.UIMenuInitializer;
import org.apache.skywalking.oap.server.core.management.ui.menu.UIMenuManagementService;
@ -66,6 +68,7 @@ import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
import org.apache.skywalking.oap.server.core.query.AlarmQueryService;
import org.apache.skywalking.oap.server.core.query.BrowserLogQueryService;
import org.apache.skywalking.oap.server.core.query.EventQueryService;
import org.apache.skywalking.oap.server.core.query.HierarchyQueryService;
import org.apache.skywalking.oap.server.core.query.LogQueryService;
import org.apache.skywalking.oap.server.core.query.MetadataQueryService;
import org.apache.skywalking.oap.server.core.query.MetricsMetadataQueryService;
@ -253,6 +256,8 @@ public class CoreModuleProvider extends ModuleProvider {
this.registerServiceImplementation(ConfigService.class, new ConfigService(moduleConfig, this));
this.registerServiceImplementation(ServerStatusService.class, new ServerStatusService(getManager(), moduleConfig));
this.registerServiceImplementation(HierarchyDefinitionService.class, new HierarchyDefinitionService(moduleConfig));
this.registerServiceImplementation(HierarchyService.class, new HierarchyService(getManager(), moduleConfig));
this.registerServiceImplementation(
DownSamplingConfigService.class, new DownSamplingConfigService(moduleConfig.getDownsampling()));
@ -293,6 +298,7 @@ public class CoreModuleProvider extends ModuleProvider {
this.registerServiceImplementation(
TagAutoCompleteQueryService.class, new TagAutoCompleteQueryService(getManager(), moduleConfig));
this.registerServiceImplementation(RecordQueryService.class, new RecordQueryService(getManager()));
this.registerServiceImplementation(HierarchyQueryService.class, new HierarchyQueryService(getManager(), moduleConfig));
// add profile service implementations
this.registerServiceImplementation(

View File

@ -71,6 +71,15 @@ public class IDManager {
return define.sourceId + Const.RELATION_ID_CONNECTOR + define.destId;
}
/**
* @return encoded service hierarchy relation id
*/
public static String buildServiceHierarchyRelationId(ServiceHierarchyRelationDefine define) {
return define.serviceId + Const.SERVICE_ID_CONNECTOR + define.serviceLayer.value() +
Const.RELATION_ID_CONNECTOR +
define.relatedServiceId + Const.SERVICE_ID_CONNECTOR + define.relatedServiceLayer.value();
}
/**
* @return service relation ID object decoded from {@link #buildRelationId(ServiceRelationDefine)} result
*/
@ -100,6 +109,16 @@ public class IDManager {
private final String sourceId;
private final String destId;
}
@RequiredArgsConstructor
@Getter
@EqualsAndHashCode
public static class ServiceHierarchyRelationDefine {
private final String serviceId;
private final Layer serviceLayer;
private final String relatedServiceId;
private final Layer relatedServiceLayer;
}
}
/**
@ -140,6 +159,15 @@ public class IDManager {
return define.sourceId + Const.RELATION_ID_CONNECTOR + define.destId;
}
/**
* @return encoded instance hierarchy relation id
*/
public static String buildInstanceHierarchyRelationId(InstanceHierarchyRelationDefine define) {
return define.instanceId + Const.SERVICE_ID_CONNECTOR + define.serviceLayer.value() +
Const.RELATION_ID_CONNECTOR +
define.relatedInstanceId + Const.SERVICE_ID_CONNECTOR + define.relatedServiceLayer.value();
}
/**
* @return service instance relation ID object decoded from {@link #buildRelationId(ServiceInstanceRelationDefine)}
* result
@ -175,6 +203,16 @@ public class IDManager {
*/
private final String destId;
}
@RequiredArgsConstructor
@Getter
@EqualsAndHashCode
public static class InstanceHierarchyRelationDefine {
private final String instanceId;
private final Layer serviceLayer;
private final String relatedInstanceId;
private final Layer relatedServiceLayer;
}
}
/**

View File

@ -0,0 +1,79 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.config;
import java.io.FileNotFoundException;
import java.io.Reader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.oap.server.core.CoreModuleConfig;
import org.apache.skywalking.oap.server.core.UnexpectedException;
import org.apache.skywalking.oap.server.library.module.Service;
import org.apache.skywalking.oap.server.library.util.ResourceUtils;
import org.yaml.snakeyaml.Yaml;
@Slf4j
public class HierarchyDefinitionService implements Service {
@Getter
private Map<String, List<String>> hierarchyDefinition;
public HierarchyDefinitionService(CoreModuleConfig moduleConfig) {
this.hierarchyDefinition = new HashMap<>();
if (moduleConfig.isEnableHierarchy()) {
this.init();
this.checkLayers();
}
}
private void init() {
try {
Reader applicationReader = ResourceUtils.read("hierarchy-definition.yml");
Yaml yaml = new Yaml();
this.hierarchyDefinition = yaml.loadAs(applicationReader, Map.class);
} catch (FileNotFoundException e) {
throw new UnexpectedException("hierarchy-definition.yml not found.", e);
}
}
private void checkLayers() {
this.hierarchyDefinition.forEach((layer, lowerLayers) -> {
if (lowerLayers.contains(layer)) {
throw new IllegalArgumentException(
"hierarchy-definition.yml " + layer + " contains recursive hierarchy relation.");
}
checkRecursive(layer);
});
}
private void checkRecursive(String layerName) {
try {
List<String> lowerLayers = this.hierarchyDefinition.get(layerName);
if (lowerLayers == null) {
return;
}
lowerLayers.forEach(this::checkRecursive);
} catch (Throwable e) {
throw new IllegalArgumentException(
"hierarchy-definition.yml " + layerName + " contains recursive hierarchy relation.");
}
}
}

View File

@ -0,0 +1,143 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.hierarchy;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.oap.server.core.CoreModule;
import org.apache.skywalking.oap.server.core.CoreModuleConfig;
import org.apache.skywalking.oap.server.core.analysis.Layer;
import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
import org.apache.skywalking.oap.server.core.config.HierarchyDefinitionService;
import org.apache.skywalking.oap.server.core.hierarchy.instance.InstanceHierarchyRelation;
import org.apache.skywalking.oap.server.core.hierarchy.service.ServiceHierarchyRelation;
import org.apache.skywalking.oap.server.core.source.SourceReceiver;
import org.apache.skywalking.oap.server.library.module.ModuleManager;
import org.apache.skywalking.oap.server.library.module.Service;
@Slf4j
public class HierarchyService implements Service {
private final ModuleManager moduleManager;
private final boolean isEnableHierarchy;
private SourceReceiver sourceReceiver;
private Map<String, List<String>> hierarchyDefinition;
public HierarchyService(ModuleManager moduleManager, CoreModuleConfig moduleConfig) {
this.moduleManager = moduleManager;
this.isEnableHierarchy = moduleConfig.isEnableHierarchy();
}
private SourceReceiver getSourceReceiver() {
if (sourceReceiver == null) {
this.sourceReceiver = moduleManager.find(CoreModule.NAME).provider().getService(SourceReceiver.class);
}
return sourceReceiver;
}
private Map<String, List<String>> getHierarchyDefinition() {
if (hierarchyDefinition == null) {
hierarchyDefinition = moduleManager.find(CoreModule.NAME)
.provider()
.getService(HierarchyDefinitionService.class).getHierarchyDefinition();
}
return hierarchyDefinition;
}
/**
* Build the hierarchy relation between the 2 services. the `serviceLayer` and `relatedServiceLayer` hierarchy
* relations should be defined in `config/hierarchy-definition.yml`. Generally, if service A and service B could detect
* each other, then build the hierarchy in one side is enough.
*
* @param serviceName the name of the source service (self)
* @param serviceLayer the layer of the source service
* @param relatedServiceName the name of the detected related service
* @param relatedServiceLayer the layer of the detected related service
*/
public void toServiceHierarchyRelation(String serviceName,
Layer serviceLayer,
String relatedServiceName,
Layer relatedServiceLayer) {
if (!this.isEnableHierarchy) {
return;
}
if (!checkHierarchyDefinition(serviceLayer, relatedServiceLayer)) {
return;
}
ServiceHierarchyRelation serviceHierarchy = new ServiceHierarchyRelation();
serviceHierarchy.setServiceName(serviceName);
serviceHierarchy.setServiceLayer(serviceLayer);
serviceHierarchy.setRelatedServiceName(relatedServiceName);
serviceHierarchy.setRelatedServiceLayer(relatedServiceLayer);
serviceHierarchy.setTimeBucket(TimeBucket.getMinuteTimeBucket(System.currentTimeMillis()));
this.getSourceReceiver().receive(serviceHierarchy);
}
/**
* Build the hierarchy relation between the 2 instances. the `serviceLayer` and `relatedServiceLayer` hierarchy
* relations should be defined in `config/hierarchy-definition.yml`. Generally, if instance A and instance B could detect
* each other, then build the hierarchy in one side is enough.
*
* @param instanceName the name of the source instance (self)
* @param serviceName the name of the source service (self)
* @param serviceLayer the layer of the source service
* @param relatedInstanceName the name of the detected related instance
* @param relatedServiceName the name of the detected related service
* @param relatedServiceLayer the layer of the detected related service
*/
public void toInstanceHierarchyRelation(String instanceName,
String serviceName,
Layer serviceLayer,
String relatedInstanceName,
String relatedServiceName,
Layer relatedServiceLayer) {
if (!this.isEnableHierarchy) {
return;
}
if (!checkHierarchyDefinition(serviceLayer, relatedServiceLayer)) {
return;
}
InstanceHierarchyRelation instanceHierarchy = new InstanceHierarchyRelation();
instanceHierarchy.setInstanceName(instanceName);
instanceHierarchy.setServiceName(serviceName);
instanceHierarchy.setServiceLayer(serviceLayer);
instanceHierarchy.setRelatedInstanceName(relatedInstanceName);
instanceHierarchy.setRelatedServiceName(relatedServiceName);
instanceHierarchy.setRelatedServiceLayer(relatedServiceLayer);
instanceHierarchy.setTimeBucket(TimeBucket.getMinuteTimeBucket(System.currentTimeMillis()));
this.getSourceReceiver().receive(instanceHierarchy);
}
private boolean checkHierarchyDefinition(Layer serviceLayer, Layer relatedServiceLayer) {
List<String> lowerLayers = getHierarchyDefinition().get(serviceLayer.name());
List<String> relatedLowerLayers = getHierarchyDefinition().get(relatedServiceLayer.name());
if (lowerLayers == null || relatedLowerLayers == null) {
log.error("serviceLayer " + serviceLayer.name() + " or relatedServiceLayer " + relatedServiceLayer.name()
+ " is not defined in hierarchy-definition.yml.");
return false;
}
if (!lowerLayers.contains(relatedServiceLayer.name()) || !relatedLowerLayers.contains(serviceLayer.name())) {
log.error("serviceLayer " + serviceLayer.name() + " and relatedServiceLayer " + relatedServiceLayer.name()
+ " should have the hierarchy relation in hierarchy-definition.yml.");
return false;
}
return true;
}
}

View File

@ -0,0 +1,75 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.hierarchy.instance;
import lombok.Getter;
import lombok.Setter;
import org.apache.skywalking.oap.server.core.analysis.IDManager;
import org.apache.skywalking.oap.server.core.analysis.Layer;
import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
import org.apache.skywalking.oap.server.core.source.ScopeDeclaration;
import org.apache.skywalking.oap.server.core.source.Source;
@ScopeDeclaration(id = DefaultScopeDefine.INSTANCE_HIERARCHY_RELATION, name = "InstanceHierarchyRelation")
public class InstanceHierarchyRelation extends Source {
@Setter
@Getter
private String instanceName;
@Getter
private String instanceId;
@Setter
@Getter
private String serviceName;
@Getter
private String serviceId;
@Setter
@Getter
private Layer serviceLayer;
@Setter
@Getter
private String relatedInstanceName;
@Getter
private String relatedInstanceId;
@Setter
@Getter
private String relatedServiceName;
@Getter
private String relatedServiceId;
@Setter
@Getter
private Layer relatedServiceLayer;
@Override
public int scope() {
return DefaultScopeDefine.INSTANCE_HIERARCHY_RELATION;
}
@Override
public String getEntityId() {
return null;
}
@Override
public void prepare() {
serviceId = IDManager.ServiceID.buildId(serviceName, serviceLayer.isNormal());
relatedServiceId = IDManager.ServiceID.buildId(relatedServiceName, relatedServiceLayer.isNormal());
instanceId = IDManager.ServiceInstanceID.buildId(serviceId, instanceName);
relatedInstanceId = IDManager.ServiceInstanceID.buildId(relatedServiceId, relatedInstanceName);
}
}

View File

@ -0,0 +1,170 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.hierarchy.instance;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.apache.skywalking.oap.server.core.analysis.IDManager;
import org.apache.skywalking.oap.server.core.analysis.Layer;
import org.apache.skywalking.oap.server.core.analysis.MetricsExtension;
import org.apache.skywalking.oap.server.core.analysis.Stream;
import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
import org.apache.skywalking.oap.server.core.storage.StorageID;
import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
import org.apache.skywalking.oap.server.core.storage.annotation.Column;
import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
@Stream(name = InstanceHierarchyRelationTraffic.INDEX_NAME, scopeId = DefaultScopeDefine.INSTANCE_HIERARCHY_RELATION,
builder = InstanceHierarchyRelationTraffic.Builder.class, processor = MetricsStreamProcessor.class)
@MetricsExtension(supportDownSampling = false, supportUpdate = false)
@EqualsAndHashCode(of = {
"instanceId",
"serviceLayer",
"relatedInstanceId",
"relatedServiceLayer"
}, callSuper = true)
public class InstanceHierarchyRelationTraffic extends Metrics {
public static final String INDEX_NAME = "instance_hierarchy_relation";
public static final String SERVICE_LAYER = "service_layer";
public static final String INSTANCE_ID = "instance_id";
public static final String RELATED_SERVICE_LAYER = "related_service_layer";
public static final String RELATED_INSTANCE_ID = "related_instance_id";
@Setter
@Getter
@Column(name = INSTANCE_ID, length = 250)
@BanyanDB.SeriesID(index = 0)
private String instanceId;
@Setter
@Getter
@Column(name = SERVICE_LAYER)
@BanyanDB.SeriesID(index = 1)
private Layer serviceLayer = Layer.UNDEFINED;
@Setter
@Getter
@Column(name = RELATED_INSTANCE_ID, length = 250)
@BanyanDB.SeriesID(index = 2)
private String relatedInstanceId;
@Setter
@Getter
@Column(name = RELATED_SERVICE_LAYER)
@BanyanDB.SeriesID(index = 3)
private Layer relatedServiceLayer = Layer.UNDEFINED;
@Override
protected StorageID id0() {
String id = IDManager.ServiceInstanceID.buildInstanceHierarchyRelationId(
new IDManager.ServiceInstanceID.InstanceHierarchyRelationDefine(
instanceId, serviceLayer, relatedInstanceId, relatedServiceLayer));
return new StorageID().appendMutant(new String[] {
INSTANCE_ID,
RELATED_INSTANCE_ID,
SERVICE_LAYER,
RELATED_SERVICE_LAYER
}, id);
}
@Override
public boolean combine(final Metrics metrics) {
return true;
}
@Override
public void calculate() {
}
@Override
public Metrics toHour() {
return null;
}
@Override
public Metrics toDay() {
return null;
}
@Override
public void deserialize(final RemoteData remoteData) {
setInstanceId(remoteData.getDataStrings(0));
setServiceLayer(Layer.valueOf(remoteData.getDataIntegers(0)));
setRelatedInstanceId(remoteData.getDataStrings(1));
setRelatedServiceLayer(Layer.valueOf(remoteData.getDataIntegers(1)));
setTimeBucket(remoteData.getDataLongs(0));
}
@Override
public RemoteData.Builder serialize() {
final RemoteData.Builder builder = RemoteData.newBuilder();
builder.addDataStrings(instanceId);
builder.addDataIntegers(serviceLayer.value());
builder.addDataStrings(relatedInstanceId);
builder.addDataIntegers(relatedServiceLayer.value());
builder.addDataLongs(getTimeBucket());
return builder;
}
@Override
public int remoteHashCode() {
return this.hashCode();
}
public static class Builder implements StorageBuilder<InstanceHierarchyRelationTraffic> {
@Override
public InstanceHierarchyRelationTraffic storage2Entity(final Convert2Entity converter) {
InstanceHierarchyRelationTraffic traffic = new InstanceHierarchyRelationTraffic();
traffic.setInstanceId((String) converter.get(INSTANCE_ID));
traffic.setRelatedInstanceId((String) converter.get(RELATED_INSTANCE_ID));
if (converter.get(SERVICE_LAYER) != null) {
traffic.setServiceLayer(Layer.valueOf(((Number) converter.get(SERVICE_LAYER)).intValue()));
} else {
traffic.setServiceLayer(Layer.UNDEFINED);
}
if (converter.get(RELATED_SERVICE_LAYER) != null) {
traffic.setRelatedServiceLayer(
Layer.valueOf(((Number) converter.get(RELATED_SERVICE_LAYER)).intValue()));
} else {
traffic.setRelatedServiceLayer(Layer.UNDEFINED);
}
if (converter.get(TIME_BUCKET) != null) {
traffic.setTimeBucket(((Number) converter.get(TIME_BUCKET)).longValue());
}
return traffic;
}
@Override
public void entity2Storage(final InstanceHierarchyRelationTraffic storageData,
final Convert2Storage converter) {
converter.accept(INSTANCE_ID, storageData.getInstanceId());
converter.accept(RELATED_INSTANCE_ID, storageData.getRelatedInstanceId());
converter.accept(SERVICE_LAYER, storageData.getServiceLayer().value());
converter.accept(RELATED_SERVICE_LAYER, storageData.getRelatedServiceLayer().value());
converter.accept(TIME_BUCKET, storageData.getTimeBucket());
}
}
}

View File

@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.hierarchy.instance;
import org.apache.skywalking.oap.server.core.analysis.SourceDispatcher;
import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
public class InstanceHierarchyTrafficRelationDispatcher implements SourceDispatcher<InstanceHierarchyRelation> {
@Override
public void dispatch(final InstanceHierarchyRelation source) {
InstanceHierarchyRelationTraffic traffic = new InstanceHierarchyRelationTraffic();
traffic.setInstanceId(source.getInstanceId());
traffic.setServiceLayer(source.getServiceLayer());
traffic.setRelatedInstanceId(source.getRelatedInstanceId());
traffic.setRelatedServiceLayer(source.getRelatedServiceLayer());
traffic.setTimeBucket(source.getTimeBucket());
MetricsStreamProcessor.getInstance().in(traffic);
}
}

View File

@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.hierarchy.service;
import lombok.Getter;
import lombok.Setter;
import org.apache.skywalking.oap.server.core.analysis.IDManager;
import org.apache.skywalking.oap.server.core.analysis.Layer;
import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
import org.apache.skywalking.oap.server.core.source.ScopeDeclaration;
import org.apache.skywalking.oap.server.core.source.Source;
@ScopeDeclaration(id = DefaultScopeDefine.SERVICE_HIERARCHY_RELATION, name = "ServiceHierarchyRelation")
public class ServiceHierarchyRelation extends Source {
@Setter
@Getter
private String serviceName;
@Getter
private String serviceId;
@Setter
@Getter
private Layer serviceLayer;
@Setter
@Getter
private String relatedServiceName;
@Getter
private String relatedServiceId;
@Setter
@Getter
private Layer relatedServiceLayer;
@Override
public int scope() {
return DefaultScopeDefine.SERVICE_HIERARCHY_RELATION;
}
@Override
public String getEntityId() {
return null;
}
@Override
public void prepare() {
serviceId = IDManager.ServiceID.buildId(serviceName, serviceLayer.isNormal());
relatedServiceId = IDManager.ServiceID.buildId(relatedServiceName, relatedServiceLayer.isNormal());
}
}

View File

@ -0,0 +1,170 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.hierarchy.service;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.apache.skywalking.oap.server.core.analysis.IDManager;
import org.apache.skywalking.oap.server.core.analysis.Layer;
import org.apache.skywalking.oap.server.core.analysis.MetricsExtension;
import org.apache.skywalking.oap.server.core.analysis.Stream;
import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
import org.apache.skywalking.oap.server.core.storage.StorageID;
import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
import org.apache.skywalking.oap.server.core.storage.annotation.Column;
import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
@Stream(name = ServiceHierarchyRelationTraffic.INDEX_NAME, scopeId = DefaultScopeDefine.SERVICE_HIERARCHY_RELATION,
builder = ServiceHierarchyRelationTraffic.Builder.class, processor = MetricsStreamProcessor.class)
@MetricsExtension(supportDownSampling = false, supportUpdate = false)
@EqualsAndHashCode(of = {
"serviceId",
"serviceLayer",
"relatedServiceId",
"relatedServiceLayer"
}, callSuper = true)
public class ServiceHierarchyRelationTraffic extends Metrics {
public static final String INDEX_NAME = "service_hierarchy_relation";
public static final String SERVICE_ID = "service_id";
public static final String SERVICE_LAYER = "service_layer";
public static final String RELATED_SERVICE_ID = "related_service_id";
public static final String RELATED_SERVICE_LAYER = "related_service_layer";
@Setter
@Getter
@Column(name = SERVICE_ID, length = 250)
@BanyanDB.SeriesID(index = 0)
private String serviceId;
@Setter
@Getter
@Column(name = SERVICE_LAYER)
@BanyanDB.SeriesID(index = 1)
private Layer serviceLayer = Layer.UNDEFINED;
@Setter
@Getter
@Column(name = RELATED_SERVICE_ID, length = 250)
@BanyanDB.SeriesID(index = 2)
private String relatedServiceId;
@Setter
@Getter
@Column(name = RELATED_SERVICE_LAYER)
@BanyanDB.SeriesID(index = 3)
private Layer relatedServiceLayer = Layer.UNDEFINED;
@Override
protected StorageID id0() {
String id = IDManager.ServiceID.buildServiceHierarchyRelationId(
new IDManager.ServiceID.ServiceHierarchyRelationDefine(
serviceId, serviceLayer, relatedServiceId, relatedServiceLayer));
return new StorageID().appendMutant(new String[] {
SERVICE_ID,
SERVICE_LAYER,
RELATED_SERVICE_ID,
RELATED_SERVICE_LAYER
}, id);
}
@Override
public boolean combine(final Metrics metrics) {
return true;
}
@Override
public void calculate() {
}
@Override
public Metrics toHour() {
return null;
}
@Override
public Metrics toDay() {
return null;
}
@Override
public void deserialize(final RemoteData remoteData) {
setServiceId(remoteData.getDataStrings(0));
setServiceLayer(Layer.valueOf(remoteData.getDataIntegers(0)));
setRelatedServiceId(remoteData.getDataStrings(1));
setRelatedServiceLayer(Layer.valueOf(remoteData.getDataIntegers(1)));
setTimeBucket(remoteData.getDataLongs(0));
}
@Override
public RemoteData.Builder serialize() {
final RemoteData.Builder builder = RemoteData.newBuilder();
builder.addDataStrings(serviceId);
builder.addDataIntegers(serviceLayer.value());
builder.addDataStrings(relatedServiceId);
builder.addDataIntegers(relatedServiceLayer.value());
builder.addDataLongs(getTimeBucket());
return builder;
}
@Override
public int remoteHashCode() {
return this.hashCode();
}
public static class Builder implements StorageBuilder<ServiceHierarchyRelationTraffic> {
@Override
public ServiceHierarchyRelationTraffic storage2Entity(final Convert2Entity converter) {
ServiceHierarchyRelationTraffic traffic = new ServiceHierarchyRelationTraffic();
traffic.setServiceId((String) converter.get(SERVICE_ID));
traffic.setRelatedServiceId((String) converter.get(RELATED_SERVICE_ID));
if (converter.get(SERVICE_LAYER) != null) {
traffic.setServiceLayer(Layer.valueOf(((Number) converter.get(SERVICE_LAYER)).intValue()));
} else {
traffic.setServiceLayer(Layer.UNDEFINED);
}
if (converter.get(RELATED_SERVICE_LAYER) != null) {
traffic.setRelatedServiceLayer(
Layer.valueOf(((Number) converter.get(RELATED_SERVICE_LAYER)).intValue()));
} else {
traffic.setRelatedServiceLayer(Layer.UNDEFINED);
}
if (converter.get(TIME_BUCKET) != null) {
traffic.setTimeBucket(((Number) converter.get(TIME_BUCKET)).longValue());
}
return traffic;
}
@Override
public void entity2Storage(final ServiceHierarchyRelationTraffic storageData, final Convert2Storage converter) {
converter.accept(SERVICE_ID, storageData.getServiceId());
converter.accept(RELATED_SERVICE_ID, storageData.getRelatedServiceId());
converter.accept(SERVICE_LAYER, storageData.getServiceLayer().value());
converter.accept(RELATED_SERVICE_LAYER, storageData.getRelatedServiceLayer().value());
converter.accept(TIME_BUCKET, storageData.getTimeBucket());
}
}
}

View File

@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.hierarchy.service;
import org.apache.skywalking.oap.server.core.analysis.SourceDispatcher;
import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
public class ServiceHierarchyTrafficRelationDispatcher implements SourceDispatcher<ServiceHierarchyRelation> {
@Override
public void dispatch(final ServiceHierarchyRelation source) {
ServiceHierarchyRelationTraffic traffic = new ServiceHierarchyRelationTraffic();
traffic.setServiceId(source.getServiceId());
traffic.setServiceLayer(source.getServiceLayer());
traffic.setRelatedServiceId(source.getRelatedServiceId());
traffic.setRelatedServiceLayer(source.getRelatedServiceLayer());
traffic.setTimeBucket(source.getTimeBucket());
MetricsStreamProcessor.getInstance().in(traffic);
}
}

View File

@ -0,0 +1,189 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.query;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.oap.server.core.CoreModule;
import org.apache.skywalking.oap.server.core.CoreModuleConfig;
import org.apache.skywalking.oap.server.core.analysis.IDManager;
import org.apache.skywalking.oap.server.core.config.HierarchyDefinitionService;
import org.apache.skywalking.oap.server.core.hierarchy.instance.InstanceHierarchyRelationTraffic;
import org.apache.skywalking.oap.server.core.hierarchy.service.ServiceHierarchyRelationTraffic;
import org.apache.skywalking.oap.server.core.query.type.HierarchyInstanceRelation;
import org.apache.skywalking.oap.server.core.query.type.HierarchyRelatedInstance;
import org.apache.skywalking.oap.server.core.query.type.HierarchyRelatedService;
import org.apache.skywalking.oap.server.core.query.type.HierarchyServiceRelation;
import org.apache.skywalking.oap.server.core.query.type.InstanceHierarchy;
import org.apache.skywalking.oap.server.core.query.type.ServiceHierarchy;
import org.apache.skywalking.oap.server.core.storage.StorageModule;
import org.apache.skywalking.oap.server.core.storage.query.IHierarchyQueryDAO;
import org.apache.skywalking.oap.server.library.module.ModuleManager;
import org.apache.skywalking.oap.server.library.module.Service;
@Slf4j
public class HierarchyQueryService implements Service {
private final ModuleManager moduleManager;
private final boolean isEnableHierarchy;
private IHierarchyQueryDAO hierarchyQueryDAO;
private Map<String, List<String>> hierarchyDefinition;
private LoadingCache<Boolean, Map<HierarchyRelatedService, ServiceRelations>> serviceHierarchyCache;
public HierarchyQueryService(ModuleManager moduleManager, CoreModuleConfig moduleConfig) {
this.moduleManager = moduleManager;
this.isEnableHierarchy = moduleConfig.isEnableHierarchy();
if (moduleConfig.isEnableHierarchy()) {
this.serviceHierarchyCache =
CacheBuilder.newBuilder()
.maximumSize(1)
.refreshAfterWrite(moduleConfig.getServiceCacheRefreshInterval(), TimeUnit.SECONDS)
.build(
new CacheLoader<>() {
@Override
public Map<HierarchyRelatedService, ServiceRelations> load(final Boolean key) throws Exception {
return mapServiceHierarchy();
}
});
}
}
private IHierarchyQueryDAO getHierarchyQueryDAO() {
if (hierarchyQueryDAO == null) {
this.hierarchyQueryDAO = moduleManager.find(StorageModule.NAME)
.provider()
.getService(IHierarchyQueryDAO.class);
}
return hierarchyQueryDAO;
}
private Map<String, List<String>> getHierarchyDefinition() {
if (hierarchyDefinition == null) {
hierarchyDefinition = moduleManager.find(CoreModule.NAME)
.provider()
.getService(HierarchyDefinitionService.class).getHierarchyDefinition();
}
return hierarchyDefinition;
}
private Map<HierarchyRelatedService, ServiceRelations> mapServiceHierarchy() throws Exception {
List<ServiceHierarchyRelationTraffic> traffics = getHierarchyQueryDAO().readAllServiceHierarchyRelations();
Map<HierarchyRelatedService, ServiceRelations> serviceRelationsMap = new HashMap<>();
for (ServiceHierarchyRelationTraffic traffic : traffics) {
HierarchyRelatedService service = new HierarchyRelatedService();
service.setId(traffic.getServiceId());
service.setName(IDManager.ServiceID.analysisId(traffic.getServiceId()).getName());
service.setLayer(traffic.getServiceLayer().name());
HierarchyRelatedService relatedService = new HierarchyRelatedService();
relatedService.setId(traffic.getRelatedServiceId());
relatedService.setName(IDManager.ServiceID.analysisId(traffic.getRelatedServiceId()).getName());
relatedService.setLayer(traffic.getRelatedServiceLayer().name());
ServiceRelations serviceRelations = serviceRelationsMap.computeIfAbsent(
service, k -> new ServiceRelations());
ServiceRelations relationServiceRelations = serviceRelationsMap.computeIfAbsent(
relatedService, k -> new ServiceRelations());
List<String> lowerLayers = getHierarchyDefinition().getOrDefault(
traffic.getServiceLayer().name(), new ArrayList<>());
List<String> relatedLowerLayers = getHierarchyDefinition().getOrDefault(
traffic.getRelatedServiceLayer().name(), new ArrayList<>());
// Build the relations in 2 directions
if (lowerLayers.contains(traffic.getRelatedServiceLayer().name())) {
serviceRelations.getLowerServices().add(relatedService);
relationServiceRelations.getUpperServices().add(service);
} else if (relatedLowerLayers.contains(traffic.getServiceLayer().name())) {
serviceRelations.getUpperServices().add(relatedService);
relationServiceRelations.getLowerServices().add(service);
}
}
return serviceRelationsMap;
}
public ServiceHierarchy getServiceHierarchy(String serviceId, String layer) throws Exception {
if (!this.isEnableHierarchy) {
log.warn("CoreModuleConfig config {enableHierarchy} is false, return empty ServiceHierarchy.");
return new ServiceHierarchy();
}
ServiceHierarchy hierarchy = new ServiceHierarchy();
HierarchyRelatedService self = new HierarchyRelatedService();
self.setId(serviceId);
self.setName(IDManager.ServiceID.analysisId(serviceId).getName());
self.setLayer(layer);
Map<HierarchyRelatedService, ServiceRelations> serviceRelationsMap = serviceHierarchyCache.get(true);
ServiceRelations serviceRelations = serviceRelationsMap.getOrDefault(self, new ServiceRelations());
serviceRelations.getLowerServices().forEach(relatedService -> {
hierarchy.getRelations().add(new HierarchyServiceRelation(self, relatedService));
});
serviceRelations.getUpperServices().forEach(relatedService -> {
hierarchy.getRelations().add(new HierarchyServiceRelation(relatedService, self));
});
return hierarchy;
}
public InstanceHierarchy getInstanceHierarchy(String instanceId, String layer) throws Exception {
if (!this.isEnableHierarchy) {
log.warn("CoreModuleConfig config {enableHierarchy} is false, return empty InstanceHierarchy.");
return new InstanceHierarchy();
}
InstanceHierarchy hierarchy = new InstanceHierarchy();
List<InstanceHierarchyRelationTraffic> traffics = getHierarchyQueryDAO().readInstanceHierarchyRelations(
instanceId, layer);
for (InstanceHierarchyRelationTraffic traffic : traffics) {
HierarchyRelatedInstance instance = new HierarchyRelatedInstance();
instance.setId(traffic.getInstanceId());
instance.setName(IDManager.ServiceInstanceID.analysisId(traffic.getInstanceId()).getName());
instance.setLayer(traffic.getServiceLayer().name());
HierarchyRelatedInstance relatedInstance = new HierarchyRelatedInstance();
relatedInstance.setId(traffic.getRelatedInstanceId());
relatedInstance.setName(IDManager.ServiceInstanceID.analysisId(traffic.getRelatedInstanceId()).getName());
relatedInstance.setLayer(traffic.getRelatedServiceLayer().name());
List<String> lowerLayers = getHierarchyDefinition().getOrDefault(
traffic.getServiceLayer().name(), new ArrayList<>());
List<String> relatedLowerLayers = getHierarchyDefinition().getOrDefault(
traffic.getRelatedServiceLayer().name(), new ArrayList<>());
//should build the relations in 2 direction
if (lowerLayers.contains(traffic.getRelatedServiceLayer().name())) {
hierarchy.getRelations().add(new HierarchyInstanceRelation(instance, relatedInstance));
} else if (relatedLowerLayers.contains(traffic.getServiceLayer().name())) {
hierarchy.getRelations().add(new HierarchyInstanceRelation(relatedInstance, instance));
}
}
return hierarchy;
}
@Data
static class ServiceRelations {
private List<HierarchyRelatedService> upperServices = new ArrayList<>();
private List<HierarchyRelatedService> lowerServices = new ArrayList<>();
}
}

View File

@ -0,0 +1,31 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.query.type;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class HierarchyInstanceRelation {
private HierarchyRelatedInstance upperInstance;
private HierarchyRelatedInstance lowerInstance;
}

View File

@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.query.type;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@EqualsAndHashCode
public class HierarchyRelatedInstance {
private String id;
private String name;
private String layer;
}

View File

@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.query.type;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@EqualsAndHashCode(of = {"id", "layer"})
public class HierarchyRelatedService {
private String id;
private String name;
private String layer;
}

View File

@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.query.type;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
public class HierarchyServiceRelation {
private HierarchyRelatedService upperService;
private HierarchyRelatedService lowerService;
}

View File

@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.query.type;
import java.util.ArrayList;
import java.util.List;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@EqualsAndHashCode
public class InstanceHierarchy {
private List<HierarchyInstanceRelation> relations = new ArrayList<>();
}

View File

@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.query.type;
import java.util.ArrayList;
import java.util.List;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@EqualsAndHashCode
public class ServiceHierarchy {
private List<HierarchyServiceRelation> relations = new ArrayList<>();
}

View File

@ -127,6 +127,8 @@ public class DefaultScopeDefine {
public static final int UI_MENU = 69;
public static final int SERVICE_HIERARCHY_RELATION = 70;
public static final int INSTANCE_HIERARCHY_RELATION = 71;
/**
* Catalog of scope, the metrics processor could use this to group all generated metrics by oal rt.
*/

View File

@ -33,6 +33,7 @@ import org.apache.skywalking.oap.server.core.storage.profiling.ebpf.IEBPFProfili
import org.apache.skywalking.oap.server.core.storage.profiling.ebpf.IEBPFProfilingScheduleDAO;
import org.apache.skywalking.oap.server.core.storage.profiling.ebpf.IEBPFProfilingTaskDAO;
import org.apache.skywalking.oap.server.core.storage.query.IEventQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IHierarchyQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.ILogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetadataQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetricsQueryDAO;
@ -86,7 +87,8 @@ public class StorageModule extends ModuleDefine {
IServiceLabelDAO.class,
ITagAutoCompleteQueryDAO.class,
IZipkinQueryDAO.class,
ISpanAttachedEventQueryDAO.class
ISpanAttachedEventQueryDAO.class,
IHierarchyQueryDAO.class
};
}
}

View File

@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.storage.query;
import java.util.List;
import org.apache.skywalking.oap.server.core.hierarchy.instance.InstanceHierarchyRelationTraffic;
import org.apache.skywalking.oap.server.core.hierarchy.service.ServiceHierarchyRelationTraffic;
import org.apache.skywalking.oap.server.core.storage.DAO;
public interface IHierarchyQueryDAO extends DAO {
List<ServiceHierarchyRelationTraffic> readAllServiceHierarchyRelations() throws Exception;
/**
* Return the given instance's hierarchy.
*/
List<InstanceHierarchyRelationTraffic> readInstanceHierarchyRelations(String instanceId, String layer) throws Exception;
}

View File

@ -26,6 +26,6 @@ public class CoreModuleTest {
public void testOpenServiceList() {
CoreModule coreModule = new CoreModule();
Assertions.assertEquals(41, coreModule.services().length);
Assertions.assertEquals(44, coreModule.services().length);
}
}

View File

@ -32,6 +32,7 @@ import org.apache.skywalking.oap.query.graphql.resolver.EBPFProcessProfilingMuta
import org.apache.skywalking.oap.query.graphql.resolver.EBPFProcessProfilingQuery;
import org.apache.skywalking.oap.query.graphql.resolver.EventQuery;
import org.apache.skywalking.oap.query.graphql.resolver.HealthQuery;
import org.apache.skywalking.oap.query.graphql.resolver.HierarchyQuery;
import org.apache.skywalking.oap.query.graphql.resolver.LogQuery;
import org.apache.skywalking.oap.query.graphql.resolver.LogTestQuery;
import org.apache.skywalking.oap.query.graphql.resolver.MetadataQuery;
@ -143,7 +144,8 @@ public class GraphQLQueryProvider extends ModuleProvider {
.file("query-protocol/continuous-profiling.graphqls")
.resolvers(new ContinuousProfilingQuery(getManager()), new ContinuousProfilingMutation(getManager()))
.file("query-protocol/record.graphqls")
.resolvers(new RecordsQuery(getManager()));
.resolvers(new RecordsQuery(getManager()))
.file("query-protocol/hierarchy.graphqls").resolvers(new HierarchyQuery(getManager()));
if (config.isEnableOnDemandPodLog()) {
schemaBuilder

View File

@ -0,0 +1,52 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.query.graphql.resolver;
import graphql.kickstart.tools.GraphQLQueryResolver;
import org.apache.skywalking.oap.server.core.CoreModule;
import org.apache.skywalking.oap.server.core.query.HierarchyQueryService;
import org.apache.skywalking.oap.server.core.query.type.InstanceHierarchy;
import org.apache.skywalking.oap.server.core.query.type.ServiceHierarchy;
import org.apache.skywalking.oap.server.library.module.ModuleManager;
public class HierarchyQuery implements GraphQLQueryResolver {
private final ModuleManager moduleManager;
private HierarchyQueryService hierarchyQueryService;
public HierarchyQuery(ModuleManager moduleManager) {
this.moduleManager = moduleManager;
}
private HierarchyQueryService getHierarchyQueryService() {
if (hierarchyQueryService == null) {
this.hierarchyQueryService = moduleManager.find(CoreModule.NAME)
.provider()
.getService(HierarchyQueryService.class);
}
return hierarchyQueryService;
}
public ServiceHierarchy getServiceHierarchy(String serviceId, String layer) throws Exception {
return getHierarchyQueryService().getServiceHierarchy(serviceId, layer);
}
public InstanceHierarchy getInstanceHierarchy(String instanceId, String layer) throws Exception {
return getHierarchyQueryService().getInstanceHierarchy(instanceId, layer);
}
}

@ -1 +1 @@
Subproject commit e08b0a78258a4c56e67076424add6bc2d0a1dd08
Subproject commit b5fe539bce21d464e5dff360a691b79729bf065b

View File

@ -0,0 +1,29 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Define the hierarchy of layers, the layers under the specific layer are lower of the layer.
# All the layers are defined in the file `org.apache.skywalking.oap.server.core.analysis.Layers.java`.
MESH:
- MESH_DP
- K8S_SERVICE
- K8S
MESH_DP:
- K8S_SERVICE
- K8S
K8S_SERVICE:
- K8S

View File

@ -43,6 +43,7 @@ import org.apache.skywalking.oap.server.core.storage.query.IAggregationQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IAlarmQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IEventQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IHierarchyQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.ILogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetadataQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetricsQueryDAO;
@ -58,6 +59,7 @@ import org.apache.skywalking.oap.server.library.module.ModuleStartException;
import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException;
import org.apache.skywalking.oap.server.storage.plugin.banyandb.measure.BanyanDBEBPFProfilingScheduleQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.banyandb.measure.BanyanDBEventQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.banyandb.measure.BanyanDBHierarchyQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.banyandb.measure.BanyanDBMetadataQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.banyandb.measure.BanyanDBMetricsQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.banyandb.measure.BanyanDBNetworkAddressAliasDAO;
@ -163,6 +165,7 @@ public class BanyanDBStorageProvider extends ModuleProvider {
this.registerServiceImplementation(IRecordsQueryDAO.class, new BanyanDBRecordsQueryDAO(client));
this.registerServiceImplementation(IZipkinQueryDAO.class, new BanyanDBZipkinQueryDAO(client));
this.registerServiceImplementation(ISpanAttachedEventQueryDAO.class, new BanyanDBSpanAttachedEventQueryDAO(client));
this.registerServiceImplementation(IHierarchyQueryDAO.class, new BanyanDBHierarchyQueryDAO(client));
}
@Override

View File

@ -0,0 +1,123 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.storage.plugin.banyandb.measure;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.apache.skywalking.banyandb.v1.client.AbstractCriteria;
import org.apache.skywalking.banyandb.v1.client.DataPoint;
import org.apache.skywalking.banyandb.v1.client.MeasureQuery;
import org.apache.skywalking.banyandb.v1.client.MeasureQueryResponse;
import org.apache.skywalking.oap.server.core.analysis.DownSampling;
import org.apache.skywalking.oap.server.core.analysis.Layer;
import org.apache.skywalking.oap.server.core.hierarchy.instance.InstanceHierarchyRelationTraffic;
import org.apache.skywalking.oap.server.core.hierarchy.service.ServiceHierarchyRelationTraffic;
import org.apache.skywalking.oap.server.core.storage.query.IHierarchyQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBConverter;
import org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageClient;
import org.apache.skywalking.oap.server.storage.plugin.banyandb.MetadataRegistry;
import org.apache.skywalking.oap.server.storage.plugin.banyandb.stream.AbstractBanyanDBDAO;
public class BanyanDBHierarchyQueryDAO extends AbstractBanyanDBDAO implements IHierarchyQueryDAO {
private static final Set<String> SERVICE_HIERARCHY_RELATION_TAGS = ImmutableSet.of(
ServiceHierarchyRelationTraffic.SERVICE_ID,
ServiceHierarchyRelationTraffic.SERVICE_LAYER,
ServiceHierarchyRelationTraffic.RELATED_SERVICE_ID,
ServiceHierarchyRelationTraffic.RELATED_SERVICE_LAYER
);
private static final Set<String> INSTANCE_HIERARCHY_RELATION_TAGS = ImmutableSet.of(
InstanceHierarchyRelationTraffic.INSTANCE_ID,
InstanceHierarchyRelationTraffic.SERVICE_LAYER,
InstanceHierarchyRelationTraffic.RELATED_INSTANCE_ID,
InstanceHierarchyRelationTraffic.RELATED_SERVICE_LAYER
);
public BanyanDBHierarchyQueryDAO(final BanyanDBStorageClient client) {
super(client);
}
@Override
public List<ServiceHierarchyRelationTraffic> readAllServiceHierarchyRelations() throws Exception {
MeasureQueryResponse resp = query(ServiceHierarchyRelationTraffic.INDEX_NAME,
SERVICE_HIERARCHY_RELATION_TAGS,
Collections.emptySet(), new QueryBuilder<>() {
@Override
protected void apply(MeasureQuery query) {
}
}
);
final List<ServiceHierarchyRelationTraffic> relations = new ArrayList<>();
MetadataRegistry.Schema schema = MetadataRegistry.INSTANCE.findMetadata(
ServiceHierarchyRelationTraffic.INDEX_NAME, DownSampling.Minute);
for (final DataPoint dataPoint : resp.getDataPoints()) {
relations.add(new ServiceHierarchyRelationTraffic.Builder().storage2Entity(
new BanyanDBConverter.StorageToMeasure(schema, dataPoint)));
}
return relations;
}
@Override
public List<InstanceHierarchyRelationTraffic> readInstanceHierarchyRelations(final String instanceId,
final String layer) throws Exception {
MeasureQueryResponse resp = query(InstanceHierarchyRelationTraffic.INDEX_NAME,
INSTANCE_HIERARCHY_RELATION_TAGS,
Collections.emptySet(), buildInstanceRelationsQuery(instanceId, layer)
);
List<InstanceHierarchyRelationTraffic> relations = new ArrayList<>();
MetadataRegistry.Schema schema = MetadataRegistry.INSTANCE.findMetadata(
InstanceHierarchyRelationTraffic.INDEX_NAME, DownSampling.Minute);
for (final DataPoint dataPoint : resp.getDataPoints()) {
relations.add(new InstanceHierarchyRelationTraffic.Builder().storage2Entity(
new BanyanDBConverter.StorageToMeasure(schema, dataPoint)));
}
return relations;
}
private QueryBuilder<MeasureQuery> buildInstanceRelationsQuery(String instanceId, String layer) {
int layerValue = Layer.valueOf(layer).value();
return new QueryBuilder<>() {
@Override
protected void apply(MeasureQuery query) {
List<AbstractCriteria> instanceRelationsQueryConditions = new ArrayList<>(2);
instanceRelationsQueryConditions.add(
and(Lists.newArrayList(
eq(InstanceHierarchyRelationTraffic.INSTANCE_ID, instanceId),
eq(InstanceHierarchyRelationTraffic.SERVICE_LAYER, layerValue))
));
instanceRelationsQueryConditions.add(
and(Lists.newArrayList(
eq(InstanceHierarchyRelationTraffic.RELATED_INSTANCE_ID, instanceId),
eq(InstanceHierarchyRelationTraffic.RELATED_SERVICE_LAYER, layerValue)
))
);
query.criteria(or(instanceRelationsQueryConditions));
}
};
}
}

View File

@ -48,6 +48,7 @@ import org.apache.skywalking.oap.server.core.storage.query.IAggregationQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IAlarmQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IEventQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IHierarchyQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.ILogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetadataQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetricsQueryDAO;
@ -79,6 +80,7 @@ import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.EBPFP
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.EBPFProfilingScheduleEsDAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.EBPFProfilingTaskEsDAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.ESEventQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.HierarchyQueryEsDAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.LogQueryEsDAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.MetadataQueryEsDAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.MetricsQueryEsDAO;
@ -254,6 +256,7 @@ public class StorageModuleElasticsearchProvider extends ModuleProvider {
ISpanAttachedEventQueryDAO.class, new SpanAttachedEventEsDAO(elasticSearchClient, config));
IndexController.INSTANCE.setLogicSharding(config.isLogicSharding());
IndexController.INSTANCE.setEnableCustomRouting(config.isEnableCustomRouting());
this.registerServiceImplementation(IHierarchyQueryDAO.class, new HierarchyQueryEsDAO(elasticSearchClient, config));
}
@Override

View File

@ -0,0 +1,133 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import org.apache.skywalking.library.elasticsearch.requests.search.BoolQueryBuilder;
import org.apache.skywalking.library.elasticsearch.requests.search.Query;
import org.apache.skywalking.library.elasticsearch.requests.search.Search;
import org.apache.skywalking.library.elasticsearch.requests.search.SearchBuilder;
import org.apache.skywalking.library.elasticsearch.response.search.SearchHit;
import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse;
import org.apache.skywalking.oap.server.core.analysis.Layer;
import org.apache.skywalking.oap.server.core.hierarchy.instance.InstanceHierarchyRelationTraffic;
import org.apache.skywalking.oap.server.core.hierarchy.service.ServiceHierarchyRelationTraffic;
import org.apache.skywalking.oap.server.core.storage.query.IHierarchyQueryDAO;
import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchScroller;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.StorageModuleElasticsearchConfig;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.ElasticSearchConverter;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.IndexController;
public class HierarchyQueryEsDAO extends EsDAO implements IHierarchyQueryDAO {
private final int queryMaxSize;
private final int scrollingBatchSize;
protected final Function<SearchHit, ServiceHierarchyRelationTraffic> serviceRelationsFunction = hit -> {
final var sourceAsMap = hit.getSource();
final var builder = new ServiceHierarchyRelationTraffic.Builder();
return builder.storage2Entity(
new ElasticSearchConverter.ToEntity(ServiceHierarchyRelationTraffic.INDEX_NAME, sourceAsMap));
};
protected final Function<SearchHit, InstanceHierarchyRelationTraffic> instanceRelationsFunction = hit -> {
final var sourceAsMap = hit.getSource();
final var builder = new InstanceHierarchyRelationTraffic.Builder();
return builder.storage2Entity(
new ElasticSearchConverter.ToEntity(InstanceHierarchyRelationTraffic.INDEX_NAME, sourceAsMap));
};
public HierarchyQueryEsDAO(final ElasticSearchClient client,
final StorageModuleElasticsearchConfig config) {
super(client);
this.queryMaxSize = config.getMetadataQueryMaxSize();
this.scrollingBatchSize = config.getScrollingBatchSize();
}
@Override
public List<ServiceHierarchyRelationTraffic> readAllServiceHierarchyRelations() {
final String index =
IndexController.LogicIndicesRegister.getPhysicalTableName(ServiceHierarchyRelationTraffic.INDEX_NAME);
final int batchSize = Math.min(queryMaxSize, scrollingBatchSize);
final BoolQueryBuilder query = Query.bool();
final SearchBuilder search = Search.builder().query(query).size(batchSize);
if (IndexController.LogicIndicesRegister.isMergedTable(ServiceHierarchyRelationTraffic.INDEX_NAME)) {
query.must(Query.term(
IndexController.LogicIndicesRegister.METRIC_TABLE_NAME,
ServiceHierarchyRelationTraffic.INDEX_NAME
));
}
final var scroller = ElasticSearchScroller
.<ServiceHierarchyRelationTraffic>builder()
.client(getClient())
.search(search.build())
.index(index)
.queryMaxSize(queryMaxSize)
.resultConverter(serviceRelationsFunction)
.build();
return scroller.scroll();
}
@Override
public List<InstanceHierarchyRelationTraffic> readInstanceHierarchyRelations(final String instanceId, final String layer) {
final String index =
IndexController.LogicIndicesRegister.getPhysicalTableName(InstanceHierarchyRelationTraffic.INDEX_NAME);
int layerValue = Layer.valueOf(layer).value();
final BoolQueryBuilder instanceSide =
Query.bool()
.must(Query.term(InstanceHierarchyRelationTraffic.INSTANCE_ID, instanceId))
.must(Query.term(InstanceHierarchyRelationTraffic.SERVICE_LAYER, layerValue));
final BoolQueryBuilder relatedInstanceSide =
Query.bool()
.must(Query.term(InstanceHierarchyRelationTraffic.RELATED_INSTANCE_ID, instanceId))
.must(Query.term(InstanceHierarchyRelationTraffic.RELATED_SERVICE_LAYER, layerValue));
final BoolQueryBuilder instanceQuery =
Query.bool()
.should(instanceSide)
.should(relatedInstanceSide);
final BoolQueryBuilder query =
Query.bool()
.must(instanceQuery);
if (IndexController.LogicIndicesRegister.isMergedTable(InstanceHierarchyRelationTraffic.INDEX_NAME)) {
query.must(Query.term(
IndexController.LogicIndicesRegister.METRIC_TABLE_NAME,
InstanceHierarchyRelationTraffic.INDEX_NAME
));
}
final SearchBuilder search = Search.builder().query(query);
final SearchResponse response = getClient().search(index, search.build());
return buildInstanceHierarchyRelations(response);
}
private List<InstanceHierarchyRelationTraffic> buildInstanceHierarchyRelations(SearchResponse response) {
List<InstanceHierarchyRelationTraffic> relations = new ArrayList<>();
for (SearchHit searchHit : response.getHits()) {
relations.add(instanceRelationsFunction.apply(searchHit));
}
return relations;
}
}

View File

@ -42,6 +42,7 @@ import org.apache.skywalking.oap.server.core.storage.query.IAggregationQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IAlarmQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IEventQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IHierarchyQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.ILogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetadataQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetricsQueryDAO;
@ -65,6 +66,7 @@ import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCEBPFP
import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCEBPFProfilingScheduleDAO;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCEBPFProfilingTaskDAO;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCEventQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCHierarchyQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCHistoryDeleteDAO;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCLogQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCMetadataQueryDAO;
@ -221,6 +223,8 @@ public abstract class JDBCStorageProvider extends ModuleProvider {
this.registerServiceImplementation(
ISpanAttachedEventQueryDAO.class,
new JDBCSpanAttachedEventQueryDAO(jdbcClient, tableHelper));
this.registerServiceImplementation(IHierarchyQueryDAO.class,
new JDBCHierarchyQueryDAO(jdbcClient, config.getMetadataQueryMaxSize(), tableHelper));
}
@Override

View File

@ -0,0 +1,142 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.skywalking.oap.server.core.analysis.Layer;
import org.apache.skywalking.oap.server.core.hierarchy.instance.InstanceHierarchyRelationTraffic;
import org.apache.skywalking.oap.server.core.hierarchy.service.ServiceHierarchyRelationTraffic;
import org.apache.skywalking.oap.server.core.query.type.Call;
import org.apache.skywalking.oap.server.core.storage.query.IHierarchyQueryDAO;
import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCEntityConverters;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.SQLAndParameters;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
import static java.util.stream.Collectors.toList;
public class JDBCHierarchyQueryDAO implements IHierarchyQueryDAO {
private final JDBCClient jdbcClient;
private final int queryMaxSize;
private final TableHelper tableHelper;
public JDBCHierarchyQueryDAO(JDBCClient jdbcClient, int metadataQueryMaxSize, TableHelper tableHelper) {
this.jdbcClient = jdbcClient;
this.queryMaxSize = metadataQueryMaxSize * 2;
this.tableHelper = tableHelper;
}
@Override
public List<ServiceHierarchyRelationTraffic> readAllServiceHierarchyRelations() throws Exception {
final var results = new ArrayList<ServiceHierarchyRelationTraffic>();
final var tables = tableHelper.getTablesWithinTTL(ServiceHierarchyRelationTraffic.INDEX_NAME);
for (final var table : tables) {
final var sqlAndParameters = buildSQLForReadAllServiceRelations(table);
results.addAll(jdbcClient.executeQuery(
sqlAndParameters.sql(),
this::buildServiceRelations,
sqlAndParameters.parameters()
)
);
}
return results
.stream()
.limit(queryMaxSize)
.collect(toList());
}
@Override
public List<InstanceHierarchyRelationTraffic> readInstanceHierarchyRelations(final String instanceId,
final String layer) throws Exception {
final var results = new ArrayList<InstanceHierarchyRelationTraffic>();
final var tables = tableHelper.getTablesWithinTTL(InstanceHierarchyRelationTraffic.INDEX_NAME);
final var layerValue = Layer.valueOf(layer).value();
List<Call.CallDetail> calls = new ArrayList<>();
for (final var table : tables) {
final var sqlAndParameters = buildSQLForReadInstanceRelations(table, instanceId, layerValue);
results.addAll(jdbcClient.executeQuery(
sqlAndParameters.sql(),
this::buildInstanceRelations,
sqlAndParameters.parameters()
)
);
}
return results;
}
protected SQLAndParameters buildSQLForReadAllServiceRelations(String table) {
final var sql = new StringBuilder();
final var parameters = new ArrayList<>(5);
sql.append("select * from ").append(table)
.append(" where ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ");
parameters.add(ServiceHierarchyRelationTraffic.INDEX_NAME);
sql.append(" limit ").append(queryMaxSize);
return new SQLAndParameters(sql.toString(), parameters);
}
protected SQLAndParameters buildSQLForReadInstanceRelations(String table, String instanceId, int layerValue) {
final var sql = new StringBuilder();
final var parameters = new ArrayList<>(5) {
{
add(InstanceHierarchyRelationTraffic.INDEX_NAME);
add(instanceId);
add(layerValue);
add(instanceId);
add(layerValue);
}
};
sql.append("select * from ").append(table)
.append(" where ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ")
.append("and ((").append(InstanceHierarchyRelationTraffic.INSTANCE_ID)
.append("=? and ")
.append(InstanceHierarchyRelationTraffic.SERVICE_LAYER)
.append("=?")
.append(") or (")
.append(InstanceHierarchyRelationTraffic.RELATED_INSTANCE_ID)
.append("=? and ")
.append(InstanceHierarchyRelationTraffic.RELATED_SERVICE_LAYER)
.append("=?")
.append("))");
return new SQLAndParameters(sql.toString(), parameters);
}
private List<ServiceHierarchyRelationTraffic> buildServiceRelations(ResultSet resultSet) throws SQLException {
final var relations = new ArrayList<ServiceHierarchyRelationTraffic>();
while (resultSet.next()) {
relations.add(new ServiceHierarchyRelationTraffic.Builder().storage2Entity(
JDBCEntityConverters.toEntity(resultSet)));
}
return relations;
}
private List<InstanceHierarchyRelationTraffic> buildInstanceRelations(ResultSet resultSet) throws SQLException {
final var relations = new ArrayList<InstanceHierarchyRelationTraffic>();
while (resultSet.next()) {
relations.add(new InstanceHierarchyRelationTraffic.Builder().storage2Entity(
JDBCEntityConverters.toEntity(resultSet)));
}
return relations;
}
}