TypechoJoeTheme

香草物语

统计
登录
用户名
密码
/
注册
用户名
邮箱
输入密码
确认密码

Spring Cloud Alibaba笔记修订版-第三章Nacos Discovery--服务治理

Laughing博主
2022-11-24
/
0 评论
/
552 阅读
/
2422 个字
/
百度已收录
11/24
本文最后更新于2024年03月15日,已超过42天没有更新。如果文章内容或图片资源失效,请留言反馈,我会及时处理,谢谢!

一、什么是服务治理

服务治理是微服务架构中最核心最基本的模块,用于实现各个微服务的自动化注册与发现

  • 服务注册:在服务治理框架中,都会构建一个注册中心,每个服务单元向注册中心登记自己提供的服务的详细信息。并在注册中心形成一张服务清单,服务注册中心需要以心跳的方式去监测清单中的服务是否可用,若不可用,需要再服务清单中剔除不可用的服务。
  • 服务发现:服务调用方向服务注册中心咨询服务,保宁获取所有服务的实例清单,实现对具体服务实例的访问。

通过上面的图会发现,除了微服务,还有一个组件是服务注册中心,它是微服务架构中非常重要的一个组件,在微服务架构里起到了一个协调者的作用。

注册中心一般包含以下几个功能:

  1. 服务发现

    • 服务注册:保存服务提供者和服务调用者信息
    • 服务订阅:服务调用者订阅服务提供者的信息,注册中心向订阅者推送提供者信息
  2. 服务配置

    • 配置订阅:服务提供者和服务调用者订阅微服务相关配置
    • 配置下发:主动将配置推送给服务提供者和服务调用者
  3. 服务健康检测

    检测服务提供者的健康状况,如果发现异常,执行服务剔除

常见的服务注册中心包括:Zookeeper、Eureka、Consul、Nacos。

Nacos是Spring Cloud Alibaba组件之一,负责服务注册发现和服务配置,因为我们使用Spring Cloud Alibaba,所以这里只介绍Nacos的使用。

二、Nacos简介

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

三、搭建Nacos环境

注意

使用Nacos之前,需要先配置好Java环境变量。

我这里使用的服务器环境是Ubuntu 20.04,以下Nacos安装使用均以此为准,目前Nacos最新版本是2.1.2

Nacos下载地址:Releases · alibaba/nacos (github.com)

这里只介绍Nacos的基本使用,具体集群等高级用法,可以自行查找相关资料。

3.1、下载Nacos

下载nacos-server-2.1.2.tar.gz后,加压到任意位置。

3.2、Nacos数据库文件

运行Nacos之前,需要将Nacos数据库配置文件导入,我这里使用的是MySql,我直接导入上面Demo里面的数据库了。

MySql的语句如下

/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info   */
/******************************************/
CREATE TABLE `config_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(255) DEFAULT NULL,
  `content` longtext NOT NULL COMMENT 'content',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
  `app_name` varchar(128) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  `c_desc` varchar(256) DEFAULT NULL,
  `c_use` varchar(64) DEFAULT NULL,
  `effect` varchar(64) DEFAULT NULL,
  `type` varchar(64) DEFAULT NULL,
  `c_schema` text,
  `encrypted_data_key` text NOT NULL COMMENT '秘钥',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_aggr   */
/******************************************/
CREATE TABLE `config_info_aggr` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(255) NOT NULL COMMENT 'group_id',
  `datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
  `content` longtext NOT NULL COMMENT '内容',
  `gmt_modified` datetime NOT NULL COMMENT '修改时间',
  `app_name` varchar(128) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';


/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_beta   */
/******************************************/
CREATE TABLE `config_info_beta` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL COMMENT 'content',
  `beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  `encrypted_data_key` text NOT NULL COMMENT '秘钥',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_tag   */
/******************************************/
CREATE TABLE `config_info_tag` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
  `tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL COMMENT 'content',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_tags_relation   */
