一、Alibaba Nacos 服务注册中心
1、Nacos简介
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。
Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。
2、什么是 Nacos?
服务(Service)是 Nacos 世界的一等公民。Nacos 支持几乎所有主流类型的“服务”的发现、配置和管理:
Nacos 的关键特性包括:
-
服务发现和服务健康监测
Nacos 支持基于 DNS 和基于 RPC 的服务发现。服务提供者使用
原生SDK
、
OpenAPI
、或一个
独立的Agent TODO
注册 Service 后,服务消费者可以使用
DNS TODO
或
HTTP&API
查找和发现服务。Nacos 提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求。Nacos 支持传输层 (PING 或 TCP)和应用层 (如 HTTP、MySQL、用户自定义)的健康检查。 对于复杂的云环境和网络拓扑环境中(如 VPC、边缘网络等)服务的健康检查,Nacos 提供了 agent 上报模式和服务端主动检测2种健康检查模式。Nacos 还提供了统一的健康检查仪表盘,帮助您根据健康状态管理服务的可用性及流量。
-
动态配置服务
动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。
动态配置消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。
配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。
Nacos 提供了一个简洁易用的UI (
控制台样例 Demo
) 帮助您管理所有的服务和应用的配置。Nacos 还提供包括配置版本跟踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性,帮助您更安全地在生产环境中管理配置变更和降低配置变更带来的风险。 -
动态 DNS 服务
动态 DNS 服务支持权重路由,让您更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务。动态DNS服务还能让您更容易地实现以 DNS 协议为基础的服务发现,以帮助您消除耦合到厂商私有服务发现 API 上的风险。
Nacos 提供了一些简单的
DNS APIs TODO
帮助您管理服务的关联域名和可用的 IP:PORT 列表. -
服务及其元数据管理
Nacos 能让您从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA 以及最首要的 metrics 统计数据。
3、Nacos 地图
一图看懂 Nacos,下面架构部分会详细介绍。
- 特性大图:要从功能特性,非功能特性,全面介绍我们要解的问题域的特性诉求
- 架构大图:通过清晰架构,让您快速进入 Nacos 世界
- 业务大图:利用当前特性可以支持的业务场景,及其最佳实践
- 生态大图:系统梳理 Nacos 和主流技术生态的关系
- 优势大图:展示 Nacos 核心竞争力
- 战略大图:要从战略到战术层面讲 Nacos 的宏观优势
4、Nacos 生态图
如 Nacos 全景图所示,Nacos 无缝支持一些主流的开源生态,例如
使用 Nacos 简化服务发现、配置管理、服务治理及管理的解决方案,让微服务的发现、管理、共享、组合更加容易。
5、Nacos架构
基本架构及概念
服务 (Service)
服务是指一个或一组软件功能(例如特定信息的检索或一组操作的执行),其目的是不同的客户端可以为不同的目的重用(例如通过跨进程的网络调用)。Nacos 支持主流的服务生态,如 Kubernetes Service、gRPC|Dubbo RPC Service 或者 Spring Cloud RESTful Service.
服务注册中心 (Service Registry)
服务注册中心,它是服务,其实例及元数据的数据库。服务实例在启动时注册到服务注册表,并在关闭时注销。服务和路由器的客户端查询服务注册表以查找服务的可用实例。服务注册中心可能会调用服务实例的健康检查 API 来验证它是否能够处理请求。
服务元数据 (Service Metadata)
服务元数据是指包括服务端点(endpoints)、服务标签、服务版本号、服务实例权重、路由规则、安全策略等描述服务的数据
服务提供方 (Service Provider)
是指提供可复用和可调用服务的应用方
服务消费方 (Service Consumer)
是指会发起对某个服务调用的应用方
配置 (Configuration)
在系统开发过程中通常会将一些需要变更的参数、变量等从代码中分离出来独立管理,以独立的配置文件的形式存在。目的是让静态的系统工件或者交付物(如 WAR,JAR 包等)更好地和实际的物理运行环境进行适配。配置管理一般包含在系统部署的过程中,由系统管理员或者运维人员完成这个步骤。配置变更是调整系统运行时的行为的有效手段之一。
配置管理 (Configuration Management)
在数据中心中,系统中所有配置的编辑、存储、分发、变更管理、历史版本管理、变更审计等所有与配置相关的活动统称为配置管理。
名字服务 (Naming Service)
提供分布式系统中所有对象(Object)、实体(Entity)的“名字”到关联的元数据之间的映射管理服务,例如 ServiceName -> Endpoints Info, Distributed Lock Name -> Lock Owner/Status Info, DNS Domain Name -> IP List, 服务发现和 DNS 就是名字服务的2大场景。
配置服务 (Configuration Service)
在服务或者应用运行过程中,提供动态配置或者元数据以及配置管理的服务提供者。
更多概念…
逻辑架构及其组件介绍
- 服务管理:实现服务CRUD,域名CRUD,服务健康状态检查,服务权重管理等功能
- 配置管理:实现配置管CRUD,版本管理,灰度管理,监听管理,推送轨迹,聚合数据等功能
- 元数据管理:提供元数据CURD 和打标能力
- 插件机制:实现三个模块可分可合能力,实现扩展点SPI机制
- 事件机制:实现异步化事件通知,sdk数据变化异步通知等逻辑
- 日志模块:管理日志分类,日志级别,日志可移植性(尤其避免冲突),日志格式,异常码+帮助文档
- 回调机制:sdk通知数据,通过统一的模式回调用户处理。接口和数据结构需要具备可扩展性
- 寻址模式:解决ip,域名,nameserver、广播等多种寻址模式,需要可扩展
- 推送通道:解决server与存储、server间、server与sdk间推送性能问题
- 容量管理:管理每个租户,分组下的容量,防止存储被写爆,影响服务可用性
- 流量管理:按照租户,分组等多个维度对请求频率,长链接个数,报文大小,请求流控进行控制
- 缓存机制:容灾目录,本地缓存,server缓存机制。容灾目录使用需要工具
- 启动模式:按照单机模式,配置模式,服务模式,dns模式,或者all模式,启动不同的程序+UI
- 一致性协议:解决不同数据,不同一致性要求情况下,不同一致性机制
- 存储模块:解决数据持久化、非持久化存储,解决数据分片问题
- Nameserver:解决namespace到clusterid的路由问题,解决用户环境与nacos物理环境映射问题
- CMDB:解决元数据存储,与三方cmdb系统对接问题,解决应用,人,资源关系
- Metrics:暴露标准metrics数据,方便与三方监控系统打通
- Trace:暴露标准trace,方便与SLA系统打通,日志白平化,推送轨迹等能力,并且可以和计量计费系统打通
- 接入管理:相当于阿里云开通服务,分配身份、容量、权限过程
- 用户管理:解决用户管理,登录,sso等问题
- 权限管理:解决身份识别,访问控制,角色管理等问题
- 审计系统:扩展接口方便与不同公司审计系统打通
- 通知系统:核心数据变更,或者操作,方便通过SMS系统打通,通知到对应人数据变更
- OpenAPI:暴露标准Rest风格HTTP接口,简单易用,方便多语言集成
- Console:易用控制台,做服务管理、配置管理等操作
- SDK:多语言sdk
- Agent:dns-f类似模式,或者与mesh等方案集成
- CLI:命令行对产品进行轻量化管理,像git一样好用
二、为什么选择Nacos作为注册中心?
1、CAP理论
- 一致性(Consistency) (所有节点在同一时间具有相同的数据)
- 可用性(Availability) (保证每个请求不管成功或者失败都有响应)
- 分隔容忍(Partition tolerance) (系统中任意信息的丢失或失败不会影响系统的继续运作)
CAP 理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。
- CA – 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
- CP – 满足一致性,分区容忍性的系统,通常性能不是特别高。
- AP – 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。
2、选择Nacos的原因
从 CAP 模型来分析, 优雅的注册中心,需要AP模型,根据以上多维度对比,Eurake 和 Nacos 是 AP 模型,由于Netflix Eurake 2.0 已经停止更新,推荐阿里巴巴Nacos。
3、详细对比
Nacos |
Eureka |
Consul |
CoreDNS |
Zookeeper |
|
---|---|---|---|---|---|
一致性协议 | CP+AP | AP | CP | — | CP |
健康检查 | TCP/HTTP/MYSQL/Client Beat | Client Beat | TCP/HTTP/gRPC/Cmd | — | Keep Alive |
负载均衡策略 | 权重/ metadata/Selector | Ribbon | Fabio | RoundRobin | — |
雪崩保护 | 有 | 有 | 无 | 无 | 无 |
自动注销实例 | 支持 | 支持 | 不支持 | 不支持 | 支持 |
访问协议 | HTTP/DNS | HTTP | HTTP/DNS | DNS | TCP |
监听支持 | 支持 | 支持 | 支持 | 不支持 | 支持 |
多数据中心 | 支持 | 支持 | 支持 | 不支持 | 不支持 |
跨注册中心同步 | 支持 | 不支持 | 支持 | 不支持 | 不支持 |
SpringCloud集成 | 支持 | 支持 | 支持 | 不支持 | 不支持 |
Dubbo集成 | 支持 | 不支持 | 不支持 | 不支持 | 支持 |
K8S集成 | 支持 | 不支持 | 支持 | 支持 | 不支持 |
三、Nacos安装
1.预备环境准备
Nacos 依赖
Java
环境来运行。如果您是从代码开始构建并运行Nacos,还需要为此配置
Maven
环境,请确保是在以下版本环境中安装使用:
- 64 bit OS,支持 Linux/Unix/Mac/Windows,推荐选用 Linux/Unix/Mac。
-
64 bit JDK 1.8+;
下载
&
配置
。 -
Maven 3.2.x+;
下载
&
配置
。
配置java环境变量
cat >> /etc/profile << EOF
export JAVA_HOME=/usr/local/jdk1.8.0_211
export CLASSPATH=\$:CLASSPATH:\$JAVA_HOME/lib/
export PATH=\$PATH:\$JAVA_HOME/bin
EOF
source /etc/profile
2.下载安装包
你可以通过源码和发行包两种方式来获取 Nacos。
您可以从
最新稳定版本
下载
nacos-server-$version.zip
包。
#解压
unzip nacos-server-$version.zip 或者 tar -xvf nacos-server-$version.tar.gz
cd nacos/bin
3.启动服务器
Linux/Unix/Mac
启动命令(standalone代表着单机模式运行,非集群模式):
sh startup.sh -m standalone
如果您使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行:
bash startup.sh -m standalone
Windows
启动命令:
cmd startup.cmd
或者双击startup.cmd运行文件。
启动成功访问 http://192.168.1.120:8848/nacos/index.html
看到如下界面代表安装成功
默认账号nacos
默认密码nacos
![]()
四、SpringCloudAlibaba整合Nacos
1、启动服务注册与发现模型
服务注册与发现
- register:服务提供者注册服务
- discovery:服务消费者发现服务
服务的提供者与消费者
- 提供者:指服务的被调用方(即:为其它服务提供服务的服务)
- 消费者:指服务的调用方(即:调用或者聚合其他服务的服务)
服务的上下线会记录服务的一些数据。注册的主要数据包括服务名、机器ip、端口号、域名等等。
2、服务的提供者—-库存、订单服务
服务名称 | 服务介绍 | 端口号 |
---|---|---|
shop-service-order-provider | 订单服务的提供者 | 9200 |
shop-service-store-provider | 库存服务的提供者 | 9300 |
2.1、shop-service-order-provider
用springboot创建名为 shop-service-order-provider 的服务
在springboot项目整合nacos需要添加如下依赖
<!--Nacos服务注册与发现的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2.1.1、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>
<parent>
<groupId>com.aishang</groupId>
<artifactId>shop</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>shop-service-order-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
<spring-cloud-alibaba.verion>2.1.0.RELEASE</spring-cloud-alibaba.verion>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--Nacos服务注册与发现的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.aishang.order.OrderProviderApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.1.2、在shop工程中添加模块
<modules>
<module>shop-service-order-provider</module>
</modules>
2.1.3、application.yml
spring:
application:
# 服务名
name: shop-service-order-provider
cloud:
nacos:
discovery:
# 服务注册中心
server-addr: 192.168.1.120:8848
server:
# 服务端口
port: 9200
management:
# 端点检查(健康检查)
endpoints:
web:
exposure:
include: "*"
2.1.4、启动类
通过 Spring Cloud 原生注解
@EnableDiscoveryClient
开启服务注册发现功能
package com.aishang.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @Author Harry
* @ClassName OrderProviderApplication
* @Description TODO:(一句话描述这个类)
*/
@SpringBootApplication
@EnableDiscoveryClient
public class OrderProviderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderProviderApplication.class);
}
}
启动项目
访问 http://192.168.1.120:8848/nacos/index.html
查看服务列表,即可看到我们注册的服务,代表整合成功
2.2、shop-service-store-provider
2.2.1、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>
<parent>
<groupId>com.aishang</groupId>
<artifactId>shop</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>shop-service-store-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
<spring-cloud-alibaba.verion>2.1.0.RELEASE</spring-cloud-alibaba.verion>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--Nacos服务注册与发现的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.aishang.store.StoreProviderApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.2.2、application.yml
spring:
application:
# 服务名
name: shop-service-store-provider
cloud:
nacos:
discovery:
# 服务注册中心
server-addr: 192.168.1.120:8848
server:
# 服务端口
port: 9300
management:
# 端点检查(健康检查)
endpoints:
web:
exposure:
include: "*"
2.2.3、启动类
package com.aishang.store;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @Author Harry
* @ClassName StoreProviderApplication
* @Description TODO:(一句话描述这个类)
*/
@SpringBootApplication
@EnableDiscoveryClient
public class StoreProviderApplication {
public static void main(String[] args) {
SpringApplication.run(StoreProviderApplication.class);
}
}
启动项目时
3、服务的消费者—-订单服务
服务名称 | 服务介绍 | 端口号 |
---|---|---|
shop-service-order-consumer | 订单服务的消费者 | 9100 |
3.1、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>
<parent>
<groupId>com.aishang</groupId>
<artifactId>shop</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>shop-service-order-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
<spring-cloud-alibaba.verion>2.1.0.RELEASE</spring-cloud-alibaba.verion>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--Nacos服务注册与发现的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.aishang.order.OrderConsumerApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
3.2、application.yml
spring:
application:
# 服务名
name: shop-service-order-consumer
cloud:
nacos:
discovery:
# 服务注册中心
server-addr: 192.168.1.120:8848
server:
# 服务端口
port: 9100
management:
# 端点检查(健康检查)
endpoints:
web:
exposure:
include: "*"
3.3、启动类
package com.aishang.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @Author Harry
* @ClassName OrderConsumerApplication
* @Description TODO:(一句话描述这个类)
*/
@SpringBootApplication
@EnableDiscoveryClient
public class OrderConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(OrderConsumerApplication.class);
}
}
启动项目时
五、服务间的通信-Spring Cloud OpenFeign
上面我们创建了三个服务,但是还没有完善业务逻辑,下面思考一个问题,我们存在着订单服务的消费者调用订单服务的生产者和库存服务的生产者。那我如何在一个服务中去调用另外一个服务呢?
答:在项目中使用http客户端 OpenFeign
1、OpenFeign 简介
- 声明式REST客户端:Feign创建一个用JAX-RS(Java API for RESTful Web Services)或Spring MVC注释修饰的接口的动态实现。
- Nacos 也很好的兼容了 Feign,默认实现负载均衡的效果
2、项目整合OpenFeign
服务需整合openfeign依赖
<!--openFeign客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.1、shop-service-order-provider
生产者端需整合openfeign
<!--openFeign客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
controller
package com.aishang.order.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author Harry
* @ClassName OrderController
* @Description TODO:(一句话描述这个类)
*/
@RestController
public class OrderController {
@GetMapping("/test/{str}")
public String test (@PathVariable("str") String str){
return "我是订单服务提供者, message是 :"+str;
}
}
测试
访问地址 http://localhost:9200/test/aaa
2.2、shop-service-order-consumer
消费者服务 shop-service-order-consumer 的pom中添加 openfeign依赖
<!--openFeign客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
启动类
启动类上须添加@EnableFeignClients注解代表开启feign功能
package com.aishang.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @Author Harry
* @ClassName OrderConsumerApplication
* @Description TODO:(一句话描述这个类)
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(OrderConsumerApplication.class);
}
}
controller
package com.aishang.order.controller;
import com.aishang.order.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author Harry
* @ClassName OrderController
* @Description TODO:(一句话描述这个类)
*/
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/test/{str}")
public String test (@PathVariable("str") String str){
return "我是订单服务消费者 ->"+orderService.test(str);
}
}
service
在接口上添加
@FeignClient("服务名")
注解来指定调用哪个服务
package com.aishang.order.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @Author Harry
* @ClassName OrderService
* @Description TODO:(一句话描述这个类)
*/
@FeignClient(value = "shop-service-order-provider")
public interface OrderService {
@GetMapping("/test/{str}")
String test(@PathVariable("str") String str);
}
测试
访问地址 http://localhost:9100/test/aaa
代表服务间的通信完成(订单服务消费者完成了调用订单服务生产者的行为)
3、openfeign实现负载均衡
如果订单服务的消费者单节点压力过大,我们必须采用多节点部署,因此就需要在调用服务时保证服务集群的负载均衡。openfeign支持默认的负载均衡算法为轮询。
服务提供者 shop-service-order-provider
修改controller逻辑,注入端口号。
3.1、controller
package com.aishang.order.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author Harry
* @ClassName OrderController
* @Description TODO:(一句话描述这个类)
*/
@RestController
public class OrderController {
@Value("${server.port}")
private String port;
@GetMapping("/test/{str}")
public String test (@PathVariable("str") String str){
return "我是订单服务提供者, run in :"+port;
}
}
3.2、测试
修改服务提供者 shop-service-order-provider 的端口号。启动三个节点分别在9200,9201,9202端口
查看nacos服务列表,
访问消费者地址 http://localhost:9100/test/aaa 并不断刷新,结果如下
4、负载均衡算法
轮循
Round Robin:
这种方法会将收到的请求循环分配到服务器集群中的每台机器,即有效服务器。如果使用这种方式,所有的标记进入虚拟服务的服务器应该有相近的资源容量 以及负载形同的应用程序。如果所有的服务器有相同或者相近的性能那么选择这种方式会使服务器负载形同。基于这个前提,轮循调度是一个简单而有效的分配请求 的方式。然而对于服务器不同的情况,选择这种方式就意味着能力比较弱的服务器也会在下一轮循环中接受轮循,即使这个服务器已经不能再处理当前这个请求了。 这可能导致能力较弱的服务器超载。
加权轮循
Weighted Round Robin:
这种算法解决了简单轮循调度算法的缺点:传入的请求按顺序被分配到集群中服务器,但是会考虑提前为每台服务器分配的权重。管理员只是简单的通过服务 器的处理能力来定义各台服务器的权重。例如,能力最强的服务器 A 给的权重是 100,同时能力最低的服务器给的权重是 50。这意味着在服务器 B 接收到第一个 请求之前前,服务器 A 会连续的接受到 2 个请求,以此类推。
最少连接数
Least Connection:
以上两种方法都没有考虑的是系统不能识别在给定的时间里保持了多少连接。因此可能发生,服务器 B 服务器收到的连接比服务器 A 少但是它已经超载,因为 服务器 B 上的用户打开连接持续的时间更长。这就是说连接数即服务器的负载是累加的。这种潜在的问题可以通过 “最少连接数” 算法来避免:传入的请求是根据每 台服务器当前所打开的连接数来分配的。即活跃连接数最少的服务器会自动接收下一个传入的请求。接本上和简单轮询的原则相同:所有拥有虚拟服务的服务器资源 容量应该相近。值得注意的是,在流量率低的配置环境中,各服务器的流量并不是相同的,会优先考虑第一台服务器。这是因为,如果所有的服务器是相同的,那么 第一个服务器优先,直到第一台服务器有连续的活跃流量,否则总是会优先选择第一台服务器。
最少连接数慢启动时间
Least Connection Slow Start Time:
对最少连接数和带权重的最小连接数调度方法来说,当一个服务器刚加入线上环境是,可以为其配置一个时间段,在这段时间内连接数是有限制的而且是缓慢 增加的。这为服务器提供了一个‘过渡时间’以保证这个服务器不会因为刚启动后因为分配的连接数过多而超载。这个值在 L7 配置界面设置。
加权最少连接
Weighted Least Connection:
如果服务器的资源容量各不相同,那么 “加权最少连接” 方法更合适:由管理员根据服务器情况定制的权重所决定的活跃连接数一般提供了一种对服务器非常 平衡的利用,因为他它借鉴了最少连接和权重两者的优势。通常,这是一个非常公平的分配方式,因为它使用了连接数和服务器权重比例;集群中比例最低的服务器 自动接收下一个请求。但是请注意,在低流量情况中使用这种方法时,请参考 “最小连接数” 方法中的注意事项。
基于代理的自适应负载均衡
Agent Based Adaptive Balancing:
除了上述方法之外,负载主机包含一个自适用逻辑用来定时监测服务器状态和该服务器的权重。对于非常强大的 “基于代理的自适应负载均衡” 方法来说,负 载主机以这种方式来定时检测所有服务器负载情况:每台服务器都必须提供一个包含文件,这个文件包含一个 0~99 的数字用来标明改服务器的实际负载情况 (0 = 空前,99 = 超载,101 = 失败,102 = 管理员禁用),而服务器同构 http get 方法来获取这个文件;同时对集群中服务器来说,以二进制文件形式提供自身负载情况也是该服务器工作之一,然而,并没有限制服务器如何计算自身的负载 情况。根据服务器整体负载情况,有两种策略可以选择:在常规的操作中,调度算法通过收集的服务器负载值和分配给该服务器的连接数的比例计算出一个权重比 例。因此,如果一个服务器负载过大,权重会通过系统透明的作重新调整。和加权轮循调度方法一样,不正确的分配可以被记录下来使得可以有效的为不同服务器分 配不同的权重。然而,在流量非常低的环境下,服务器报上来的负载值将不能建立一个有代表性的样本;那么基于这些值来分配负载的话将导致失控以及指令震荡。 因此,在这种情况下更合理的做法是基于静态的权重比来计算负载分配。当所有服务器的负载低于管理员定义的下限时,负载主机就会自动切换为加权轮循方式来分 配请求;如果负载大于管理员定义的下限,那么负载主机又会切换回自适应方式。
固定权重
Fixed Weighted:
最高权重只有在其他服务器的权重值都很低时才使用。然而,如果最高权重的服务器下降,则下一个最高优先级的服务器将为客户端服务。这种方式中每个真实服务器的权重需要基于服务器优先级来配置。
加权响应
Weighted Response:
流量的调度是通过加权轮循方式。加权轮循中所使用的权重是根据服务器有效性检测的响应时间来计算。每个有效性检测都会被计时,用来标记它响应成功花 了多长时间。但是需要注意的是,这种方式假定服务器心跳检测是基于机器的快慢,但是这种假设也许不总是能够成立。所有服务器在虚拟服务上的响应时间的总和 加在一起,通过这个值来计算单个服务物理服务器的权重;这个权重值大约每 15 秒计算一次。
源 IP 哈希
Source IP Hash:
这种方式通过生成请求源 IP 的哈希值,并通过这个哈希值来找到正确的真实服务器。这意味着对于同一主机来说他对应的服务器总是相同。使用这种方式,你不需要保存任何源 IP。但是需要注意,这种方式可能导致服务器负载不平衡。
六、分布式配置中心
目前我们只有三个服务还好,如果服务数量庞大那么每个服务的配置文件的管理就显得尤为重要。在SpringCloud体系中之前是用SpringCloud config 解决这一问题。那么在SpringCloudAlibaba体系中Nacos已经集成了这一功能。
1、Spring Cloud Alibaba Nacos Config 介绍
Nacos 提供用于存储配置和其他元数据的 key/value 存储,为分布式系统中的外部化配置提供服务器端和客户端支持。使用 Spring Cloud Alibaba Nacos Config,您可以在 Nacos Server 集中管理你 Spring Cloud 应用的外部属性配置。
Spring Cloud Alibaba Nacos Config 是 Config Server 和 Client 的替代方案,客户端和服务器上的概念与 Spring Environment 和 PropertySource 有着一致的抽象,在特殊的 bootstrap 阶段,配置被加载到 Spring 环境中。当应用程序通过部署管道从开发到测试再到生产时,您可以管理这些环境之间的配置,并确保应用程序具有迁移时需要运行的所有内容。
2、整合配置中心
在服务中引入 nacos config starter
pom.xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
必须使用 bootstrap.properties 配置文件来配置Nacos Server 地址(必须删除application.yml配置文件),
注意:
Spring Boot 配置文件的加载顺序,依次为
bootstrap.properties
->
bootstrap.yml
->
application.properties
->
application.yml
,其中
bootstrap.properties
配置为最高优先级
例如:
bootstrap.properties
#服务名称
spring.application.name=shop-service-order-consumer
#nacos-server的ip+port
spring.cloud.nacos.config.server-addr=192.168.1.120:8848
#服务的配置文件类型
spring.cloud.nacos.config.file-extension=yaml
nacos控制台->配置管理->配置列表->新增配置
注意:配置
Data ID
时要加上**.yaml**结尾
配置完成后启动项目,控制台输出如下,且服务可正常使用。
2020-06-28 11:23:32.888 INFO 6988 --- [ main] c.a.c.n.c.NacosPropertySourceBuilder : Loading nacos data, dataId: 'shop-service-order-consumer.yaml', group: 'DEFAULT_GROUP'
2020-06-28 11:23:32.951 INFO 6988 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: CompositePropertySource {name='NACOS', propertySources=[NacosPropertySource {name='shop-service-order-consumer.yaml'}]}
3、支持配置的动态更新
某些时候我们需要对于配置文件作出改动时,可在nacos配置中心直接修改而无需重启配置
spring-cloud-starter-alibaba-nacos-config 也支持配置的动态更新
例如
在nacos配置中心,新增配置user.username
controller
添加
@RefreshScope
打开动态刷新功能
package com.aishang.order.controller;
import com.aishang.order.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author Harry
* @ClassName OrderController
* @Description TODO:(一句话描述这个类)
*/
@RestController
@RefreshScope
public class OrderController {
@Value("${user.username}")
private String username;
@GetMapping("/refresh-test")
public String test (){
return username;
}
@Autowired
private OrderService orderService;
@GetMapping("/test/{str}")
public String test (@PathVariable("str") String str){
return "我是订单服务消费者 ->"+orderService.test(str);
}
}
访问http://localhost:9100/refresh-test
修改nacos配置中心的user.username的值为 hello 微服务
再次访问上述接口
则说明动态配置刷新成功!