Java微服务统一配置中心详解
微服务中的统一配置热更新中心
在Java微服务应用中,因为服务器本身是无状态的,所以我们一定会需要用到一个统一的配置中心,这样配置文件热更新主要应用于无需重启服务即可动态调整配置的场景,如修改日志级别、切换数据源等。 比如阿里的diamond , 或者外面的nacos等等。
其原理通常基于监听机制与发布-订阅模式实现。
首先,应用启动时会加载初始配置,并通过特定API或SDK注册到配置中心。当配置发生变化时,配置中心将变化推送给已注册的应用实例。这些实例接收到变更通知后,会触发回调函数重新加载最新的配置信息,从而达到热更新的效果。为保证配置最终一致性,系统设计时需考虑使用版本控制、乐观锁或者分布式锁等机制来避免并发写入导致的数据不一致问题。此外,还可以结合健康检查和自动回滚策略,确保配置更新过程的安全性与稳定性。
Nacos介绍:阿里巴巴开源的微服务统一配置中心
Nacos 是阿里巴巴开源的一个帮助开发者更易于构建云原生应用配置中心平台,它集成了服务发现、配置管理和服务管理等功能。借助 Nacos,用户可以轻松实现微服务架构下的服务自动发现与健康检查,并通过中心化的配置管理支持 Java 应用程序中的配置文件热更新,这极大地简化了配置变更流程,无需重启服务即可生效。此外,Nacos 还提供了动态 DNS 服务和全面的服务及元数据管理能力,有助于流量管理和安全策略实施。这些特性使 Nacos 成为一个强大而灵活的选择,广泛应用于各种规模的企业级解决方案中,特别是在需要快速响应变化且追求高可用性的场景下表现出色。
附主流配置中心的对比表格:
服务端核心功能对比
| 功能 | 子功能点 | Nacos | Apollo | Spring Cloud Config | |
| 发布配置 | 二阶段发布(编辑草稿->发布) | 无 | 有 | 有 | |
| properties key单行变更 | 无 | 有 | 无 | ||
| 格式校验 | 有 | 有 | 无 | ||
| 实时推送 | 有 | 有 | 无 | ||
| 变更历史 | 正式历史 | 有 | 有 | 无 | |
| 灰度历史 | 有 | 有 | 无 | ||
| 变更对比 | 无 | 有 | 无 | nacos只展示变更前的内容 apollo支持单key维度变更前后对比,及全量对比 | |
| 配置对比 | 跨实例对比 | 有 | 有 | 无 | nacos跨实例对比对应apollo的跨环境对比 |
| 跨分组对比 | 有 | 有 | 无 | nacos跨分组对比对应apollo跨集群对比 | |
| 跨dataId对比 | 有 | 无 | 无 | nacos支持任意配置对比, apollo支持appId下的某个namespace跨环境和集群对比 | |
| 单行key级别对比 | 无 | 有 | 有 | ||
| 配置克隆 | 有 | 无 | 无 | ||
| 灰度发布 | 有 | 有 | 无 | nacos 基于IP+标签(多key可扩展) apollo 基于IP+标签(单key) | |
| 监听查询 | 有 | 有 | 无 | apollo中展示ip最新配置查询时间 nacos中展示 | |
| 推送轨迹 | 配置推送轨迹 | 有 | 无 | 无 | apollo在监听查询中展示最新配置获取时间(nacos中可优化),但没有md5 |
| IP推送轨迹 | 有 | 无 | 无 | ||
| 鉴权管理 | 写权限 | 有 | 有 | 有 | apollo对创建配置和发布配置分配不同的权限 |
| 读身份 | 有 | 有 | 有 | ||
| 读权限 | 有 | 无 | 有 | nacos基于ram支持实例,分组,dataId命名空间维度鉴权 apollo支持配置秘钥,只校验身份,无鉴权 | |
| 细粒度鉴权 | 有 | 有 | 有 | nacos基于ram支持实例,分组,dataId命名空间维度鉴权 apollo支持namespace维度 apollo易用性更高 | |
| 运维管理 | 部门管理 | 无 | 有 | 无 | |
| 应用管理 | 无 | 有 | 无 | ||
| 用户管理 | 有 | 有 | 无 | ||
| 加解密 | 有 | 无 | 无 | apollo需要自行加解密 | |
| 导入导出 | 有 | 有 | 无 | ||
| 多实例管理 | 无 | 有 | 无 | 控制台和配置服务分离,支持通过env区分多个配置中心实例 | |
| 运维审计日志 | 创建用户,创建应用,创建配置,修改配置,发布灰度 | 无 | 有 | 无 | apollo在控制台的操作均计入审计 nacos actiontrail上线 |
| 容量保护 | 集群容量,命名空间容量 | 有 | 无 | 无 | |
| 反脆弱 | 查询配置,发布配置限流 | 有 | 无 | 无 | |
| 监控 | 基础监控及业务监控 | 有 | 无 | 无 |
客户端的功能对比:
| 功能 | 子功能 | Nacos | Apollo | Spring Cloud Config |
| 查询配置 | 本地容灾 | 有 | 有 | 无 |
| 本地缓存 | 有 | 有 | 无 | |
| 监听回调 | 配置整体监听 | 有 | 有 | 无 |
| 单行key级别监听 | 有 | 有 | 无 | |
| 注解 | Spring Value注解注入key值 | 有 | 有 | 有 |
| 注解监听回调 | 有 | 有 | 无 | |
| 对象级别变更回调 | 有 | 无 | 无 | |
| 配置注入对象 | 有 | 有 | 无 | |
| 发布配置 | 有 | 无 | 无 | |
| 删除配置 | 有 | 无 | 无 |
使用Nacos订阅配置的示例
基于Nacos订阅配置的样例
我们知道Nacos无论是作为注册中心还是配置中心,其订阅都是独立的。也就是说,当一个服务或配置发生变化时,Nacos会将变更推送到每一个订阅者上。基于这一特性,我们可以编写一个详细的例子来展示如何订阅Nacos上的配置,并在配置更新时作出相应的处理。
1. 准备工作
首先确保你的环境中已经安装并启动了Nacos服务器,并且该服务器能够通过网络访问。此外,需要准备Java开发环境,因为下面的例子使用Java语言实现。
2. 配置文件 config.properties
创建一个名为config.properties的基础配置文件,内容如下:
# Nacos server address
serverAddr=127.0.0.1:8848
# Username and password for authentication (if required)
username=nacos
password=nacos
# Data ID of the configuration to listen to
dataId=config.example
# Group of the configuration
group=DEFAULT_GROUP
这里假设你想要监听的数据标识符为config.example,并且它属于默认组DEFAULT_GROUP。如果启用了鉴权功能,请确保提供的用户名和密码正确无误。
3. Java客户端代码
接下来是主要的Java客户端代码部分,用于连接到Nacos、订阅特定配置,并在收到更新时执行自定义逻辑。
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.NacosFactory;
import java.util.Properties;
import java.util.concurrent.Executor;
public class NacosConfigExample {
public static void main(String[] args) {
Properties properties = new Properties();
try {
// Load config from file
properties.load(NacosConfigExample.class.getClassLoader().getResourceAsStream("config.properties"));
// Create ConfigService
ConfigService configService = NacosFactory.createConfigService(properties);
// Add listener to monitor changes
String dataId = properties.getProperty("dataId");
String group = properties.getProperty("group");
configService.addListener(dataId, group, new Listener() {
@Override
public Executor getExecutor() {
return null; // Use default executor
}
@Override
public void receiveConfigInfo(String configInfo) {
System.out.println("Received updated configuration: " + configInfo);
// Handle the new configuration here
}
});
// Keep the application running
Thread.sleep(Long.MAX_VALUE);
} catch (Exception e) {
e.printStackTrace();
}
}
}
这段代码首先从config.properties中加载Nacos服务器地址及认证信息等设置,然后建立与Nacos服务器之间的连接。之后,通过调用addListener方法添加一个监听器以监视指定dataId和group下的配置变化。每当配置被修改时,receiveConfigInfo方法会被自动调用,你可以在此处加入你需要的业务逻辑来处理新的配置值。
4. 运行示例
- 确保Nacos服务器处于运行状态。
- 将上述代码保存为
NacosConfigExample.java。
- 使用命令
javac -cp nacos-client.jar NacosConfigExample.java编译(假设nacos-client.jar已在类路径下)。
- 最后,运行编译后的程序:
java -cp .:nacos-client.jar NacosConfigExample。
以上步骤完成了一个简单的Nacos配置监听示例。当Nacos服务器上的相应配置项发生变动时,本示例程序能够接收到通知并打印出最新的配置内容。这提供了一种基本但有效的方式来保持应用程序配置的一致性和动态性。
使用Nacos配置更新插件的示例
基于Nacos发布配置的样例,我们将会利用到Nacos提供的配置变更插件功能。这里将详细展示如何创建一个自定义插件以监听配置文件config.properties的更新,并在更新发生时执行特定逻辑(例如发送通知)。请注意,以下步骤假设您已经安装并运行了Nacos服务端2.3.0或更高版本。
1. 创建项目结构
首先,创建一个新的Maven项目,并加入必要的依赖项。需要添加nacos-config-plugin库来开发我们的插件。编辑项目的pom.xml文件如下:
<dependencies>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-config-plugin</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
确保${project.version}被设置为你正在使用的Nacos版本号。
2. 实现ConfigChangePluginService接口
接下来,实现ConfigChangePluginService接口,这个接口允许我们在配置更改前后插入自定义行为。我们将关注于当通过HTTP API发布或更新名为config.properties的配置时触发的行为。
import com.alibaba.nacos.plugin.config.spi.ConfigChangePluginService;
import com.alibaba.nacos.plugin.config.constants.ConfigChangeExecuteTypes;
import com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes;
import com.alibaba.nacos.plugin.config.request.ConfigChangeRequest;
import com.alibaba.nacos.plugin.config.response.ConfigChangeResponse;
public class MyConfigChangePlugin implements ConfigChangePluginService {
@Override
public String getServiceType() {
return "my-plugin"; // 插件唯一标识
}
@Override
public int getOrder() {
return 1; // 执行顺序
}
@Override
public ConfigChangeExecuteTypes executeType() {
return ConfigChangeExecuteTypes.EXECUTE_AFTER_TYPE; // 配置变更后执行
}
@Override
public ConfigChangePointCutTypes[] pointcutMethodNames() {
return new ConfigChangePointCutTypes[]{ConfigChangePointCutTypes.PUBLISH_BY_HTTP}; // 监听HTTP方式发布/更新配置
}
@Override
public void execute(ConfigChangeRequest request, ConfigChangeResponse response) {
if ("config.properties".equals(request.getRequestArgs().get("dataId"))) { // 检查是否为指定的数据ID
System.out.println("Configuration updated: " + request.getRequestArgs());
// 在这里添加您的处理逻辑
}
}
}
3. 配置插件加载
将上述代码编译打包成jar文件。之后,请按照官方文档指导,在Nacos服务器上部署该jar文件。具体来说,把jar放在plugins目录下,并在application.properties中启用你的插件:
nacos.core.config.plugin.my-plugin.enabled=true
然后重启Nacos服务使更改生效。
4. 测试插件
最后一步是验证插件是否按预期工作。使用Nacos控制台或API尝试更新config.properties文件的内容。如果一切正常,你应该能看到命令行输出显示配置已被更新的消息,以及任何你可能添加到execute方法中的额外逻辑。
以上就是基于Nacos发布配置并做相应处理的一个完整示例。此过程展示了如何构建一个简单的插件来监听和响应特定配置的变化。对于更复杂的场景,可以根据实际需求调整插件的具体实现。
Nacos单机版简易部署指南
Nacos server的单机版快速部署
1. 环境准备
在开始部署Nacos单机模式之前,请确保您的系统已安装了以下软件:
- Java 8 或更高版本
- MySQL(可选,如果选择使用外部数据库)
2. 下载Nacos
从Nacos官方GitHub仓库下载最新的稳定版Nacos压缩包。您可以直接访问该链接并选择适合您操作系统的版本进行下载。
3. 解压Nacos
将下载好的Nacos压缩包解压到您希望安装Nacos的目录下,比如/opt/nacos。使用如下命令解压(以Linux为例):
tar -xvf nacos-server-x.x.x.tar.gz -C /opt/
这里的x.x.x是您所下载的具体版本号。
4. 配置Nacos
根据是否需要使用MySQL作为存储引擎来决定配置步骤:
使用内置Derby数据库
如果您打算使用Nacos自带的Derby数据库,则不需要额外配置,直接跳转至启动部分。
使用MySQL数据库
若要使用MySQL数据库作为Nacos的数据存储,请先确保已经安装好符合要求的MySQL实例,并且创建好相应的数据库。接下来修改Nacos配置文件,以便连接到您的MySQL数据库。
- 在Nacos的
conf目录下找到application.properties文件。
- 修改或添加如下配置项,替换
${mysql_host}、${mysql_port}等占位符为实际值:
spring.sql.init.platform=mysql
db.num=1
db.url.0=jdbc:mysql://${mysql_host}:${mysql_port}/${nacos_database}?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=${mysql_user}
db.password=${mysql_password}
5. 启动Nacos服务
完成上述配置后,可以通过执行以下命令来启动Nacos服务器:
cd /opt/nacos/bin
sh startup.sh -m standalone
这将会以单机模式启动Nacos。如果一切正常,您将在控制台看到类似“Nacos started successfully in stand alone mode”的消息。
6. 访问Nacos控制台
打开浏览器并输入http://<Nacos_IP>:8848/nacos进入Nacos管理界面,默认用户名和密码均为nacos。
注意事项
- 当首次运行时,请确认防火墙规则允许通过端口8848访问。
- 如果遇到任何问题,可以检查位于
logs目录下的日志文件获取更多信息。
按照以上步骤,即可顺利完成一个Nacos单机版程序的下载、安装及部署过程。对于更高级的功能配置或者遇到特定错误时的解决方案,建议参考官方文档或社区论坛中的相关讨论。
更多推荐



所有评论(0)