Nacos源码下载地址:https://github.com/alibaba/nacos/
nacos-server下载地址:https://github.com/alibaba/nacos/releases
本篇文章中的Nacos版本: Nacos 1.4.1
文档: https://nacos.io/docs/v1/what-is-nacos/
中文文档:https://nacos.io/zh-cn/docs/what-is-nacos.html
Nacos简介
全称:Dynamic Naming and Configuration Service
Nacos 是国产的,是阿里开源的
阿里为 SpringCloud 贡献了一个子项目,叫做 SpringCloud Alibaba,其中包括了微服务开发中的几个基础组件,Nacos 就是此项目中的一项技术,可以实现服务注册中心、分布式配置中心。
在服务的注册与发现上,与Eureka和zk的使用差不多
服务注册中心
何为服务发现?
分布式系统中,包含多个独立的服务,服务之间存在需要调用的需求,应该如何调用?
服务调用时必须知道目标服务实例的 IP、端口、API 接口。
其中 API 信息可以通过服务接口文档中获知,但 IP、端口 都是动态的,每次部署服务实例的时候可能都会变。
知道了目标服务实例的地址,就相当于发现了对方。具体怎么发现目标服务?这就是服务发现机制。
如上图,在服务实例数量少的时候,每个服务实例可以自己维护相关服务实例的地址信息,也就是自己维护一个通讯录。
例如通过配置文件来记录,相关服务实例地址发生变更的时候就修改一下,有点麻烦,但还可以忍受。
但是,当服务实例数量变大之后,就无法自己维护了,相关服务数量多、地址变化频繁。
此时必须有一种更优的发现机制,就出现了服务注册中心。
如上图,每个服务实例启动之后,都主动向注册中心登记自己的地址信息,这样注册中心便拥有了所有服务实例的记录,类似于查号台。
当某个服务实例停止运行的时候,主动让注册中心销毁自己的信息。
如果服务实例不是主动停止,而是因为故障等原因死掉的,如何处理?需要注册中心能够主动清理。
注册中心要能够实时知道各个服务实例的状态,通过心跳机制来实现,实例定时向注册中心发送请求,表明自己还活着,如果心跳没了,注册中心就可以对其清理。
一个服务实例在调用另一个服务时,可以根据服务名称从注册中心获取此服务的实例信息列表,从中选取一个实例进行调用。
以上就是注册中心这种服务发现机制的工作方式。
分布式配置中心
分布式配置概念简介
每个服务都会有自己的配置信息,例如 SpringBoot 项目中的配置文件,服务运行时会读取配置文件中的配置项。
一个服务通常会启动多个实例,来提供其可靠性,那么每个实例中就都会包含这个配置文件,一个服务的各个实例中配置都是相同的。
如果要改某个配置项的值,怎么办?
修改配置文件,然后重新部署此服务的所有实例。麻烦低效。
如果把服务的配置信息提出来,不放在自己的配置文件中,而是放到一个第三方的配置中心,服务实例从配置中心读取属于自己的配置,而且,在配置中心里面修改配置项之后,所有相关实例都可以立即拿到最新值,不用重新部署了,这样就方便很多。
所以分布式配置有2大好处:
- 方便维护,集中维护优于分散式维护每个服务的配置文件
- 动态更新,配置修改后直接生效,不用重新部署
此外,Nacos 还可以做配置的版本管理,轻松实现历史版本的回滚。
分布式系统CAP架构
CAP定理是分布式系统中最基础的原则,所以理解和掌握了CAP对系统架构的设计至关重要。分布式架构下所有系统不可能同时满足以下三点:Consisteny(一致性)、Availability(可用性)、Partition tolerance(分区容错性)
CAP指明了任何分布式系统只能同时满足这三项中的两项。分布式系统肯定都要保证其容错性 ,那么可用性和一致性就只能选一个了
几种常见注册中心的区别
注册中心在分布式应用中是经常用到的,也是必不可少的,那注册中心,又分为以下几种:Eureka、Zookeeper、Nacos等。这些注册中心最大的区别就是其基于AP架构还是CP架构,简单介绍一下:
Zookeeper:zk集群下一旦leader节点宕机了,在短时间内服务都不可通讯,因为它们在一定时间内follower进行选举来推出新的leader,因为在这段时间内,所有的服务通信将受到影响,而且leader选取时间比较长,需要花费几十秒甚至上百秒的时间,因此:可以理解为 Zookeeper是实现的CP,也就是将失去A(可用性)。
Eureka:Eureka集群下每个节点之间都会定时发送心跳,定时同步数据,没有master/slave之分,是一个完全去中心化的架构。因此每个注册到Eureka下的实例都会定时同步ip,服务之间的调用也是根据Eureka拿到的缓存服务数据进行调用。若一台Eureka服务宕机,其他Eureka在一定时间内未感知到这台Eureka服务宕机,各个服务之间还是可以正常调用。Eureka的集群中,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。当数据出现不一致时,虽然A, B上的注册信息不完全相同,但每个Eureka节点依然能够正常对外提供服务,这会出现查询服务信息时如果请求A查不到,但请求B就能查到。如此保证了可用性但牺牲了一致性。
Nacos:同时支持CP和AP架构,根据根据服务注册选择临时和永久来决定走AP模式还是CP模式。如果注册Nacos的client节点注册时ephemeral=true,那么Nacos集群对这个client节点的效果就是AP,采用distro协议实现;而注册Nacos的client节点注册时ephemeral=false,那么Nacos集群对这个节点的效果就是CP的,采用raft协议实现。
主流的注册中心支持的功能和区别
Nacos集成案例
Nacos跟docker、spring、springboot的集成案例可以参考 nacos-group :
Windows下Nacos源码调试运行
nacos源码导入要求maven 3.2.5以上版本
# nacos源码下载地址,源码包结构如下:
编译
进入nacos目录,执行编译命令,增加 -Drat.skip=true 参数 ,可以跳过licensing 检查
执行:mvn -Prelease-nacos -Dmaven.test.skip=true -Drat.skip=true clean install -U,编译成功后会在distribution/target目录下生成nacos-server-1.4.1.tar.gz
配置mysql数据库
修改console中的application.properties文件配置,放开mysql,配置为我们自己的mysql数据库。这样服务注册的值就会持久化到数据库,不会服务重启后就消失
application.properties文件位于console\src\main\resources\application.properties
### If use MySQL as datasource:
spring.datasource.platform=mysql
### Count of DB:
db.num=1
### Connect URL of DB:
db.url.0=jdbc:mysql://192.168.30.13:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=username
db.password.0=pwd
执行mysql脚本创建mysql数据库表
mysql脚本位于:distribution/conf/nacos-mysql.sql,执行成功后建表如下:
配置启动参数
单机模式执行需要指定-Dnacos.standalone=true
如果还是启动失败那么尝试-Dnacos.standalone=true -Dnacos.home=D:\code\java_yuanma\nacos-1.4.1
启动console模块下的com.alibaba.nacos.Nacos类
进入console模块,找到启动类 com.alibaba.nacos.Nacos,执行main方法
启动Nacos.java后控制台输出日志如下,显示启动成功:
"C:\Program Files\Java\jdk1.8.0_271\bin\java.exe" -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:64973,suspend=y,server=n -Dnacos.standalone=true ...省略classpath
Connected to the target VM, address: '127.0.0.1:64973', transport: 'socket'
,--.
,--.'|
,--,: : | Nacos
,`--.'`| ' : ,---. Running in stand alone mode, All function modules
| : : | | ' ,'\ .--.--. Port: 8848
: | \ | : ,--.--. ,---. / / | / / ' Pid: 9624
| : ' '; | / \ / \. ; ,. :| : /`./ Console: http://192.168.5.173:8848/nacos/index.html
' ' ;. ;.--. .-. | / / '' | |: :| : ;_
| | | \ | \__\/: . .. ' / ' | .; : \ \ `. https://nacos.io
' : | ; .' ," .--.; |' ; :__| : | `----. \
| | '`--' / / ,. |' | '.'|\ \ / / /`--' /
' : | ; : .' \ : : `----' '--'. /
; |.' | , .-./\ \ / `--'---'
'---' `--`---' `----'
2024-05-08 19:10:45.981 INFO 9624 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler@7316523a' of type [org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2024-05-08 19:10:45.981 INFO 9624 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'methodSecurityMetadataSource' of type [org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2024-05-08 19:10:46.345 INFO 9624 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8848 (http)
2024-05-08 19:10:46.818 INFO 9624 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3576 ms
2024-05-08 19:10:49.250 WARN 9624 --- [ main] c.a.nacos.common.notify.NotifyCenter : There are no [com.alibaba.nacos.config.server.model.event.LocalDataChangeEvent] publishers for this event, please register
2024-05-08 19:10:49.266 WARN 9624 --- [ main] c.a.nacos.common.notify.NotifyCenter : There are no [com.alibaba.nacos.config.server.model.event.LocalDataChangeEvent] publishers for this event, please register
2024-05-08 19:10:49.266 WARN 9624 --- [ main] c.a.nacos.common.notify.NotifyCenter : There are no [com.alibaba.nacos.config.server.model.event.LocalDataChangeEvent] publishers for this event, please register
2024-05-08 19:10:49.266 WARN 9624 --- [ main] c.a.nacos.common.notify.NotifyCenter : There are no [com.alibaba.nacos.config.server.model.event.LocalDataChangeEvent] publishers for this event, please register
2024-05-08 19:10:49.266 WARN 9624 --- [ main] c.a.nacos.common.notify.NotifyCenter : There are no [com.alibaba.nacos.config.server.model.event.LocalDataChangeEvent] publishers for this event, please register
2024-05-08 19:10:49.266 WARN 9624 --- [ main] c.a.nacos.common.notify.NotifyCenter : There are no [com.alibaba.nacos.config.server.model.event.LocalDataChangeEvent] publishers for this event, please register
2024-05-08 19:10:49.754 INFO 9624 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2024-05-08 19:10:49.864 INFO 9624 --- [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page: class path resource [static/index.html]
2024-05-08 19:10:50.225 INFO 9624 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/**'], []
2024-05-08 19:10:50.256 INFO 9624 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@2aa811f9, org.springframework.security.web.context.SecurityContextPersistenceFilter@59c862af, org.springframework.security.web.header.HeaderWriterFilter@45539bd8, org.springframework.security.web.csrf.CsrfFilter@2e4b5da1, org.springframework.security.web.authentication.logout.LogoutFilter@60b553f, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@673a9db4, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@558127d2, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@66abb2fa, org.springframework.security.web.session.SessionManagementFilter@408d945b, org.springframework.security.web.access.ExceptionTranslationFilter@6a0e97fc]
2024-05-08 19:10:50.350 INFO 9624 --- [ main] o.s.s.c.ThreadPoolTaskScheduler : Initializing ExecutorService 'taskScheduler'
2024-05-08 19:10:50.366 INFO 9624 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 2 endpoint(s) beneath base path '/actuator'
2024-05-08 19:10:50.475 INFO 9624 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8848 (http) with context path '/nacos'
2024-05-08 19:10:50.475 INFO 9624 --- [ main] c.a.n.c.l.StartingApplicationListener : Nacos started successfully in stand alone mode. use external storage
2024-05-08 19:10:52.152 INFO 9624 --- [)-192.168.5.173] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2024-05-08 19:10:52.152 INFO 9624 --- [)-192.168.5.173] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
访问后台
访问链接:http://localhost:8848/nacos/
用户名和密码都是:nacos
模拟手动服务注册&发现和配置管理
调用以下命令,同时观察nacos控制台中服务列表和配置列表的变化
服务注册
curl -X POST 'http://192.168.5.173:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080'
服务发现
curl -X GET 'http://192.168.5.173:8848/nacos/v1/ns/instance/list?serviceName=nacos.naming.serviceName'
发布配置
curl -X POST "http://192.168.5.173:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld"
获取配置
curl -X GET "http://192.168.5.173:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"
console模块虽然是负责管理控制台的,但是它本身也依赖了config和naming模块,所以也支持restful风格动态注册config和naming。可以在nacos源码中搜索ConfigController和InstanceController观察服务注册和配置注册的底层实现
Linux下启动Nacos Server
下载Nacos Server包
Nacos Server下载地址:github.com/alibaba/nac…
Nacos-1.4.1下载位置:github.com/alibaba/nac…
单机启动
下载zip或者tar.gz包后上传到linux服务器上解压缩,进入其bin目录后发现有四个脚本:shutdown.cmd shutdown.sh startup.cmd startup.sh,支持:
- linux下单机模式启动:
startup.sh -m standalone - windows下单机模式启动:
startup.cmd -m standalone
当然我们也可以配置conf/application.properties中的mysql,从而达到服务持久化的功能,具体配置可以参考上面的Windows下Nacos源码调试运行
访问后台
Nacos Server的后台访问地址:http://ip:8848/nacos ,默认账号和密码为:nacos
Nacos三种部署模式
- 单机模式:用于测试和单机试用。见上面的
Linux下启动Nacos Server - 集群模式:用于生产环境,确保高可用。请参考集群模式下运行Nacos
- 多集群模式:用于多数据中心场景。
Nacos架构
nacos架构图如下: