默认5s发送一次心跳
。对于超过15s没有收到客户端心跳的实例会将它的healthy属性置为false
(客户端服务发现时不会发现),如果某个实例超过30秒没有收到心跳,直接剔除该实例
(被剔除的实例如果恢复发送心跳则会重新注册)官方文档: https://nacos.io/zh-cn/docs/deployment.html
下载安装包:https://github.com/alibaba/nacos/releases/
解压,进入nacos目录
单机下:不配置Naocs默认使用内存数据库
Mysql数据库:使用conf/nacos-mysql.sql初始化表
application.properties Mysql配置: conf/application.properties
单机模式:
./bin/startup.sh -m standalone
集群模式:
./bin/startup.sh
or ./bin/startup.sh -m cluster
conf/cluster.conf.example
#example
192.168.16.101:8848
192.168.16.102:8848
192.168.16.103:8848
如果是一台集群需要区分nacos.home目录配置 nacos.home=/nacos-cluster/nacos-8847
需要创建目录并在目录下新建/nacos-cluster/nacos-8847/conf/cluster.conf
Nacos2.x版本相比1.X新增了gRPC的通信方式,因此需要增加2个端口
新增端口是在配置的主端口(server.port 8848)基础上,进行一定偏移量自动生成
端口 | 与主端口的偏移量 | 描述 |
---|---|---|
9848 | 1000 | 客户端gRPC请求服务端端口,用于客户端向服务端发起连接和请求 |
9849 | 1001 | 服务端gRPC请求服务端端口,用于服务间同步等 |
如果碰到mysql-connector-java不兼容添加
对应jar包到nacos下plugins/mysql文件夹里面
pom.xml
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
application.yml
spring:
application:
name: open-api-global-quartz
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: 2cd251e2-5fb4-491a-955e-67c43be601f4
group: open-api
config:
server-addr: localhost:8848
file-extension: yaml
group: open-api
更多配置:https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-discovery
测试,通过Open API查询实例列表
open-api 目前还是1.x.x
http://localhost:8848/nacos/v1/ns/instance/list?serviceName=open-api-service-product&groupName=open-api&namespaceId=2cd251e2-5fb4-491a-955e-67c43be601f4
/* Refer to document: https://github.com/alibaba/nacos/blob/master/example/src/main/java/com/alibaba/nacos/example
* pom.xml
com.alibaba.nacos
nacos-client
${latest.version}
*/
package com.alibaba.nacos.example;
import java.util.Properties;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.Event;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
/**
* @author nkorange
*/
public class NamingExample {
public static void main(String[] args) throws NacosException {
Properties properties = new Properties();
properties.setProperty("serverAddr", System.getProperty("serverAddr"));
properties.setProperty("namespace", System.getProperty("namespace"));
NamingService naming = NamingFactory.createNamingService(properties);
naming.registerInstance("open-api-service-product", "11.11.11.11", 8888, "TEST1");
naming.registerInstance("open-api-service-product", "2.2.2.2", 9999, "DEFAULT");
System.out.println(naming.getAllInstances("open-api-service-product"));
naming.deregisterInstance("open-api-service-product", "2.2.2.2", 9999, "DEFAULT");
System.out.println(naming.getAllInstances("open-api-service-product"));
naming.subscribe("open-api-service-product", new EventListener() {
@Override
public void onEvent(Event event) {
System.out.println(((NamingEvent)event).getServiceName());
System.out.println(((NamingEvent)event).getInstances());
}
});
}
}
@Configuration
public class RestConfig {
@Bean
@LoadBalanced //open-api-service-product => ip:port
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@Slf4j
@RestController
@RequestMapping("/demo")
public class RestTemplateController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/product")
public String productIndex() {
log.info("demo product start");
String url = "http://open-api-service-product/check";
String result = restTemplate.getForObject(url, String.class);
log.info("demo product result = " + result);
return result;
}
}
服务-集群-实例 三层模型
在定义上区分临时实例和持久化实例的关键是健康检查的方式
在大中型的公司里往往:
Nacos 1.x 中持久化及非持久化的属性是作为实例的⼀个元数据进行存储和识别。
Nacos 2.x 中继续沿用了持久化及非持久化的设定,但是有了⼀些调整。在 Nacos2.0 中将是否持久化的数据抽象至服务级别, 且不再允许⼀个服务同时存在持久化实例和非持久化实例
,实例的持久化属性继承自服务的持久化属性。
# 持久化实例
spring.cloud.nacos.discovery.ephemeral: false
临时实例变更为持久实例:删除 nacos/data/protocol/raft/naming_persistent_service_v2
org.springframework.cloud.client.serviceregistry.ServiceRegistry
com.alibaba.cloud.nacos.registry.NacosServiceRegistry implements ServiceRegistry
public abstract class AbstractAutoServiceRegistration<R extends Registration>
implements AutoServiceRegistration, ApplicationContextAware, ApplicationListener<WebServerInitializedEvent> {
...
public void onApplicationEvent(WebServerInitializedEvent event) {
bind(event);
}
...
}
public class NacosServiceRegistry implements ServiceRegistry<Registration> {
...
@Override
public void register(Registration registration) {
if (StringUtils.isEmpty(registration.getServiceId())) {
log.warn("No service to register for nacos client...");
return;
}
String serviceId = registration.getServiceId();
String group = nacosDiscoveryProperties.getGroup();
Instance instance = getNacosInstanceFromRegistration(registration);
try {
// Nacos namingService 注册
namingService.registerInstance(serviceId, group, instance);
log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,
instance.getIp(), instance.getPort());
}
catch (Exception e) {
log.error("nacos registry, {} register failed...{},", serviceId,
registration.toString(), e);
// rethrow a RuntimeException if the registration is failed.
// issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132
rethrowRuntimeException(e);
}
}
...
}
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>
spring:
application:
name: stock-service
cloud:
nacos:
config:
server-addr: localhost:8848
cluster-name: Beijing
namespace: dev
file-extension: yaml
shared-configs[0]:
dataId: nacos-share.yaml
refresh: true
extension-configs[0]:
dataId: nacos-ext.yaml
refresh: true
@RestController
@RequestMapping("/nacos")
@RefreshScope
public class NacosConfigController {
@Value("${mxnacos.nacos-ext.name}")
private String nacosExtName;
@Value("${mxnacos.nacos-share.name}")
private String nacosShareName;
@Value("${mxnacos.stock-service.name}")
private String stockServiceName;
@GetMapping("/config")
public String deductStock() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("nacosShareName: " + nacosShareName);
stringBuilder.append(" < ");
stringBuilder.append("nacosExtName: " + nacosExtName);
stringBuilder.append(" < ");
stringBuilder.append("stockServiceName: " + stockServiceName);
return stringBuilder.toString();
}
}
https://github.com/nacos-group/nacos-examples