服务注册与发现

一、服务注册与发现

通过服务注册与发现中心,解决服务间的相互发现问题:
在这里插入图片描述

1.1 概念

  • 服务注册 ,就是将提供某个服务的模块(服务提供者)信息注册到服务注册与发现中心上去
    • Dubbo------- zookeeper
    • SpringCloud Netflix ------- Eureka
    • SpringCloud Alibaba ------ Nacos
  • 服务发现 ,就是服务消费者通过服务注册与发现中心查询对应的服务提供者信息

1.2 注册中心对比

nacos :是阿里开源的,经过了阿里实践的
eureka :netflix公司的,现在不维护了,不开源了
Consul : HashiCorp 公司推出的开源产品,用于实现分布式系统的服务发现、服务隔离、服务配置
Zookeeper : Appache dubbo分布式框架的注册中心使用的是zookeeper
在这里插入图片描述
在这里插入图片描述

二、Nacos简介与安装

2.1 Nacos简介

官网:https://nacos.io/zh-cn/docs/what-is-nacos.html
Nacos /nɑ:kəʊs/ 是Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

  • 服务发现——服务注册与发现中心
  • 配置管理——分布式配置中心

2.2 Nacos安装

  1. 下载地址:https://github.com/alibaba/nacos/tags
  2. 解压(即安装)
  3. 创建数据库数据表要求数据库的版本必须是5.7或者以上创建名为nacos的数据库
    运用sql脚本文件nacos/conf/nacos-mysql.sql
  4. 配置nacos数据源
    在nacos/conf/application.properties配置数据库连接信息
  5. 修改nacos为单机模式
    在nacos/bin/startup.cmd修改为单机启动模式
  6. 启动并访问nacos
    启动:运行startup.cmd (注意:①必须要配置JAVA_HOME, ②nacos不要解压在中文目录)访问:浏览器访问http://localhost:8848/nacos/#/login
    输入账号密码:nacos/nacos

三、服务提供者 - 注册服务

向nacos注册一个可用于被访问的服务——服务提供者

3.1 SpringBoot与SpringCloud版本

  • 一个服务即一个SpringBoot应用,SpringCloud依赖SpringBoot,并且版本需要进行严格的对应
  • 通过查看springcloud alibaba 官网https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说

3.2 创建服务提供者

建议大家使用springcloud进行项目开发时,创建服务使用阿里的远程服务: https://start.aliyun.com

  • 创建SpringBoot应用,添加依赖
    在这里插入图片描述

  • 配置application.yml文件如下:

    • 服务端口
    • 服务名称
    • nacos服务注册与发现中心连接信息
server:
port: 9001
spring:
application:
name: product-basic-provider #指定servicename
cloud:
nacos:
discovery:
server-addr: localhost:8848 #指定注册中心的地址
username: nacos
password: nacos
ip: 127.0.0.1 #指定服务的监听ip地址
  • 启动类添加@EnableDiscoveryClient注解,开启服务注册与发现
@SpringBootApplication
@EnableDiscoveryClient //开启服务的注册与发现
public class ServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceProvider01Application.class, args);
}
}

3.3 开发服务提供者接口

根据商品id查询商品基本信息

  • 实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
private String productId;
private String productName;
private Double productPrice;
private String productDesc;
}
  • 接口
@RestController
@CrossOrigin
@RequestMapping("/product_basic")
public class ProductBasicController {
@GetMapping("/get/{productId}")
public Product get(@PathVariable("productId") String productId){
System.out.println("------服务提供者");
return new Product(productId,"哇哈哈AD钙奶",2.50,"好喝不长胖!");
}
}

3.4 商品套餐查询服务开发

  • 创建 product-sku-prodiver服务
    • lombok
    • spring web
    • nacos service
    • acturator
  • 配置服务的的application.yml文件
server:
port: 9002
spring:
application:
name: product-sku-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: nacos
password: nacos
ip: 127.0.0.1
  • 在启动类添加 @EnableDiscoveryClient注解
@SpringBootApplication
@EnableDiscoveryClient
public class ProductSkuProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProductSkuProviderApplication.class, args);
}
}
  • 完成商品套餐查询服务

    1.创建ProductSku实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProductSku {
private String skuId;
private String skuName;
private double skuPrice;
private String skuColor;
private int skuStore;
}

      2.创建商品套餐查询接口

