关于nacos
相信大多数人一样,在接触微服务的时候知道有Netflix系列和alibaba系列
但是Netflix这一套如今由于部分组件不在开源,又有alibaba这一套的出现,市面上,alibaba系列微服务架构已经是最火热的了,而nacos则是alibaba系列组件充当服务注册发现和配置中心的角色
1.nacos服务注册
1.1来自官方对于服务注册的介绍
服务发现是微服务架构体系中最关键的组件之一。如果尝试着用手动的方式来给每一个客户端来配置所有服务提供者的服务列表是一件非常困难的事,而且也不利于 服务的动态扩缩容。Nacos Discovery Starter 可以帮助您将服务自动注册到 Nacos 服务端并且能够动态感知和刷新某个服务实例的服务列表。除此之外,Nacos Discovery Starter 也将服务实例自身的一些元数据信息-例如 host,port,健康检查URL,主页等-注册到 Nacos 。
说白了,就是将每个服务都在一个固定位置进行登记,并且记录每个服务的地址、名称、健康状态,对服务进行统一管理,以便于整个项目能够更好的运作;
1.2 注册中心对比
显然nacos是支持对多的,尤其是K8s集成。
另外说说什么是CAP特性
首先对于所有的微服务或分布式架构来说,在CAP(C:一致性,A:可用性,P:分区容错性)特性中,只能是选择性的满足其中两个,一般就是CP或AP
C:一致性,在分布式系统中的任意一个节点都会查询到相同的信息(拿到的都是最新的)
A:可用性,服务一直可用,而且是正常响应时间,好的可用性主要是指系统能够很好的为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况。(只要我访问你就给我返回,如果要满足分布式(P),机器之间网络断掉的话,直接和C冲突)
P:分区容错性,当分布式系统中一部分节点崩溃的时候,当前系统仍旧能够正常对外提供服务(多台机器,分布式,不满足P就是单机么)
贴个链接:https://blog.csdn.net/yhquser/article/details/96836897
1.3nacos下载启动
首先要下载nacos包,没有科学上网,可以搜搜资源或者下一下源码用命令压一下
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U
参考:https://blog.csdn.net/qq_41369135/article/details/127870322
下载解压之后,修改单机启动,因为默认是集群模式(后面会有集群的例子)
启动之后就可以访问到了,默认端口8848 http://localhost:8848/nacos
1.4springcloudalibaba微服务框架搭建
首先要做的是明确版本,因为spring cloud alibaba及其组件、spring cloud和spring boot之间是存在强依赖关系的,明确版本就能避免因为版本问题而导致的一系列问题
官方版本依赖说明地址:https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明
此文章中选择
spring cloud alibaba version 2.2.9.RELEASE
spring cloud version Hoxton.SR12
spring boot version 2.3.12.RELEASE
工程结构
父工程依赖,所添加的三个继承依赖中,包含了基本的工程所需依赖,而在spring-cloud-alibaba-dependencies中,维护了当前版本alibaba微服务的组件版本,例如nacos,sentinel等
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lipengg</groupId>
<artifactId>springcloud_alibaba</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>order</module>
<module>order-nacos</module>
<module>stock</module>
<module>stock-nacos</module>
</modules>
<packaging>pom</packaging>
<!--springboot的版本管理器-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring.cloud.version>Hoxton.SR12</spring.cloud.version>
<spring.cloud.alibaba.version>2.2.9.RELEASE</spring.cloud.alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<!--spring_cloud的版本管理器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--spring_cloud_alibaba的版本管理器-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
接下来,就在将子工程启动,并且能够将其注册到我们的nacos中
package com.lipengg;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
// nacos服务注册发现的依赖,在1.4版本之后不需要特别添加此依赖
@EnableDiscoveryClient
public class StockApplication {
public static void main(String[] args) {
SpringApplication.run(StockApplication.class,args);
}
}
yml配置文件
server:
port: 8889
spring:
application:
name: stock-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1 # nacos地址
username: nacos # 账号
password: nacos # 密码
# namespace: public # 命名空间,默认是public
# ephemeral: false # 是否是永久实例,默认是true(临时实例,服务挂了,就不在注册中心了)
# service: 默认取spring.application.name的值
# group: 默认default_group
# weight: 默认1,权重通常结合权重的负载均衡策略使用才有意义
# metadata: 元数据 例如 version=1,元数据是key-value的形式,来获取服务列表的时候可以获得
启动之后就会在naocs中看到服务了
1.5nacos中关于服务注册一些常见的功能点
首先在1.4的图中,可以看到,在服务列表中及时我们注册的服务,但是正式环境中,可能存在不同的环境,开发组,所以可以通过命名空间和分组名称来对服务进行细粒度的管理
例如,namespace可以是dev,pro,test等不同环境,group可以是项目组下的不同业务方向,然后再试各种服务
服务详情
从服务详情中可以看到,最需要关注的几个点就是权重和健康状态了,一目了然
值得注意的是,前面我们看到,nacos具有雪崩保护的作用,所以保护阈值就是用来触发雪崩保护机制的
关于nacos的雪崩保护
naocs的雪崩保护要通过保护阈值和永久实例来实现
保护阈值: 0-1之间的数, 健康实例数 / 总实例数 < 保护阈值就会触发雪崩保护
永久实例: 在配置文件中可以通过
spring:
cloud:
nacos:
discovery:
ephemeral: false # 是否是永久实例,默认是true(临时实例,服务挂了,就不在注册中心了)
来设置,因为零时实例在宕机之间,就会被删除,所以就不存在计算保护阈值一说了
总结: 当健康实例数 / 总实例数 < 保护阈值,nacos会把不健康的永久服务给调用者使用,防止洪峰流量的到来直接冲垮原本还健康的服务;例如,A,B服务,每个都能正常响应10万的流量,但是B挂掉之后,突然来了20万流量,势必冲垮健康的A,从而导致系统的一个缓解出问题,继而引发整个系统的奔溃!
注: 正式情况下回通过sentinel来完成雪崩保护,但是也得知道这个
订阅者列表,可以在订阅者列表里面,查看某一个服务提供者被调用的情况
可以通过权限管理来给不同的登录者不同的权限,
命名空间就是对其namespace进行一个管理,集群管理在下面看
1.6 使用了注册中心之后服务之间的调用
在使用nacos之后,我们在调用服务时,就不必在通过ip+端口的形式去调用服务了,此时就可以使用服务名了
但是在请求之后,我们会发现报500错误,原因是虽然我们通过注册中心拿到了服务的路由表信息,但是restTemplate并不能通过服务名拿到服务的地址,此时需要通过负载均衡器来完成.
我们在依赖了
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
之后,此依赖中是自带ribbon负载均衡器的依赖的
只需在restTemplate的配置类的注解上加@LoadBalanced即可,默认是负载均衡策略是轮询
1.7关于nacos2.0版本之后集群的坑(提前避开)
nacos2.0开始相当于之前版本开始,实测性能是之前的10倍,它将通信层统一到了gRPC协议,同时完善了客户端和服务端的流量控制和负载均衡能力,提升的整体吞吐。
在结合nginx部署时,由于新加了2个端口,所以在nginx进行反向代理时,要加gRPC协议配置
gRPC的端口时根据集群的端口加偏移量完成的,看红框里,这里就决定了nacos集群如果在同一linux服务器里,端口一定时不能连续的
1.8 nacos集群
首先准备linux服务器,naocs2.1.1版本,nginx1.24.0(安装nginx的时候一定要有stram模块), mysql5.7以上,建议就用5.7的版本(版本太低主要是执行naocs的sql脚本时会出问题)
引用一张图,关于nacos集群的架构,这里没有mysql集群,就一个单体mysql
准备好nacos之后,修改nacos中的配置文件
-
修改nacos中conf下application.properties的mysql配置,因为集群中需要做到一致性,默认nacos使用的内存
### Default web server port: 端口 server.port=8840 #*************** Config Module Related Configurations ***************# ### If use MySQL as datasource: 是否启动mysql spring.datasource.platform=mysql ### Count of DB: 连接数 db.num=1 ### Connect URL of DB: db.url.0=jdbc:mysql://localhost:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user.0=root db.password.0=123456
-
拷贝一份cluster.conf.example 叫cluster.conf
#it is ip #example 在这里添加你集群各个服务器的地址和端口 192.168.182.17:8840 192.168.182.17:8850 192.168.182.17:8860
-
如果虚拟机内存够大忽略这一步,修改启动文件
if [[ "${MODE}" == "standalone" ]]; then JAVA_OPT="${JAVA_OPT} -Xms512m -Xmx512m -Xmn256m" JAVA_OPT="${JAVA_OPT} -Dnacos.standalone=true" else if [[ "${EMBEDDED_STORAGE}" == "embedded" ]]; then JAVA_OPT="${JAVA_OPT} -DembeddedStorage=true" fi // 修改这里的启动时指定的推内存大小 -Xms:初始堆的可用大小 -Xmx:堆的最大可用大小 -Xmn(新生代) 新生代大小 JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m -Xmn256m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m" JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR}/logs/java_heapdump.hprof"
上述完成之后就可以启动当前的naocs了,启动之后查看logs/start.out文件
像红框里这样就成功了,此时记得关闭防火墙,然后直接访问 http://192.168.182.17:8840/nacos/index.html#/login就可以了
上述启动完成之后安装nginx ,参考这篇https://blog.csdn.net/qq_40179653/article/details/125736200安装linux了
完成之后修成默认安装路径下的usr/local/nginx/conf/nginx.conf linux配置
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
upstream nacos-cluster {
server 192.168.182.17:8840;
server 192.168.182.17:8850;
server 192.168.182.17:8860;
}
server {
# listen 80;
# server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
# location / {
# root html;
# index index.html index.htm;
# }
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
listen 8848;
server_name 192.168.182.17;
location /nacos { #监听的请求路径为/nacos
proxy_pass http://nacos-cluster; #反向代理配置
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
stream{
upstream nacoscluster-grpc {
server 192.168.182.17:9840;
server 192.168.182.17:9850;
server 192.168.182.17:9860;
}
server {
listen 9848;
proxy_pass nacoscluster-grpc;
}
}
保存之后记得刷新nginx的配置文件
# 刷新配置文件
./nginx -s reload
nginx的一些命令,一定要在/usr/local/nginx/sbin下使用命令哦
# 查看nginx语法是否正确
./nginx -t
# 启动nginx
./nginx
# 刷新配置文件
./nginx -s reload
# 查看版本 任意地方可执行
nginx -V
# 正常关闭
./nginx -s quit
# 强制关闭
./nginx -s stop
# 查看nginx进程
ps aux|grep nginx
之后访问nginx监听的端口就可以看到了
那nacos的连接日志在nacos目录的bin/logs下面,如/home/lpg/nacos/nacos8849/bin/logs/access_log.2023-05-15.log
然后在java工程的配置文件里将nacos的地址改成nginx代理的地址就可以启动了
server:
port: 8888
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: 192.168.182.17:8848 # 集群nginx代理地址
username: nacos
password: nacos
# namespace: public # 命名空间,默认是public
# ephemeral: false # 是否是永久实例,默认是true(临时实例,服务挂了,就不在注册中心了)
# service: 默认取spring.application.name的值
# group: 默认default_group
# weight: 默认1,权重通常结合权重的负载均衡策略使用才有意义
# metadata: 元数据 例如 version=1,元数据是key-value的形式,来获取服务列表的时候可以获得
2.nacos配置中心
2.1什么是配置中心
只说自己的理解:配置中心,故名思意,在微服务中,将所有的工程配置文件收集起来,集中管理,供使用的微服务直接在配置中心获取,而不用单独配置,使各个配置都散落在微服务各处。如此,方便了配置文件的后期维护,修改等工作;更重要的是,拿nacos而言,其作为配置中心,但配置项发生改变的时候,无需重启相关服务,就可以做到生效;
另外,防止恶意修改配置文件,naocs可以利用其权限管理功能,针对不同账户和命名空间赋予不同权限,例如对服务和配置只读,从而保证其配置文件内容的安全;
需要注意的是,如果要给账户设置权限的话(只读,只写,读写),需要将nacos服务中的权限管理打开
在nacos服务中的配置文件下的application.properties,默认是false,需要改为true
另外,在开启了权限之后,在配置文件中,一定要写nacos服务的user和password
综上所述:使用配置中心是具有,1.维护性 2.时效性 3.安全性 的特点的
2.2对比springcloud config
- spring cloud config是需要集合git进行使用的,而且很明显的一点是spring cloud config在修改配置文件之后,是需要依赖spring cloud bus消息总线来通知客户端有变化,并不像nacos是自动感知的,1s内就能完成所有更新;
- spring cloud config是不提供可视化界面的
- 在单机和集群上,nacos的tps(每秒事务处理量)等性能是最强的
2.3naocs配置中心的命名规则
nacos配置中心和注册中心一样,都有命名空间,group,dataId
通过命名空间按照环境区分,如dev,test,pro,group可以是项目名称,或者你们小组负责业务名称,data ID官方推荐的命名规则就是工程groupId + artifactId 如com.lipengg.order
2.4创建配置,使用配置
- 创建配置文件(注意了,nacos默认的文件格式是properties,如果是其他格式需要在配置文件中指定,否则访问不到)
-
在微服务中添加依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
-
使用配置中心的时候,需要使用bootstrap.yml/properties来作配置文件
server: port: 8888 spring: application: # 如果没有指定data ID的时候,nacos默认会根据服务名去获取对应的配置文件,所以配置文件名和服务名一致时无需配置 name: order-service cloud: nacos: server-addr: 192.168.182.17:8848 username: nacos password: nacos
-
在application启动文件中获取配置信息
public static void main(String[] args) throws InterruptedException { ConfigurableApplicationContext run = SpringApplication.run(OrderApplication.class, args); while (true) { String property = run.getEnvironment().getProperty("user.name"); System.out.println(property); TimeUnit.SECONDS.sleep(1L); } }
2.5nacos配置中心的扩展
- 配置中心也可以使用profile进行细粒度控制
在传统的spring boot服务中,我们开发过程中,一般会通过profile进行细粒度的控制配置文件的环境,如dev,test,pro等
同样在naocs配置中心,也可以通过profile进行粒度控制,并且,profile的优先级是大于默认配置的的,但是还是不建议这样使用,因为使用profile不能做安全控制,nacos的安全控制,只能是用户和命名空间结合来完成,所以使用配置中心时,还是使用namespace进行区分环境更好
但是注意了,这里的配置文件在创建是要加后缀
application.yml
server:
port: 8888
spring:
profiles:
active: dev
# 在配置中心,也可以通过profiles进行更细粒度的配置文件设置
# 值得注意的是,在使用非默认的后缀格式的时候,在创建配置文件的时候得加上文件后缀
# 如 order-service-dev.yaml
# 配置文件的优先级 (优先级大的覆盖优先级小的,并且行成互不,即profiles中没有的话从默认配置文件拿)
# profiles > 默认配置文件
bootstrap.yml
server:
port: 8888
spring:
application:
name: order-service # 如果没有指定data ID的时候,nacos默认会根据服务名去
# 获取对应的配置文件,所以配置文件名和服务名一致时无需配置
cloud:
nacos:
server-addr: 192.168.182.17:8848
username: nacos
password: nacos
config:
namespace: dev # 命名空间,默认是public
另外,说个注意事项,在不同的命名空间里,创建命名空间的时候,要注意了,咱们在配置文件里写的是namespace是dev,这个dev是和命名空间的ID一致的,否则你不填的,自动生成的和dev是匹配不上的,就读不到配置文件
-
自定义data ID
自动以data ID在配置过程中有两种方式,但是其也存在优先级关系
share-configs和
配置时主要两个属性需要写,data-id和开启动态刷新,而group是有默认值得,文件扩展名fileExtension是继承自dataID的后缀(我们在自定义配置文件的时候,都会写后缀)
bootstrap.yml
server: port: 8888 spring: application: name: order-service # 如果没有指定data ID的时候,nacos默认会根据服务名去 # 获取对应的配置文件,所以配置文件名和服务名一致时无需配置 cloud: nacos: server-addr: 192.168.182.17:8848 username: nacos password: nacos config: # file-extension: yaml # 配置文件的后缀,默认是properties,只针对默认配置和profile的模式 # refresh-enabled: false # 是否能够动态刷新,一般不用 namespace: dev # 命名空间,默认是public # group: # 群组,默认是DEFAULT_GROUP shared-configs: # 自定义data ID 是个数组,在yml中配置时,有两种方式变数数组,- 和下标 - data-id: com.lipengg.common.properties # 也可以写成是dataId group: ywu # 默认是DEFAULT_GROUP refresh: true - data-id: com.lipengg.common01.properties # 也可以写成是dataId group: ywu # 默认是DEFAULT_GROUP refresh: true extension-configs[0]: data-id: com.lipengg.common02.properties refresh: true # 配置文件的优先级 (优先级大的覆盖优先级小的,并且行成互不,即profiles中没有的话从默认配置文件拿) # profiles > 默认配置文件 > extension-configs(同类别,同样是下标大优先级高) > shared-configs(同一个share-config里面,下标大的优先级高)
2.6 在接口文件等地方获取配置信息
package com.lipengg.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author lipengg * @date 2023/5/17 */ @RestController @RequestMapping("/config") @RefreshScope // 加这个注解才会感知到配置文件更新 它会重新从BeanFactory获取一个新的实例(该实例使用新的配置) public class ConfigController { @Value("${user.name}") private String userName; @RequestMapping("/getConfig") public String getUserName(){ return userName; } }
在这里就结束了,如果有其他需要,请参考官方文档,真的有用
官网文档地址:https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html