阿里巴巴Nacos简介
1. 引言
在大数据和众多潜在参与方并存的场景下,分布式至关重要。为此,既有简单的解决方案,也有复杂的解决方案。
在本教程中,我们将了解 Alibaba Nacos。首先,我们看看它是什么。接着,我们介绍配置和使用 Nacos 的不同方式。最后,我们演示该平台能实现哪些功能。
2. 什么是 Nacos?
Nacos 是一个提供多种工具的平台:
- 动态服务发现
- 配置管理
- 分布式锁
它主要用于构建高度分布式的系统。
Nacos 的核心是提供服务发现系统,使我们能够动态启停不同服务的实例,同时让其他服务仍然可以访问到它们。这在微服务应用中尤其有价值,因为微服务应用中可能包含大量应用,而每个应用又可能有数量不等的运行实例。
Nacos 还提供管理应用配置的工具,允许在单一位置配置所有内容,并让运行中的实例集群自动反映这些配置。此外,它还提供分布式锁工具,使分布式应用能够无冲突地共享有限资源。
当然,Nacos 还引入了一些用于 AI Agent 的新特性——包括 MCP 服务器、技能、提示词和 AgentCard 发现。但这些不在本文讨论范围之内。
3. 运行 Nacos
快速上手 Nacos 最简单的方式是使用 Docker。
具体来说,我们可以通过一个相当简单的 docker-compose.yml 文件来启动一个单机 Nacos 实例:
NACOS_AUTH_TOKEN 变量必须包含一个至少 32 个字符的字符串,然后进行 base64 编码。而 NACOS_AUTH_IDENTITY_KEY 和 NACOS_AUTH_IDENTITY_VALUE 可以包含任何标识当前 Nacos 实例的值。
现在,我们可以运行该配置:
启动后,我们可以通过 http://localhost:8080 访问控制台。
首次访问时,我们需要为 nacos 用户配置密码: [LOADING...]
现在,让我们登录管理控制台: [LOADING...]
以这种方式运行 Nacos,我们会得到一组默认数据供使用,但我们也可以使用此 UI 来配置自定义环境。
4. 使用 Java SDK 操作 Nacos
现在我们已经启动了 Nacos,便可以在应用中使用它。
为此,我们首先需要将 客户端依赖 添加到项目中。撰写本文时,最新版本是 3.2.1。
如果使用 Maven,可以在 pom.xml 文件中包含此依赖:
为了在应用中使用 Nacos,我们需要知道所操作的 Nacos 服务器的地址、要使用的命名空间(如果不是默认命名空间),以及该服务的其他配置属性:
然后,我们可以为所需的每个 Nacos 服务创建一个客户端:
这些服务客户端即可供我们使用。
5. 配置管理
Nacos 可以在一个中心位置管理配置设置,使服务能够自动使用它们。
5.1. 管理配置
具体来说,我们可以通过管理控制台来管理配置设置:选择侧边栏中的“配置管理”条目即可: [LOADING...]
该部分显示了系统中当前的所有配置条目,并允许我们添加新的条目。
使用顶部的“新建配置”按钮可以添加新条目: [LOADING...]
在此界面中,我们为每个配置元素输入值:
- 数据 ID:配置条目的 ID,通常采用与完全限定类名相同的格式
- 分组:配置条目所属的分组,通常代表该配置对应的产品
- 格式:配置条目的格式,通常是 Text、JSON、XML、YAML、HTML、Properties 或 TOML 之一
- 内容:实际的配置条目,以指定格式书写
此外,我们还可以指定描述、应用和标签。但这些只是条目的元数据,不会影响其使用。
方便的是,我们可以查看配置的历史版本: [LOADING...]
因此,我们可以编辑或删除配置设置,查看条目的详细信息以及所有更改的历史记录。
5.2. 获取配置
配置设置好后,我们需要能够使用它。为此,我们通过之前创建的 ConfigService 来设置配置。
具体来说,最简单的方式可能是直接调用 getConfig() 方法,传入数据 ID、分组以及超时时间(毫秒):
这样,我们就能立即获得该配置设置的值。如果配置不存在或无法连接到 Nacos,则返回 null。
但是,这只能得到原始值。通常我们需要预先知道它的类型,才能知道如何处理。为避免这种情况,我们可以改用 getConfigWithResult() 方法,返回一个更丰富的对象,其中包含配置设置的类型(text、JSON 等),从而知道如何处理它:
这样,即使配置设置不存在或 Nacos 服务器不可达,我们也总能获得结果。在这些情况下,我们会得到一个有效的 ConfigQueryResult 对象,其内容和配置类型均为 null。
5.3. 监听配置变更
除了在某一时刻获取配置值之外,我们还可以注册一个回调,用于在值发生变化时触发。这样,我们就能对配置变更做出响应,而无需手动轮询值。
具体来说,我们可以使用 addListener() 方法为特定的配置设置注册一个监听器:
每当该配置设置发生变化时,此代码块就会运行,并传入新值。但遗憾的是,只有在值发生变化时才会触发,而不会立即执行。
另一种方式是使用 getConfigAndSignListener() 方法,它既能获取当前配置,又能立即注册一个监听器:
这样,我们既能立即获得当前配置使用,又能在配置发生变化时做出响应。从某种意义上说,这相当于将 getConfig() 和 addListener() 合并为一次调用。
6. 服务发现
除配置外,Nacos 还提供分布式服务的服务发现功能。其工作原理是:服务将其地址和端口注册到一个众所周知的名称下,随后客户端可以通过该名称查找这些服务。
6.1. 注册服务
首先,我们使用之前构建的 NamingService 来注册服务。我们使用 registerInstance() 方法,传入服务名称和地址:
或者,我们可以传入一个包含更多服务详细信息的 Instance 类:
需要注意的是,如果这样做,我们必须确保 enabled 和 healthy 标志已设置,因为它们默认为 false,因此服务将无法用于发现。
如果需要更新服务注册信息——例如,更改服务是否健康——我们可以简单地使用新的详细信息重新注册相同的服务名称和地址。Nacos 会检测到这些是相同的详细信息,从而进行更新而不是创建新的注册。
6.2. 注销服务
重要的是,NamingService 客户端在关闭时会自动注销它所注册的所有服务。这意味着我们不需要做任何特殊处理,一旦服务关闭,Nacos 应该会自动移除它。但这还取决于心跳和临时实例等其他因素。
然而,有时我们需要在不关闭整个服务的情况下自行注销。为此,我们可以使用 deregisterInstance() 方法:
该方法接受服务名称以及地址和端口,或者 Instance 类(与 registerInstance() 类似)。有了这些信息,deregisterInstance() 会立即从 Nacos 服务器中移除该地址,从而阻止发现。
6.3. 发现服务实例
服务注册后,我们需要能够发现它们,以便实际利用它们提供的功能。Nacos 提供了多种实现方式。
服务发现中最有用的方法可能是 selectOneHealthyInstance()。该方法接受服务名称,并随机返回一个健康的已注册实例:
如果给定的服务名称没有注册任何实例,代码会抛出 IllegalStateException 以指示该情况,因为这意味着当前没有可用的服务。
或者,selectInstances() 和 getAllInstances() 可以返回所有已注册的实例,而不仅仅是一个:
需要注意的是,selectInstances() 和 selectOneHealthyInstance() 只返回标记为 enabled 且 healthy 标志符合预期的服务。getAllInstances() 则返回所有实例,不论这些标志如何。
6.4. 监听服务发现变更
除了在需要时选择一个实例外,我们还可以注册一个回调,当某个服务名称的实例发生变更时触发:
我们可以利用这些信息做任何想做的事情——例如,维护一个实例的本地缓存,这样就不需要每次查找实例时都调用 Nacos。
7. 分布式锁
Nacos 的另一个重要功能是支持资源的分布式锁。具体来说,Nacos 支持对资源的访问控制,使得不同服务或线程无法同时访问同一资源。
为了获取锁,我们使用之前创建的 LockService,并调用 lock() 方法,提供我们想要获取的锁的定义:
在获取锁时,我们需要提供资源的标识符和锁的最大持续时间(以毫秒为单位)。关键的是,我们会收到一个结果,表明是否成功获取了锁。
锁可以在指定持续时间后自动释放,也可以通过显式调用 unlock() 方法来释放:
与服务注册不同,当客户端断开连接时,锁不会自动移除,因此我们需要确保合理地管理锁。## 8. 总结
在本文中,我们快速了解了阿里巴巴 Nacos,看到了它是什么以及如何在应用程序中使用它。
总而言之,Nacos 是一个通过提供服务发现、集中配置和协调能力来管理分布式系统的平台。
像往常一样,本文中的所有示例都可以在 GitHub 上找到。