提交 2e846c60 编写于 作者: wu-sheng's avatar wu-sheng 提交者: 彭勇升 pengys

Dynamic Configuration and Dynamic Configuration Service (#2810)

* Implement the base of config API module.

* Finish configuration module codebases w/o tests, revert some changes.

* Finish mock tests.

* Add new gRPC service for configuration.

* Make gRPC configuration sync provider works.

* Add database slow statement dynamic setting.

* Finish the dynamic configuration service.

* Fix version.
上级 5036e833
......@@ -72,6 +72,7 @@ a oap image with name `bar/oap:foo`, run the following command
* `grpc-java` and `java` folders in **oap-server/server-core/target/generated-sources/protobuf**
* `grpc-java` and `java` folders in **oap-server/server-receiver-plugin/receiver-proto/target/generated-sources/protobuf**
* `grpc-java` and `java` folders in **oap-server/exporter/target/generated-sources/protobuf**
* `grpc-java` and `java` folders in **oap-server/server-configuration/grpc-configuration-sync/target/generated-sources/protobuf**
* `antlr4` folder in **oap-server/generate-tool-grammar/target/generated-sources**
* `oal` folder in **oap-server/generated-analysis/target/generated-sources**
......
......@@ -81,6 +81,8 @@ scale and support high payload, you may need this.
system.
1. [Time To Live (TTL)](ttl.md). Metrics and trace are time series data, they would be saved forever, you could
set the expired time for each dimension.
1. [Dynamic Configuration](dynamic-config.md). Make configuration of OAP changed dynamic, from remote service
or 3rd party configuration management system.
## Telemetry for backend
OAP backend cluster itself underlying is a distributed streaming process system. For helping the Ops team,
......
# Dynamic Configuration
SkyWalking Configurations mostly are set through `application.yml` and OS system environment variables.
But some of them are supporting dynamic settings from upstream management system.
Right now, SkyWalking supports following dynamic configurations.
| Config Key | Value Description | Value Format Example |
|:----:|:----:|:----:|
|receiver-trace.default.slowDBAccessThreshold| Thresholds of slow Database statement, override `receiver-trace/default/slowDBAccessThreshold` of `applciation.yml`. | default:200,mongodb:50|
This feature depends on upstream service, so it is **OFF** as default.
```yaml
configuration:
none:
```
## Dynamic Configuration Service, DCS
[Dynamic Configuration Service](../../../../oap-server/server-configuration/grpc-configuration-sync/src/main/proto/configuration-service.proto)
is a gRPC service, which requires the upstream system implemented.
The SkyWalking OAP fetches the configuration from the implementation(any system), after you open this implementation like this.
```yaml
configuration:
grpc:
# Upstream system hostname
host: 127.0.0.1
# Upstream system port
port: 9555
#period : 60 # Unit seconds, sync period. Default fetch every 60 seconds.
#clusterName: "default" # the name of current cluster, set the name if you want to upstream system known.
```
## 3rd party Configuration Center
We are welcome contributions to implement this module provider to support popular configuration center,
such as Zookeeper, etcd, Consul, Nacos. Submit issue to discuss.
......@@ -42,6 +42,7 @@
<module>server-telemetry</module>
<module>generate-tool-grammar</module>
<module>exporter</module>
<module>server-configuration</module>
</modules>
<properties>
......
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>server-configuration</artifactId>
<groupId>org.apache.skywalking</groupId>
<version>6.2.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>configuration-api</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>library-module</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
/*
* 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.configuration.api;
import org.apache.skywalking.oap.server.library.module.*;
/**
* The recommendation default base implementor of Configuration module. The real implementor could extend this provider
* to make a new one, easily.
*
* @author wusheng
*/
public abstract class AbstractConfigurationProvider extends ModuleProvider {
private ConfigWatcherRegister configWatcherRegister;
@Override public Class<? extends ModuleDefine> module() {
return ConfigurationModule.class;
}
@Override public void prepare() throws ServiceNotProvidedException, ModuleStartException {
configWatcherRegister = initConfigReader();
this.registerServiceImplementation(DynamicConfigurationService.class, configWatcherRegister);
}
protected abstract ConfigWatcherRegister initConfigReader() throws ModuleStartException;
@Override public void start() throws ServiceNotProvidedException, ModuleStartException {
}
@Override public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException {
configWatcherRegister.start();
}
@Override public String[] requiredModules() {
return new String[0];
}
}
/*
* 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.configuration.api;
import lombok.*;
import org.apache.skywalking.oap.server.library.module.*;
/**
* ConfigChangeWatcher represents a watcher implementor, it will be called when the target value changed.
*
* @author wusheng
*/
@Getter
public abstract class ConfigChangeWatcher {
private final String module;
private final ModuleProvider provider;
private final String itemName;
public ConfigChangeWatcher(String module, ModuleProvider provider, String itemName) {
this.module = module;
this.provider = provider;
this.itemName = itemName;
}
/**
* Notify the watcher, the new value received.
*
* @param value of new.
*/
public abstract void notify(ConfigChangeEvent value);
/**
* @return current value of current config.
*/
public abstract String value();
@Override public String toString() {
return "ConfigChangeWatcher{" +
"module=" + module +
", provider=" + provider +
", itemName='" + itemName + '\'' +
'}';
}
@Setter(AccessLevel.PACKAGE)
@Getter
public static class ConfigChangeEvent {
private String newValue;
private EventType eventType;
public ConfigChangeEvent(String newValue,
EventType eventType) {
this.newValue = newValue;
this.eventType = eventType;
}
}
public enum EventType {
ADD, MODIFY, DELETE
}
}
......@@ -16,36 +16,33 @@
*
*/
package org.apache.skywalking.oap.server.receiver.trace.provider;
package org.apache.skywalking.oap.server.configuration.api;
import java.util.*;
import lombok.*;
/**
* ConfigTable contains all config.
*
* @author wusheng
*/
public class DBLatencyThresholds {
private Map<String, Integer> thresholds;
public class ConfigTable {
@Getter
private List<ConfigItem> items = new ArrayList<>();
DBLatencyThresholds(String config) {
thresholds = new HashMap<>();
String[] settings = config.split(",");
for (String setting : settings) {
String[] typeValue = setting.split(":");
if (typeValue.length == 2) {
thresholds.put(typeValue[0].trim().toLowerCase(), Integer.parseInt(typeValue[1].trim()));
}
}
if (!thresholds.containsKey("default")) {
thresholds.put("default", 10000);
}
public void add(ConfigItem item) {
items.add(item);
}
public int getThreshold(String type) {
type = type.toLowerCase();
if (thresholds.containsKey(type)) {
return thresholds.get(type);
} else {
return thresholds.get("default");
@Getter
@Setter
public static class ConfigItem {
private String name;
private String value;
public ConfigItem(String name, String value) {
this.name = name;
this.value = value;
}
}
}
/*
* 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.configuration.api;
import java.util.*;
import java.util.concurrent.*;
import lombok.Getter;
import org.apache.skywalking.apm.util.RunnableWithExceptionProtection;
import org.slf4j.*;
/**
* The default implementor of Config Watcher register.
*
* @author wusheng
*/
public abstract class ConfigWatcherRegister implements DynamicConfigurationService {
private static final Logger logger = LoggerFactory.getLogger(ConfigWatcherRegister.class);
public static final String LINE_SEPARATOR = System.getProperty("line.separator", "\n");
private Register register = new Register();
private volatile boolean isStarted = false;
private final long syncPeriod;
public ConfigWatcherRegister() {
this(60);
}
public ConfigWatcherRegister(long syncPeriod) {
this.syncPeriod = syncPeriod;
}
@Override synchronized public void registerConfigChangeWatcher(ConfigChangeWatcher watcher) {
if (isStarted) {
throw new IllegalStateException("Config Register has been started. Can't register new watcher.");
}
WatcherHolder holder = new WatcherHolder(watcher);
if (register.containsKey(holder.getKey())) {
throw new IllegalStateException("Duplicate register, watcher=" + watcher);
}
register.put(holder.getKey(), holder);
}
public void start() {
isStarted = true;
configSync();
logger.info("Current configurations after the bootstrap sync." + LINE_SEPARATOR + register.toString());
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(
new RunnableWithExceptionProtection(() -> configSync(),
t -> logger.error("Sync config center error.", t)), syncPeriod, syncPeriod, TimeUnit.SECONDS);
}
void configSync() {
ConfigTable configTable = readConfig();
configTable.getItems().forEach(item -> {
String itemName = item.getName();
WatcherHolder holder = register.get(itemName);
if (holder != null) {
ConfigChangeWatcher watcher = holder.getWatcher();
String newItemValue = item.getValue();
if (newItemValue == null) {
if (watcher.value() != null) {
// Notify watcher, the new value is null with delete event type.
watcher.notify(new ConfigChangeWatcher.ConfigChangeEvent(null, ConfigChangeWatcher.EventType.DELETE));
} else {
// Don't need to notify, stay in null.
}
} else {
if (!newItemValue.equals(watcher.value())) {
watcher.notify(new ConfigChangeWatcher.ConfigChangeEvent(newItemValue, ConfigChangeWatcher.EventType.MODIFY));
} else {
// Don't need to notify, stay in the same config value.
}
}
} else {
logger.warn("Config {} from configuration center, doesn't match any watcher, ignore.", itemName);
}
});
logger.trace("Current configurations after the sync." + LINE_SEPARATOR + register.toString());
}
public abstract ConfigTable readConfig();
public class Register {
private Map<String, WatcherHolder> register = new HashMap<>();
private boolean containsKey(String key) {
return register.containsKey(key);
}
private void put(String key, WatcherHolder holder) {
register.put(key, holder);
}
public WatcherHolder get(String name) {
return register.get(name);
}
@Override public String toString() {
StringBuilder registerTableDescription = new StringBuilder();
registerTableDescription.append("Following dynamic config items are available.").append(LINE_SEPARATOR);
registerTableDescription.append("---------------------------------------------").append(LINE_SEPARATOR);
register.forEach((key, holder) -> {
ConfigChangeWatcher watcher = holder.getWatcher();
registerTableDescription.append("key:").append(key)
.append(" module:").append(watcher.getModule())
.append(" provider:").append(watcher.getProvider().name())
.append(" value(current):").append(watcher.value())
.append(LINE_SEPARATOR);
});
return registerTableDescription.toString();
}
}
@Getter
private class WatcherHolder {
private ConfigChangeWatcher watcher;
private final String key;
public WatcherHolder(ConfigChangeWatcher watcher) {
this.watcher = watcher;
this.key = String.join(".", watcher.getModule(), watcher.getProvider().name(), watcher.getItemName());
}
}
}
/*
* 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.configuration.api;
import org.apache.skywalking.oap.server.library.module.ModuleDefine;
/**
* Configuration Module sync the settings from remote service, the remote service could be implemented by this module
* provider.
*
* Any configuration item in the whole OAP backend could register a watcher to configuration module, the item change
* watcher will be called, if the value changed.
*
* @author wusheng
*/
public class ConfigurationModule extends ModuleDefine {
public static final String NAME = "configuration";
public ConfigurationModule() {
super(NAME);
}
@Override public Class[] services() {
return new Class[] {DynamicConfigurationService.class};
}
}
/*
* 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.configuration.api;
import org.apache.skywalking.oap.server.library.module.*;
/**
* DynamicConfigurationService provides API to register config change watcher.
*
* @author wusheng
*/
public interface DynamicConfigurationService extends Service {
/**
* Register a watcher to the target value
*
* @param watcher to register
*/
void registerConfigChangeWatcher(ConfigChangeWatcher watcher);
}
/*
* 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.configuration.api;
import org.apache.skywalking.oap.server.library.module.*;
/**
* A nutshell configuration implementor.
*
* @author wusheng
*/
public class NoneConfigurationProvider extends ModuleProvider {
@Override public String name() {
return "none";
}
@Override public Class<? extends ModuleDefine> module() {
return ConfigurationModule.class;
}
@Override public ModuleConfig createConfigBeanIfAbsent() {
return null;
}
@Override public void prepare() throws ServiceNotProvidedException, ModuleStartException {
this.registerServiceImplementation(DynamicConfigurationService.class, new DynamicConfigurationService() {
@Override public void registerConfigChangeWatcher(ConfigChangeWatcher watcher) {
}
});
}
@Override public void start() throws ServiceNotProvidedException, ModuleStartException {
}
@Override public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException {
}
@Override public String[] requiredModules() {
return new String[0];
}
}
#
# 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.
#
#
org.apache.skywalking.oap.server.configuration.api.ConfigurationModule
\ No newline at end of file
#
# 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.
#
#
#
org.apache.skywalking.oap.server.configuration.api.NoneConfigurationProvider
\ No newline at end of file
/*
* 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.configuration.api;
import org.apache.skywalking.oap.server.library.module.*;
import org.junit.*;
import org.powermock.reflect.Whitebox;
/**
* @author wusheng
*/
public class ConfigWatcherRegisterTest {
private ConfigWatcherRegister register;
@Before
public void setup() {
register = new MockConfigWatcherRegister();
}
@After
public void tearDown() {
register = null;
}
@Test
public void testInit() {
final String[] newValue = new String[1];
register.registerConfigChangeWatcher(new ConfigChangeWatcher("MockModule", new MockProvider(), "prop2") {
@Override public void notify(ConfigChangeEvent value) {
newValue[0] = value.getNewValue();
}
@Override public String value() {
return null;
}
});
register.configSync();
Assert.assertEquals("abc2", newValue[0]);
}
@Test
public void testRegisterTableLog() {
register.registerConfigChangeWatcher(new ConfigChangeWatcher("MockModule", new MockProvider(), "prop2") {
@Override public void notify(ConfigChangeEvent value) {
}
@Override public String value() {
return null;
}
});
register.configSync();
ConfigWatcherRegister.Register registerTable = Whitebox.getInternalState(this.register, "register");
String expected = "Following dynamic config items are available." + ConfigWatcherRegister.LINE_SEPARATOR +
"---------------------------------------------" + ConfigWatcherRegister.LINE_SEPARATOR +
"key:MockModule.provider.prop2 module:MockModule provider:provider value(current):null" + ConfigWatcherRegister.LINE_SEPARATOR;
Assert.assertEquals(expected, registerTable.toString());
}
public static class MockConfigWatcherRegister extends ConfigWatcherRegister {
@Override public ConfigTable readConfig() {
ConfigTable.ConfigItem item1 = new ConfigTable.ConfigItem("module.provider.prop1", "abc");
ConfigTable.ConfigItem item2 = new ConfigTable.ConfigItem("MockModule.provider.prop2", "abc2");
ConfigTable table = new ConfigTable();
table.add(item1);
table.add(item2);
return table;
}
}
public static class MockModule extends ModuleDefine {
public MockModule() {
super("MockModule");
}
@Override public Class[] services() {
return new Class[0];
}
}
public static class MockProvider extends ModuleProvider {
@Override public String name() {
return "provider";
}
@Override public Class<? extends ModuleDefine> module() {
return MockModule.class;
}
@Override public ModuleConfig createConfigBeanIfAbsent() {
return null;
}
@Override public void prepare() throws ServiceNotProvidedException, ModuleStartException {
}
@Override public void start() throws ServiceNotProvidedException, ModuleStartException {
}
@Override public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException {
}
@Override public String[] requiredModules() {
return new String[0];
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>server-configuration</artifactId>
<groupId>org.apache.skywalking</groupId>
<version>6.2.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>grpc-configuration-sync</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>configuration-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>library-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-core</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
</dependency>
</dependencies>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.4.1.Final</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4.3</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.0</version>
<configuration>
<!--
The version of protoc must match protobuf-java. If you don't depend on
protobuf-java directly, you will be transitively depending on the
protobuf-java version that grpc depends on.
-->
<protocArtifact>com.google.protobuf:protoc:3.3.0:exe:${os.detected.classifier}
</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.4.0:exe:${os.detected.classifier}
</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
/*
* 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.configuration.grpc;
import io.grpc.netty.NettyChannelBuilder;
import org.apache.skywalking.oap.server.configuration.api.*;
import org.apache.skywalking.oap.server.configuration.service.*;
import org.slf4j.*;
/**
* @author wusheng
*/
public class GRPCConfigWatcherRegister extends ConfigWatcherRegister {
private static final Logger logger = LoggerFactory.getLogger(GRPCConfigWatcherRegister.class);
private RemoteEndpointSettings settings;
private ConfigurationServiceGrpc.ConfigurationServiceBlockingStub stub;
public GRPCConfigWatcherRegister(RemoteEndpointSettings settings) {
super(settings.getPeriod());
this.settings = settings;
stub = ConfigurationServiceGrpc.newBlockingStub(NettyChannelBuilder.forAddress(settings.getHost(), settings.getPort()).usePlaintext().build());
}
@Override public ConfigTable readConfig() {
ConfigTable table = new ConfigTable();
try {
ConfigurationResponse response = stub.call(ConfigurationRequest.newBuilder().setClusterName(settings.getClusterName()).build());
response.getConfigTableList().forEach(config -> {
table.add(new ConfigTable.ConfigItem(config.getName(), config.getValue()));
});
} catch (Exception e) {
logger.error("Remote config center [" + settings + "] is not available.", e);
}
return table;
}
}
/*
* 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.configuration.grpc;
import com.google.common.base.Strings;
import org.apache.skywalking.oap.server.configuration.api.*;
import org.apache.skywalking.oap.server.library.module.*;
/**
* Get configuration from remote through gRPC protocol.
*
* Read configuration-service.proto for more details.
*
* @author wusheng
*/
public class GRPCConfigurationProvider extends AbstractConfigurationProvider {
private RemoteEndpointSettings settings;
public GRPCConfigurationProvider() {
settings = new RemoteEndpointSettings();
}
@Override public String name() {
return "grpc";
}
@Override public ModuleConfig createConfigBeanIfAbsent() {
return settings;
}
@Override protected ConfigWatcherRegister initConfigReader() throws ModuleStartException {
if (Strings.isNullOrEmpty(settings.getHost())) {
throw new ModuleStartException("No host setting.");
}
if (settings.getPort() < 1) {
throw new ModuleStartException("No port setting.");
}
return new GRPCConfigWatcherRegister(settings);
}
}
/*
* 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.configuration.grpc;
import lombok.*;
import org.apache.skywalking.oap.server.library.module.ModuleConfig;
/**
* @author wusheng
*/
@Setter
@Getter
public class RemoteEndpointSettings extends ModuleConfig {
private String host;
private int port;
private String clusterName = "default";
// Sync configuration per 60 seconds.
private int period = 60;
@Override public String toString() {
return "RemoteEndpointSettings{" +
"host='" + host + '\'' +
", port=" + port +
", clusterName='" + clusterName + '\'' +
'}';
}
}
/*
* 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.
*
*/
syntax = "proto3";
option java_multiple_files = true;
option java_package = "org.apache.skywalking.oap.server.configuration.service";
service ConfigurationService {
rpc call (ConfigurationRequest) returns (ConfigurationResponse) {
}
}
message ConfigurationRequest {
// Logic name of this cluster,
// in case the remote configuration center implementation support
// configuration management for multiple clusters.
string clusterName = 1;
}
message ConfigurationResponse {
// Include all config items.
// All config name should be not empty,
// the name is composed by "module name"."provider name"."item name".
// Each watcher implementor provides this, and it will be notified when the value changed.
//
// If the config center wants to set the value to NULL or empty,
// must set the name with empty value explicitly.
repeated Config configTable = 1;
}
message Config {
string name = 1;
string value = 2;
}
\ No newline at end of file
#
# 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.
#
#
org.apache.skywalking.oap.server.configuration.grpc.GRPCConfigurationProvider
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>oap-server</artifactId>
<groupId>org.apache.skywalking</groupId>
<version>6.2.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>server-configuration</artifactId>
<packaging>pom</packaging>
<modules>
<module>configuration-api</module>
<module>grpc-configuration-sync</module>
</modules>
</project>
\ No newline at end of file
......@@ -44,6 +44,11 @@
<artifactId>telemetry-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>configuration-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>library-util</artifactId>
......
......@@ -19,6 +19,7 @@
package org.apache.skywalking.oap.server.core;
import java.io.IOException;
import org.apache.skywalking.oap.server.configuration.api.ConfigurationModule;
import org.apache.skywalking.oap.server.core.analysis.*;
import org.apache.skywalking.oap.server.core.annotation.AnnotationScan;
import org.apache.skywalking.oap.server.core.cache.*;
......@@ -188,6 +189,6 @@ public class CoreModuleProvider extends ModuleProvider {
@Override
public String[] requiredModules() {
return new String[] {TelemetryModule.NAME};
return new String[] {TelemetryModule.NAME, ConfigurationModule.NAME};
}
}
......@@ -22,6 +22,9 @@ package org.apache.skywalking.oap.server.library.module;
* @author peng-yongsheng
*/
public class ModuleStartException extends Exception {
public ModuleStartException(String message) {
super(message);
}
public ModuleStartException(String message, Throwable cause) {
super(message, cause);
......
/*
* 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.receiver.trace.provider;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.skywalking.oap.server.configuration.api.ConfigChangeWatcher;
import org.apache.skywalking.oap.server.receiver.trace.module.TraceModule;
/**
* @author wusheng
*/
public class DBLatencyThresholdsAndWatcher extends ConfigChangeWatcher {
private AtomicReference<Map<String, Integer>> thresholds;
private AtomicReference<String> settingsString;
DBLatencyThresholdsAndWatcher(String config, TraceModuleProvider provider) {
super(TraceModule.NAME, provider, "slowDBAccessThreshold");
thresholds = new AtomicReference(new HashMap<>());
settingsString = new AtomicReference<>("");
activeSetting(config);
}
private void activeSetting(String config) {
Map<String, Integer> newThresholds = new HashMap<>();
String[] settings = config.split(",");
for (String setting : settings) {
String[] typeValue = setting.split(":");
if (typeValue.length == 2) {
newThresholds.put(typeValue[0].trim().toLowerCase(), Integer.parseInt(typeValue[1].trim()));
}
}
if (!newThresholds.containsKey("default")) {
newThresholds.put("default", 10000);
}
thresholds.set(newThresholds);
settingsString.set(config);
}
public int getThreshold(String type) {
type = type.toLowerCase();
if (thresholds.get().containsKey(type)) {
return thresholds.get().get(type);
} else {
return thresholds.get().get("default");
}
}
@Override public void notify(ConfigChangeEvent value) {
if (EventType.DELETE.equals(value.getEventType())) {
activeSetting("");
} else {
activeSetting(value.getNewValue());
}
}
@Override public String value() {
return settingsString.get();
}
}
......@@ -19,6 +19,7 @@
package org.apache.skywalking.oap.server.receiver.trace.provider;
import java.io.IOException;
import org.apache.skywalking.oap.server.configuration.api.*;
import org.apache.skywalking.oap.server.core.CoreModule;
import org.apache.skywalking.oap.server.core.server.*;
import org.apache.skywalking.oap.server.library.module.*;
......@@ -42,6 +43,7 @@ public class TraceModuleProvider extends ModuleProvider {
private final TraceServiceModuleConfig moduleConfig;
private SegmentParse.Producer segmentProducer;
private SegmentParseV2.Producer segmentProducerV2;
private DBLatencyThresholdsAndWatcher thresholds;
public TraceModuleProvider() {
this.moduleConfig = new TraceServiceModuleConfig();
......@@ -60,7 +62,9 @@ public class TraceModuleProvider extends ModuleProvider {
}
@Override public void prepare() throws ServiceNotProvidedException {
moduleConfig.setDbLatencyThresholds(new DBLatencyThresholds(moduleConfig.getSlowDBAccessThreshold()));
thresholds = new DBLatencyThresholdsAndWatcher(moduleConfig.getSlowDBAccessThreshold(), this);
moduleConfig.setDbLatencyThresholdsAndWatcher(thresholds);
SegmentParserListenerManager listenerManager = new SegmentParserListenerManager();
if (moduleConfig.isTraceAnalysis()) {
......@@ -84,9 +88,11 @@ public class TraceModuleProvider extends ModuleProvider {
}
@Override public void start() throws ModuleStartException {
DynamicConfigurationService dynamicConfigurationService = getManager().find(ConfigurationModule.NAME).provider().getService(DynamicConfigurationService.class);
GRPCHandlerRegister grpcHandlerRegister = getManager().find(SharingServerModule.NAME).provider().getService(GRPCHandlerRegister.class);
JettyHandlerRegister jettyHandlerRegister = getManager().find(SharingServerModule.NAME).provider().getService(JettyHandlerRegister.class);
try {
dynamicConfigurationService.registerConfigChangeWatcher(thresholds);
grpcHandlerRegister.addHandler(new TraceSegmentServiceHandler(segmentProducer));
grpcHandlerRegister.addHandler(new TraceSegmentReportServiceHandler(segmentProducerV2, getManager()));
......@@ -111,6 +117,6 @@ public class TraceModuleProvider extends ModuleProvider {
}
@Override public String[] requiredModules() {
return new String[] {TelemetryModule.NAME, CoreModule.NAME, SharingServerModule.NAME};
return new String[] {TelemetryModule.NAME, CoreModule.NAME, SharingServerModule.NAME, ConfigurationModule.NAME};
}
}
......@@ -38,7 +38,7 @@ public class TraceServiceModuleConfig extends ModuleConfig {
* The threshold used to check the slow database access. Unit, millisecond.
*/
@Setter @Getter private String slowDBAccessThreshold = "default:200";
@Setter @Getter private DBLatencyThresholds dbLatencyThresholds;
@Setter @Getter private DBLatencyThresholdsAndWatcher dbLatencyThresholdsAndWatcher;
/**
* Analysis trace status.
*
......
......@@ -165,7 +165,7 @@ public class MultiScopesSpanListener implements EntrySpanListener, ExitSpanListe
} else if (SpanTags.DB_TYPE.equals(tag.getKey())) {
String dbType = tag.getValue();
DBLatencyThresholds thresholds = config.getDbLatencyThresholds();
DBLatencyThresholdsAndWatcher thresholds = config.getDbLatencyThresholdsAndWatcher();
int threshold = thresholds.getThreshold(dbType);
if (sourceBuilder.getLatency() > threshold) {
isSlowDBAccess = true;
......
......@@ -171,6 +171,13 @@
<artifactId>exporter</artifactId>
<version>${project.version}</version>
</dependency>
<!-- configuration -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>grpc-configuration-sync</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<finalName>skywalking-oap</finalName>
......
......@@ -123,6 +123,8 @@ alarm:
default:
telemetry:
none:
configuration:
none:
#exporter:
# grpc:
# targetHost: ${SW_EXPORTER_GRPC_HOST:127.0.0.1}
......
......@@ -129,6 +129,8 @@ telemetry:
prometheus:
host: ${SW_TELEMETRY_PROMETHEUS_HOST:0.0.0.0}
port: ${SW_TELEMETRY_PROMETHEUS_PORT:1234}
configuration:
none:
#exporter:
# grpc:
# targetHost: ${SW_EXPORTER_GRPC_HOST:127.0.0.1}
......
......@@ -485,7 +485,8 @@
org/apache/skywalking/apm/network/language/**/*.java,
org/apache/skywalking/oap/server/core/remote/grpc/proto/*.java,
org/apache/skywalking/oal/tool/grammar/*.java,
org/apache/skywalking/oap/server/exporter/grpc/*.java
org/apache/skywalking/oap/server/exporter/grpc/*.java,
org/apache/skywalking/oap/server/configuration/service/*.java
</excludes>
</configuration>
<goals>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册