SpringCloud学习笔记(五、视图微服务-RIBBON)

本文涉及的产品
云原生网关 MSE Higress,422元/月
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: SpringCloud学习笔记(五、视图微服务-RIBBON)

RIBBON是什么?

前面已经做好了数据微服务,现在是时候整个视图微服务访问前面注册好的数据微服务了。 springcloud 提供了两种方式,一种是 Ribbon,一种是 Feign。

Ribbon 是使用 restTemplate 进行调用,并进行客户端负载均衡。 什么是客户端负载均衡呢? 在前面 注册数据微服务  里,注册了8001和8002两个微服务, Ribbon 会从注册中心获知这个信息,然后由 Ribbon  这个客户端自己决定是调用哪个,这个就叫做客户端负载均衡。

Feign 是什么呢? Feign 是对 Ribbon的封装,调用起来更简单。

建立子项目

创建子项目 product-view-service-ribbon:

image.png

pom.xml

spring-cloud-starter-netflix-eureka-client: eureka 客户端

spring-boot-starter-web: springmvc

spring-boot-starter-thymeleaf: thymeleaf 做服务端渲染

<?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>springcloud</artifactId>
        <groupId>edu.hpu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>product-view-service-ribbon</artifactId>
    <name>product-view-service-ribbon</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>  <!--eureka 客户端-->
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>  <!--SpringMvc-->
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>
</project>
实体类
package edu.hpu.springcloud.pojo;
public class Product {
    private int id;
    private String name;
    private int price;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getPrice() {
        return price;
    }
    public void setPrice(int price) {
        this.price = price;
    }
    public Product(int id, String name, int price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }
    public Product() {
    }
}
Ribbon 客户端

Ribbon 客户端, 通过 restTemplate 访问 http://PRODUCT-DATA-SERVICE/products , 而 product-data-service 既不是域名也不是ip地址,而是 数据服务在 eureka 注册中心的名称。

看一下注册中心:

image.png上面那个地址只指定了服务,没有指定端口号。

package edu.hpu.springcloud.client;
import edu.hpu.springcloud.pojo.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.List;
//Ribbon 客户端
@Component
public class ProductClientRibbon {
    @Autowired
    RestTemplate restTemplate;
    public List<Product> listProcucts(){
        return restTemplate.getForObject("http://PRODUCT-DATA-SERVICE/products",List.class);
    }
}
服务层

服务层数据从客户端获取

package edu.hpu.springcloud.service;
import edu.hpu.springcloud.client.ProductClientRibbon;
import edu.hpu.springcloud.pojo.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ProductService {
    @Autowired
    ProductClientRibbon productClientRibbon;
    public List<Product> listProducts(){
        return productClientRibbon.listProcucts();   //从productClientRibbon中获得数据服务
    }
}
控制层
package edu.hpu.springcloud.controller;
import edu.hpu.springcloud.pojo.Product;
import edu.hpu.springcloud.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@Controller
public class ProductController {
    @Autowired
    ProductService productService;
    @RequestMapping("/products")
    public Object products(Model m){
        List<Product> ps=productService.listProducts();
        m.addAttribute("ps",ps);
        return "products";
    }
}
视图

视图采用thymeleaf:

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>products</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <style>
        table {
            border-collapse:collapse;
            width:400px;
            margin:20px auto;
        }
        td,th{
            border:1px solid gray;
        }
    </style>
</head>
<body>
<div class="workingArea">
    <table>
        <thead>
        <tr>
            <th>id</th>
            <th>产品名称</th>
            <th>价格</th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="p: ${ps}">
            <td th:text="${p.id}"></td>
            <td th:text="${p.name}"></td>
            <td th:text="${p.price}"></td>
        </tr>
        </tbody>
    </table>
</div>
</body>
</html>
配置

application.yml,eureka server 的地址,以及自己的名称。 另外是一些 thymeleaf 的默认配置

eureka:
  clg: UTF-8
    content-type: text/html
    mode: HTML5ient:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
spring:
  application:
    name: product-view-service-ribbon
  thymeleaf:
    cache: false
    prefix: classpath:/templates/
    suffix: .html
    encodin
启动类

ProductDataServiceApplication,

启动类, 注解多了个 @EnableDiscoveryClient, 表示用于发现eureka 注册中心的微服务。

还多了个 RestTemplate,就表示用 restTemplate 这个工具来做负载均衡

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

在ribbon客户端中使用了这个RestTemplate.

