B003-springcloud alibaba 服务治理 nacos discovery ribbon feign

目录

服务治理

服务治理介绍

通过上一章的操作,我们已经可以实现微服务之间的调用。但是我们把服务提供者的网络地址(ip,端口)等硬编码到了代码中,这种做法存在许多问题:

一旦服务提供者地址变化,就需要手工修改代码

一旦是多个服务提供者,无法实现负载均衡功能

一旦服务变得越来越多,人工维护调用关系困难

那么应该怎么解决呢,这时候就需要通过注册中心动态的实现服务治理。

什么是服务治理

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

服务注册和心跳机制/续约:在服务治理框架中,都会构建一个注册中心,每个服务单元向注册中心登记自己提供服务的详细信息,并在注册中心形成一张服务的清单,服务注册中心需要以心跳的方式去监测清单中的服务是否可用,如果不可用,需要在服务清单中剔除不可用的服务。

服务发现:服务调用方向服务注册中心咨询服务,并获取所有服务的实例清单,实现对具体服务实例的访问。

相关方案

zookeeper

zookeeper是一个分布式服务框架,是Apache Hadoop的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。
consul

Consul是基于GO语言开发的开源工具,主要面向分布式,服务化的系统提供服务注册、服务发现和配置管理的功能。Consul的功能都很实用,其中包括:服务注册/发现、健康检查、Key/Value存储、多数据中心和分布式一致性保证等特性。Consul本身只是一个二进制的可执行文件,所以安装和部署都非常简单,只需要从官网下载后,在执行对应的启动脚本即可。
eureka

Eureka是Springcloud Netflix中的重要组件,主要作用就是做服务注册和发现。但是现在已经闭源
nacos

Nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。它是Spring Cloud Alibaba组件之一,负责服务注册发现和服务配置,可以这样认为nacos=eureka+config。

nacos实战入门

搭建nacos环境
安装nacos

下载地址:https://github.com/alibaba/nacos/releases

下载zip版本,解压缩

启动nacos

双击或命令行

复制代码
cd nacos/bin
startup.cmd -m standalone
访问nacos

打开浏览器输入http://localhost:8848/nacos,即可访问服务,默认密码是nacos/nacos

如果有服务注册进来会显示在服务列表

将商品微服务注册进nacos

导包

xml 复制代码
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

application.yml中添加nacos服务地址

yml 复制代码
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

启动类注解

java 复制代码
@SpringBootApplication
@EnableDiscoveryClient
public class ProductApp {

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

启动服务,观察nacos的控制面板中是否有注册上来的商品微服务

将订单微服务注册进nacos

导包,配置,启动类注解,都同上

订单服务通过nacos调用商品服务

OrderController

java 复制代码
    /**
     * 用nacos调用服务
     */
	@RequestMapping("/order/product2/{pid}")
    public Order createOrder2(@PathVariable("pid") Integer pid) {
        log.info("接收到{}号商品的下单请求,接下来调用商品微服务查询此商品信息", pid);
        // 调用商品微服务,查询商品信息
        List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
        ServiceInstance instance = instances.get(0);
        Product product = restTemplate.getForObject("http://" + instance.getHost() + ":" + instance.getPort() + "/product/" + pid, Product.class);
        log.info("查询到{}号商品的信息,内容是{}", pid, JSON.toJSONString(product));

        // 下单/创建订单
        Order order = new Order();
        order.setUid(1);
        order.setUsername("测试用户");
        order.setPid(product.getPid());
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(1);
        orderService.createOrder(order);
        log.info("创建订单成功,订单信息为{}", JSON.toJSONString(order));
        return order;
    }

浏览器访问测试:http://localhost:8091/order/product2/2

实现服务调用的负载均衡

什么是负载均衡

通俗的讲,负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元(服务器,组件)上进行执行。根据负载均衡发生位置的不同,一般分为服务端负载均衡和客户端负载均衡。

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

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

我们在微服务调用关系中一般会选择客户端负载均衡,也就是在服务调用的一方来决定服务由哪个提供者执行。

代码实现负载均衡
增加一个服务提供者

一个项目并行运行的第二种方式:

编辑配置 - 添加新配置 - springboot

设置新名称,如ProductApp2

设置启动类,如ProductApp

修改端口号,如虚拟机选项:-Dserver.port=8082

启动后可在nacos中看到增加了一个服务实例

自定义实现负载均衡

修改消费者中OrderController的代码

java 复制代码
    /**
     * 用nacos调用服务,并自定义实现负载均衡
     */
    @RequestMapping("/order/product3/{pid}")
    public Order createOrder3(@PathVariable("pid") Integer pid) {
        log.info("接收到{}号商品的下单请求,接下来调用商品微服务查询此商品信息", pid);
        // 调用商品微服务,查询商品信息
        List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
        int i = new Random().nextInt(instances.size());
        ServiceInstance instance = instances.get(i);
        log.info("第{}台机器,端口号是{}",i+1,instances.get(i).getPort());
        Product product = restTemplate.getForObject("http://" + instance.getHost() + ":" + instance.getPort() + "/product/" + pid, Product.class);
        log.info("查询到{}号商品的信息,内容是{}", pid, JSON.toJSONString(product));

        // 下单/创建订单
        Order order = new Order();
        order.setUid(1);
        order.setUsername("测试用户");
        order.setPid(product.getPid());
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(1);
        orderService.createOrder(order);
        log.info("创建订单成功,订单信息为{}", JSON.toJSONString(order));
        return order;
    }

浏览器访问测试:http://localhost:8091/order/product3/3

用ribbon实现负载均衡

添加LoadBalanced注解

java 复制代码
@SpringBootApplication
@EnableDiscoveryClient
public class OrderApp {

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

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

修改消费者的OrderController的代码

java 复制代码
    /**
     * 用nacos调用服务,并用ribbon实现负载均衡
     */
    @RequestMapping("/order/product4/{pid}")
    public Order createOrder4(@PathVariable("pid") Integer pid) {
        log.info("接收到{}号商品的下单请求,接下来调用商品微服务查询此商品信息", pid);
        // 调用商品微服务,查询商品信息
        Product product = restTemplate.getForObject("http://service-product/product/" + pid, Product.class);
        log.info("查询到{}号商品的信息,内容是{}", pid, JSON.toJSONString(product));

        // 下单/创建订单
        Order order = new Order();
        order.setUid(1);
        order.setUsername("测试用户");
        order.setPid(product.getPid());
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(1);
        orderService.createOrder(order);
        log.info("创建订单成功,订单信息为{}", JSON.toJSONString(order));
        return order;
    }

浏览器访问测试:http://localhost:8091/order/product4/1

如果想用默认的轮询以外的其他策略可在消费者的yml中加入以下配置

yml 复制代码
service-product: # 调用的提供者的名称
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

基于feign实现服务调用

什么是feign

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

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

feign的使用

导包

xml 复制代码
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>

启动类加注解

java 复制代码
@EnableFeignClients(basePackages = "cn.ming.client") //如果是主内所在子包,可以不用加basePackages,但是最好加上

调用接口

java 复制代码
@FeignClient(value = "service-product") //value用于指定调用nacos下哪个微服务
public interface ProductClient {

