SpringCloud Alibaba Nacos

博文目录


注册中心设计思路

注册中心有一个数据结构, 用来存储服务提供者信息, 服务名, ip, port, status(enable/disable), registerAt, lastRenewAt, …

每一个客户端服务启动时像注册中心发送心跳, 包含服务名, ip, port等, 假如发送间隔是10s

注册中心首次收到某服务时, 加入到列表中, 状态是enable, 每次收到心跳, 更新lastRenewAt和status

注册中心有定时任务, 每秒执行一次, 扫描30s内没有收到续期请求的服务, status改为disable

注册中心有定时任务, 每秒执行一次, 扫描60s内没有收到续期请求的服务, 直接删除该服务提供者的信息

阈值保护: 假如注册中心和服务提供者网络异常, 但是服务消费者和服务提供者网络通畅, 当某服务提供者全都不可用时, 也不能全部删除, 防止系统雪崩, 至少得保证 disable数/all数>=阈值

注册中心演变及设计思想

在这里插入图片描述

Nacos

Nacos 官网
什么是 Nacos
Nacos 概念
Nacos 架构
Nacos Open Api
GitHub Nacos
GitHub Spring Coud Alibaba
下载链接

Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。

Nacos 的关键特性包括:

  • 服务发现和服务健康监测 Service Discovery and Service Health Check
  • 动态配置服务 Dynamic Configuration Management
  • 动态 DNS 服务 Dynamic DNS Service
  • 服务及其元数据管理 Service and MetaData Management

简单来说, Nacos包含两大功能, 注册中心和配置中心

在这里插入图片描述
Nacos 架构
在这里插入图片描述
NamingService: 命名服务,注册中心核心接口
ConfigService:配置服务,配置中心核心接口

Nacos注册中心架构

在这里插入图片描述

核心功能

  • 服务注册:Nacos Client会通过发送REST请求的方式向Nacos Server注册自己的服务,提供自身的元数据,比如ip地址、端口等信息。Nacos Server接收到注册请求后,就会把这些元数据信息存储在一个双层的内存Map中。
  • 服务心跳:在服务注册后,Nacos Client会维护一个定时心跳来持续通知Nacos Server,说明服务一直处于可用状态,防止被剔除。默认5s发送一次心跳。
  • 服务同步:Nacos Server集群之间会互相同步服务实例,用来保证服务信息的一致性。 leader raft
  • 服务发现:服务消费者(Nacos Client)在调用服务提供者的服务时,会发送一个REST请求给Nacos Server,获取上面注册的服务清单,并且缓存在Nacos Client本地,同时会在Nacos Client本地开启一个定时任务定时拉取服务端最新的注册表信息更新到本地缓存
  • 服务健康检查:Nacos Server会开启一个定时任务用来检查注册服务实例的健康情况,对于超过15s没有收到客户端心跳的实例会将它的healthy属性置为false(客户端服务发现时不会发现),如果某个实例超过30秒没有收到心跳,直接剔除该实例(被剔除的实例如果恢复发送心跳则会重新注册)

服务注册表结构

在这里插入图片描述
service: 某一个服务
cluster: 某服务有多个不同地域的集群, 提供同城加速与容灾备份

服务领域模型

在这里插入图片描述

环境搭建

Nacos支持三种部署模式

  • 单机模式 - 用于测试和单机试用。
  • 集群模式 - 用于生产环境,确保高可用。
  • 多集群模式 - 用于多数据中心场景。

单机模式部署

下载链接

官方文档

bin/startup.sh -m standalone
bin/shutdown.sh

Nacos 是一个 SpringBoot 应用, 依赖JRE环境, 有 application.properties 配置文件, 但JVM参数需要在 startup.sh 中修改

Nacos 启动日志

