File: README.md
English | δΈζ
Apollo - A reliable configuration management system
Apollo is a reliable configuration management system. It can centrally manage the configurations of different applications and different clusters. It is suitable for microservice configuration management scenarios.
The server side is developed based on Spring Boot and Spring Cloud, which can simply run without the need to install additional application containers such as Tomcat.
The Java SDK does not rely on any framework and can run in all Java runtime environments. It also has good support for Spring/Spring Boot environments.
The .Net SDK does not rely on any framework and can run in all .Net runtime environments.
For more details of the product introduction, please refer Introduction to Apollo Configuration Center.
To try Apollo locally, please refer Quick Start or Docker Quick Start.
Screenshots
Features
- Unified management of the configurations of different environments and different clusters
- Apollo provides a unified interface to centrally manage the configurations of different environments, different clusters, and different namespaces
- The same codebase could have different configurations when deployed in different clusters
- With the namespace concept, it is easy to support multiple applications to share the same configurations, while also allowing them to customize the configurations
- Multiple languages is provided in user interface(currently Chinese and English)
- Configuration changes takes effect in real time (hot release)
- After the user modified the configuration and released it in Apollo, the sdk will receive the latest configurations in real time (1 second) and notify the application
- Release version management
- Every configuration releases are versioned, which is friendly to support configuration rollback
- Grayscale release
- Support grayscale configuration release, for example, after clicking release, it will only take effect for some application instances. After a period of observation, we could push the configurations to all application instances if there is no problem
- Global Search Configuration Items
- A fuzzy search of the key and value of a configuration item finds in which application, environment, cluster, namespace the configuration item with the corresponding value is used
- It is easy for administrators and SRE roles to quickly and easily find and change the configuration values of resources by highlighting, paging and jumping through configurations
- Authorization management, release approval and operation audit
- Great authorization mechanism is designed for applications and configurations management, and the management of configurations is divided into two operations: editing and publishing, therefore greatly reducing human errors
- All operations have audit logs for easy tracking of problems
- Client side configuration information monitoring
- It's very easy to see which instances are using the configurations and what versions they are using
- Rich SDKs available
- Provides native sdks of Java and .Net to facilitate application integration
- Support Spring Placeholder, Annotation and Spring Boot ConfigurationProperties for easy application use (requires Spring 3.1.1+)
- Http APIs are provided, so non-Java and .Net applications can integrate conveniently
- Rich third party sdks are also available, e.g. Golang, Python, NodeJS, PHP, C, etc
- Open platform API
- Apollo itself provides a unified configuration management interface, which supports features such as multi-environment, multi-data center configuration management, permissions, and process governance
- However, for the sake of versatility, Apollo will not put too many restrictions on the modification of the configuration, as long as it conforms to the basic format, it can be saved.
- In our research, we found that for some users, their configurations may have more complicated formats, such as xml, json, and the format needs to be verified
- There are also some users such as DAL, which not only have a specific format, but also need to verify the entered value before saving, such as checking whether the database, username and password match
- For this type of application, Apollo allows the application to modify and release configurations through open APIs, which has great authorization and permission control mechanism built in
- Simple deployment
- As an infrastructure service, the configuration center has very high availability requirements, which forces Apollo to rely on external dependencies as little as possible
- Currently, the only external dependency is MySQL, so the deployment is very simple. Apollo can run as long as Java and MySQL are installed
- Apollo also provides a packaging script, which can generate all required installation packages with just one click, and supports customization of runtime parameters
Usage
- Apollo User Guide
- Apollo Open APIs
- Apollo Use Cases
- Apollo User Practices
- Apollo Security Best Practices
SDK
- Java SDK User Guide
- .Net SDK user Guide
- Golang SDK User Guide
- Python SDK User Guide
- NodeJS SDK User Guide
- PHP SDK User Guide
- C SDK User Guide
- Rust SDK User Guide
- HTTP API Guide
Design
- Apollo Design
- Apollo Core Concept - Namespace
- Apollo Architecture Analysis
- Apollo Source Code Explanation
Development
Deployment
Release Notes
FAQ
Presentation
Publication
Community
License
The project is licensed under the Apache 2 license.
Known Users
Sorted by registration orderοΌusers are welcome to register in https://github.com/apolloconfig/apollo/issues/451 (reference purpose only for the community)
| More... |
Awards
Stargazers over time
File: apollo-audit/README.md
Features: Apollo-Audit-Log
This module provides audit log functions for other Apollo modules.
Only apolloconfig's developer need to read it,
apolloconfig's user doesn't need.
How to enable/disable
We can switch this module freely by properties:
by adding properties to application.properties:
# true: enabled the new feature of audit log
# false/missing: disable it
apollo.audit.log.enabled = trueHow to generate audit log
Append an AuditLog
Through an AuditLog, we have the ability to record Who, When, Why, Where, What and How operates something.
We can do this by using annotations:
@ApolloAuditLog(type=OpType.CREATE,name="App.create")
public App create() {
// ...
}Through this, an AuditLog will be created and its AuditScope will be activated during the execution of this method.
Equally, we can use ApolloAuditLogApi to do this manually:
public App create() {
try(AutoCloseable auditScope = api.appendAuditLog(type, name)) {
// ...
}
}
/**************OR**************/
public App create() {
Autocloseable auditScope = api.appendAuditLog(type, name);
// ...
auditScope.close();
}The only thing you need to pay attention to is that you need to close this scope manuallyο½
Append DataInfluence
This function can also be implemented automatically and manually.
There is a corresponding relationship between DataInfluences and a certain AuditLog, and they are caused by this AuditLog. But not all AuditLogs will generate DataInfluences!
Mark which data change
First, we need to add audit-bean-definition to class of the entity you want to audit:
@ApolloAuditLogDataInfluenceTable(tableName = "App")
public class App extends BaseEntity {
@ApolloAuditLogDataInfluenceTableField(fieldName = "Name")
private String name;
private String orgId;
}In class App, we define that its data-influence table' name is "App", the field "name" needs to be audited and its audit field name in the table "App" is "Name". The field "orgId" is no need to be audited.
Second, use API's method to append it:
Actually we don't need to manually call it. We can depend on the DomainEvents that pre-set in BaseEntity:
@DomainEvents
public Collection<ApolloAuditLogDataInfluenceEvent> domainEvents() {
return Collections.singletonList(new ApolloAuditLogDataInfluenceEvent(this.getClass(), this));
}And this will call appendDataInfluences automatically by the listener.
Manually
/**
* Append DataInfluences by a list of entities needs to be audited, and their
* audit-bean-definition.
*/
ApolloAuditLogApi.appendDataInfluences(List<Object> entities, Class<?> beanDefinition);Just call the api method in an active scope, the data influences will combine with the log automatically.
public App create() {
try(AutoCloseable auditScope = api.appendAuditLog(type, name)) {
// ...
api.appendDataInfluences(appList, App.class);
// or.
api.appendDataInfluence("App","10001","Name","xxx");
}
}some tricky situations
Yet, sometimes we can't catch the domain events like some operations that directly change database fields. We can use annotations to catch the input parameters:
@ApolloAuditLog(type=OpType.DELETE,name="AppNamespace.batchDeleteByAppId")
public AppNamespace batchDeleteByAppId(
@ApolloAuditLogDataInfluence
@ApolloAuditLogDataInfluenceTable(tableName="AppNamespace")
@ApolloAuditLogDataInfluenceTableField(fieldName="AppId") String appId) {
// ...
}This will generate a special data influence. It means that all entities matching the input parameter value have been affected.
How to verify the audit-log work
check-by-UI
The entrance of audit log UI is in Admin Tools.
Then, we can check if the AuditLogs are created properly by searching or just find in table below.
Then, check in the trace detail page.
We can check if the relationship between AuditLogs are correct and the DataInfluences caused by certain AuditLog is logically established.
In the rightmost column, we can view the historical operation records of the specified field's value. Null means being deleted~
check-by-database
The databases are in ApolloPortalDB, the table AuditLog and AuditLogDataInfluence.
We can verify if the parent/followsfrom relationships are in line with our expectations.
File: docs/en/client/c-sdks-user-guide.md
Apollo C client
Project address: apollo-c-client
Thanks @lzeqian for providing support for the C Apollo client
File: docs/en/client/dotnet-sdk-user-guide.md
Note: This document is intended for users of Apollo systems. If you are a developer/maintainer of Apollo systems in your company, it is recommended to refer to Apollo Development Guide first.
! Important !
Net access documentation, please refer to Apollo.net Framework Integration
I. Preparation
1.1 Environment requirements
- .Net: 4.0+
1.2 Mandatory settings
Apollo client relies on AppId, Environment and other environment information to work, so make sure to read the following instructions and do the correct configuration.
1.2.1 AppId
AppId is the identity of the application and is an important piece of information to get the configuration from the server.
Make sure you have the AppID configuration in app.config or web.config, where the content looks like
<?xml version="1.0"?>
<configuration>
<appSettings>
<! -- Change to the actual app id -->
<add key="Apollo.AppId" value="100004458"/>
</appSettings>
</configuration>Note: app.id is a unique id used to identify the application identity in string format.
1.2.2 Environment
Apollo supports applications that have different configurations for different environments, so Environment is another important piece of information to get the configuration from the server.
Environment is specified through a configuration file in the location C:\opt\settings\server.properties, with the contents of the file shaped like this
env=DEVCurrently, env supports the following values (case-insensitive).
- DEV
- Development environment
- FAT
- Feature Acceptance Test environment
- UAT
- User Acceptance Test environment
- PRO
- Production environment
1.2.3 Service address
Apollo clients get their configuration from different servers for different environments, so make sure that the server address (Apollo.{ENV}.Meta) is correctly configured in app.config or web.config, where the content looks like
<?xml version="1.0"?>
<configuration>
<appSettings>
<! -- Change to the actual app id -->
<add key="Apollo.AppId" value="100004458"/>
<! -- Should change the apollo config service url for each environment -->
<add key="Apollo.DEV.Meta" value="http://dev-configservice:8080"/>
<add key="Apollo.FAT.Meta" value="http://fat-configservice:8080"/>
<add key="Apollo.UAT.Meta" value="http://uat-configservice:8080"/>
<Meta" value="http://pro-configservice:8080"/>
</appSettings>
</configuration>1.2.4 Local cache path
The Apollo client will cache a copy of the configuration obtained from the server in the local file system, so that if the service is unavailable or the network is down, the configuration can still be restored locally without affecting the normal operation of the application.
The local cache path is located in C:\opt\data\{appId}\config-cache, so please make sure that the C:\opt\data\ directory exists and the application has read/write access.
1.2.5 Optional settings
Cluster
Apollo supports configuration by cluster, meaning that for an appId and an environment, there can be different configurations for different clusters.
If you need to use this feature, you can specify the runtime clusters by.
via App Config
- We can specify the runtime cluster by setting Apollo.Cluster in the App.config file (note the case)
- For example, the following screenshot configuration specifies the runtime cluster as SomeCluster
via configuration file
- First make sure that
C:\opt\settings\server.propertiesexists on the target machine - In this file, you can set the data center cluster, such as
idc=xxx - Note that the key is all lowercase
- First make sure that
Cluster Precedence (cluster order)
If
Apollo.Clusterandidcare both specified.- We will first try to load the configuration from the cluster specified by
Apollo.Cluster - If no configuration is found, we will try to load the configuration from the cluster specified by
idc. - If nothing is found, we will load from the default cluster (
default)
- We will first try to load the configuration from the cluster specified by
If only
Apollo.Clusteris specified.- We will first try to load the configuration from the cluster specified by
Apollo.Cluster - If not found, it will be loaded from the default cluster (
default)
- We will first try to load the configuration from the cluster specified by
If only
idcis specified.- We will first try to load the configuration from the cluster specified by
idc - If not found, it will be loaded from the default cluster (
default)
- We will first try to load the configuration from the cluster specified by
If neither
Apollo.Clusternoridcis specified.- It will load the configuration from the default cluster (
default)
- It will load the configuration from the default cluster (
II. DLL references
Net client project address is located at: https://github.com/ctripcorp/apollo.net.
Download the project locally, switch to the Release configuration, compile the Solution and it will generate Framework.Apollo.Client.dll in apollo.net\Apollo\bin\Release.
Just reference Framework.Apollo.Client.dll in your application.
.Net Core, you can refer to dotnet-core and nuget repository
III. Client-side usage
3.1 Get the configuration of the default namespace (application)
Config config = ConfigService.GetAppConfig(); //config instance is singleton for each namespace and is never null
string someKey = "someKeyFromDefaultNamespace";
string someDefaultValue = "someDefaultValueForTheKey";
string value = config.GetProperty(someKey, someDefaultValue);With the above config.getProperty you can get the real-time latest configuration value corresponding to someKey.
In addition, the configuration values are fetched from memory, so there is no need for the application to do its own caching.
3.2 Listening for configuration change events
Listening for configuration change events is only used when the application really cares about configuration changes and needs to be notified when the configuration changes, e.g. when the database connection string changes and the connection needs to be rebuilt, etc.
If you just want to fetch the latest configuration every time, just call config.GetProperty as in the example above.
Config config = ConfigService.GetAppConfig(); //config instance is singleton for each namespace and is never null
config.ConfigChanged += new ConfigChangeEvent(OnChanged);
private void OnChanged(object sender, ConfigChangeEventArgs changeEvent)
{
Console.WriteLine("Changes for namespace {0}", changeEvent.Namespace);
foreach (string key in changeEvent.ChangedKeys)
{
ConfigChange change = changeEvent.GetChange(key);
Console.WriteLine("Change - key: {0}, oldValue: {1}, newValue: {2}, changeType: {3}", change.PropertyName, change, NewValue, change.ChangeType);
}
}3.3 Get the configuration of the public Namespace
string somePublicNamespace = "CAT";
Config config = ConfigService.GetConfig(somePublicNamespace); //config instance is singleton for each namespace and is never null
string someKey = "someKeyFromPublicNamespace";
string someDefaultValue = "someDefaultValueForTheKey";
string value = config.GetProperty(someKey, someDefaultValue);3.4 Demo
There is a sample client project in apollo.net project: ApolloDemo, you can refer to 2.4 .Net sample client startup for more information.
Net client open source version will output logs directly to the Console by default, you can implement your own logging-related features.
See https://github.com/ctripcorp/apollo.net/tree/master/Apollo/Logging/Spi for more details .
IV. Client design
The above diagram briefly describes the principle of Apollo client implementation.
- The client and the server maintain a long connection, so that the first time to get the configuration updates pushed. (achieved through Http Long Polling) .
- The client also regularly pulls the latest configuration of the application from the Apollo Configuration Center server.
- This is a fallback mechanism to prevent the configuration from being updated due to the failure of the push mechanism.
- The client will report the local version of the timed pull, so in general, for the timed pull operation, the server will return 304 - Not Modified.
- Timing frequency is pulled every 5 minutes by default, client can also set
Apollo.RefreshIntervalthrough App.config to override it in milliseconds.
- The client will save the latest configuration of the application in memory after getting it from the Apollo Configuration Center server
- The client will cache a copy of the configuration obtained from the server in the local file system. In case of service unavailability or network failure, the configuration can still be restored locally.
- The application can get the latest configuration from the Apollo client, subscribe to configuration update notifications.
V. Local Development Mode
Apollo client also supports local development mode, which is mainly used when the development environment cannot connect to Apollo server, such as doing related function development on cruise ships or airplanes.
In local development mode, Apollo will only read configuration information from local files, not from Apollo server.
You can enable Apollo local development mode by following the steps below.
5.1 Modify the environment
Modify the C:\opt\settings\server.properties file to set the env to Local:
env=Local5.2 Preparing local configuration files
In local development mode, Apollo client will read files from local, so we need to prepare the configuration file beforehand.
5.2.1 Local configuration directory
The local configuration directory is located at: C:\opt\data{appId}\config-cache.
The appId is the appId of the application, e.g. 100004458.
Please make sure that the directory exists and the application has read access to the directory.
[Tip] The recommended way is to use Apollo in normal mode first, so that Apollo will automatically create the directory and generate the configuration file under it.
5.2.2 Local configuration files
Local configuration files need to be placed in the local configuration directory according to a certain file name format, which is as follows.
{appId}+{cluster}+{namespace}.json
- AppId is the application's own appId, such as 100004458
- Cluster is the cluster used by the application, generally in local mode without configuration, it is default
- Namespace is the configuration
namespaceused by the application, usuallyapplication
The content of the file is stored in json format, for example, if there are two keys, one is request.timeout, the other is batch, then the content of the file is the following format.
{
"request.timeout": "1000",
"batch": "2000"
}5.3 Modifying the configuration
In local development mode, Apollo does not monitor the file content for changes in real time, so if you modify the configuration, you need to restart the application to take effect.
File: docs/en/client/golang-sdks-user-guide.md
Apollo Go client 1
Project address: apolloconfig/agollo
Thanks @zouyx for providing support for the Go Apollo client
Apollo Go client 2
Project address: philchia/agollo
Thanks @philchia for providing support for the Go Apollo client
Apollo Go client 3
Project address: shima-park/agollo
Thanks @shima-park for providing support for the Go Apollo client
Apollo Go client 4
Project address: go-microservices/php_conf_agent
Thanks @GanymedeNil for providing support for the Go Apollo client
Apollo Go client 5
Project address: hyperjiang/lunar
Thanks @hyperjiang for providing support for the Go Apollo client
Apollo Go client 6
Project address: tagconfig/tagconfig
Thanks @n0trace for providing support for the Go Apollo client
Apollo Go client 7
Project address: go-chassis/go-archaius
Thanks @tianxiaoliang and @Shonminh for providing support for the Go Apollo client
Apollo Go client 8
Project address: xhrg-product/apollo-client-golang
Thanks @xhrg for providing support for the Go Apollo client
Apollo Go client 9
Project address: xnzone/apollo-go
Thanks @xnzone for providing support for the Go Apollo client
File: docs/en/client/java-sdk-user-guide.md
Note: This document is intended for users of Apollo systems. If you are a developer/maintainer of Apollo systems in your company, it is recommended to refer to Apollo Development Guide first.
I. Preparation
1.1 Environment requirements
- Java: 1.8+
- To run in Java 1.7 runtime environment, please use 1.x version of apollo client, such as 1.9.1
- Guava: 22.0+
- The Apollo client will reference Guava 32 by default. If your project references other versions, make sure the version number is greater than or equal to 22.0
Note: For Apollo client, you can make a few code changes to downgrade to Java 1.6 if needed, see Issue 483 for details
1.2 Mandatory settings
Apollo client depends on AppId, Apollo Meta Server and other environment information to work, so please make sure to read the following instructions and do the correct configuration.
1.2.1 AppId
AppId is the identity of the application and is an important piece of information to get the configuration from the server.
There are several ways to set it, from highest to lowest priority, as follows.
- System Property
Apollo 0.7.0+ supports passing in app.id information via System Property, such as
-Dapp.id=YOUR-APP-ID- System Environment of the operating system
Apollo 1.4.0+ supports passing app.id information via the operating system's System Environment APP_ID, as in
APP_ID=YOUR-APP-ID- Spring Boot application.properties
Apollo 1.0.0+ supports configuration via Spring Boot's application.properties file, such as
app.id=YOUR-APP-IDThis configuration does not work with multiple war packages deployed in the same tomcat
- app.properties
Make sure that the classpath:/META-INF/app.properties file exists and that its contents look like.
app.id=YOUR-APP-ID
The file location reference is as follows.
Note: app.id is a unique id used to identify the application identity in the format string.
1.2.2 Apollo Meta Server
Apollo supports applications with different configurations in different environments, so you need to provide the Apollo Meta Server information of the current environment to Apollo clients at runtime. By default, the meta server and config service are deployed in the same JVM process, so the address of the meta server is the address of the config service.
To achieve high availability of meta server, it is recommended to do dynamic load balancing by SLB (Software Load Balancer). meta server address can also be filled with IP, such as http://1.1.1.1:8080,http://2.2.2.2:8080, but it is still recommended for production environment Use the domain name (go SLB), because machine expansion, shrinkage, etc. may lead to changes in the IP list.
The following ways to configure apollo meta server information are supported since version 1.0.0, in descending order of priority
- Via the Java System Property
apollo.meta- Can be specified via the Java System Property
apollo.meta - Can be specified in the Java program startup script with
-Dapollo.meta=http://config-service-url- If you are running a jar file, you need to note that the format is
java -Dapollo.meta=http://config-service-url -jar xxx.jar
- If you are running a jar file, you need to note that the format is
- You can also specify it programmatically, e.g.
System.setProperty("apollo.meta", "http://config-service-url");
- Can be specified via the Java System Property
- Through the Spring Boot configuration file
- You can specify
apollo.meta=http://config-service-urlinapplication.propertiesorbootstrap.propertiesof Spring Boot
- You can specify
This configuration does not work with multiple war packages deployed in the same tomcat
- Through the operating system's System Environment
APOLLO_META- Can be specified by System Environment
APOLLO_METAof the operating system - Note that the key is all-caps and separated by
_.
- Can be specified by System Environment
- Via
server.propertiesconfiguration file- You can specify
apollo.meta=http://config-service-urlin theserver.propertiesconfiguration file - For Mac/Linux, the default file location is
/sopt/settings/server.properties. - For Windows, the default file location is
C:\opt\settings\server.properties
- You can specify
- Via the
app.propertiesconfiguration file- You can specify
apollo.meta=http://config-service-urlinclasspath:/META-INF/app.properties
- You can specify
- Via Java system property
${env}_meta- If the current env is
dev, then the user can configure-Ddev_meta=http://config-service-url - Using this configuration method, then the Environment must be configured correctly, see 1.2.4.1 Environment for details
- If the current env is
- Via the OS System Environment
${ENV}_META(supported since version 1.2.0)- If the current env is
dev, then the user can configure the OS System EnvironmentDEV_META=http://config-service-url - Note that the key is all-caps
- Using this configuration method, then the Environment must be configured correctly, see 1.2.4.1 Environment for details
- If the current env is
- Via the
apollo-env.propertiesfile- The user can also create an
apollo-env.propertiesand put it under the classpath of the application or under the config directory of the spring boot application - If you use this configuration, then you must configure the Environment correctly, see 1.2.4.1 Environment
- The contents of the file look like this.
- The user can also create an
dev.meta=http://1.1.1.1:8080
fat.meta=http://apollo.fat.xxx.com
uat.meta=http://apollo.uat.xxx.com
pro.meta=http://apollo.xxx.comIf the Meta Server address cannot be obtained by any of the above means, Apollo will eventually fallback to
http://apollo.metaas the Meta Server address
1.2.2.1 Customizing Apollo Meta Server Address Location Logic
In version 1.0.0, Apollo provides the MetaServerProvider SPI, which allows users to inject their own MetaServerProvider to customize the Meta Server address location logic.
Since we use the typical Java Service Loader pattern, it is still relatively simple to implement.
One thing to note is that apollo will iterate through all MetaServerProviders in order at runtime until a MetaServerProvider provides a non-empty Meta Server address, so users need to pay extra attention to the Order of the custom MetaServerProvider. The rule is that smaller Order has higher priority, so MetaServerProvider with Order=0 will be ranked ahead of MetaServerProvider with Order=1.
If your company has many applications that need to access Apollo, it is recommended to package a jar package and then provide a custom Apollo Meta Server positioning logic so that the applications that access Apollo can be used with zero configuration. For example, write your own xx-company-apollo-client, the jar package depends on apollo-client, define a custom MetaServerProvider implementation in the jar package by spi, and then the application directly depends on xx-company-apollo-client.
The implementation of MetaServerProvider can be found in LegacyMetaServerProvider and DefaultMetaServerProvider.
1.2.2.2 Skip Apollo Meta Server service discovery
For apollo-client version 0.11.0 and above
In general, it is recommended to use Apollo's Meta Server mechanism to implement service discovery for Config Service, so that high availability of Config Service can be achieved. However, apollo-client also supports skipping Meta Server service discovery, which is mainly used in the following scenarios: 1.
- Config Service is deployed on the public cloud, and the address registered to Meta Server is an intranet address, so the local development environment cannot connect directly
- If the Config Service is exposed through the public SLB, remember to set the IP whitelist to avoid data leakage.
- Config Service is deployed in docker environment, and the address registered to Meta Server is docker intranet address, so local development environment cannot connect to it directly.
- Config Service is deployed in kubernetes, and you want to use kubernetes' own service discovery capability (Service).
For the above scenarios, you can skip Meta Server service discovery by directly specifying the Config Service address, in descending order of priority, as follows
- Via Java System Property
apollo.config-service(1.9.0+) orapollo.configService(before 1.9.0)- Can be specified via Java's System Property
apollo.config-service(1.9.0+) orapollo.configService(before 1.9.0) - In the Java program startup script, you can specify
-Dapollo.config-service=http://config-service-url:port- If you are running a jar file, you need to note that the format is
java -Dapollo.configService=http://config-service-url:port -jar xxx.jar
- If you are running a jar file, you need to note that the format is
- It can also be specified programmatically, such as
System.setProperty("apollo.config-service", "http://config-service-url:port");
- Can be specified via Java's System Property
- Through the operating system's System Environment
APOLLO_CONFIG_SERVICE(1.9.0+) orAPOLLO_CONFIGSERVICE(before 1.9.0)- Can be specified by System Environment
APOLLO_CONFIG_SERVICE(1.9.0+) orAPOLLO_CONFIGSERVICE(before 1.9.0) of the operating system - Note that the key is all-caps and separated by
_.
- Can be specified by System Environment
- Via
server.propertiesconfiguration file- You can specify
apollo.config-service=http://config-service-url:port(1.9.0+) orapollo.configService=http://config-service-url:portin theserver.propertiesconfiguration file (before 1.9.0) - For Mac/Linux, the default file location is
/opt/settings/server.properties - For Windows, the default file location is
C:\opt\settings\server.properties
- You can specify
1.2.3 Local cache path
The Apollo client will cache a copy of the configuration obtained from the server in the local file system, so that if the service is unavailable or the network is down, the configuration can still be restored locally without affecting the normal operation of the application.
The local cache path is located in the following path by default, so please make sure /opt/data or C:\opt\data\ directory exists and the application has read/write permission.
- Mac/Linux: /opt/data/{appId}/config-cache
- Windows: C:\opt\data\{appId}\config-cache
The local configuration file will be placed under the local cache path in the following filename format.
{appId}+{cluster}+{namespace}.properties
- AppId is the application's own appId, e.g. 100004458
- Cluster is the cluster used by the application, generally in local mode without configuration, it is default
- Namespace is the configuration
namespaceused by the application, usuallyapplication
The content of the file is stored in properties format, for example, if there are two keys, one is request.timeout, and the other is batch, then the content of the file is in the following format.
request.timeout=2000
batch=2000Note: If deployed in a Kubernetes environment, you can also enable the configMap cache to further improve availability
1.2.3.1 Customizing the cache path
The following custom cache paths are supported since version 1.0.0, in descending order of priority
- Via the Java System Property
apollo.cache-dir(1.9.0+) orapollo.cacheDir(before 1.9.0)- Can be specified by Java's System Property
apollo.cache-dir(1.9.0+) orapollo.cacheDir(before 1.9.0) - In the Java program startup script, you can specify
-Dapollo.cache-dir=/opt/data/some-cache-dir(1.9.0+) orapollo.cacheDir=/opt/data/some-cache-dir(before 1.9.0)- If you are running a jar file, note that the format is
java -Dapollo.cache-dir=/opt/data/some-cache-dir -jar xxx.jar(1.9.0+) orjava -Dapollo.cacheDir=/opt/data/some-cache-dir -jar xxx.jar(before 1.9.0)
- If you are running a jar file, note that the format is
- Can also be specified programmatically, e.g.
System.setProperty("apollo.cache-dir", "/opt/data/some-cache-dir");(1.9.0+) orSystem.setProperty("apollo.cacheDir", "/opt/data/some-cache-dir");(before 1.9.0)
- Can be specified by Java's System Property
- Via the Spring Boot configuration file
- You can specify
apollo.cache-dir=/opt/data/some-cache-dir(1.9.0+) orapollo. cacheDir=/opt/data/some-cache-dir(before 1.9.0)
- You can specify
- Via OS System Environment
APOLLO_CACHE_DIR(1.9.0+) orAPOLLO_CACHEDIR(before 1.9.0)- Can be specified by the OS System Environment
APOLLO_CACHE_DIR(1.9.0+) orAPOLLO_CACHEDIR(before 1.9.0) - Note that the key is all-caps and separated by
_.
- Can be specified by the OS System Environment
- Via
server.propertiesconfiguration file- You can specify
apollo.cache-dir=/opt/data/some-cache-dir(1.9.0+) orapollo.cacheDir=/opt/data/some-cache-dir(before 1.9. 0) in theserver.propertiesconfiguration file. 0 or earlier) - For Mac/Linux, the default file location is
/opt/settings/server.properties - For Windows, the default file location is
C:\opt\settings\server.properties
- You can specify
Note: The local cache path can also be used for the disaster recovery directory. If the application needs to be expanded when all the config services are down, then the configuration can also be copied from the cache path on the existing machine to the same cache path on the new machine first
1.2.4 Optional settings
1.2.4.1 Environment
The Environment can be configured in any of the following 3 ways.
Via Java System Property
- Environment can be specified through Java's System Property
env. - In the Java program startup script, you can specify
-Denv=YOUR-ENVIRONMENT- If you are running a jar file, note that the format is
java -Denv=YOUR-ENVIRONMENT -jar xxx.jar
- If you are running a jar file, note that the format is
- Note that the key is all lowercase
- Environment can be specified through Java's System Property
Through the operating system's System Environment
- You can also specify the System Environment
ENVof the operating system - Note that the key is all uppercase
- You can also specify the System Environment
Through the configuration file
- The last recommended way is to specify
env=YOUR-ENVIRONMENTthrough the configuration file - For Mac/Linux, the default file location is
/opt/settings/server.properties. - For Windows, the default file location is
C:\opt\settings\server.properties.
- The last recommended way is to specify
The contents of the file look like :
env=DEVCurrently, env supports the following values (case-insensitive).
- DEV
- Development environment
- FAT
- Feature Acceptance Test environment
- UAT
- User Acceptance Test environment
- PRO
- Production environment
For more environment definitions, you can refer to Env.java
1.2.4.2 Cluster
Apollo supports configuration by cluster, which means that for an appId and an environment, there can be different configurations for different clusters.
The following ways of clustering are supported since version 1.0.0, in descending order of priority.
- Via Java System Property
apollo.cluster- can be specified via Java's System Property
apollo.cluster - Can be specified in the Java program startup script with
-Dapollo.cluster=SomeCluster- If you are running a jar file, you need to note that the format is
java -Dapollo.cluster=SomeCluster -jar xxx.jar
- If you are running a jar file, you need to note that the format is
- You can also specify it programmatically, e.g.
System.setProperty("apollo.cluster", "SomeCluster");
- can be specified via Java's System Property
- Through the Spring Boot configuration file
- You can specify
apollo.cluster=SomeClusterinapplication.propertiesorbootstrap.propertiesof Spring Boot
- You can specify
- Via Java System Property
- You can specify the environment via Java's System Property
idc. - In the Java program startup script, you can specify
-Didc=xxx- If you are running a jar file, you should note that the format is
java -Didc=xxx -jar xxx.jar
- If you are running a jar file, you should note that the format is
- Note that the key is all lowercase
- You can specify the environment via Java's System Property
- Through the operating system's System Environment
- Can also be specified by the operating system's System Environment `IDC
- Note that the key is all uppercase
- Through the
server.propertiesconfiguration file- You can specify
idc=xxxin theserver.propertiesconfiguration file - For Mac/Linux, the default file location is
/opt/settings/server.properties. - For Windows, the default file location is
C:\opt\settings\server.properties
- You can specify
Cluster Precedence (cluster order)
If
apollo.clusterandidcare both specified.- It will first try to load the configuration from the cluster specified by
apollo.cluster - If nothing is found, we try to load the configuration from the cluster specified by
idc. - If nothing is found, we will load from the default cluster (
default)
- It will first try to load the configuration from the cluster specified by
If only
apollo.clusteris specified.- We will first try to load the configuration from the cluster specified by
apollo.cluster - If not found, it will be loaded from the default cluster (
default)
- We will first try to load the configuration from the cluster specified by
If only
idcis specified.- We will first try to load the configuration from the cluster specified by
idc - If not found, it will be loaded from the default cluster (
default)
- We will first try to load the configuration from the cluster specified by
If neither
apollo.clusternoridcis specified.- It will load the configuration from the default cluster (
default)
- It will load the configuration from the default cluster (
1.2.4.3 Set whether the in-memory configuration items remain in the same order as they are on the page
For versions 1.6.0 and above
By default, the in-memory configuration of the apollo client is stored in Properties (Hashtable underneath) and is not intentionally kept in the same order as seen on the page, which has no effect on most scenarios. However, some scenarios will strongly rely on the order of configuration items (such as the routing rules of spring cloud zuul), for this case, you can turn on the OrderedProperties feature to make the in-memory configuration order consistent with what you see on the page.
The configuration methods, in descending order of priority, are
- Via the Java System Property `apollo.properties.order.enable
- Can be specified via Java's System Property
apollo.property.order.enable - You can specify
-Dapollo.property.order.enable=truein the Java program startup script- If you are running a jar file, you need to note that the format is
java -Dapollo.property.order.enable=true -jar xxx.jar
- If you are running a jar file, you need to note that the format is
- You can also specify it programmatically, such as
System.setProperty("apollo.property.order.enable", "true");
- Can be specified via Java's System Property
- Via the Spring Boot configuration file
- You can specify
apollo.properties.order.enable=truein Spring Boot'sapplication.propertiesorbootstrap.properties
- You can specify
- Via the
app.propertiesconfiguration file- You can specify
apollo.properties.order.enable=trueinclasspath:/META-INF/app.properties
- You can specify
1.2.4.4 Configuring access keys
For versions 1.6.0 and above
Apollo has added an access key mechanism since version 1.6.0 so that only authenticated clients can access sensitive configurations. If the application has access keys enabled, the client needs to configure the keys, otherwise the configuration cannot be accessed.
The configuration methods are as follows, in descending order of priority
- Via Java System Property
apollo.access-key.secret(1.9.0+) orapollo.accessskey.secret(before 1.9.0)- Can be specified via Java's System Property
apollo.access-key.secret(1.9.0+) orapollo.accessskey.secret(before 1.9.0) - In the Java application startup script, you can specify
-Dapollo.access-key.secret=1cf998c4e2ad4704b45a98a509d15719(1.9.0+) or-Dapollo.accesskey.secret=1cf998c4e2ad4704b45a98a509d15719(before 1.9.0)- If running a jar file, note that the format is
java -Dapollo.access-key.secret=1cf998c4e2ad4704b45a98a509d15719 -jar xxx.jar(1.9.0+) orjava -Dapollo.accesskey.secret=1cf998c4e2ad4704b45a98a509d15719 -jar xxx.jar(before 1.9.0)
- If running a jar file, note that the format is
- Can also be specified programmatically, such as
System.setProperty("apollo.access-key.secret", "1cf998c4e2ad4704b45a98a509d15719");(1.9.0+) orSystem.setProperty("apollo.accesskey.secret", "1cf998c4e2ad4704b45a98a509d15719");(before 1.9.0)
- Can be specified via Java's System Property
- Via the Spring Boot configuration file
- You can specify
apollo.access-key.secret=1cf998c4e2ad4704b45a98a509d15719inapplication.propertiesorbootstrap.propertiesof Spring Boot (1.9.0 +) orapollo.accesskey.secret=1cf998c4e2ad4704b45a98a509d15719(before 1.9.0)
- You can specify
- Through the operating system's System Environment
- Can also be specified through the OS System Environment
APOLLO_ACCESS_KEY_SECRET(1.9.0+) orAPOLLO_ACCESSKEY_SECRET(before 1.9.0) - Note that the key is all-caps
- Can also be specified through the OS System Environment
- Via
app.propertiesconfiguration file- You can specify
apollo.access-key.secret=1cf998c4e2ad4704b45a98a509d15719(1.9.0+) orapollo.accessskey.secret=1cf998c4e2ad4704b45a98a509d15719(before 1.9.0)
- You can specify
1.2.4.5 Custom server.properties path
for version 1.8.0 and above
The following ways to customize the server.properties path are supported since version 1.8.0, in descending order of priority
- Via the Java System Property
apollo.path.server.properties- Can be specified via the Java System Property
apollo.path.server.properties - You can specify
-Dapollo.path.server.properties=/some-dir/some-file.propertiesin the Java program startup script- If you are running a jar file, you need to note that the format is
java -Dapollo.path.server.properties=/some-dir/some-file.properties -jar xxx.jar
- If you are running a jar file, you need to note that the format is
- Can also be specified programmatically, e.g.
System.setProperty("apollo.path.server.properties", "/some-dir/some-file.properties");
- Can be specified via the Java System Property
- Via the operating system's System Environment
APOLLO_PATH_SERVER_PROPERTIES- can be specified by System Environment
APOLLO_PATH_SERVER_PROPERTIESof the operating system - Note that the key is all-caps and separated by
_.
- can be specified by System Environment
1.2.4.6 Enables `propertyNames` caching, which can significantly improve startup speed in a large number of configuration scenarios
For version 1.9.0 and above
In scenarios where @ConfigurationProperties is used and there are a large number of configuration items, the Spring container can be slow to start. This configuration can be turned on to significantly improve startup speed, and the cache will be automatically cleared when the configuration changes, default is false. See: issue 3800
The configuration methods, in descending order of priority, are
- via Java System Property
apollo.property.names.cache.enable- can be specified via the Java System Property
apollo.property.names.cache.enable - You can specify
-Dapollo.property.names.cache.enable=truein the Java program startup script- If you are running a jar file, note that the format is
java -Dapollo.property.names.cache.enable=true -jar xxx.jar
- If you are running a jar file, note that the format is
- You can also specify it programmatically, such as
System.setProperty("apollo.property.names.cache.enable", "true");
- can be specified via the Java System Property
- via system environment variables
- Configure the environment variable
APOLLO_PROPERTY_NAMES_CACHE_ENABLE=truebefore starting the program to specify - Note that the key is all-caps and separated by
_.
- Configure the environment variable
- via the Spring Boot configuration file
- You can specify
apollo.properties.names.cache.enable=truein Spring Boot'sapplication.propertiesorbootstrap.properties.
- You can specify
- via the
app.propertiesconfiguration file- You can specify
apollo.property.names.cache.enable=trueinclasspath:/META-INF/app.properties
- You can specify
1.2.4.7 Apollo-Label
ApolloLabel is the label information of the application, an important piece of information to get the configuration from the server side for the grayscale rules.
There are several ways to set it, from highest to lowest priority, as follows.
- System Property
Apollo 2.0.0+ supports passing in apollo.label information via System Property, such as
-Dapollo.label=YOUR-APOLLO-LABEL- System Environment of the operating system
Apollo 2.0.0+ supports passing apollo.label information through the operating system's System Environment APP_LABEL, as in
APOLLO_LABEL=YOUR-APOLLO-LABEL- Spring boot
application.properties
Apollo 2.0.0+ supports configuration via Spring Boot's application.properties file, such as
apollo.label=YOUR-APOLLO-LABELThis configuration is not suitable for multiple war packages deployed in the same tomcat scenario
app.properties
Make sure that the classpath:/META-INF/app.properties file exists and that its contents are shaped like.
apollo.label=YOUR-APOLLO-LABEL
The file location reference is as follows.
Note: apollo.label is a label used to identify the application identity in the format string.
1.2.4.8 Enable Apollo Override System Properties
For version 2.1.0 and above
Flag to indicate that Apollo's remote properties should override system properties. Default true.
The configuration methods, in descending order of priority, are
- Via the Java System Property
apollo.override-system-properties- Can be specified via Java's System Property
apollo.override-system-properties - You can specify
-Dapollo.override-system-properties=truein the Java program startup script- If you are running a jar file, you need to note that the format is
java -Dapollo.override-system-properties=true -jar xxx.jar
- If you are running a jar file, you need to note that the format is
- You can also specify it programmatically, such as
System.setProperty("apollo.override-system-properties", "true");
- Can be specified via Java's System Property
- Via the Spring Boot configuration file
- You can specify
apollo.override-system-properties=truein Spring Boot'sapplication.propertiesorbootstrap.properties
- You can specify
- Via the
app.propertiesconfiguration file- You can specify
apollo.override-system-properties=trueinclasspath:/META-INF/app.properties
- You can specify
1.2.4.9 Enable Client Monitoring
For version 2.4.0 and above
After enabling the following configurations, you can use ConfigService.getConfigMonitor() to retrieve client monitoring information and enable automatic reporting.
# 1. Whether to enable the Monitor mechanism, i.e., whether ConfigMonitor is enabled. Default is false.
apollo.client.monitor.enabled = true
# 2. Whether to expose Monitor data by JMX. When enabled, you can view related information through tools like J-console. Default is false.
apollo.client.monitor.jmx.enabled = true
# 3. The maximum number of exception logs that Monitor can store. The default is 25, following the FIFO principle.
apollo.client.monitor.exception-queue-size = 30
# 4. Specify the Exporter type for exporting metric data to the corresponding monitoring system.
# If you introduce apollo-plugin-client-prometheus, set this to "prometheus" to enable it.
# This depends on the SPI implementation of MetricsExporter.
apollo.client.monitor.external.type = prometheus
# 5. Specify the frequency at which the Exporter exports status information from Monitor as metric data.
# The default is once every 10 seconds.
apollo.client.monitor.external.export-period = 201.2.4.10 ConfigMap cache
For version 2.4.0 and above
Starting from version 2.4.0, the availability of the client in the Kubernetes environment has been enhanced. After enabling the ConfigMap cache, the client will cache a copy of the configuration information fetched from the server in the ConfigMap. In the case of service unavailability, network issues, and loss of local cache files, the configuration can still be restored from the ConfigMap. Here are the relevant configurations:
apollo.cache.kubernetes.enableοΌWhether to enable the ConfigMap cache mechanism, the default is false.
apollo.cache.kubernetes.namespaceοΌThe namespace of the ConfigMap to be used (the namespace in Kubernetes), the default value is "default".
The configuration information will be placed in the specified ConfigMap according to the following correspondence:
namespace: Use the specified value, if not specified, the default is "default"
configMapName: apollo-configcache-{appId}
key:{cluster}___{namespace}
value: The content is the JSON format string of the corresponding configuration information.
appId is the application's own appId, such as 100004458.
cluster is the cluster used by the application, which is usually default if not configured locally
namespace Indicates the configuration namespace used by the application. If '_' appears in the namespace, it will be escaped to '__' when the key is concatenated.
Since this feature is extended, so the client-java dependency is set to optional. You need to import the matching version
Since read and write operations on the ConfigMap are required, the pod where the client is located must have the corresponding permissions. The specific configuration method can be referred to below.
How to authorize a Pod's Service Account to have read and write permissions for ConfigMap:
Create a Service Account: If there is no Service Account, you need to create one.
yamlapiVersion: v1 kind: ServiceAccount metadata: name: my-service-account namespace: defaultCreate a Role or ClusterRole: Define a Role or ClusterRole to grant read and write permissions for a specific ConfigMap. If the ConfigMap is used across multiple Namespaces, a ClusterRole should be used.
yamlapiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: default name: configmap-role rules: - apiGroups: [""] resources: ["configmaps"] verbs: ["get", "list", "watch", "create", "update", "delete"]Bind the Service Account to the Role or ClusterRole: Use RoleBinding or ClusterRoleBinding to bind the Service Account to the Role or ClusterRole created above.
yamlapiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: configmap-reader-binding namespace: default subjects: - kind: ServiceAccount name: my-service-account namespace: default roleRef: kind: Role name: configmap-role apiGroup: rbac.authorization.k8s.ioSpecify the Service Account in the Pod configuration: Ensure that the Pod's configuration uses the Service Account created above.
yamlapiVersion: v1 kind: Pod metadata: name: my-pod namespace: default spec: serviceAccountName: my-service-account containers: - name: my-container image: my-imageApply the configuration: Use the kubectl command-line tool to apply these configurations.
yamlkubectl apply -f service-account.yaml kubectl apply -f role.yaml kubectl apply -f role-binding.yaml kubectl apply -f pod.yamlThese steps give the Service Account in the Pod read and write permissions for the specified ConfigMap.
If the ConfigMap is cross-namespace, use ClusterRole and ClusterRoleBinding instead of Role and RoleBinding, and ensure that these configurations are applied in all Namespaces that need to access the ConfigMap.
II. Maven Dependency
Apollo's client jar package has been uploaded to the central repository, the application only needs to be introduced in the following way when it is actually used.
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.7.0</version>
</dependency>III. Client Usage
Apollo supports API approach and Spring integration approach, how to choose which one to use?
The API approach is flexible, fully functional, configuration values are updated in real time (hot release), and supports all Java environments.
Spring approach is easy to access and has N cool ways to play with Spring, such as
- Placeholder way.
- Direct use in the code, such as:
@Value("${someKeyFromApollo:someDefaultValue}") - Replace the placeholder in the configuration file, e.g.:
spring.datasource.url: ${someKeyFromApollo:someDefaultValue} - Directly hosting spring's configuration, such as directly configuring
spring.datasource.url=jdbc:mysql://localhost:3306/somedb?characterEncoding=utf8in apollo
- Direct use in the code, such as:
- Spring boot's @ConfigurationProperties method
- Versions from v0.10.0 onwards support automatic update of placeholder at runtime, see PR #972 for details. (Versions prior to v0.10.0 do not re-inject after configuration changes and require a restart to update. If you need real-time updates of configuration values, you can refer to the subsequent description in 3.2.2 Use of Spring Placeholder
- Placeholder way.
The Spring approach can also be used in combination with the API approach, such as injecting Apollo's Config object, you can get the configuration as usual through the API approach:
java@ApolloConfig private Config config; //inject config for namespace applicationFor more interesting practical usage scenarios and sample code, please refer to apollo-use-cases
3.1 API Usage
The API approach is the easiest and most efficient way to use Apollo configuration without relying on the Spring Framework to use it.
3.1.1 Get the configuration of the default namespace (application)
Config config = ConfigService.getAppConfig(); //config instance is singleton for each namespace and is never null
String someKey = "someKeyFromDefaultNamespace";
String someDefaultValue = "someDefaultValueForTheKey";
String value = config.getProperty(someKey, someDefaultValue);With the above config.getProperty you can get the real-time latest configuration value corresponding to someKey.
In addition, the configuration values are fetched from memory, so there is no need for the application to do its own caching.
3.1.2 Listening for configuration change events
Listening for configuration change events is only used when the application really cares about configuration changes and needs to be notified when the configuration changes, e.g. when the database connection string changes and the connection needs to be rebuilt, etc.
If you just want to fetch the latest configuration every time, just follow the example above and call config.getProperty.
Config config = ConfigService.getAppConfig(); //config instance is singleton for each namespace and is never null
config.addChangeListener(new ConfigChangeListener() {
@Override
public void onChange(ConfigChangeEvent changeEvent) {
System.out.println("Changes for namespace " + changeEvent.getNamespace());
for (String key : changeEvent.changedKeys()) {
ConfigChange change = changeEvent.getChange(key);
System.out.println(String.format("Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s", change.getPropertyName(), change. getOldValue(), change.getNewValue(), change.getChangeType()));
}
}
});3.1.3 Get the configuration of the public Namespace
String somePublicNamespace = "CAT";
Config config = ConfigService.getConfig(somePublicNamespace); //config instance is singleton for each namespace and is never null
String someKey = "someKeyFromPublicNamespace";
String someDefaultValue = "someDefaultValueForTheKey";
String value = config.getProperty(someKey, someDefaultValue);3.1.4 Get the configuration of a non-properties format namespace
3.1.4.1 Namespace in yaml/yml format
Apollo-Client version 1.3.0 starts to make better support for yaml/yml, which is used in the same way as properties format.
Config config = ConfigService.getConfig("application.yml");
String someKey = "someKeyFromYmlNamespace";
String someDefaultValue = "someDefaultValueForTheKey";
String value = config.getProperty(someKey, someDefaultValue);3.1.4.2 Namespace in non-yaml/yml format
To get it, you need to use the ConfigService.getConfigFile interface and specify the Format, such as ConfigFileFormat.XML.
String someNamespace = "test";
ConfigFile configFile = ConfigService.getConfigFile("test", ConfigFileFormat.XML);
String content = configFile.getContent();3.1.5 Read the configuration corresponding to multiple appid and their namespaces.(added in version 2.4.0)
Specify the corresponding appid and namespace to retrieve the config, and then obtain the properties.
String someAppId = "Animal";
String somePublicNamespace = "CAT";
Config config = ConfigService.getConfig(someAppId, somePublicNamespace);
String someKey = "someKeyFromPublicNamespace";
String someDefaultValue = "someDefaultValueForTheKey";
String value = config.getProperty(someKey, someDefaultValue);3.1.6 Retrieve Client Monitoring Metrics
For version 2.4.0 and above
Apollo Client significantly enhanced observability since version 2.4.0, providing the ConfigMonitor API as well as metric export options via JMX and Prometheus. For configuration details, see 1.2.4.9 Enable Client Monitoring.
3.1.6.1 Retrieve Monitoring Data via ConfigMonitor
ConfigMonitor configMonitor = ConfigService.getConfigMonitor();
// Error-related monitoring API
ApolloClientExceptionMonitorApi exceptionMonitorApi = configMonitor.getExceptionMonitorApi();
List<Exception> apolloConfigExceptionList = exceptionMonitorApi.getApolloConfigExceptionList();
// Namespace-related monitoring API
ApolloClientNamespaceMonitorApi namespaceMonitorApi = configMonitor.getNamespaceMonitorApi();
List<String> namespace404 = namespaceMonitorApi.getNotFoundNamespaces();
// Bootstrap parameter-related monitoring API
ApolloClientBootstrapArgsMonitorApi runningParamsMonitorApi = configMonitor.getBootstrapArgsMonitorApi();
String bootstrapNamespaces = runningParamsMonitorApi.getBootstrapNamespaces();
// Thread pool-related monitoring API
ApolloClientThreadPoolMonitorApi threadPoolMonitorApi = configMonitor.getThreadPoolMonitorApi();
ApolloThreadPoolInfo remoteConfigRepositoryThreadPoolInfo = threadPoolMonitorApi.getRemoteConfigRepositoryThreadPoolInfo();3.1.6.2 Expose Status Information via JMX
Enable the relevant configuration:
apollo.client.monitor.enabled = true
apollo.client.monitor.jmx.enabled = trueAfter starting the application, use J-console or similar tools to view the metrics. Below is an example using J-console:
3.1.6.3 Client Export Metrics to External Monitoring Systems
Users can customize the integration with monitoring systems such as Prometheus as needed. The client provides an SPI, see 7.3 Exporting Metrics to Custom Monitoring Systems. for details.
Related Metrics Data Tables
Namespace Metrics
Metric corresponding API: ApolloClientNamespaceMonitorApi
| Metric Name | Tag | Corresponding Monitor-API |
|---|---|---|
| apollo_client_namespace_usage_total | namespace | namespaceMetrics.getUsageCount() |
| apollo_client_namespace_item_num | namespace | namespaceMetrics.getFirstLoadTimeSpendInMs() |
| apollo_client_namespace_not_found | namespaceMonitorApi.getNotFoundNamespaces() | |
| apollo_client_namespace_timeout | namespaceMonitorApi.getTimeoutNamespaces() | |
| apollo_client_namespace_first_load_time_spend_in_ms | namespace | namespaceMetrics.getLatestUpdateTime |
Thread Pool Metrics
Metric corresponding API: ApolloClientThreadPoolMonitorApi
| Metric Name | Tag | Corresponding Monitor-API |
|---|---|---|
| apollo_client_thread_pool_pool_size | thread_pool_name | threadPoolInfo.getPoolSize() |
| apollo_client_thread_pool_maximum_pool_size | thread_pool_name | threadPoolInfo.getMaximumPoolSize() |
| apollo_client_thread_pool_largest_pool_size | thread_pool_name | threadPoolInfo.getLargestPoolSize() |
| apollo_client_thread_pool_completed_task_count | thread_pool_name | threadPoolInfo.getCompletedTaskCount() |
| apollo_client_thread_pool_queue_remaining_capacity | thread_pool_name | threadPoolInfo.getQueueRemainingCapacity() |
| apollo_client_thread_pool_total_task_count | thread_pool_name | threadPoolInfo.getTotalTaskCount() |
| apollo_client_thread_pool_active_task_count | thread_pool_name | threadPoolInfo.getActiveTaskCount() |
| apollo_client_thread_pool_core_pool_size | thread_pool_name | threadPoolInfo.getCorePoolSize() |
| apollo_client_thread_pool_queue_size | thread_pool_name | threadPoolInfo.getQueueSize() |
Exception Metrics
Metric corresponding API: ApolloClientExceptionMonitorApi
| Metric Name | Tag |
|---|---|
| apollo_client_exception_num_total | exceptionMonitorApi.getExceptionCountFromStartup() |
3.2 Spring integration approach
3.2.1 Configuration
Apollo also supports integration with Spring (Spring 3.1.1+), and only requires some simple configuration.
Apollo currently supports both the more traditional XML-based configuration and the currently more popular Java-based (recommended) configuration.
In case of Spring Boot environments, it is recommended to refer to 3.2.1.3 Spring Boot integration methods (recommended) for configuration.
Note that if you have previously used org.springframework.beans.factory.config.PropertyPlaceholderConfigurer, please replace it with org.springframework.context.support.PropertySourcesPlaceholderConfigurer. It is not recommended to use PropertyPlaceholderConfigurer after Spring 3.1, use PropertySourcesPlaceholderConfigurer instead.
If you have used <context:property-placeholder> before, please note that the spring-context.xsd version introduced in the xml needs to be 3.1 or higher (usually it will be upgraded automatically as long as no version is specified), and it is recommended to introduce it without the version number, e.g.: http://www.springframework.org/schema/context/spring-context.xsd
Note 1: namespace in yaml/yml format supports integration with Spring since version 1.3.0, when injecting you need to fill in the full name with a suffix, such as application.yml
Note 2: Non-properties, non-yaml/yml formatted namespace (e.g. xml, json, etc.) do not support integration with Spring at this time.
3.2.1.1 XML-based configuration
Note: You need to add apollo related xml namespace to the configuration file header, otherwise it will report xml syntax errors.
- Inject the default namespace configuration into Spring
<?xml version="1.0" encoding="UTF-8"?>
<! -- This is the simplest form of configuration, which is generally sufficient for applications, and is used to instruct Apollo to inject the configuration of the application namespace into the Spring environment -->
<apollo:config/>- Inject multiple namespace configuration into Spring
<?xml version="1.0" encoding="UTF-8"?>
<! -- This is the simplest form of configuration, which is generally sufficient for applications, and is used to instruct Apollo to inject the configuration of the application namespace into the Spring environment -->
<apollo:config/>
<! -- This is a slightly more complex form of configuration that instructs Apollo to inject the configuration of FX.apollo and application.yml namespace into the Spring environment -->
<apollo:config namespaces="FX.apollo,application.yml"/>- Inject multiple namespaces and specify the order
If multiple property sources have the same key, then the configuration with the highest order will take effect.
If apollo:config does not specify an order, then the default is the lowest priority.
<?xml version="1.0" encoding="UTF-8"?>
<apollo:config order="2"/>
<! -- This is the most complex form of configuration, instructing Apollo to inject the configuration of FX.apollo and application.yml namespace into the Spring environment, and in order before application -->
<apollo:config namespaces="FX.apollo,application.yml" order="1"/>3.2.1.2 Java-based configuration (recommended)
Java-based configuration is currently the more popular approach as opposed to XML-based configuration.
Note that @EnableApolloConfig should be used together with @Configuration, otherwise it will not take effect.
- Inject the default namespace configuration into Spring
// This is the simplest form of configuration and is generally used by applications to instruct Apollo to inject the configuration of application namespace into the Spring environment
@Configuration
@EnableApolloConfig
public class AppConfig {
@Bean
public TestJavaConfigBean javaConfigBean() {
return new TestJavaConfigBean();
}
}- Inject multiple namespace configuration into Spring
@Configuration
@EnableApolloConfig
public class SomeAppConfig {
@Bean
public TestJavaConfigBean javaConfigBean() {
return new TestJavaConfigBean();
}
}
// This is a slightly more complex form of configuration, instructing Apollo to inject the configuration of FX.apollo and application.yml namespace into the Spring environment
@Configuration
@EnableApolloConfig({"FX.apollo", "application.yml"})
public class AnotherAppConfig {}- Inject multiple namespaces and specify the order
// This is the most complex form of configuration, instructing Apollo to inject the configuration of FX.apollo and application.yml namespace into the Spring environment, and in the order before application
@Configuration
@EnableApolloConfig(order = 2)
public class SomeAppConfig {
@Bean
public TestJavaConfigBean javaConfigBean() {
return new TestJavaConfigBean();
}
}
@Configuration
@EnableApolloConfig(value = {"FX.apollo", "application.yml"}, order = 1)
public class AnotherAppConfig {}4.Support for multiple appid (added in version 2.4.0)
// Added support for loading multiple appid their corresponding namespaces.
// Note that when using multiple appid, if there are keys that are the same,
// only the key from the prioritized loaded appid will be retrieved
@Configuration
@EnableApolloConfig(value = {"FX.apollo", "application.yml"},
multipleConfigs = {@MultipleConfig(appid = "ORDER_SERVICE", namespaces = {"ORDER.apollo"})}
)
public class SomeAppConfig {}3.2.1.3 Spring Boot integration methods (recommended)
Spring Boot supports the above two integration methods in addition to configuration via application.properties/bootstrap.properties, which enables configuration to be injected at an earlier stage, such as scenarios that use @ConditionalOnProperty or have some spring-boot-starter needs to read the configuration to do something in the startup phase (e.g. dubbo-spring-boot-project). So for Spring Boot environment it is recommended to access Apollo (requires version 0.10.0 and above) by the following way.
It is very simple to use, you just need to configure it in application.properties/bootstrap.properties according to the following sample.
- Example configuration with default
applicationnamespace injected
# will inject 'application' namespace in bootstrap phase
apollo.bootstrap.enabled = true- Example configuration for injecting non-default
applicationnamespace or multiple namespaces
apollo.bootstrap.enabled = true
# will inject 'application', 'FX.apollo' and 'application.yml' namespaces in bootstrap phase
apollo.bootstrap.namespaces = application,FX.apollo,application.yml- Load Apollo configuration before initializing the logging system (1.2.0+)
Starting with version 1.2.0, if you wish to put logging-related configuration (such as logging.level.root=info or parameters in logback-spring.xml) in Apollo management as well, then you can additionally configure apollo.bootstrap.eagerLoad. enabled=true to put Apollo loading order before logging system loading, for more information you can refer to PR 1614. The reference configuration example is as follows.
# will inject 'application' namespace in bootstrap phase
apollo.bootstrap.enabled = true
# put apollo initialization before logging system initialization
apollo.bootstrap.eagerLoad.enabled = true3.2.1.4 Spring Boot Config Data Loader (Spring Boot 2.4+, Apollo Client 1.9.0+ recommended)
For Spring Boot 2.4+ versions there is also support for loading configurations via Config Data Loader mode
3.2.1.4.1 Adding maven dependencies
apollo-client-config-data already depends on apollo-client, so you only need to add this one dependency, not the apollo-client dependency
<dependencies>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client-config-data</artifactId>
<version>1.9.0</version>
</dependency
</dependencies>3.2.1.4.2 Configure `app.id`, `env`, `apollo.meta` (or `apollo.config-service`), `apollo.cluster` as described above
3.2.1.4.3 Configure `application.properties` or `application.yml`
Use the default namespace application
# old way
# apollo.bootstrap.enabled=true
# do not configure apollo.bootstrap.namespaces
# new way
spring.config.import=apollo://or
# old way
# apollo.bootstrap.enabled=true
# apollo.bootstrap.namespaces=application
# new way
spring.config.import=apollo://applicationUse custom namespace
# old way
# apollo.bootstrap.enabled=true
# apollo.bootstrap.namespaces=your-namespace
# new way
spring.config.import=apollo://your-namespaceUsing multiple namespaces
Note: spring.config.import loads the configuration from back to front, while apollo.bootstrap.namespaces loads it from back to front, just the opposite. To ensure consistency with the original logic, reverse the order of namespaces
# old way
# apollo.bootstrap.enabled=true
# apollo.bootstrap.namespaces=namespace1,namespace2,namespace3
# new way
spring.config.import=apollo://namespace3, apollo://namespace2, apollo://namespace13.2.1.5 Spring Boot Config Data Loader (Spring Boot 2.4+, Apollo Client 1.9.0+ recommended) + webClient extension
For Spring Boot version 2.4 and above, it also supports loading configuration through Config Data Loader mode
Apollo's Config Data Loader also provides a webClient-based http client to replace the original http client, so as to easily extend the http client
3.2.1.5.1 Add maven dependency
WebClient can be based on multiple implementations (reactor netty httpclient, jetty reactive httpclient, apache httpclient5), the dependencies to be added are as follows
Reactor netty httpclient
<dependencies>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client-config-data</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty-http</artifactId>
</dependency>
</dependencies>Jetty reactive httpclient
<dependencies>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client-config-data</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-reactive-httpclient</artifactId>
</dependency>
</dependencies>Apache httpclient5
Spring boot does not specify the version of apache httpclient5, so you need to manually specify the version here
<dependencies>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client-config-data</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.core5</groupId>
<artifactId>httpcore5-reactive</artifactId>
<version>5.1</version>
</dependency>
</dependencies>3.2.1.5.2 Configure `app.id`, `env`, `apollo.meta` (or `apollo.config-service`), `apollo.cluster` as described above
3.2.1.5.3 Configuring `application.properties` or `application.yml`
The default namespace is used here as an example. Please refer to 3.2.1.4.3 for the configuration of namespace.
spring.config.import=apollo://application
apollo.client.extension.enabled=true3.2.1.5.4 Provide implementation of spi
Provides a spi implementation of interface com.ctrip.framework.apollo.config.data.extension.webclient.customizer.spi.ApolloClientWebClientCustomizerFactory
After configuring apollo.client.extension.enabled=true, Apollo's Config Data Loader will try to load the spi's implementation class to customize the webClient
3.2.2 Use of Spring Placeholder
Spring applications usually use Placeholder to inject configuration in the form of ${someKey:someDefaultValue}, such as ${timeout:100}. The key before the colon is the key, and the default value after the colon.
It is recommended to give the default value as much as possible in actual use, so as to avoid runtime errors due to the undefined key.
Versions starting from v0.10.0 support automatic update of placeholders at runtime, see PR #972.
If you need to turn off the automatic update function of placeholder at runtime, you can turn it off in the following two ways:
By setting the System Property
apollo.autoUpdateInjectedSpringProperties, such as passing in-Dapollo.autoUpdateInjectedSpringProperties=falseat startupBy setting the
apollo.autoUpdateInjectedSpringPropertiesproperty in META-INF/app.properties, such as
app.id=SampleApp
apollo.autoUpdateInjectedSpringProperties=false3.2.2.1 XML usage
Suppose I have a TestXmlBean with two configuration items that need to be injected:
public class TestXmlBean {
private int timeout;
private int batch;
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public void setBatch(int batch) {
this.batch = batch;
}
public int getTimeout() {
return timeout;
}
public int getBatch() {
return batch;
}
}Then, I will use the following way to define in XML (assuming that the default application namespace of the application has timeout and batch configuration items):
<?xml version="1.0" encoding="UTF-8"?>
<apollo:config/>3.2.2.2 How to use Java Config
Suppose I have a TestJavaConfigBean, which can also be injected using @Value through Java Config:
public class TestJavaConfigBean {
@Value("${timeout:100}")
private int timeout;
private int batch;
@Value("${batch:200}")
public void setBatch(int batch) {
this.batch = batch;
}
public int getTimeout() {
return timeout;
}
public int getBatch() {
return batch;
}
}In the Configuration class, use it in the following way (assuming the default application namespace of the application has timeout and batch configuration items):
@Configuration
@EnableApolloConfig
public class AppConfig {
@Bean
public TestJavaConfigBean javaConfigBean() {
return new TestJavaConfigBean();
}
}3.2.2.3 How to use ConfigurationProperties
Spring Boot provides @ConfigurationProperties to inject configuration into bean objects .
Apollo also supports this method. The following example will inject redis.cache.expireSeconds and redis.cache.commandTimeout into the expireSeconds and commandTimeout fields of SampleRedisConfig respectively.
@ConfigurationProperties(prefix = "redis.cache")
public class SampleRedisConfig {
private int expireSeconds;
private int commandTimeout;
public void setExpireSeconds(int expireSeconds) {
this.expireSeconds = expireSeconds;
}
public void setCommandTimeout(int commandTimeout) {
this.commandTimeout = commandTimeout;
}
}In the Configuration class, use it in the following way (assuming the default application namespace of the application has redis.cache.expireSeconds and redis.cache.commandTimeout configuration items):
@Configuration
@EnableApolloConfig
public class AppConfig {
@Bean
public SampleRedisConfig sampleRedisConfig() {
return new SampleRedisConfig();
}
}It should be noted that if @ConfigurationProperties needs to automatically update the injected value when the Apollo configuration changes, you need to use EnvironmentChangeEvent or RefreshScope. For related code implementation, please refer to ZuulPropertiesRefresher.java and SampleRedisConfig.java and SpringBootApolloRefreshConfig.java
3.2.3 Spring Annotation Support
Apollo also adds several new Annotations to simplify usage in the Spring environment.
- @ApolloConfig
- Used to automatically inject the Config object
- @ApolloConfigChangeListener
- Used to automatically register ConfigChangeListener
- @ApolloJsonValue
- Used to automatically inject the configured json string as an object
Example of usage is as follows:
/* Detailed source-code truncated for AI context efficiency. */Use it in the Configuration class as follows:
@Configuration
@EnableApolloConfig
public class AppConfig {
@Bean
public TestApolloAnnotationBean testApolloAnnotationBean() {
return new TestApolloAnnotationBean();
}
}3.2.4 Existing configuration migration
In many cases, the application may already have a lot of configuration, such as Spring Boot application, there will be configurations such as bootstrap.properties/yml, application.properties/yml, etc.
After the application is connected to Apollo, these configurations can be easily migrated to Apollo. The specific steps are as follows:
- Create a new project for the application in Apollo
- Configure
META-INF/app.propertiesin the application - It is recommended to convert the original configuration to the properties format, and then paste it into the application namespace of the application through the text editing mode provided by Apollo, and publish the configuration
- If the original format is yml, you can use YamlPropertiesFactoryBean.getObject into properties format
- If the original is yml and you want to continue to use yml to edit the configuration, you can create a private application.yml namespace, paste all the original configuration into it, and publish the configuration
- Requires
apollo-clientto be version1.3.0and above
- Requires
- Delete the original configuration files such as bootstrap.properties/yml, application.properties/yml from the project
- If you need to keep the local configuration file, it should be noted that some configurations such as
server.portmust ensure that the configuration item has been deleted from the local file
- If you need to keep the local configuration file, it should be noted that some configurations such as
Such as:
spring.application.name=reservation-service
server.port = 8080
logging.level = ERROR
eureka.client.service-url.defaultZone = http://127.0.0.1:8761/eureka/
eureka.client.healthcheck.enabled=true
eureka.client.register-with-eureka = true
eureka.client.fetch-registry = true
eureka.client.eureka-service-url-poll-interval-seconds = 60
eureka.instance.prefer-ip-address = true3.3 Demo
There is a sample client project in the project: apollo-demo, for details, please refer to 2.3 Java Sample Client Start in Apollo Development Guide section.
For more use case demos, please refer to Apollo usage scenarios and sample code.
IV. Client design
The above diagram briefly describes the principle of Apollo client implementation.
- The client and the server maintain a long connection so that it can get the first push of configuration updates. (achieved through Http Long Polling) .
- The client also regularly pulls the latest configuration of the application from the Apollo Configuration Center server.
- This is a fallback mechanism to prevent the configuration from being updated due to the failure of the push mechanism.
- The client will report the local version of the timed pull, so in general, for the timed pull operation, the server will return 304 - Not Modified.
- Timing frequency defaults to pulling every 5 minutes. Clients can also override this by specifying System Property:
apollo.refreshIntervalat runtime, in minutes.
- After the client gets the latest configuration of the application from the Apollo Configuration Center server, it will be saved in memory.
- The client will cache a copy of the configuration obtained from the server in the local file system. In case of service unavailability or network failure, the configuration can still be restored locally.
- The application can get the latest configuration from the Apollo client, subscribe to configuration update notifications.
V. Local Development Mode
Apollo client also supports local development mode, which is mainly used when the development environment cannot connect to Apollo server, such as doing related function development on cruise ships or airplanes.
In local development mode, Apollo will only read configuration information from local files, not from Apollo server.
You can enable Apollo local development mode by following the steps below.
5.1 Modifying the environment
Modify the /opt/settings/server.properties (Mac/Linux) or C:\opt\settings\server.properties (Windows) file to set the env to Local:
env=LocalFor more ways to configure the environment, please refer to 1.2.4.1 Environment
5.2 Preparing local configuration files
In local development mode, Apollo client will read the files from local, so we need to prepare the configuration file beforehand.
5.2.1 Local configuration directory
The local configuration directory is located at.
- Mac/Linux: /opt/data/{appId}/config-cache
- Windows: C:\opt\data\{appId}\config-cache
The appId is the appId of the application, e.g. 100004458.
Please make sure the directory exists and the application has read access to it.
[Tip] The recommended way is to use Apollo in normal mode first, so that Apollo will automatically create the directory and generate the configuration file under it.
5.2.2 Local configuration files
Local configuration files need to be placed in the local configuration directory according to a certain file name format, which is as follows.
{appId}+{cluster}+{namespace}.properties
- AppId is the application's own appId, such as 100004458
- Cluster is the cluster used by the application, generally in local mode without configuration, it is default
- Namespace is the configuration
namespaceused by theapplication, usuallyapplication
The content of the file is stored in properties format, for example, if there are two keys, one is request.timeout and the other is batch, then the content of the file is in the following format.
request.timeout=2000
batch=20005.3 Modifying the configuration
In local development mode, Apollo does not monitor the file content for changes in real time, so if you modify the configuration, you need to restart the application to take effect.
VI. Test mode
The apollo-mockserver has been added since version 1.1.0, so that it can well support scenarios where mock configuration is required for unit testing, using the following methods.
6.1 Introducing pom dependencies
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-mockserver</artifactId>
<version>1.7.0</version>
</dependency>6.2 Placing mock data under test's resources
The file name convention is mockdata-{namespace}.properties
6.3 Writing test classes
For more usage demos, see ApolloMockServerApiTest.java and ApolloMockServerSpringIntegrationTest.java.
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfiguration.class)
public class SpringIntegrationTest {
// startup apollo's mockserver
@ClassRule
public static EmbeddedApollo embeddedApollo = new EmbeddedApollo();
@Test
@DirtiesContext // This annotation is necessary because configuration injection can mess up the application context
public void testPropertyInject(){
assertEquals("value1", testBean.key1);
assertEquals("value2", testBean.key2);
}
@Test
@DirtiesContext
public void testListenerTriggeredByAdd() throws InterruptedException, ExecutionException, TimeoutException {
String otherNamespace = "othernamespace";
embeddedApollo.addOrModifyPropery(otherNamespace,"someKey","someValue");
ConfigChangeEvent changeEvent = testBean.futureData.get(5000, TimeUnit.MILLISECONDS);
assertEquals(otherNamespace, changeEvent.getNamespace());
assertEquals("someValue", changeEvent.getChange("someKey").getNewValue());
}
@EnableApolloConfig("application")
@Configuration
static class TestConfiguration{
@Bean
public TestBean testBean(){
return new TestBean();
}
}
static class TestBean{
@Value("${key1:default}")
String key1;
@Value("${key2:default}")
String key2;
SettableFuture<ConfigChangeEvent> futureData = SettableFuture.create();
@ApolloConfigChangeListener("othernamespace")
private void onChange(ConfigChangeEvent changeEvent) {
futureData.set(changeEvent);
}
}
}β ¦. apollo-client customization
7.1 ConfigService load balancing algorithm
from version 2.1.0
To satisfy users' different demands on ConfigService load balancing algorithm when using apollo-client, we provide spi since version 2.1.0
The interface is com.ctrip.framework.apollo.spi.ConfigServiceLoadBalancerClient.
The Input is multiple ConfigServices returned by meta server, and the output is a ConfigService selected.
The default service provider is com.ctrip.framework.apollo.spi.RandomConfigServiceLoadBalancerClient, which chooses one ConfigService from multiple ConfigServices using random strategy .
7.2 Exporting Metrics to Prometheus
For 2.4.0 and above
Metrics can be exported to Prometheus, or different implementations can be written based on SPI to integrate with various monitoring systems.
Import the client plugin
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-plugin-client-prometheus</artifactId>
<version>2.4.0</version>
</dependency>Adjust the configuration
apollo.client.monitor.enabled=true
apollo.client.monitor.external.type=prometheusYou can obtain the ExporterData via ConfigMonitor (the format depends on the monitoring system you configure, here it supports Prometheus format).
Since Prometheus retrieves metrics via pulling, users need to expose the endpoint by themselves and implement a controller like the one below.
Example code
@RestController
@ResponseBody
public class TestController {
@GetMapping("/metrics")
public String metrics() {
ConfigMonitor configMonitor = ConfigService.getConfigMonitor();
return configMonitor.getExporterData();
}
}After starting the application, let Prometheus listen to the endpoint, and by printing the request logs, you will see information in a format similar to the following.
/* Detailed source-code truncated for AI context efficiency. */At the same time, you can also view the following information on the Prometheus console:
7.3 Exporting Metrics to Custom Monitoring Systems
Applicable to version 2.4.0 and above
Users need to implement a MetricsExporter by extending AbstractApolloClientMetricsExporter and implement the following methods:
- doInit (Initialization method)
- isSupport (Method to check if the external-type configuration is supported)
- registerOrUpdateCounterSample (Method to register or update Counter metrics)
- registerOrUpdateGaugeSample (Method to register or update Gauge metrics)
- response (Method to export the required metric data)
Additionally, you need to configure the corresponding SPI files.
MetricsExporter Loading Flowchart:
sequenceDiagram
participant Factory as DefaultMetricsExporterFactory
participant Exporter as MetricsExporter
participant SPI as SPI Loader
%% Step 1: Factory loads all Exporters using SPI
Factory->>SPI: loadAllOrdered(MetricsExporter)
SPI-->>Factory: List<MetricsExporter>
%% Step 2: Factory checks for supported Exporter
Factory->>Exporter: isSupport(externalSystemType)
Exporter-->>Factory: true / false
alt Exporter Found
%% Step 3: Factory initializes the Exporter
Factory->>Exporter: init(listeners, exportPeriod)
Factory-->>Client: Exporter Instance
else No Exporter Found
%% Step 4: Factory returns null
Factory-->>Client: null
end7.3.1 SkyWalking Example
By configuring:
apollo.client.monitor.enabled=true
# Defined within the exporter
apollo.client.monitor.external.type=skywalkingCreate a SkyWalkingMetricsExporter class, which extends AbstractApolloClientMetricsExporter.
The basic code after inheritance is as follows:
Note: This is just an example, do not use it directly in production. Implement it according to your company's specific situation.
/* Detailed source-code truncated for AI context efficiency. */The doInit method is for users to extend during initialization. It will be called within the init method in AbstractApolloClientMetricsExporter.
@Override
public void init(List<ApolloClientMonitorEventListener> collectors, long collectPeriod) {
// code
doInit();
// code
}Import Micrometer:
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-micrometer-1.10</artifactId>
</dependency>Initialize the SkywalkingMeterRegistry according to Micrometer's mechanism,
and use some maps to store metric data.
private static final String SKYWALKING = "skywalking";
private SkywalkingMeterRegistry registry;
// When designing, users should consider if the data structure for storing metrics consumes too much memory.
private Map<String, Counter> counterMap;
private Map<String, Gauge> gaugeMap;
private Map<String, AtomicReference<Double>> gaugeValues;
@Override
public void doInit() {
registry = new SkywalkingMeterRegistry();
counterMap = new ConcurrentHashMap<>();
gaugeValues = new ConcurrentHashMap<>();
gaugeMap = new ConcurrentHashMap<>();
}The isSupport method will be called when DefaultApolloClientMetricsExporterFactory reads the MetricsExporter via SPI, to check if the correct exporter is enabled when there are multiple SPI implementations.
For example, when configuring and enabling SkyWalking, and you set the apollo.client.monitor.external.type configuration value as skyWalking, the method will be implemented like this:
@Override
public boolean isSupport(String form) {
return SKYWALKING.equals(form);
}The registerOrUpdateCounterSample and registerOrUpdateGaugeSample methods are used to register Counter and Gauge type metrics. You just need to register and update the data as per the parameters passed in.
@Override
public void registerOrUpdateCounterSample(String name, Map<String, String> tags, double incrValue) {
String key = name + tags.toString();
Counter counter = counterMap.get(key);
if (counter == null) {
counter = createCounter(name, tags);
counterMap.put(key, counter);
}
counter.increment(incrValue);
}
private Counter createCounter(String name, Map<String, String> tags) {
return Counter.builder(name)
.tags(tags.entrySet().stream()
.map(entry -> Tag.of(entry.getKey(), entry.getValue()))
.collect(Collectors.toList()))
.register(registry);
}
@Override
public void registerOrUpdateGaugeSample(String name, Map<String, String> tags, double value) {
String key = name + tags.toString();
Gauge gauge = gaugeMap.get(key);
if (gauge == null) {
createGauge(name, tags, value);
} else {
gaugeValues.get(key).set(value);
}
}
public void createGauge(String name, Map<String, String> tags, double value) {
String key = name + tags.toString();
AtomicReference<Double> valueHolder = gaugeValues.computeIfAbsent(key, k -> new AtomicReference<>(value));
gaugeMap.computeIfAbsent(key, k -> Gauge.builder(name, valueHolder::get)
.tags(tags.entrySet().stream()
.map(entry -> Tag.of(entry.getKey(), entry.getValue()))
.collect(Collectors.toList()))
.register(registry));
}The response method is for monitoring systems with pull-based metrics retrieval, like Prometheus. However, since SkyWalking uses a push mode, this method does not need to be implemented. Just configure SkyWalking for your use case.
@Override
public String response() {
// No need to implement in SkyWalking's push mode
return "This method does not need to be implemented in SkyWalking's push mode";
}Finally, in the project directory under resources/META-INF/services,
create the corresponding SPI file to tell the framework to load this class. The file name should be com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter.
your.package.SkyWalkingMetricsExporterAt this point, the client metrics data has been integrated into SkyWalking.
7.3.2 Prometheus Example
PrometheusApolloClientMetricsExporter.java
File: docs/en/client/k8s-configmap-user-guide.md
Apollo K8S ConfigMap Integration
Automatically sync Apollo configurations to K8S ConfigMap.
Project URL: apollo-configmap
File: docs/en/client/nodejs-sdks-user-guide.md
Apollo NodeJS client 1
Project address: node-apollo
Thanks @Quinton for providing support for the NodeJS Apollo client
Apollo NodeJS client 2
Project address: ctrip-apollo
Thanks @kaelzhang for providing support for the NodeJS Apollo client
Apollo NodeJS client 3
Project address: node-apollo-client
Thanks @shinux for providing support for the NodeJS Apollo client
Apollo NodeJS client 4
Project address: ctrip-apollo-client
Thanks @lvgithub for providing support for the NodeJS Apollo client
Apollo NodeJS client 5
Project address: apollo-node
Thanks @lengyuxuan for providing support for the NodeJS Apollo client
Apollo NodeJS client 6
Project address: egg-apollo-client
Thanks @xuezier for providing support for the NodeJS Apollo client
Apollo NodeJS client 7
Project address: apollo-node-client
Thanks @zhangxh1023 for providing support for the NodeJS Apollo client
Apollo NodeJS(WebAssembly) client 8
A client for Apollo that supports both Rust and WASM.
Project address: apollo-rust-client
Thanks to @qqiao for providing support for the NodeJS Apollo client
File: docs/en/client/other-language-client-user-guide.md
At present, Apollo team only provides Java and .Net clients due to manpower constraints. For applications in other languages, you can directly obtain the configuration through the Http interface through the introduction of this article.
Also, if any team/individual is interested, they are welcome to help us to implement the client in other languages, please contact @nobodyiam and @lepdou for details.
Note: There are already clients for Go, Python, NodeJS, PHP, C++ contributed by enthusiastic users, for more information you can refer to "SDK Guide"
1.1 Application access to Apollo
First you need to access your application in Apollo, you can refer to application access document for the specific steps.
1.2 Reading configuration from Apollo via Http interface with cache
This interface will fetch the configuration from the cache and is suitable for more frequent configuration pull requests, such as a simple polling of the configuration every 30 seconds.
Since the cache has a delay of at most one second, if you need to work with configuration push notifications to achieve real-time configuration updates, please refer to 1.3 Reading configuration from Apollo via Http interface without cache.
1.2.1 Http interface description
URL: {config_server_url}/configfiles/json/{appId}/{clusterName}/{namespaceName}?ip={clientIp}
Method: GET
Parameter Description.
| Parameter Name | Required | Parameter Value | Remarks |
|---|---|---|---|
| config_server_url | Yes | The address of the Apollo configuration service | |
| appId | Yes | The appId of the application | |
| clusterName | Yes | clusterName | Normally, just pass in default. If you want to configure by cluster, you can refer to cluster-independent configuration instructions to do the relevant configuration, and then fill in the corresponding cluster name here. |
| namespaceName | is the name of the namespace | If no new namespace has been created, just pass in application. If you have created a Namespace and need to use the configuration of that Namespace, pass the corresponding Namespace name. For other types of namespace, you need to pass the namespace name with a suffix, such as datasources.json | ip |
| ip | no | ip of the machine where the application will be deployed | This parameter is optional and is used to implement grayscale publishing. If you don't want to pass this parameter, please note that the URL from ? Please note that the entire query parameters starting with the ? sign should not appear in the URL. |
1.2.2 Http interface return format
The Http interface returns JSON format, UTF-8 encoding, which contains all the configuration items in the corresponding namespace.
If the namespace is of type properties, the return content sample is as follows:
{
"portal.elastic.document.type": "biz",
"portal.elastic.cluster.name": "hermes-es-fws"
}If the namespace is not of type properties, the return content sample is as follows:
{
"content": "{\"portal.elastic.document.type\":\"biz\",\"portal.elastic.cluster.name\":\"hermes-es-fws\"}"
}You can get the raw configuration content without escaping via
{config_server_url}/configfiles/raw/{appId}/{clusterName}/{namespaceName}?ip={clientIp}.
The configuration in the form of properties can be obtained via
{config_server_url}/configfiles/{appId}/{clusterName}/{namespaceName}?ip={clientIp}
1.2.3 Testing
Since it is an Http interface, after the URL is assembled OK, it can be accessed directly through a browser, or a relevant http interface testing tool.
1.3 Reading configuration from Apollo via Http interface without cache
This interface will get the configuration directly from the database and can be used with configuration push notifications to achieve real-time configuration updates.
1.3.1 Http interface description
URL: {config_server_url}/configs/{appId}/{clusterName}/{namespaceName}?releaseKey={releaseKey}&messages={messages}&label={label}&ip={clientIp}
Method: GET
Parameter Description.
| Parameter Name | Required | Parameter Value | Remarks |
|---|---|---|---|
| config_server_url | Yes | The address of the Apollo configuration service | |
| appId | Yes | The appId of the application | |
| clusterName | Yes | clusterName | Normally, just pass in default. If you want to configure by cluster, you can refer to cluster-independent configuration instructions to do the relevant configuration, and then fill in the corresponding cluster name here. |
| namespaceName | Yes | is the name of the namespace | If no new namespace has been created, just pass in application. If you have created a Namespace and need to use the configuration of that Namespace, pass the corresponding Namespace name. **If the namespace is created and needs to use the configuration of the namespace, pass the namespace name. |
| releaseKey | No | Previous releaseKey | The releaseKey of the last release object can be passed to the server to compare the version, if there is no change in the version, the server will return 304 to save traffic and computing. |
| messages | No | Latest notificationId | To update the memory cache on the server in real-time, if the releaseKey parameter is passed without the messages parameter, there is a chance that the latest configuration will not be obtained in a multi-instance server environment with memory caching enabled. The messages parameter is a JSON string structure {"details":{"key":notificationId}}. The appId, clusterName, and namespaceName need to be concatenated using the + sign to form the key. Assuming appId=app, clusterName=default, namespaceName=test, and notificationId=11, the messages parameter would be {"details":{"app+default+test":11}}. When using the messages parameter, URL encoding is required. |
| label | No | Labels for grayscale configuration | This parameter is optional and is used for label rule matching in grayscale publishing. |
| ip | No | The ip of the machine where the application is deployed | This parameter is optional and is used for ip rule matching in grayscale publishing. |
1.3.2 Http interface return format
This Http interface returns JSON format, UTF-8 encoding.
If the configuration has not changed (the incoming releaseKey and the server-side equal), HttpStatus 304 is returned, and the response body is empty.
If the configuration has changed, HttpStatus 200 is returned, and the response body is the meta information of the corresponding namespace and all configuration items in it.
The return content Sample is as follows.
{
"appId": "100004458",
"cluster": "default",
"namespaceName": "application",
"configurations": {
"portal.elastic.document.type": "biz",
"portal.elastic.cluster.name": "hermes-es-fws"
},
"releaseKey": "20170430092936-dee2d58e74515ff3"
}1.3.3 Testing
Since it is an Http interface, after the URL is assembled OK, it can be accessed directly through a browser, or a relevant http interface testing tool.
1.4 Application-aware configuration updates
Apollo provides push notifications for configuration updates based on Http long polling, and third-party clients can decide whether they need to use this feature depending on their actual needs.
If you are not so sensitive to the configuration update time, you can sense the configuration update by refreshing it at regular intervals, the refresh frequency can be determined by the application itself, and it is recommended to be above 30 seconds.
If you need to be aware of configuration updates in real time (1 second), you can refer to the following document to implement the configuration update push feature.
1.4.1 Configuration update push idea
Here we suggest you to refer to Apollo's Java implementation: RemoteConfigLongPollService.java, which has more than 200 lines of code and is relatively simple in general.
1.4.1.1 Initialization
The first thing we need to do is to determine which namespaces need to be configured for update pushing. Apollo's implementation is to register a namespace when the program gets its configuration for the first time, so we know which namespaces need to be configured for update pushing.
The result of the initialization is a Map of notifications, the content is namespaceName -> notificationId (initial value of -1).
If you find any new namespace that needs to be configured for update pushing during the run, you can directly stuff it into the notification Map.
1.4.1.2 Request Service
Once you have the notifications Map, you can request services. Here we describe the logic of requesting services, please refer to the interface description later for specific URL parameters and descriptions.
- request the remote service, bring your application information and notifications information
- The server checks whether the notificationId is up-to-date for each namespace and corresponding notificationId passed to it.
- if they are the latest, hold the request for 60 seconds, if there is no configuration change within 60 seconds, then return HttpStatus 304. if there is a configuration change within 60 seconds, then return the latest notificationId of the corresponding namespace, HttpStatus 200.
If the notificationId is found to be older than the server, the latest notificationId of the corresponding namespace, HttpStatus 200, will be returned directly. - After the client gets the server side return, determine the return HttpStatus .
- If the returned HttpStatus is 304, that the configuration has not changed, re-execute step 1.
- If the returned HttpStatus is 200, the configuration has changed, for the change of namespace to pull configuration from the server again, see 1.3 Read configuration from Apollo through the Http interface without cache. Also update the notificationId in the notifications map. re-run step 1.
1.4.2 Http interface description
URL: {config_server_url}/notifications/v2?appId={appId}&cluster={clusterName}¬ifications={notifications}
Method: GET
Parameter Description.
| Parameter Name | Required | Parameter Value | Remarks |
|---|---|---|---|
| config_server_url | Yes | The address of the Apollo configuration service | |
| appId | Yes | The appId of the application | |
| clusterName | Yes | clusterName | Normally, just pass in default. If you want to configure by cluster, you can refer to cluster-independent configuration instructions to do the relevant configuration, and then fill in the corresponding cluster name here. |
| notifications | yes | notifications information | pass in the local notifications information, note that here need to be in the form of array to json pass in, such as: [{"namespaceName": "application", "notificationId": 100}, {"namespaceName": "FX.apollo", "notificationId": 200}]. Note that for namespace of properties type, you only need to pass in the namespace name, such as application. for other types of namespace, you need to pass in the namespace name plus the suffix, such as datasources.json |
Note 1: Since the server side will hold the request for 60 seconds, please make sure that the timeout for the client to access the server side is greater than 60 seconds.
Note 2: Don't forget to url encode for the parameters
1.4.3 Http interface return format
The Http interface returns a JSON format, UTF-8 encoding, containing the namespace with changes and the latest notificationId.
The return content Sample is as follows.
[
{
"namespaceName": "application",
"notificationId": 101
}
]1.4.4 Testing
Since it is an Http interface, after the URL is assembled OK, it can be accessed directly through a browser, or a relevant http interface test tool.
1.5 Configuring access keys
Apollo has added an access key mechanism since version 1.6.0, so that only authenticated clients can access sensitive configurations. If the application has access keys enabled, the client needs to add a signature when sending a request, otherwise the configuration cannot be accessed.
Header information to be set.
| Header | Value | Remarks |
|---|---|---|
| Authorization | Apollo ${appId}:${signature} | appId: The appId of the application, signature: Generate a signature by combining the access key with the current timestamp in milliseconds, as well as the path and query components of the visited URL. The specific implementation can be found in Signature.signature |
| Timestamp | Number of milliseconds elapsed from 1970-1-1 00:00:00 UTC+0 to now |
See System.currentTimeMillis |
1.6 Error Code Description
Under normal circumstances, the Http status code returned by the interface is 200, the following lists the non-200 error code descriptions that Apollo will return.
1.6.1 400 - Bad Request
The client needs to check whether the corresponding parameter is correct according to the prompt.
1.6.2 401 - Unauthorized
The client is not authorized, e.g. the server has configured the access key, but the client is not configured or configured incorrectly.
1.6.3 404 - Not Found
The resource to be accessed by the interface does not exist, usually the URL or the parameters of the URL are wrong, or the corresponding namespace has not yet been published for configuration.
1.6.4 405 - Method Not Allowed
The interface access method is incorrect, for example, the interface should use GET to use POST access, etc. The client needs to check whether the interface access method is correct.
1.6.5 500 - Internal Server Error
Other types of errors will return 500 by default. For this type of error, if the application cannot find the cause based on the prompt, you can try to check the server logs to troubleshoot the problem.
File: docs/en/client/php-sdks-user-guide.md
Apollo PHP client 1
Project address: apollo-php-client
Thanks @t04041143 for providing support for the PHP Apollo client
Apollo PHP client 2
Project address: apollo-sdk-config
Project address: apollo-sdk-clientd
Thanks @fengzhibin for providing PHP Apollo client support