@RestController
@CrossOrigin
@RequestMapping("/product_sku")
public class ProductSkuController {
// ..../product_sku/get/1 2---mi12
@GetMapping("/get/{productId}")
public List<ProductSku> get(@PathVariable("productId") String
productId){
System.out.println("---------服务提供者:product-sku-provider");
ArrayList<ProductSku> productSku = new ArrayList<>();
productSku.add( new ProductSku("101","mi12 标准版
8+128",3999.00,"黑色",9));
productSku.add( new ProductSku("102","mi12 高配版
12+256",4999.00,"黑色",17));
return productSku;
}
}

四、服务消费者 - 发现服务

4.1 创建服务消费者

  • 创建SpringBoot应用添加依赖
    在这里插入图片描述

  • 配置application.yml文件如下:

    • 服务端口
    • 服务名称
    • nacos服务注册与发现中心连接信息
server:
port: 8001
spring:
application:
name: product-detail-api #自定义服务名,保证唯一
cloud:
nacos:
discovery:
server-addr: localhost:8848 #指定nacos注册中心的连接地址
username: nacos
password: nacos
ip: 127.0.0.1 #指定服务监听ip地址
management:
endpoints:
web:
exposure:
include: "*" #暴露端点监控所有的endpoint
  • 启动类添加@EnableDiscoveryClient注解,开启服务注册与发现
@SpringBootApplication
@EnableDiscoveryClient
public class ProductDetailApiApplication {
public static void main(String[] args) {
SpringApplication.run(ProductDetailApiApplication.class, args);
}
}
  • 配置REST客户端(Ribbon负载均衡)
@Bean
@LoadBalanced //RestTemplate发送请求都要通过ribbon去(nacos注册中心)获取服务实例列public RestTemplate restTemplate(){
return new RestTemplate();
}

4.2 开发服务消费者

  • 创建与服务提供者返回数据相同的实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
private String productId;
private String productName;
private Double productPrice;
private String productDesc;
}
  • 创建ResultVO
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResultVO<T> {
private int code;
private String msg;
private T data;
}
  • 创建Service,调用服务查询商品基本信息、商品套餐信息
public interface ProductService {
public ResultVO getProductDetail(String productId);
}
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private RestTemplate restTemplate;
@Override
public ResultVO getProductDetail(String productId) {
//1.调用 product-basic-provider 服务 查询商品基本信息 (发送HTTP请求)
Product product = restTemplate.getForObject("http://product-basicprovider/product_basic/get/1", Product.class);
//2.调用 product-sku-provider 服务 查询商品的套餐信息 (发送HTTP请求)
//3.调用 product-img-provider 服务 查询商品的图片信息 (发送HTTP请求)
return new ResultVO(200,"success",product);
}
}
  • 创建接口,在接口中调用Service
@RestController
@CrossOrigin
@RequestMapping("/product")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/get/{productId}")
public ResultVO get(@PathVariable("productId") String productId){
ResultVO vo = productService.getProductDetail(productId);
return vo;
}
}

五、负载均衡 - Ribbon

Ribbon是Netflix公司开源的一个负载均衡的项目,是一个"客户端"负载均衡器,运行在客户端上

5.1 Ribbon配置

  • 添加依赖
    在这里插入图片描述

  • 配置

@Bean
@LoadBalanced //RestTemplate发送请求都要通过ribbon去(nacos注册中心)获取服务实例列public RestTemplate restTemplate(){
return new RestTemplate();
}

5.2 Ribbon负载均衡原理

  • 原理流程图
    在这里插入图片描述
  1. 当使用restTemplate对象向服务提供者发送请求时,被Ribbon的负载均衡拦截器进行拦截
  2. 拦截之后获取到调用的服务的服务名,向nacos查询这个服务名对应的可用的服务器地址列表
  3. Ribbon根据配置的负载均衡策略从服务器地址列表中选择一个服务器,并发送请求

5.3 Ribbon源码解析

  1. spring-cloud-starter-netflix-ribbon中的自动配置类,注入了负载均衡服务器拦截所有服务请求;
    在这里插入图片描述

  2. 负载均衡拦截器拦截到所有请求之后,通过nacos-server获取访问服务列表
    在这里插入图片描述
    在这里插入图片描述

  3. 根据负载均衡策略,选择一个服务
    在这里插入图片描述

  4. 负载均衡策略 (IRule接口的实现类)
    在这里插入图片描述
    在这里插入图片描述

5.4 配置负载均衡策略

  • 在配置类中注入IRule对象
@Bean
public IRule getRule(){
return new BestAvailableRule();
}

5.5 Ribbon参数传递

5.5.1 RestTemplate请求方法

SpringCloud的服务调用是基于REST的,因此当服务提供者规定了请求的方式,服务消费者必须发送对应方式的请求才能完成服务的调用,RestTemplate提供了多个方法用于发送不同形式的请求

