1. Background
At present, each team of our company uses different configuration centers. The e-commerce company uses Spring Cloud Config, the payment uses Apollo, and the APP team uses Apollo+Nacos. In order to better cope with the development of the company's business, a unified infrastructure technology stack is essential.
Image source: Live broadcast "How to do a good job in microservice infrastructure selection" – Li Yunhua
In addition, the Spring Cloud Config used by the e-commerce team faces the following technical pain points:
- Modifying the configuration requires restarting the service
- Configuration management is not friendly (modified through gitlab)
- Lack of features such as permission control, format inspection, and security configuration
2. Configuration center selection
Open source product analysis
- Spring Cloud Config
Open source in September 2014, Spring Cloud ecological components can be seamlessly integrated with the Spring Cloud system.
- Apollo
In May 2016, Ctrip open sourced a reliable distributed configuration management center. It can centrally manage the configuration of different environments and different clusters of applications. After the configuration is modified, it can be pushed to the application side in real time, and it has the characteristics of standardized permissions and process governance. It is suitable for microservice configuration management scenarios.
- Nacos
In June 2018, Ali open sourced a dynamic service discovery, configuration management, and service management platform that is easier to build cloud-native applications. It was incubated in Alibaba and grew up in the peak test of Double Eleven in ten years. It has accumulated the core competitiveness of being easy to use, stable and reliable, and excellent performance.
comparison item | Nacos | Apollo | Spring Cloud Config | |
---|---|---|---|---|
Community activity | open source time | 2018.6 | 2016.5 | 2014.9 |
github follow | 20.5k | 26K | 1.7K | |
document | Complete | Complete | Complete | |
performance | Stand-alone read (QPS) | 15000 | 9000 | 7 (due to current limitation) |
Stand-alone write (QPS) | 1800 | 1100 | 5 (due to current limitation) | |
availability | Impact of service shutdown (configuration service) | Started clients do not affect | Started clients do not affect | Started clients do not affect |
deployment mode | cluster | cluster | cluster | |
ease of use | Configuration effective time | real time | real time | Restart to take effect, or manual refresh to take effect |
data consistency | HTTP asynchronous notification | The database simulates the message queue, and Apollo regularly reads the message for one minute to take effect in real time | Git guarantees data consistency, and Config-server reads data from Git | |
configuration interface | support | support | not support | |
Configuration format check | support | support | not support | |
configuration rollback | support | support | Supported (git-based rollback) | |
version management | support | support | Support (git-based version management) | |
Client Supported Languages | Official java Unofficial Go, Python, NodeJS, C++ | Official java .net Unofficial Go, Python, NodeJS, PHP, C++ | ||
client use | nacos client | apollo client | cloud config client | |
safety | authority management | support | Complete data permissions are relatively complete | support (git) |
Authorization/Audit/Review | support | Direct operation on the interface and support separation of modification and publishing permissions | Rely on git permission management | |
data encryption | not support | not support | Encrypt and Decrypt Property Values | |
architectural complexity | Operation and maintenance cost | Nacos+MySQL (simple deployment) | Config+Admin+Portal+MySQL (complex deployment) | Config-server+Git+MQ (complex deployment) |
service dependency | It is the registration and discovery center of Alibaba Cloud. The two functions are separated. | Distributed requires registration center with built-in eureka | Registry required | |
Gray release | Support client configuration and routing rule client computing coupling is high and cumbersome | Supports server-side configuration and routing rules server-side calculation client is transparent and simple | support | |
mail service | not support | support | not support | |
Query configuration monitoring | support | support | support |
- From the perspective of performance: read and write performance Nacos > Apollo > Spring Cloud Config.
- From the perspective of function: function completeness Apollo > Nacos > Spring Cloud Config.
- From the perspective of community activity: it turns out that Spring Cloud’s ecological Netflix basically doesn’t maintain much, because it doesn’t make money; but Spring Alibaba’s microservice ecosystem will always be open source and maintained, because Ali makes money after converting this piece of SaaS.
- Advantages of Nacos: Simple. It integrates the registration center and configuration center functions, and its deployment and operation are more intuitive and simpler than Apollo, so it simplifies the complexity of the architecture and reduces the work of operation and maintenance and deployment.
performance comparison
- Press information
Processor: Intel® Core™ i5-9500 CPU @ 3.00GHz 3.00 GHz
System: windows 10
Internal test: 16G
- Pressure measurement tool: JMeter
- Pressure test strategy: 100 users request thread 10 incrementally open, duration 100s
Scenario 1: Calling the server
The test results are as follows:
Through the pressure test, it is found that the TPS of Nacos read configuration is about 11,000, and the TPS of write configuration is about 1800, while the TPS of Apollo read configuration is about 1100, and the TPS of write configuration is about 310. Nacos has obvious advantages in read and write performance.
Scenario 2: Call the client
The test results are as follows:
It can be seen that the read performance is not much different.
in conclusion
Reason for selection | Reason for not choosing | |
---|---|---|
Nacos | Unified technology stack can solve the pain points of existing technologies Low operation and maintenance costs | |
Apollo | Rely on Eureka | |
Spring Cloud Config |
Reference documents:
3. Quick use
Reference document: https://nacos.io/en-us/docs/quick-start-spring-boot.html
upgrade dependencies
Remove spring-cloud-config dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
Add Nacos dependency:
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-config-spring-boot-starter</artifactId>
<version>0.1.8</version>
</dependency>
Replace Nacos configuration
Replace the config configuration in the original bootstrap.yml file with the nacos configuration.
spring:
application:
name: {
应用名}
cloud: # 移除
config: # 移除
uri: http://config-center.alpha-intra.dbses.com/conf # 移除
label: alpha # 移除
The replacement results are as follows:
spring:
application:
name: {
应用名}
nacos:
config:
server-addr: http://ec-nacos.dbses.com
namespace: alpha
group: {
组名}
Add annotations to the startup class
// dataId 对应服务的配置
@NacosPropertySource(groupId = "${nacos.config.group}", dataId = "${spring.application.name}.yml", first = true)
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
4. Practice
Configure Dynamic Refresh
Method 1: Use @NacosValue
To use this method, you need to add autoRefreshed=true to @NacosPropertySource. The sample code is as follows:
@NacosPropertySource(groupId = "infra", dataId = "zebra-service.yml", first = true, autoRefreshed = true)
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
Nacos is configured as follows:
test1:
config: 2
The interface code is as follows:
@RestController
public class TestController {
@NacosValue(value = "${test1.config}", autoRefreshed = true)
private String config;
@GetMapping("/config")
public String getConfig() {
return config;
}
}
Method 2: Use @NacosConfigurationProperties
The sample code is as follows:
@Configuration
@Data
@NacosConfigurationProperties(prefix = "test2", dataId = "zebra-service.yml", groupId = "infra", autoRefreshed = true)
public class TestConfig {
private List<String> config;
private Map<String, String> map;
@Override
public String toString() {
return "TestConfig{" + "config=" + config + ", map=" + map + '}';
}
}
Nacos is configured as follows:
test2:
config:
- yang
- wang
map:
courier: yang
zebra: wang
The interface code is as follows:
@RestController
public class TestController {
@Autowired
private TestConfig testConfig;
@GetMapping("/config2")
public String getConfig2() {
return testConfig.toString();
}
}
Notice
Refresh the map dynamically, the modified key will be accumulated, and the original key will not be deleted. For example, after changing test2.map.zebra in zebra-service.yml configuration to test2.map.zebr, the obtained results are as follows:
TestConfig{config=[yang, money], map={courier=yang, zebra=money, zebr=money}}
Method 3: Use @NacosConfigListener
Nacos is configured as follows:
test1:
config: 2
The sample code is as follows:
@RestController
public class TestController {
@Value(value = "${test1.config}")
private String config;
@GetMapping("/config")
public String getConfig() {
return config;
}
@NacosConfigListener(dataId = "zebra-service.yml", groupId = "infra")
public void testConfigChange(String newContent) {
YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
yamlFactory.setResources(new ByteArrayResource(newContent.getBytes()));
Properties commonsProperties = yamlFactory.getObject();
this.config = commonsProperties.getProperty("test1.config"));
}
}
Importing multiple configurations
Problem Description
Our project has read many public configurations before, and now we want to read public configurations, what should we do?
problem solved
Multiple configuration files can be added using the @NacosPropertySources annotation.
Sample code:
@NacosPropertySources({
@NacosPropertySource(groupId = "infra", dataId = "captcha-service.yml", first = true),
@NacosPropertySource(groupId = "commons", dataId = "__common_eureka_.yml")
})
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
Here first = true means that the configuration priority of this file is the highest.
local configuration override
Problem Description
As a developer, we may need to start the program locally for debugging, but at this time the locally started program is connected to the configuration of the alpha environment. If you modify the configuration of the alpha environment, it may affect the operation of alpha and other programs.
Faced with this situation, how do we manage the priority of configuration?
Let's take the test1.config configuration as an example. The nacos configuration file is as follows:
The startup configuration is as follows:
The test code is as follows:
@RestController
public class TestController {
@NacosValue(value = "${test1.config}", autoRefreshed = true)
private String config1;
@GetMapping("/config1")
public String getConfig1() {
return config1;
}
}
The execution result is:
The local configuration does not achieve the effect of coverage.
problem analysis
We might as well transform the program startup class first.
It can be seen from the breakpoint that the priority of the application configuration (here refers to zebra-service.yml in nacos, the same below) is before the public configuration, which is necessary.
App config must precede public config.
But the application configuration is also before the system variables (systemProperties) and the system environment (systemEnvironment). So the test1.config we configured did not take effect as local.
With a slight modification:
problem solved
Then test whether the local configuration is overwritten.
The local configuration has reached the effect of coverage. The final startup class code is:
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@PrepareConfigurations({
"__common_database_", "__common_eureka_"})
@NacosPropertySource(groupId = "infra", dataId = "zebra-service.yml", autoRefreshed = true
,after = StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME
)
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
This article is published by OpenWrite, a multi-post platform for blogging !