/application/jdk-1.8.0.202/bin/java  -Xms512m -Xmx512m -Xmn256m -Dnacos.standalone=true -Dnacos.member.list= -Djava.ext.dirs=/application/jdk-1.8.0.202/jre/lib/ext:/application/jdk-1.8.0.202/lib/ext -Xloggc:/application/nacos-1.4.1/logs/nacos_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -Dloader.path=/application/nacos-1.4.1/plugins/health,/application/nacos-1.4.1/plugins/cmdb -Dnacos.home=/application/nacos-1.4.1 -jar /application/nacos-1.4.1/target/nacos-server.jar  --spring.config.additional-location=file:/application/nacos-1.4.1/conf/ --logging.config=/application/nacos-1.4.1/conf/nacos-logback.xml --server.max-http-header-size=524288

         ,--.
       ,--.'|
   ,--,:  : |                                           Nacos 1.4.1
,`--.'`|  ' :                       ,---.               Running in stand alone mode, All function modules
|   :  :  | |                      '   ,'\   .--.--.    Port: 8848
:   |   \ | :  ,--.--.     ,---.  /   /   | /  /    '   Pid: 1755
|   : '  '; | /       \   /     \.   ; ,. :|  :  /`./   Console: http://192.168.2.137:8848/nacos/index.html
'   ' ;.    ;.--.  .-. | /    / ''   | |: :|  :  ;_
|   | | \   | \__\/: . ..    ' / '   | .; : \  \    `.      https://nacos.io
'   : |  ; .' ," .--.; |'   ; :__|   :    |  `----.   \
|   | '`--'  /  /  ,.  |'   | '.'|\   \  /  /  /`--'  /
'   : |     ;  :   .'   \   :    : `----'  '--'.     /
;   |.'     |  ,     .-./\   \  /            `--'---'
'---'        `--`---'     `----'

2021-04-04 17:49:32,953 INFO Bean 'org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler@41294f8' 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)

2021-04-04 17:49:32,957 INFO 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)

2021-04-04 17:49:33,727 INFO Tomcat initialized with port(s): 8848 (http)

2021-04-04 17:49:34,452 INFO Root WebApplicationContext: initialization completed in 6567 ms

2021-04-04 17:49:40,427 INFO Initializing ExecutorService 'applicationTaskExecutor'

2021-04-04 17:49:40,677 INFO Adding welcome page: class path resource [static/index.html]

2021-04-04 17:49:41,335 INFO Creating filter chain: Ant [pattern='/**'], []

2021-04-04 17:49:41,424 INFO Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@1827a871, org.springframework.security.web.context.SecurityContextPersistenceFilter@c1fca1e, org.springframework.security.web.header.HeaderWriterFilter@5bd1ceca, org.springframework.security.web.csrf.CsrfFilter@1a15b789, org.springframework.security.web.authentication.logout.LogoutFilter@73393584, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@344344fa, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@615f972, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@48e64352, org.springframework.security.web.session.SessionManagementFilter@499b2a5c, org.springframework.security.web.access.ExceptionTranslationFilter@51650883]

2021-04-04 17:49:41,593 INFO Initializing ExecutorService 'taskScheduler'

2021-04-04 17:49:41,638 INFO Exposing 2 endpoint(s) beneath base path '/actuator'

2021-04-04 17:49:41,969 INFO Tomcat started on port(s): 8848 (http) with context path '/nacos'

2021-04-04 17:49:41,972 INFO Nacos started successfully in stand alone mode. use embedded storage

2021-04-04 17:51:42,445 INFO Initializing Servlet 'dispatcherServlet'

2021-04-04 17:51:42,474 INFO Completed initialization in 29 ms

内置Tomcat端口为8848, 默认使用内置存储服务与配置数据, 也可以使用mysql来存储数据(数据库初始化文件:conf/nacos-mysql.sql), 需要修改 nacos 的 conf/application.properties

spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://192.168.2.115:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=myPassword
# 使用mysql的日志
2021-04-05 00:27:26,596 INFO Nacos started successfully in stand alone mode. use external storage

