基本使用
一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。是Spring Cloud
Alibaba组件之一,负责服务注册发现和服务配置,可以理解为nacos=eureka+config
Nacos安装
开启外部mysql数据库支持
单机模式时nacos默认使用嵌入式数据库实现数据的存储,若想使用外部mysql存储nacos数据,需要进行以下操作
安装mysql数据库,测试使用5.6.5+,mysql8以下
- 新建数据库nacos_config,导入nacos下conf下的nacos_mysql.sl文件
- 修改conf下的application.properties文件,增加支持mysql数据源配置
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=cgroot
启动Nacos
使用命令行
cd bin
startup.cmd -m standalone
或手动双击
网页访问http://localhost:8848/nacos
默认账号密码都是nacos
微服务注册
添加依赖
<!--nacos客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
主类开启注册
service-product
@SpringBootApplication
@EnableDiscoveryClient
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class);
}
}
配置文件添加注册中心地址
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
调用服务(类似eurek)
service-order
@SpringBootApplication
@EntityScan(basePackages = "pre.cg.entity")
@EnableDiscoveryClient
public class OrderApplication {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class);
}
}
@RestController
@Slf4j
public class OrderController {
@Autowired
private OrderService orderService;
@Autowired
private DiscoveryClient discoveryClient;
/*
* @Author CG
* @Description 商品下单
* @CreateTime 2021/12/27 15:05
* @Param [pid]
* @return pre.cg.entity.Order
**/
@GetMapping("/order/prod/{pid}")
public Order order(@PathVariable("pid") Long pid) {
List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
ServiceInstance serviceInstance = instances.get(0);
Product product = restTemplate.getForObject("http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/product/" + pid, Product.class);
log.info("查询{}号商品:{}", pid, JSON.toJSONString(product));
Order order = new Order().setNumber(1).setPid(pid).setUid(1L);
log.info("订单信息{}", order.toString());
orderService.createOrder(order);
return order;
}
}
配置管理
Nacos配置管理模型
在Nacos中它能通过namespace、group、dataId定位一个配置集
- 配置集(dataId)
一个配置文件通常可以看作一个配置集。
- 配置项
配置文件中的配置称为配置项
- 配置组(groupId)
配置组就是对配置进行分组。如果配有填写配置分组,则默认为用 DEFAULT_GROUP。配置分组一般是用于区分项目,如:电商项目,旅游项目等。
- 命名空间(nameSpace)
命名空间对不同的环境配置进行区分,一般会分为:开发环境、测试环境、生产环境
新建配置
可对命名空间下的配置文件进行克隆,导出,导入等操作
获取配置信息
导入依赖
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.1.3</version>
</dependency>
public static void main(String[] args) throws NacosException {
//nacos server 地址
String serverAddr = "127.0.0.1:8848";
//配置文件 命名空间
String namespace = "3250976a-57b1-4363-b7ed-d7ae34a8c5ae";
//配置文件data id
String dataId = "nacos-simple-demo.yaml";
//配置文件 group
String group = "DEFAULT_GROUP";
Properties properties = new Properties();
properties.put("serverAddr", serverAddr);
properties.put("namespace", namespace);
//获取配置
ConfigService configService = NacosFactory.createConfigService(properties);
String config = configService.getConfig(dataId, group, 5000);
System.out.println(config);
}
历史版本
根据data id和group查询配置文件并回滚到特定时间
监听查询
代码添加监听后可监听控制台修改
public static void main(String[] args) throws NacosException, InterruptedException {
//nacos server 地址
String serverAddr = "127.0.0.1:8848";
//配置文件 命名空间
String namespace = "3250976a-57b1-4363-b7ed-d7ae34a8c5ae";
//配置文件data id
String dataId = "nacos-simple-demo.yaml";
//配置文件 group
String group = "DEFAULT_GROUP";
Properties properties = new Properties();
properties.put("serverAddr", serverAddr);
properties.put("namespace", namespace);
//获取配置
ConfigService configService = NacosFactory.createConfigService(properties);
String config = configService.getConfig(dataId, group, 5000);
System.out.println(config);
//添加监听
configService.addListener(dataId, group, new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(String s) {
System.out.println(s);
}
});
while (true) {
Thread.sleep(2000);
}
}
登录管理
nacos登录密码存储在数据库users表中,密码使用BCrypt加密
自定义密码
导入依赖
<!--BCrypt加密-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
获取加密密码,修改数据库属性字段即可
System.out.println(new BCryptPasswordEncoder().encode("cgnacos"));
//$2a$10$cPDINp205quu8xEwF6x0kuxndcT/tubEDKeTbEr5Kib0n.sxGtnLK
关闭登录功能
找到conf下application.properties文件,打开该注销即可
微服务读取配置
导入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
修改配置文件
- 修改配置文件名为:bootstrap.yml 或 bootstrap.properties
- 添加配置
server:
port: 8091
tomcat:
max-threads: 10
spring:
application:
name: service-order
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
namespace: 67a608bb-5aac-4785-a112-1d75ce11927d
group: shop
@Value("${common.conf}")
private String conf;
@GetMapping("/conf")
public String conf() {
return conf;
}
添加配置文件
注:配置文件Data ID(service-order.yaml) 由 bootstrap.yml 中 spring.application.name(service-order) 加上 spring.cloud.nacos.config.file-extension(yaml) 相同
自定义扩展Data Id配置
spring:
application:
name: service-order
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
namespace: 67a608bb-5aac-4785-a112-1d75ce11927d
group: shop
#默认组 DEFAULT_GROUP 不支持配置的动态刷新
ext-config[0]:
data-id: ext-config-common01.yaml
#不是默认组 DEFAULT_GROUP refresh 默认为false 不支持配置的动态刷新
ext-config[1]:
data-id: ext-config-common02.properties
group: GLOBALE_GROUP
#不是默认组 DEFAULT_GROUP 支持配置的动态刷新
ext-config[2]:
data-id: ext-config-common03.properties
group: REFRESH_GROUP
refresh: true
@Autowired
private ApplicationContext applicationContext;
@GetMapping("/conf")
public String conf() {
String property = applicationContext.getEnvironment().getProperty("common.name");
String property02 = applicationContext.getEnvironment().getProperty("common.age");
String property03 = applicationContext.getEnvironment().getProperty("common.sex");
return property+property02+property03;
}
自定义共享Data ID 配置
server:
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
namespace: 67a608bb-5aac-4785-a112-1d75ce11927d
group: shop
#自定义共享Data ID 配置
shared-dataids: ext-config-common01.yaml,ext-config-common02.properties
refreshable-dataids: ext-config-common03.properties
可见,非DEFAULT_GROUP组的配置无法读取,建议使用自定义扩展Data Id配置
配置的优先级
关闭配置
spring:
cloud:
nacos:
config:
enabled: false
配置动态刷新
@RestController
//配置实时更新
@RequestScope
public class PaymentController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/config/info")
public String getConfigInfo() {
return configInfo;
}
}
Nacos集群部署
3个或3个以上Nacos节点才能构成集群
- 安装3个以上Nacos
拷贝3份之前解压好的nacos文件夹中,修改conf下的application.properties
#修改端口
server.port=8848
#指定ip地址
nacos.inetutils.ip-address=127.0.0.1
- 配置集群配置文件
在所有nacos目录的conf目录下,将文件cluster.conf.example修改为cluster.conf,并将每行配置成ip:port
127.0.0.1:8848
127.0.0.1:8849
127.0.0.1:8850
- 集群模式启动
分别执行nacos目录的bin目录下的startup
startup -m cluster
- 修改配置类
server:
port: 8091
spring:
application:
name: service-order
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848,127.0.0.1:8849,127.0.0.1:8850
ribbon 负载均衡
Ribbon 负载均衡(@LoadBalanced) 默认是轮询策略
service-order
@SpringBootApplication
@EntityScan(basePackages = "pre.cg.entity")
@EnableDiscoveryClient
public class OrderApplication {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class);
}
}
@RestController
@Slf4j
public class OrderController {
@Autowired
private OrderService orderService;
@Autowired
private RestTemplate restTemplate;
/*
* @Author CG
* @Description 商品下单
* @CreateTime 2021/12/27 15:05
* @Param [pid]
* @return pre.cg.entity.Order
**/
@GetMapping("/order/prod/{pid}")
public Order order(@PathVariable("pid") Long pid) {
//直接根据服务id获取服务
Product product = restTemplate.getForObject("http://service-product/product/" + pid, Product.class);
log.info("查询{}号商品:{}", pid, JSON.toJSONString(product));
Order order = new Order().setNumber(1).setPid(pid).setUid(1L);
log.info("订单信息{}", order.toString());
orderService.createOrder(order);
return order;
}
}
修改负载均衡策略
#调用的提供者名称
service-product:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
负载均衡策略
ribbon有7种负载均衡策略可供选择:
1、随机策略——RandomRule
2、轮询策略——RoundRobinRule注:Ribbon默认策略 3、重试策略——RetryRule
4、最低并发策略——BestAvailableRule
5、可用过滤策略——AvailabilityFilteringRule过滤掉那些因为一直连接失败的被标记为circuit
tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值)
性能仅次于最低并发策略。
6、响应时间加权策略——WeightedResponseTimeRule每隔30秒计算一次服务器响应时间,以响应时间作为权重,响应时间越短的服务器被选中的概率越大。
7、区域权衡策略——ZoneAvoidanceRule
Ribbon的负载均衡策略使用建议一般情况下,推荐使用最低并发策略,这个性能比默认的轮询策略高很多。
基于Fegin的的服务调用
导入依赖
<!--fegin-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
开启fegin客户端
@SpringBootApplication
@EntityScan(basePackages = "pre.cg.entity")
@EnableFeignClients(basePackages = {"pre.cg.feign"})
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class);
}
}
编写服务接口
/**
* value 指定调用的微服务
* qualifier 指定引用名,方便调用
*/
@FeignClient(value = "service-product",qualifier = "service-product")
public interface ProductFeignClient {
@GetMapping("/product/{pid}")
@LoadBalanced
Product findByPid(@PathVariable("pid") Long pid);
}
调用服务
@RestController
@Slf4j
public class OrderController {
@Autowired
private OrderService orderService;
@Autowired
@Qualifier(value = "service-product")
private ProductFeignClient productFeignClient;
/*
* @Author CG
* @Description 商品下单
* @CreateTime 2021/12/27 15:05
* @Param [pid]
* @return pre.cg.entity.Order
**/
@GetMapping("/order/prod/{pid}")
public Order order(@PathVariable("pid") Long pid) {
//直接根据服务id获取服务
Product product = productFeignClient.findByPid(pid);
log.info("查询{}号商品:{}", pid, JSON.toJSONString(product));
Order order = new Order().setNumber(1).setPid(pid).setUid(1L);
log.info("订单信息{}", order.toString());
orderService.createOrder(order);
return order;
}
}