//post方式请求
restTemplate.postForObject();
//get方式请求
restTemplate.getForObject();
//delete方式请求
restTemplate.delete();
//put方式请求
restTemplate.put();

5.5.2 put/post请求传参

  • 服务消费者请求传参
//参数1:访问服务的url
//参数2:传递的对象参数
//参数3:指定服务提供者返回的数据类型
ResultVO vo = restTemplate.postForObject("http://order-add/order/add", order,
ResultVO.class);
  • 服务提供者接收参数
@PostMapping("/add")
public ResultVO addOrder(@RequestBody Order order){
return orderService.saveOrder(order);
}

5.5.3 get请求传参

  • 服务消费者请求传参
String userId = order.getUserId();
ResultVO vo = restTemplate.getForObject("http://order-add/order/add?
userId="+userId, ResultVO.class);
  • 服务提供者接收参数
@GetMapping("/add")
public ResultVO addOrder(Order order){
return orderService.saveOrder(order);
}
@GetMapping("/add")
public ResultVO addOrder(String userId){
//return orderService.saveOrder(order);
}

六、服务消费 - OpenFeign

OpenFeign是对Ribbon进行封装、提供服务查询、服务负载均衡、服务调用及相关的扩展功能的服务调用客户端。

6.1 配置OpenFeign

  • 添加依赖如下:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

在这里插入图片描述

  • 配置application.yml
server:
port: 8001
spring:
application:
name: product-detail-api #自定义服务名,保证唯一
cloud:
nacos:
discovery:
server-addr: localhost:8848 #指定nacos注册中心的连接地址
username: nacos
password: nacos
ip: 127.0.0.1 #指定服务监听ip地址
  • 启动类添加@EnableFeignClients注解开启Feign客户端
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients //开启OpenFeign客户端
public class ProductDetailApiApplication {
public static void main(String[] args) {
SpringApplication.run(ProductDetailApiApplication.class, args);
}
}

6.2 使用OpenFeign

在product-detail-api服务的ProductServiceImpl中,调用Product-basic-provider服务中的接口

  1. 在服务消费者中创建一个用于调用服务的FeignClient(就是一个接口)
  • 创建一个接口
  • 在接口上添加@FeignClient注解,声明此接口调用的服务
  • 在接口中定义与被调用的服务中的Controller相同的方法(方法名、参数、返回类型、请求方式、请求路径)
@FeignClient("product-basic-provider")
public interface ProductBasicClient {
@GetMapping("/product_basic/get/{productId}")
public Product get(@PathVariable("productId") String productId);
}
  1. 在需要调用服务的Service类中,注入上面FeignClient的接口的对象,通过对象调用方法即完成服务调用
    在这里插入图片描述

6.3 Feign传参

http协议 服务消费者---------->服务提供者

  • get/1
  • get?pid=1
    在这里插入图片描述
    在这里插入图片描述

6.3.1 POST请求

  • 通过请求体传递对象

1.服务提供者

@PostMapping("/add")
public ResultVO addOrder(@RequestBody Order order){
System.out.println("-------------------order-add");
System.out.println(order);
return orderService.saveOrder(order);
}
  1. 服务消费者(Feign客户端)
@FeignClient("order-add")
public interface OrderAddClient {
//Feign客户端中的方法使用post/put请求时,参数会作为请求body传递,只能传递一个参数
@PostMapping("order/add")
public ResultVO addOrder(Order order);
}
  • 通过请求行传参

1.服务提供者

@PostMapping("/add")
public ResultVO addOrder(@RequestBody Order order,String str){
System.out.println("-------------------order-add");
System.out.println(order);
System.out.println(str);
return orderService.saveOrder(order);
}

2.服务消费者(Feign客户端)

//1.对用POST请求调用服务,Feign客户端的方法参数默认为body传值(body只能有一个值)
//2.如果有多个参数,则需要通过@RequestParam声明参数为请求行传值
@PostMapping("order/add")
public ResultVO addOrder(Order order,@RequestParam("str") String str);

6.3.2 Get请求

Get请求调用服务,只能通过url传参
在Feign客户端的方法中,如果不指定参数的传值方式,则默认为body传参,Get请求也不例外;因此对于get请求传递参数,必须通过@RequestParam注解声明

服务提供者

@RestController
@CrossOrigin
@RequestMapping("/product_img")
public class ProductImgController {
@GetMapping("/get")
public List<ProductImg> get(String productId){
System.out.println("------------服务提供者:product_img_provider---
"+productId);
ArrayList<ProductImg> productImgs = new ArrayList<>();
productImgs.add(new ProductImg(1,".../imgs/a.jpg",1));
productImgs.add(new ProductImg(2,".../imgs/b.jpg",2));
productImgs.add(new ProductImg(3,".../imgs/c.jpg",3));
return productImgs;
}
}

服务消费者(Feign客户端)

@FeignClient("product-img-provider")
public interface ProductImgClient {
// 在FeignClient中,接口中方法的参数如果不添加注解,则表示使用请求体传值
// 因此对于Get请求,参数必须通过@RequestParam注解进行声明
@GetMapping("/product_img/get")
public List<ProductImg> get(@RequestParam("productId") String productId);
}

6.4 服务的集群部署

服务的集群部署
测试Ribbon的负载均衡

  • 服务都是要注册到nacos中,同一个服务的多个节点服务名称要保持一致

  • 基于IDEA启动同一个服务/项目的多个实例

    • 设置IDEA允许一个SpringBoot项目多实例启动
    • 修改需要集群启动服务的配置文件中的port
    • 从服务启动类重新运行
      在这里插入图片描述
  • 基于SpringBoot应用的jar文件进行服务集群部署

    • 启动jar文件时,动态指定启动的port
java -jar product-basic-service-0.0.1-SNAPSHOT.jar --server.port=9002

6.5 服务访问超时设置

服务消费者(调用者)调用服务提供者时,可能因为网络震荡、服务提供者并发压力大、服务提供者出现故障,导致没有及时响应服务调用者;如果此时大量的请求访问服务调用者,就会导致服务调用者线程池耗尽而出现故障。
为了避免上述问题,我们可以设置调用者的超时设置——当服务调用者在调用服务时,如果在规定的时间没有获得相应,则停止等待,抛出超时异常。

ribbon:
ConnectTimeout: 1000 # 连接超时时间
MaxAutoRetries: 2 # 连接失败的最大重试次数
ReadTimeout: 1000 # 通信超时时间
http:
client:
enabled: true # 启用RibbonClient

七、Nacos领域模型

7.1 领域模型介绍

  • nacos的服务由三元组唯一确定 (namespace、group、servicename)
  • namespace:默认值为public
  • group:默认值为DEFAULT_GROUP
  • 微服务发现另外一个微服务,通过三元组去找服务
    在这里插入图片描述

7.2 注册服务到自定义命名空间

将服务发布到指定的命名空间和组中,通过namespace可以实现多环境服务隔离

  1. 创建新的命名空间
  2. 修改服务提供者配置文件,将服务发布到指定的命名空间
  • 不同的namespace中服务是相互隔离的,不能跨namespace访问
  • 相同的namespace,不同的group服务也是相互隔离的
    在这里插入图片描述
server:
port: 9001
spring:
application:
name: service-provider #指定servicename
cloud:
nacos:
discovery:
server-addr: localhost:8848 #指定注册中心的地址
username: nacos
password: nacos
ip: 127.0.0.1 #指定服务的监听ip地址
namespace: test #指定服务注册的命名空间,如果不指定默认为 public
group: DEFAULT_GROUP #指定服务注册的分组,如果不指定默认为
DEFAULT_GROUP

八、Nacos集群

https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html

8.1 集群部署架构图

开源的时候推荐用户把所有服务列表放到一个ip下面,然后挂到一个域名下面
http://ip1:port/openAPI 直连ip模式,机器挂则需要修改ip才可以使用。
http://SLB:port/openAPI 挂载SLB模式(内网SLB,不可暴露到公网,以免带来安全风险),直连SLB即可,下面挂server真实ip,可读性不好。
http://nacos.com:port/openAPI 域名 + SLB模式(内网SLB,不可暴露到公网,以免带来安全风险),可读性好,而且换ip方便,推荐模式
在这里插入图片描述

8.2 集群搭建

在这里插入图片描述

8.2.1 集群节点信息

服务名 ip 端口 备注
nacos1 192.168.2.8 8848 节点 1
nacos2 192.168.2.8 8858 节点 2
nacos3 192.168.2.8 8868 节点 3
nginx 192.168.2.8 80 反向代理nacos3个实例

8.2.2 nacos节点配置

application.properties 配置节点port 和 mysql数据源信息
在这里插入图片描述

server.port=8848
nacos.inetutils.ip-address=192.168.1.3
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?
characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=
true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=@QFedu123

cluster.conf配置节点列表 (需要在nacos/conf目录中,拷贝cluster.conf.example,修改为cluster.conf)

#2022-11-10T11:06:02.093
192.168.1.3:8848
192.168.1.3:8858
192.168.1.3:8868

bin/startup.cmd配置 (默认就是集群启动)

set MODE="cluster"

相同的配置部署三个nacos节点(端口分别为 8848 、 8858 、 8868 ,不要设置连续的端口)

8.2.3 nginx反向代理配置

nginx.conf

upstream nacoscluster {
server 192.168.1.3:8848;
server 192.168.1.3:8858;
server 192.168.1.3:8868;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://nacoscluster/;
}
}

九、Nacos分布式配置中心

注册中心(nacos),解决是服务的注册与发现
Ribbon:客户端负载均衡器,解决的是服务集群负载均衡的问题
OpenFeign:OpenFeign 是一种声明式、模板化的 HTTP 客户端,可以实现服务之间的远程调用
配置中心:?

9.1 为什么使用配置中心

在微服务架构中,服务应用很多,每个服务都有对应的配置文件(application.yml),如果将每个服务的配置文件放在服务应用中单独进行管理:

  • 问题 1 :服务很多,配置文件也很多,不便于查找和管理
  • 问题 2 :服务应用是需要打包进行部署的,单独管理时配置文件会一并打包到jar文件中,不方便后期维护

分布式配置中心的原理流程图:
在这里插入图片描述

使用分布式配置中对多个服务中的配置文件进行统一管理:查找方便、便于维护;实现对同一个服务的多环境配置

9.2 主流配置中心对比

目前市面上用的比较多的配置中心有:Spring Cloud Config、Apollo、Nacos和Disconf等。
由于Disconf不再维护,下面主要对比一下Spring Cloud Config、Apollo和Nacos。
在这里插入图片描述

  • 从配置中心角度来看,性能方面Nacos的读写性能最高,Apollo次之,Spring Cloud Config依赖Git场景不适合开放的大规模自动化运维API。
  • 功能方面Apollo最为完善,nacos具有Apollo大部分配置管理功能,而Spring CloudConfig不带运维管理界面,需要自行开发。
  • Nacos的一大优势是整合了注册中心、配置中心功能,部署和操作相比Apollo都要直观简单,因此它简化了架构复杂度,并减轻运维及部署工作。

nacos config 官网:https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-config

9.3 配置管理领域模型

在这里插入图片描述

9.4 置中心使用

文件名dataid约定为 p r e f i x − {prefix}- prefix{spring.profiles.active}.${file-extension}
在这里插入图片描述

9.4.1 创建命名空间

创建三个命名空间
在这里插入图片描述

9.4.2 命名空间下创建配置文件

  • 在dev命名空间,创建 service-name-dev.yml文件
  • 在test命名空间,创建 service-name-test.yml文件
  • 在pro命名空间,创建 service-name-pro.yml文件
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

9.4.3 服务加载配置文件

添加依赖

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

在服务端配置bootstrap.yml

spring:
cloud:
nacos:
config:
server-addr: localhost:8848
namespace: pro
group: DEFAULT_GROUP
prefix: product-detail-api
file-extension: yml
username: nacos
password: nacos
profiles:
active: pro

9.5 多环境切换

启动一个服务时,通过参数设置服务加载nacos分布式配置中心的不同版本的配置文件进行启动

9.5.1 开发环境切换版本

# 告知服务 目标文件在哪里 ,文件名按照${prefix}-${spring.profiles.active}.${fileextension}推导
spring:
cloud:
nacos:
config:
server-addr: localhost
namespace: test # 设置要加载的配置文件,在nacos分布式配置中心的命名空间
group: DEFAULT_GROUP
prefix: service-provider01
file-extension: yml
username: nacos
password: nacos
profiles:
active: test #设置要加载的配置文件的后缀

9.5.2 生产环境通过命令行参数切换版本

当将服务进行打包之后(jar包),启动服务时通过参数指定配置文件的命名空间和后缀来指定加载的配置文件

## 启动加载 test命名空间,active为test的配置
java -jar product-basic-service-0.0.1-SNAPSHOT.jar --
spring.cloud.nacos.config.namespace=test --spring.profiles.active=test
## 启动加载 pro命名空间,active为pro的配置
java -jar product-basic-service-0.0.1-SNAPSHOT.jar --
spring.cloud.nacos.config.namespace=pro --spring.profiles.active=pro

9.6 nacos配置动态刷新

动态刷新:不停机动态修改配置,立即生效
当配置中心中配置文件发生改变,无需重启服务就可以获取更新后的数据
在这里插入图片描述

9.7 配置文件版本管理

nacos为我们的分布式系统提供了统一的配置中心,同时如果我们在nacos中对配置文件进行了更新,nacos也会对配置文件进行把版本记录,便于我们进行版本之间的切换
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pswd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值