访问Nacos控制台, 账号密码默认都为 nacos(复制的密码可能不正确, 需要手输才行)

http://192.168.2.137:8848/nacos/index.html

集群模式配置与部署

官方文档

集群部署要求必须使用外置数据源(只支持MySQL), 能让集群访问相同的数据
在这里插入图片描述
在这里插入图片描述
VIP: 虚拟浮动IP, 可通过 keepaliaved 实现

集群环境搭建

先准备3个使用MySQL数据源的单机环境配置(MySQL需要事先准备好)

默认使用内置存储服务与配置数据, 也可以使用mysql来存储数据(数据库初始化文件:conf/nacos-mysql.sql), 需要修改 nacos 的 conf/application.properties

spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://192.168.2.115:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=myPassword

在nacos的解压目录nacos/的conf目录下,有配置文件cluster.conf.example, 将其改名为cluster.conf,并将Nacos集群的IP:PORT配置好, 每行一个。(请配置3个或3个以上节点)

192.168.2.137:8848
192.168.2.138:8848
192.168.2.139:8848

修改JVM参数 (bin\startup.sh) (学习的时候没必要搞太大), 单机模式用的是 -Xms512m -Xmx512m -Xmn256m, 其他模式用的是 -Xms2g -Xmx2g -Xmn1g, 把其他模式调整到和单机模式一样

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
    JAVA_OPT="${JAVA_OPT} -server -Xms2g -Xmx2g -Xmn1g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
    JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR}/logs/java_heapdump.hprof"
    JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages"

fi
bin/startup.sh
sh shutdown.sh

在这里插入图片描述

Nginx 反向代理服务搭建(负载均衡)

这里只使用一个 Nginx 来做 Nacos 的负载均衡

Linux Nginx 下载 安装 配置 使用

在 192.168.2.137 上装 nginx

http {

	# ...

    upstream nacos {
    	server 192.168.2.137:8848;
    	server 192.168.2.138:8848;
    	server 192.168.2.139:8848;
    }

    server {
        listen       80;
        server_name  localhost;
        
		# ...
		
        location / {
            root   html;
            index  index.html index.htm;
        }

        location /nacos/ {
        	proxy_pass http://nacos/nacos/;
        }

		# ...
	
	}
}
http://192.168.2.137/nacos

普罗米修斯(prometheus) + grafana(Go开发的数据化可视工具) 监控 Nacos

nacos 启用metrics数据暴露

Nacos 0.8.0版本完善了监控系统,支持通过暴露metrics数据接入第三方监控系统监控Nacos运行状态,目前支持prometheus、elastic search和influxdb

配置application.properties文件,暴露metrics数据

management.endpoints.web.exposure.include=*

检查是否能访问到metrics数据

http://192.168.2.137/nacos/actuator/prometheus
http://192.168.2.137:8848/nacos/actuator/prometheus
http://192.168.2.138:8848/nacos/actuator/prometheus
http://192.168.2.139:8848/nacos/actuator/prometheus

在这里插入图片描述

搭建prometheus采集Nacos metrics数据

普罗米修斯官网
官网下载页

下载windows版本的普罗米修斯, 修改 prometheus.yml

    metrics_path: '/nacos/actuator/prometheus'
    static_configs:
    - targets: ['192.168.2.137:8848','192.168.2.138:8848','192.168.2.139:8848']

给应用程序 prometheus.exe 创建快捷方式, 右键快捷方式, 点击属性, 修改目标, 在原值后面添加 --config.file=prometheus.yml, 如

C:\mrathena\develop\prometheus\prometheus.exe --config.file=prometheus.yml

双击快捷方式启动普罗米修斯服务
在这里插入图片描述
可以看到加载了配置文件 prometheus.yml, 服务端口是9090, 在浏览器打开地址, 搜索 nacos_monitor 有结果说明采集数据成功

localhost:9090/graph

在这里插入图片描述

搭建grafana图形化展示metrics数据