/******************************************/
CREATE TABLE `config_tags_relation` (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
  `tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
  `nid` bigint(20) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`nid`),
  UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = group_capacity   */
/******************************************/
CREATE TABLE `group_capacity` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值',
  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = his_config_info   */
/******************************************/
CREATE TABLE `his_config_info` (
  `id` bigint(20) unsigned NOT NULL,
  `nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `data_id` varchar(255) NOT NULL,
  `group_id` varchar(128) NOT NULL,
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL,
  `md5` varchar(32) DEFAULT NULL,
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `src_user` text,
  `src_ip` varchar(50) DEFAULT NULL,
  `op_type` char(10) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  `encrypted_data_key` text NOT NULL COMMENT '秘钥',
  PRIMARY KEY (`nid`),
  KEY `idx_gmt_create` (`gmt_create`),
  KEY `idx_gmt_modified` (`gmt_modified`),
  KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';


/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = tenant_capacity   */
/******************************************/
CREATE TABLE `tenant_capacity` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';


CREATE TABLE `tenant_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `kp` varchar(128) NOT NULL COMMENT 'kp',
  `tenant_id` varchar(128) default '' COMMENT 'tenant_id',
  `tenant_name` varchar(128) default '' COMMENT 'tenant_name',
  `tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
  `create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
  `gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
  `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';

CREATE TABLE `users` (
    `username` varchar(50) NOT NULL PRIMARY KEY,
    `password` varchar(500) NOT NULL,
    `enabled` boolean NOT NULL
);

CREATE TABLE `roles` (
    `username` varchar(50) NOT NULL,
    `role` varchar(50) NOT NULL,
    UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
);

CREATE TABLE `permissions` (
    `role` varchar(50) NOT NULL,
    `resource` varchar(255) NOT NULL,
    `action` varchar(8) NOT NULL,
    UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
);

INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);

INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');

3.3、配置Nacos

conf文件夹下有一个application.properties,我们需要配置里面的数据库连接信息

把大概34行往下的位置,取消注释并根据自己情况进行配置

### If use MySQL as datasource:
spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/shop?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=root

3.4、运行Nacos

进入bin文件夹

执行

./startup.sh -m standalone

Nacos启动后,浏览器输入localhost:8848/nacos

默认用户名及密码都是nacos

四、将商品微服务注册到Nacos

我们改造商品微服务,以便支持Nacos

4.1、修改配置文件

增加Nacos依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2021.0.4.0</version>
</dependency>

4.2、主类上注解@EnableDiscoveryClient

@SpringBootApplication
@EntityScan({"net.xiangcaowuyu.shop.common.entity"})
@EnableDiscoveryClient
public class ProductApplication {

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

}

4.3、配置文件添加nacos服务的地址

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.236.2:8848

修改后配置文件如下

server:
  port: 8081
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.236.2:8848
  application:
    name: service-user
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.236.2/shop?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=true
    username: root
    password: root
  jpa:
    hibernate:
      #指定为update,每次启动项目检测表结构有变化的时候会新增字段,表不存在时会新建,如果指定create,则每次启动项目都会清空数据并删除表,再新建
      ddl-auto: update
      naming:
        #指定jpa的自动表生成策略,驼峰自动映射为下划线格式
        implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
    # 默认false,在日志里显示执行的sql语句
    show-sql: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL5Dialect
    database: mysql
    database-platform: org.hibernate.dialect.MySQL5Dialect

4.4、查看服务是否注册成功

重新启动product微服务

服务名就是我们配置文件配置的应用名称。

五、将订单微服务注册到Nacos

我们改造订单微服务,以便支持Nacos

5.1、修改配置文件

增加Nacos依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2021.0.4.0</version>
</dependency>

5.2、主类上注解@EnableDiscoveryClient

@SpringBootApplication
@EntityScan({"net.xiangcaowuyu.shop.common.entity"})
@EnableDiscoveryClient
public class OrderApplication {

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

}

5.3、配置文件添加nacos服务的地址

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.236.2:8848

修改后配置文件如下

server:
  port: 8091
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.236.2:8848
  application:
    name: service-user
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.236.2/shop?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=true
    username: root
    password: root
  jpa:
    hibernate:
      #指定为update,每次启动项目检测表结构有变化的时候会新增字段,表不存在时会新建,如果指定create,则每次启动项目都会清空数据并删除表,再新建
      ddl-auto: update
      naming:
        #指定jpa的自动表生成策略,驼峰自动映射为下划线格式
        implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
    # 默认false,在日志里显示执行的sql语句
    show-sql: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL5Dialect
    database: mysql
    database-platform: org.hibernate.dialect.MySQL5Dialect

5.4、查看服务是否注册成功

重新启动product微服务

服务名就是我们配置文件配置的应用名称。

5.5、改造订单接口,实现微服务调用

package net.xiangcaowuyu.shop.order.controller;

import lombok.extern.slf4j.Slf4j;
import net.xiangcaowuyu.shop.common.entity.Product;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.List;

@RestController
@RequestMapping("order")
@Slf4j
public class OrderController {

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private DiscoveryClient discoveryClient;

    @GetMapping("product/{id}")
    public Product order(@PathVariable("id") Integer productID) {
        List<ServiceInstance> serviceInstanceLList = discoveryClient.getInstances("service-product");
        log.info("获取到服务:" + serviceInstanceLList.size());
        //忽略下面可能导致的错误
        ServiceInstance serviceInstance = serviceInstanceLList.get(0);
        return restTemplate.getForObject(serviceInstance.getUri() + "/product/1", Product.class);
    }

}

浏览器访问订单接口

六、负载均衡

通俗的讲,负载均衡就是将负载(工作任务、访问请求)进行分摊到多个操作单元(服务器、组件)上进行执行。

根据负载均衡发生的位置不同,一般分为服务端负载均衡客户端负载均衡

服务端负载均衡指的是发生在服务提供者一方,比如nginx负载均衡

客户端负载均衡指的是发生在服务请求一方,也就是在发送请求之前已经选好了由那个实例处理请求。

微服务调用关系中一般会选择客户端负载均衡。

6.1、准备负载均衡环境

为了实现负载均衡,我们需要准备至少两个服务,这里以商品服务为例。

在上面的代码中,我们pom.xml文件都没有加入打包的插件,为了启动两个服务,我们需要现将程序打包成jar包。在shop-usershop-productshop-order三个模块都加入打包插件。

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

6.2、准备商品微服务

为了区分调用的服务,我们在商品服务输出一下端口号。

package net.xiangcaowuyu.shop.product.controller;

import lombok.extern.slf4j.Slf4j;
import net.xiangcaowuyu.shop.common.entity.Product;
import net.xiangcaowuyu.shop.product.service.ProductService;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
@Slf4j
public class ProductController {

    @Resource
    private ProductService productService;

    @Resource
    private Environment environment;

    @GetMapping("/product/{id}")
    public Product product(@PathVariable("id") Integer ID) {
        log.error("当前端口号:" + environment.getProperty("local.server.port"));
        return productService.findByID(ID);
    }
}

然后将shop-product打包成jar包,通过一下命令,启动两个服务

java -jar shop-product-1.0-SNAPSHOT.jar --server.port=8081
java -jar shop-product-1.0-SNAPSHOT.jar --server.port=8082

此时打开Nacos,可以看到shop-product有两个服务

此时,我们运行订单工程,访问接口

http://127.0.0.1:8091/order/product/1

多次刷新之后,可以用看到服务全部都打到了8081端口上。

8082一条都没有,可见并没有实现负载均衡。

6.3、基于Ribbon实现负载均衡

Ribbon是Spring Cloud的一个组件,它可以让我们使用一个注解就能轻松搞定负载均衡。

nacos 2021版本已经没有自带Ribbon的整合,所以需要引入另一个支持的jar包 loadbalancer

shop-order中引入loadbalancer实现Ribbon支持

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

RestTemplate上注解上@LoadBalanced即可。

package net.xiangcaowuyu.shop.order.config;

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 OrderConfiguration {

    @LoadBalanced
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

}

改造接口,通过服务名访问

package net.xiangcaowuyu.shop.order.controller;

import lombok.extern.slf4j.Slf4j;
import net.xiangcaowuyu.shop.common.entity.Product;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.List;

@RestController
@RequestMapping("order")
@Slf4j
public class OrderController {

    @Resource
    RestTemplate restTemplate;

    @Resource
    DiscoveryClient discoveryClient;

    @GetMapping("product/{id}")
    public Product order(@PathVariable("id") Integer productID) {
        String serviceName = "service-product";
        return restTemplate.getForObject("http://"+serviceName + "/product/1", Product.class);
    }

}

此时,我们运行订单工程,访问接口

http://127.0.0.1:8091/order/product/1

多次刷新之后,可以用看到服务平均打到了80818082端口。

Ribbon默认的均衡策略是轮训。

Ribbon自带的负载均衡策略

我们可以通过修改配置文件改变默认的负载均衡策略。

Ribbon 已经在最新的Spring Cloud 版本中被废弃,Spring Cloud Loadbalancer 是官方正式推出的一款新负载均衡利器,在未来,LoadBalancer 很有可能取代Ribbon的地位成为新一代的负载均衡器

6.4、基于Feign实现负载均衡

Feign是Spring Cloud提供的一个声明式的伪HTTP客户端,它使得调用远程服务就像调用本地服务一样简单,只需要创建一个接口并添加注解即可。

Nacos很好的兼容了Feign,Feign默认集成了Ribbon,所以在Nacos下使用Feign默认就实现了负载均衡的效果。

在进行一下代码之前,记得先移除6.3添加的Ribbon相关的代码

我们改造shop-order工程,实现Feign的使用

6.4.1、引入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>

6.4.2、在主类上添加Feign注解

package net.xiangcaowuyu.shop.order;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EntityScan({"net.xiangcaowuyu.shop.common.entity"})
@EnableDiscoveryClient
@EnableFeignClients
public class OrderApplication {

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

}

6.4.3、添加一个service

package net.xiangcaowuyu.shop.order.Service;

import net.xiangcaowuyu.shop.common.entity.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("service-product")
public interface ProductService {

    @GetMapping("/product/{id}")
    Product findByID(@PathVariable("id") Integer id);

}

Feign调用服务的地址就是@FeignClient+@GetMapping(获取其他映射)的地址

6.4.4、改造Controller

package net.xiangcaowuyu.shop.order.controller;

import lombok.extern.slf4j.Slf4j;
import net.xiangcaowuyu.shop.common.entity.Product;
import net.xiangcaowuyu.shop.order.Service.ProductService;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.List;

@RestController
@RequestMapping("order")
@Slf4j
public class OrderController {

    @Resource
    ProductService productService;

    @GetMapping("product/{id}")
    public Product order(@PathVariable("id") Integer productID) {
        return productService.findByID(productID);
    }

}

此时,我们运行订单工程,访问接口

http://127.0.0.1:8091/order/product/1

多次刷新之后,可以用看到服务平均打到了80818082端口。

6.4.5、修改轮训策略

以前的Ribbon有多种负载均衡策略但LoadBalancer貌似只提供了两种负载均衡器,不指定的时候默认用的是轮询。

  • RandomLoadBalancer 随机
  • RoundRobinLoadBalancer 轮询

添加LoadBalance配置类

package net.xiangcaowuyu.shop.order.config;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.loadbalancer.NacosLoadBalancer;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;

import javax.annotation.Resource;

public class MyLoadBalancerConfig {

    @Resource
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    //自定义loadBlancer负载均衡策略
    @Bean
    public ReactorServiceInstanceLoadBalancer reactorServiceInstanceLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);

        //返回随机轮询负载均衡方式
        return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);

        //返回加权随机轮询负载均衡方式
        //return new RoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);

        //nacos服务注册中心权重的负载均衡策略
//        return new NacosLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name, nacosDiscoveryProperties);
    }

}

启动类上配置服务使用的负载均衡策略

package net.xiangcaowuyu.shop.order;

import net.xiangcaowuyu.shop.order.config.MyLoadBalancerConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EntityScan({"net.xiangcaowuyu.shop.common.entity"})
@EnableDiscoveryClient
@EnableFeignClients
@LoadBalancerClients(value =
@LoadBalancerClient(name = "service-product",configuration = MyLoadBalancerConfig.class))
public class OrderApplication {

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

此时,我们运行订单工程,访问接口

http://127.0.0.1:8091/order/product/1

多次刷新之后,可以用看到服务随机打到了80818082端口。

Spring CloudRibbonSpring BootNacosSpring Cloud AlibabaLoadBalancer
朗读
赞(0)
赞赏
感谢您的支持,我会继续努力哒!
版权属于:

香草物语

评论 (0)