    // 商品信息查询
    @RequestMapping("/product/{pid}")   //@FeignClient的value + @RequestMapping的value值 其实就是完整的请求地址
    Product getProductByPid(@PathVariable("pid") Integer pid);
}

应用

java 复制代码
    /**
     * 用nacos调用服务,并用feign实现带有负载均衡的调用
     */
    @RequestMapping("/order/product5/{pid}")
    public Order createOrder5(@PathVariable("pid") Integer pid) {
        log.info("接收到{}号商品的下单请求,接下来调用商品微服务查询此商品信息", pid);
        // 调用商品微服务,查询商品信息
        Product product = productClient.getProductByPid(pid);
        log.info("查询到{}号商品的信息,内容是{}", pid, JSON.toJSONString(product));

        // 下单/创建订单
        Order order = new Order();
        order.setUid(1);
        order.setUsername("测试用户");
        order.setPid(product.getPid());
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(1);
        orderService.createOrder(order);
        log.info("创建订单成功,订单信息为{}", JSON.toJSONString(order));
        return order;
    }

浏览器访问测试:http://localhost:8091/order/product5/4

相关推荐
止语Lab29 分钟前
好的 DX 不等于少写代码——三种语言的摩擦力设计课
后端
吃饱了得干活29 分钟前
别再手动解析 LLM 输出了!LangChain 四种结构化输出方案对比
后端·python·langchain
程序员天天困35 分钟前
Arthas trace 命令怎么用?一行定位最慢那行代码
jvm·后端
Huiturn35 分钟前
GPT 5.6 连续编码 10 小时,纯 Python 啃下 Word 二进制格式——doc2docx 实现拆解
后端
用户2986985301441 分钟前
Python 实现 Excel 与 Markdown 互转的实用指南
后端·python·excel
用户772831049084044 分钟前
krono-job:零侵入、单二进制交付的分布式任务调度平台(开源)
后端
Conan在掘金1 小时前
鸿蒙报错速查:Function lacks ending return statement,返回路径漏 return 就炸,根因 + 真解法
后端
人间凡尔赛1 小时前
AI-Native 云原生架构:2026 年从容器编排到智能体编排的范式革命
后端·云原生·架构
IT_陈寒2 小时前
Vue的响应式让我加班到凌晨3点,原来问题出在这
前端·人工智能·后端
卷无止境2 小时前
提升 Python 代码健壮性的方法大盘点
后端·python