Grafana官网
Grafana Windows 安装教程
Grafana Windows 下载页
Grafana Windows 下载链接

下载好压缩包后, 先右键属性, 勾选"解除锁定"复选框, 点击确定, 解压后, 运行 bin\grafana-server.exe 启动 Grafana 服务, 默认账号密码都是 admin, 登录后刷新页面

http://localhost:3000

配置prometheus数据源

在这里插入图片描述
添加数据源时选择普罗米修斯, name 为 “prometheus”, 填写url, 其他默认
在这里插入图片描述

导入Nacos grafana监控模版

GitHub Nacos Grafana template

Nacos监控分为三个模块:

  • nacos monitor 展示核心监控项
  • nacos detail 展示指标的变化曲线
  • nacos alert为告警项

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

配置grafana告警

Nacos 监控手册

Nacos metrics含义

Nacos 监控手册

Nacos-Sync监控

Nacos 监控手册

Nacos-Sync metrics含义

Nacos 监控手册

Nacos 快速开始

在这里插入图片描述
在这里插入图片描述

浏览器访问

http://localhost:8083/order/query

页面打印

this is order query customer info: this is a customer

父模块 pom.xml

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mrathena.spring.cloud</groupId>
    <artifactId>spring.cloud.demo</artifactId>
    <version>1.0.0</version>
    <name>spring.cloud.demo</name>
    <packaging>pom</packaging>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <modules>
        <module>service.customer</module>
        <module>service.order</module>
    </modules>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.3.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR8</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.5.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

子模块 service.customer

pom.xml

<?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">
    <parent>
        <artifactId>spring.cloud.demo</artifactId>
        <groupId>com.mrathena.spring.cloud</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service.customer</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>

</project>

application.yml

spring:
  application:
    name: service.customer
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.2.137:8848,192.168.2.138:8848,192.168.2.139:8848
server:
  port: 8081

Application.java

package com.mrathena.customer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

CustomerController.java

package com.mrathena.customer;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("customer")
public class CustomerController {
	@RequestMapping("query")
	public Object query() {
		return "this is a customer";
	}
}

子模块 service.order

pom.xml

<?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">
    <parent>
        <artifactId>spring.cloud.demo</artifactId>
        <groupId>com.mrathena.spring.cloud</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service.order</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>

</project>

application.yml

spring:
  application:
    name: service.order
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.2.137:8848,192.168.2.138:8848,192.168.2.139:8848
server:
  port: 8083

Application.java

package com.mrathena.order;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

RestTemplateConfig.java

package com.mrathena.order;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {
	@Bean
	@LoadBalanced
	// @LoadBalanced 注解的作用
	// 负载均衡器, 拉取目标服务列表
	// RestTemplate 扩展点 ClientHttpRequestInterceptor
	// 负载均衡器组件 Ribbon 里面有一个 LoadBalancerInterceptor 实现了 ClientHttpRequestInterceptor
	// 把 服务名称 替换成 对应服务的真实地址, 同时提供负载均衡的功能
	// 不使用 @LoadBalanced 注解, 也是可以达到同样效果的
	// 注入一个 LoadBalancerClient 实例 (已经在 Spring 容器中了, 可以直接注入)
	// new 一个 LoadBalancerInterceptor 实例, 传入 LoadBalancerClient 实例
	// 给 RestTemplate 设置拦截器, restTemplate.setInterceptor(Collections.singletonList(new LoadBalancerInterceptor(loadBalancerClient)));
	public RestTemplate restTemplate() {
		return new RestTemplate();
	}
}

OrderController.java

package com.mrathena.order;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("order")
public class OrderController {
	@Autowired
	private RestTemplate restTemplate;

	@RequestMapping("query")
	public Object query() {
		// 负载均衡器实现了 服务名 和 具体服务IP:PORT 的转换
		String url = "http://service.customer/customer/query";
		return "this is order query customer info: " + restTemplate.getForObject(url, String.class);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值