package edu.hpu.springcloud;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NetUtil;
import cn.hutool.core.util.NumberUtil;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@SpringBootApplication
@EnableEurekaClient
public class ProductDataServiceApplication {
    public static void main(String[] args) {
        int port = 0;
        int defaultPort = 8003;
        Future<Integer> future = ThreadUtil.execAsync(() ->{
            int p = 0;
            System.out.println("请于5秒钟内输入端口号, 推荐  8001 、 8002  或者  8003,超过5秒将默认使用 " + defaultPort);
            Scanner scanner = new Scanner(System.in);
            while(true) {
                String strPort = scanner.nextLine();
                if(!NumberUtil.isInteger(strPort)) {
                    System.err.println("只能是数字");
                    continue;
                }
                else {
                    p = Convert.toInt(strPort);
                    scanner.close();
                    break;
                }
            }
            return p;
        });
        try{
            port=future.get(5, TimeUnit.SECONDS);
        }
        catch (InterruptedException | ExecutionException | TimeoutException e){
            port = defaultPort;
        }
        if(!NetUtil.isUsableLocalPort(port)) {
            System.err.printf("端口%d被占用了,无法启动%n", port );
            System.exit(1);
        }
        new SpringApplicationBuilder(ProductDataServiceApplication.class).properties("server.port=" + port).run(args);
    }
}
运行访问

image.png

调用图示

这里面三个角色,注册中心、服务提供者、服务消费者,数据微服务作为服务提供者,视图微服务作为服务消费者。

1、 首先数据微服务和视图微服务都被 eureka 管理起来了。

2、 数据服务是由三个实例的集群组成的,端口分别是 8001 , 8002,8003。

3、视图微服务通过 注册中心调用微服务, 然后负载均衡到 8001 、8002或者8003端口的应用上。

image.png

错误

1、springCloud com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused: connect

在默认设置下,Eureka服务注册中心也会将自己作为客户端来尝试注册它自己,所以我们需要禁用它的客户端注册行为。

禁止方式如下:在application.properties配置文件中增加以下内容

eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

.yml也差不多,写的时候注意级别就行了。

2、低级错误:注册中心和数据微服务没启动

中间关了IJ,直接启动视图微服务,爆了一堆错,一想,是注册中心和数据微服务没启动,它向谁请求、调用谁去。

3、java.lang.IllegalStateException: No instances available for PRODUCT-DATA-SERVICE

找不到这个实例,我们看一下注册中心,看看数据微服务叫什么名字。

image.png似乎也没什么错,不算了,直接给它粘贴到客户端。OK。

4、java.net.ConnectException: Connection refused: connect

刷新页面的时候发现报了这么个错误,负载均衡一到数据微服务8002这个端口的时候就报错,似乎是被占用了吧,我又注册个端口为8003的数据微服务,这个端口倒是没有问题。

image.png

参考:

【1】、http://how2j.cn/k/springcloud/springcloud-ribbon/2040.html#nowhere

【2】、https://blog.csdn.net/qq_39930369/article/details/87616077

【3】、https://www.cnblogs.com/zmblog/p/8777878.html


相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
|
1月前
|
负载均衡 监控 网络协议
SpringCloud之Ribbon使用
通过以上步骤,就可以在Spring Cloud项目中有效地使用Ribbon来实现服务调用的负载均衡,提高系统的可靠性和性能。在实际应用中,根据具体的业务场景和需求选择合适的负载均衡策略,并进行相应的配置和优化,以确保系统的稳定运行。
49 15
|
1月前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
51 5
|
3月前
|
负载均衡 Java Nacos
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
微服务介绍、SpringCloud、服务拆分和远程调用、Eureka注册中心、Ribbon负载均衡、Nacos注册中心
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
|
4月前
|
负载均衡 算法 Java
SpringCloud之Ribbon使用
通过 Ribbon,可以非常便捷的在微服务架构中实现请求负载均衡,提升系统的高可用性和伸缩性。在实际使用中,需要根据实际场景选择合适的负载均衡策略,并对其进行适当配置,以达到更佳的负载均衡效果。
96 13
|
6月前
|
负载均衡 算法 Java
Spring Cloud Netflix 之 Ribbon
Spring Cloud Netflix Ribbon是客户端负载均衡器,用于在微服务架构中分发请求。它与RestTemplate结合,自动在服务发现(如Eureka)注册的服务之间进行调用。配置包括在pom.xml中添加依赖,设置application.yml以连接Eureka服务器,并在配置类中创建@LoadBalanced的RestTemplate。通过这种方式,当调用如`/user/userInfoList`的接口时,Ribbon会自动处理到多个可用服务实例的负载均衡。
|
6月前
|
缓存 负载均衡 Java
Java一分钟之-Spring Cloud Netflix Ribbon:客户端负载均衡
【6月更文挑战第9天】Spring Cloud Netflix Ribbon是客户端负载均衡器,用于服务间的智能路由。本文介绍了Ribbon的基本概念、快速入门步骤,包括添加依赖、配置服务调用和使用RestTemplate。此外,还讨论了常见问题,如服务实例选择不均、超时和重试设置不当、服务列表更新不及时,并提供了相应的解决策略。最后,展示了如何自定义负载均衡策略。理解并正确使用Ribbon能提升微服务架构的稳定性和效率。
228 3
|
7月前
|
负载均衡 算法
SpringCloud&Ribbon负载均衡原理与实践
SpringCloud&Ribbon负载均衡原理与实践
81 3
|
7月前
|
负载均衡
【SpringCloud】Ribbon负载均衡原理、负载均衡策略、饥饿加载
【SpringCloud】Ribbon负载均衡原理、负载均衡策略、饥饿加载
89 0
|
29天前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
97 6
|
29天前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
38 1