SpringCloud入门Day01-服务注册与发现、服务通信、负载均衡与算法

news2024/11/23 7:13:03

SpringCloudNetflix入门

一、应用架构的演变

  • 伴随互联网的发展,使用互联网的人群越来越多,软件应用的体量越来越大和复杂。
  • 而传统单体应用 可能不足以支撑大数据量以及发哦并发场景
  • 应用的框架也随之进行演变
  • 从最开始的单体应用架构到分布式(SOA)架构到 今天比较火的微服务框架,以及微服务网格架构。

​ 单体–>分布式–>SOA–>微服务–>…

1、单体应用

1.1 什么是单体应用

  • 传统的应用就是单体架构,即所有的模块、组件等都在一个应用中,最终打包(war,jar),使用一个容器(如Tomcat)进行部署,且通常一个应用享用一个数据库。

在这里插入图片描述

  • 将单体应用分为三个组成部分:持久层、业务层、表现层。
  • 单体应用在初期:业务少没有问题
  • 单体应用需求不断增多,也伴随着业务逻辑、业务组件等日益扩张,应用将会变得越来越臃肿往后的开发和维护就会变得特别麻烦,
  • 再着越来越大访的问量,并发越来越高,面对海量的用户无论从应用性能还是从数据库方面都有吃不消的时候。
  • 所以,单体应用在数据量、并发量到一定程度时一定会遇到瓶颈。

1.2 单体框架的优缺点

1.2.1 单体项目缺点

  • 代码臃肿不方便开发维护(代码可读性差)
  • 代码编译系统启动变慢
  • 系统扩展性能变差(牵一发而动全身)
  • 无法针对某一个业务做扩展(集群)
  • 对大数据量,高并发量的处理不占优势
  • 技术选型单一
  • 模块/业务耦合度高

1.2.2 单体项目的优点

  • 易于开发 :架构简单,技术成本低
  • 易于测试 :所有功能在一个项目,方便测试
  • 易于部署 :一个Tomcat就可以实现部署,简单方便

1.3 单体应用于集群

  • 问题引入:
    • 在单体架构中,为提升应用的并发 和 防止单节点故障(一个Tomcat挂,应用就挂了),通常就会做集群。

1.3.1 什么是集群

  • 集群:多个单体项目合成一个集群
    • 这里的集群指:复制多个相同应用共同工作来提高作业能力,多个应用做相同的事。

在这里插入图片描述

1.3.2 单体应用于集群带来的问题

  • 当应用做集群,就会存在多个应用节点,这些节点将会暴露多个访问地址(ip:port),那么客户端是不知道该访问那个应用节点的
    • 为解决客户端不知道访问那个应用节点,就需要有一个请求分发的功能的组件(负载均衡器)将将客户端的请求相对平均的分发多个应用节点上,这就是负载均衡,而这个做请求分发的组件就是负载均衡器。

在这里插入图片描述

  • 这里的Nginx就是一个负载均衡器,它可按某种算法(轮询、ip_hash等)清请求路由分发到不同的后端服务器上,同类型负载均衡器有 HAproxy、LVS等。

  • 负载均衡算法如:轮询、随机、权重。

  • 每个功能模块使用并发数量不同,有些模块使用特别多,有些模块使用的量少

    • 解决思路:将重复的功能提取成模块,可根据需求量做集群,这些模块组合成一个完整的项目。

在这里插入图片描述

  • 上图描述
    • 每个模块就是一个项目
    • 每个项目都可以单独的做技术选型、部署、运维、维护
    • 其实该图就是一个简单的微服务了

1.4 单体项目的举例

  • 前端分离

2.分布式于SOA

2.1 分布式架构

2.2 面向服务的架构SOA

3. 微服务架构

3.1 什么是微服务

  • 微服务架构可以认识为 是一种SOA架构上的一种发展,最早由“Martin Fowler”提出:
就目前而言,对于微服务业界并没有一个统一的、标准的定义(While there is no precise definition of this architectural style ) 。但通常而言,`微服务架构是一种架构模式或者说是一种架构风格,它提倡将单一应用程序划分成一组小的服务,每个服务运行独立的自己的进程中,服务之间互相协调、互相配合,为用户提供最终价值。服务之间采用轻量级的通信机制互相沟通(通常是基于 HTTP 的 RESTful API )` 。每个服务都围绕着具体业务进行构建,并且能够被独立地部署到生产环境、类生产环境等。

另外,应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建,可以有一个非常轻量级的集中式管理来协调这些服务。可以使用不同的语言来编写服务,也可以使用不同的数据存储。
  • 从“Martin Fowler”提出观点来看,微服务架构 和 SOA 架构很像。总体来说,微服务:就是把单体应用进行进行细粒度的拆分,分成多个小(微)的服务,每个服务独立运行,每个服务只需要专注一个业务即可,并且每个服务都可以有自己的数据库(分库),服务之间互协调配合完成整个系统的业务。

  • 简单的来说,微服务:就是将一个单体项目根据需求,拆分为多个模块,每个模块就是一个项目,每个项目都可以单独的做

    技术选型、部署、运维、维护。再根据每个模块的并发量做集群。

  • 微服务机构图

在这里插入图片描述

  • 微服务做集群
    在这里插入图片描述

  • 微服务特点

    • 由多个服务组成完整的系统
    • 每个服务都是独立的,有自己的进程
    • 服务之间使用HTTP协议通信
    • 不同的服务可以使用不同的编程语言
    • 不同的服务的数据库可以多样化选择
    • 微服务是一个分布式系统
  • 微服务拆分做集群带来的问题

    • 模块之间需要通讯
    • 对于集群服务,需要负载均衡
    • 事务 怎么解决
    • session怎么处理,识别当前的用户问题
  • 解决问题的办法

    • SpringCloud
    • SpringCloud Alibaba
    • 它们是解决微服务拆分带来的一系列问题

3.2 微服务的优缺点

  • 优点
    • 单个服务业务简单,代码简单方便开发维护
    • 服务之间无耦合,服务之间升级维护互不影响
    • 轻量级HTTP通信机制,使得的不同的服务可以采用不同的编程语言
    • 微服务有极强的扩展能力,业务量大的服务可以再次拆分服务,也可以进行集群部署,剔除服务也很方便
    • 更大的系统负载能力和容错能力(集群)
    • 对于开发人员来说,通常只需要关注单一服务,新员工上手也比较快
    • 微服务架构对现在流行的敏捷开发支持优化
  • 缺点
    • 分布式事务 :服务通信机制增加了事务的复杂性,架构师要选择合适的分布式方案(CAP理论)
    • 部署麻烦 :微服务众多,部署麻烦,需要借助容器技术和自动化部署工具,这又增加了开发人员的学习成本。
    • 技术成本高 :微服务架构本身比较复杂,技术成本高,开发人员需要花更多的时间学习相关技术。
    • 服务通信对性能的损耗 : 微服务架构一定要考虑服务通信延迟对服务调用性能的损耗问题,开发人员需要选择合适的通信方式解决这一问题。

3.3 如何选型

  • 大型项目选择微服务,如电商,物流,售票等系统我们可以选择使用微服务架构
  • 中小型项目,选择单体

二、SpringCloud 介绍

1、认识SpringCloud

  • SpringCloud 是一个基于SpringBoot实现的服务治理工具包,用于微服务架构中 管理和协调服务的。
  • Spring Cloud是一系列框架的有序集合。
  • SpringCloud 利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。
  • SpringCloud 通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
  • SpringCloud让微服务架构的落地变得更简单。

2、SpringCloud常用组件

  • 采用微服务后就会引发一些列的难题需要去解决,如
    • 众多微服务的通信地址应该如何管理
    • 微服务之间应该使用何种方式发起调用
    • 微服务故障该如何处理
    • 众多微服务的配置文件如何集中管理等
  • SpringCloud为这一系列的难题提供了相应的组件来解决,如下图SpringCloud最核心

在这里插入图片描述

  • Netfli Eureka(注册中心)

    • Eureka 是用来管理微服务的通信地址清单,有了Eureka后,就可通过服务名字 实现 服务的调用。
  • Netflix Ribbon/Feign (远程调用,客户端负载均衡)

    • Ribbon 与 Feign 都是客服端负载均衡器。
    • 作用:服务发生调用时,将请求按某种规则分发到多个目标服务器上。
    • 简单理解激素是解决微服务之间的通信问题。
  • Netflix Hystrix(断路器/熔断器)

    • 有时一个请求需要多个微服务共同完成,那么一旦某个服务发生故障导致整个调用链上的微服务全都出现异常,甚至导致整个微服务架构瘫痪。
    • 作用:Hystrix就是解决微服务故障,保护服务安全的组件。
  • Netflix Zuul(服务网关)

    • zuul作为服务网关,可将它看作是微服务的大门,所有的请求都需要经过zuul之后才能到达目标服务。
    • 据zuul特性,可将微服务公共的事情交个zuul统一处理。如:用户鉴权、请求监控。
  • Spring Cloud Config (分布式配置/配置中心)

    • 微服务架构中的服务实例非常的多,而服务的配置文件分散在每个服务中,每次修改服务的配置文件和重新服务实例都是一个很麻烦的工作。
    • Spring Cloud Config作为分布式配置管理中心就是用来统一的管理服务的配置文件。
  • Spring Cloud Bus(消息总线)

    • 消息总线是在微服务中给各个微服务广播消息的一个组件,我们使用消息总线构建一个消息中心,其他微服务来接入到消息中心,当消息总线发起消息,接入的微服务都可以收到消息从而进行消费。
  • Spring Cloud sleuth(微服务链路追踪)

    • 应用采用微服务架构之后,后台可能有几十个甚至几百个服务在支撑,一个请求请求可能需要多次的服务调用最后才能完成。
    • 作用:就是来监控维护之间的调用关系,让程序员方便直观的感受到一个请求经历了哪些微服务,以及服务的请求时间,是否有异常等。

3、SpringCloud的版本

  • SpringCloud是基于SpringBoot的,所以两者的jar包都需要导入。
  • 注意:SprinbCloud的版本需要和SpringBoot的版本兼容。
  • 我的项目
    • SpringBoot版本是2.0.5.RELEASE
    • SpringCloud的版本是Finchley.SR1
Release TrainSpringBoot Version
Hoxton2.2.x
Greenwich2.1.x
Finchley2.0.x
Edgware1.5.x
Dalston1.5.x

4、服务通信协议

(1)RPC

  • RPC(Remote Produce Call)远程过程调用,类似的还有RMI。
  • 自定义数据格式,基于原生TCP通信,速度快,效率高。
  • 早期的webservice、现在dubbo,都是RPC的典型

(2)Http

  • Http其实是一种网络传输协议,基于TCP,规定了数据传输的格式。
  • 现在客户端浏览器与服务端通信基本都是采用Http协议。
  • 也可用来进行远程服务调用。
  • 缺点是消息封装臃肿。
  • Rest风格,就可以通过http协议来实现

三、 SpringCloud与Dubbo

1、Dubbo简介

  • Dubbo最早是阿里巴巴提供的一个服务治理和服务调用框架,现在已经成为Apache的顶级项目。

四、服务注册与发现

1、什么是Eureka

  • 帮助管理服务的通信地址。

2、Eureka的工作原理

(1)服务注册

  • Eureka 是一个 服务 注册与发现的组件,就是用来统一管理微服务的通信地址的组件,它包含 EurekaServer服务器(注册中心)和 EurekaClient客户端组成。
  • EurekaServer是独立的服务,而 EurekaClient需要集成到每个微服务中。
  • 微服务(EurekaClient)在启动时,会向EurekaServer提交自己的服务信息(如:服务名,ip,端口等),在在 EurekaServer会形成一个微服务的通信地址列表存储起来。----这个过程服务注册

(2)服务发现

  • 微服务(EurekaClient)会定期(RegistryFetchIntervalSeconds:默认30s)的从EurekaServer拉取一份微服务通信地址列表缓存到本地。
  • 当一个微服务在向另一个微服务发起调用的时候会根据目标服务的服务名找到其通信地址,然后基于HTTP协议向目标服务发起请求。—这叫服务发现

(3)服务续约

  • 微服务(EurekaClient)采用定时(LeaseRenewalIntervalInSeconds:默认30s)发送“心跳”请求向EurekaServer发请求进行服务续约,其实就是定时向 EurekaServer发请求报告自己的健康状况,告诉EurekaServer自己还活着,不要把自己从服务地址清单中剔除掉,那么当微服务(EurekaClient)宕机未向EurekaServer续约,或者续约请求超时,注册中心机会从服务地址清单中剔除该续约失败的服务。

(4)服务下线

  • 微服务(EurekaClient)关闭服务前向注册中心发送下线请求,注册中心(EurekaServer)接受到下线请求负责将该服务实例从注册列表剔除。

(5)Eureka工作流程

在这里插入图片描述

3、EurekaServer实例

(1)多模块项目结构

在这里插入图片描述

  • 所有的jar包交给父工程管理
  • 现在主要用到
spring-cloud-parent //父项目--Project
pom.xml	//父项目的pom
	service-eureka-server-11000 //注册中心EurekaServer 
	service-user-server-31000   //用户服务EurekaClient ,提供者--model
	service-order-server-21000  //订单服务EurekaClient ,消费者--model

(2)Spring-cloud-parent(父项目)管理依赖,在pom.xml文件中

  • 参考文档:https://cloud.spring.io/spring-cloud-static/Greenwich.SR5/multi/multi__quick_start.html#_client_side_usage
  • springcloud-parent父工程:负责管理SpringBoot和SpringCloud的jar包
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.lfg</groupId>
    <artifactId>spring-cloud-parent</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>service-eureka-11000</module>
        <module>service-order-21000</module>
        <module>service-user-31000</module>
    </modules>

    <!--公共的一些配置-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <!--1.管理 SpringBoot的jar包-->
    <!--SpringBoot-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <version>2.2.5.RELEASE</version>
        <artifactId>spring-boot-starter-parent</artifactId>
    </parent>

    <!--2.管理 SpringCloud的jar包
 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

(3)搭建EurasiaServer----service-eureka-server-11000

  • 参考文档:https://cloud.spring.io/spring-cloud-static/Greenwich.SR5/multi/multi_spring-cloud-eureka-server.html#netflix-eureka-server-starter
  • 在springcloud-parent父工程下面搭建springcloud-eureka-server-11000,然后集成EurekaServer

a.service-eureka-server-11000项目结构

在这里插入图片描述

b.在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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <!--集成自己的父工程-->
    <parent>
        <artifactId>spring-cloud-parent</artifactId>
        <groupId>com.lfg</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-eureka-11000</artifactId>

    <dependencies>
        <!--导入springboot 基础包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--导入EurekaServer包-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
</project>
  • 提示

    • spring-cloud-starter-netflix-eureka-server

      • EurekaServer端的基础依赖,同时也把EurekaClient端也导入进来了
    • spring-boot-starter-web

      • web服务的基础依赖是不可缺少的

c.配置启动类

package cn.lfg2000;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
 * 注册中心启动类
 * @EnableEurekaServer : 开启EurekaServer服务端
 */
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApp {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApp.class);
    }
}

d.配置application.yml配置文件

server:
  port: 11000 #端口号
eureka:
  instance:
    hostname: localhost #主机名
  client:  #客户端配置
    register-with-eureka: false #false:EurekaServer自己不要注册到EurekaServer自己 ,只有EurekaClient才注册
    fetch-registry: false #EurekaServer不要拉取服务的通信地址列表 ,只有EurekaClient才拉取地址列表
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  server: #注册中心的注册地址
    enable-self-preservation: false #关闭自我保护警告

e.启动测试

  • 启动springcloud-eureka-server-11000,浏览器访问http://localhost:11000,若出现下面界面Eureka注册成功

在这里插入图片描述

4、Eureka自我保护

  • 默认情况下,当EurekaServer接收到服务续约的心跳失败比例在15分钟之内低于85%,EurekaServer会把这些服务保护起来,即不会把该服务从服务注册地址清单中剔除掉,但是在此种情况下有可能会出现服务下线,那么消费者就会拿到一个无效的服务,请求会失败,那我们需要对消费者服务做一些重试,或在熔断策略。
  • 当EurekaServer开启自我保护时,监控主界面会出现红色警告信息,我们可以使用eureka.server.enable-self-preservation=false来关闭EurekaServer的保护机制,这样可以确保注册中心中不可用的实例被及时的剔除,但是不推荐

5、EurekaClient实例

  • 参考文档: https://cloud.spring.io/spring-cloud-static/Greenwich.SR5/multi/multi__service_discovery_eureka_clients.html#netflix-eureka-client-starter
  • service-user-server-31000 与 service-order-server-21000 两个都是EurekaClient客户端,都需要去集成EurekaClient,。

(1)service-user-server-31000–用户服务

a.service-user-server-31000 项目结构

在这里插入图片描述

b.在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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-cloud-parent</artifactId>
        <groupId>com.lfg</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-user-31000</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
</project>
  • 同步:顺序执行
  • 异步:不用等待上一步的执行完,才执行下一步;可以先执行下一步,再执行上一步。

c.配置启动类

package cn.lfg2000;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
 * 用户的启动类
 * @EnableEurekaClient: 标记该应用是 EurekaClient(客户端)
 */
@SpringBootApplication
@EnableEurekaClient //或者@EnableDiscoveryClient
public class UserApp {
    public static void main(String[] args) {
        SpringApplication.run(UserApp.class);
    }
}

d.配置 application.yml配置文件

#端口号
server:
  port: 31001
#指定服务的名字
spring:
  application:
    name: service-user
#注册到EurekaServer
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:11000/eureka/
  instance: #使用ip进行注册
    instance-id: service-user:31001 #实例ID
    prefer-ip-address: true #开启,使用指定ip进行注册

e.启动测试

在这里插入图片描述

(2)service-order-server-21000–订单服务

  • 操作流程与用户服务一致。
  • 启动类 和 配置文件需要修改

a.启动类

package cn.lfg2000;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

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

b.application.xml

server:
  port: 21000
spring:
  application:
    name: service-order
eureka:
  client:
    service-url:
      defaultZone: http://localhost:11000/eureka
  instance:
    prefer-ip-address: true #启动ip注册 默认使用计算机的名字注册
    instance-id: service-order:21000

五、RestTemplate 服务通信

1、服务通信流程,以订单服务通信用户服务为例

在这里插入图片描述

  • 调用关系:浏览器—>订单服务—>用户服务
  • 订单服务通过RestTemplate向用户服务发起调用,目的是要获取到用户服务返回的User对象,最终是需要浏览器获取到User。

2、RestTemplate介绍

  • 微服务的通信协议主流的有RPC,Http,SpringCloud是基于Http Restful 风格 ,在Java中发起一个Http请求的方式很多,比如 Apache的HttpClient , OKHttp等等 。
  • Spring为我们封装了一个基于Restful的使用非常简单的Http客户端工具 RestTemplate ,我们就用它来实订单服务和用户服务的通信。
  • 需要注意的是,RestTmplate本身不具备服务发现和负载均衡器的功能,案例只是演示在订单服务中使用RestTemplate基于ip和端口的方式向用户服务发起调用,即:不走注册中心,不使用服务发现方式。

3、编码实现RestTemplate

(1)搭建公共模块–service-entity

  • 该模块用户存放实体类

a.service-entity 项目结构

在这里插入图片描述

b.在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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-cloud-parent</artifactId>
        <groupId>com.lfg</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-entity</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>

c.创建实体类

  • User
package cn.lfg2000.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {
    private Long id;
    private String username;
}
  • Order
package cn.lfg2000.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Order {
    private Long id;
    private String desc;
    private Double price;
    private User user;
}

d.在用户模块、订单模块引入server-entity模块

<dependency>
    <groupId>com.lfg</groupId>
    <artifactId>service-entity</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

e.在用户模块的controller层编写执行方法

package cn.lfg2000.controller;

import cn.lfg2000.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
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;
//用户服务:暴露接口给订单访问
@RestController
public class UserController {

    // 将用户服务的端口号注入port中
    @Value("${server.port}")
    private Integer port;

    //订单服务来调用这个方法 http://localhost:31001/user/1
    @GetMapping("/user/{id}")
    public User getUserById(@PathVariable("id") long id){
        // 模拟一个user对象
        return new User(id,"一个人哭"+port);
    }
}

f.在订单模块的controller层中编写执行方法并获取User对象

  • 编写配置类RestTemplate
package cn.lfg2000.config;

import com.netflix.loadbalancer.RandomRule;
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 RestTemplateConfig {

    //配置一个RestTemplate ,Spring封装的一个机遇Restful风格的http客户端 工具
    @Bean
    /*@LoadBalanced*/
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

    /*@Bean
    public RandomRule getRandomRule(){
        return new RandomRule();
    }*/
}
  • 订单模块controller层执行方法
package cn.lfg2000.controller;

import cn.lfg2000.pojo.Order;
import cn.lfg2000.pojo.User;
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;
import org.springframework.web.client.RestTemplate;

@RestController
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/order/{id}")
    public Order getOrder(@PathVariable("id") long id){
        String url = "http://localhost:31001/user/"+id;
        User user = restTemplate.getForObject(url, User.class);
        return new Order(id,"一刀999",99.99,user);
    }
}

g.测试

在这里插入图片描述

六、Ribbon客户端负载均衡

1、为什么要Ribbon

  • 为了防止应用出现单节点故障问题,同时为了提高应用的作业能力,我们需要对应用做集群 ,如果我们对user-server(用户服务)做了集群 ,那么这个时候回衍生出一些问题:现在有两个user-server(用户服务)就意味着有两个user-server(用户服务)的通信地址,我的order-server(订单服务)在向user-server(用户服务)发起调用的时候该访问哪个?如何访问?这个时候就需要有一个组件帮我们做请求的分发,即:负载均衡器,而Ribbon就是一个 - 客户端负载均衡器。

2、什么是Ribbon

  • Ribbon是Netflix发布的云中间层服务开源项目,主要功能是提供客户端负载均衡算法
  • Ribbon客户端组件提供一系列完善的配置项,如,连接超时,重试等。
  • 简单来说,Ribbon是一个客户端负载均衡器,Ribbon可以按照负载均衡算法(如简单轮询,随机连接等)向多个服务发起调用(正好可以解决上面的问题),我们也很容易使用Ribbon实现自定义的负载均衡算法

3、Ribbon的工作机制

  • 如下图,我们将用户服务)做集群处理,增加到2个节点(注意:两个用户服务的服务名要一样,ip和端口不一样),在注册中心的服务通信地址清单中user-server(用户服务)这个服务下面会挂载两个通信地址 。
    • 真实操作就是,修改application.yml配置文件中的端口号,再运行启动类就好了
  • 订单服务 会定时拉取通信地址清单到本地进行缓存,当订单服务想用户服务发起调用时,需要指定服务名为 service-user,这时Ribbon根据service-user这个服务名找到两个service-user通信地址,然后根据Ribbon会按照负载均衡算法(morning轮询)选择其中的某个通信地址,发起和http请求实现服务的调用。

在这里插入图片描述

4、提供者service-user(用户服务)集群

(1)服务集群方案

  • 使用SpringBoot多环境配置方式集群,一个配置文件配置多个service-userr环境
  • 需要注意的是集群中的多个服务名(spring.application.name)应该一样,我们把相同的东西提取到最上面,不同的东西配置在各自的环境中

(2)用户服务集群配置

  • 真实操作就是,修改application.yml配置文件中的端口号,再运行启动类就好了
  • 第一个service-user
#注册到EurekaServer
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:11000/eureka/
  instance: #使用ip进行注册
    instance-id: service-user:31001
    prefer-ip-address: true #开启,使用指定ip进行注册
#端口号
server:
  port: 31001
#指定服务的名字
spring:
  application:
    name: service-user
  • 第二个service-user,修改application.yml ,并启动
#注册到EurekaServer
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:11000/eureka/
  instance: #使用ip进行注册
    instance-id: service-user:31000 #实例ID
    prefer-ip-address: true #开启,使用指定ip进行注册
#端口号
server:
  port: 31000
#指定服务的名字
spring:
  application:
    name: service-user

在这里插入图片描述

5、消费者service-order集成Ribbon

  • Ribbon 集成官方文档:https://cloud.spring.io/spring-cloud-static/Greenwich.SR5/multi/multi_spring-cloud-ribbon.html#netflix-ribbon-starter

(1)在service-order服务的pom.xml中引入依赖

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

(2)开启负载均衡

  • @LoadBalanced:开启负载均衡的能力
  • 修改RestTemplate的Bean的定义方法
package cn.lfg2000.config;

import com.netflix.loadbalancer.RandomRule;
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 RestTemplateConfig {

    //配置一个RestTemplate ,Spring封装的一个机遇Restful风格的http客户端 工具
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

    /*@Bean
    public RandomRule getRandomRule(){
        return new RandomRule();
    }*/
}

(3)修改service-order服务controller层的执行方法

package cn.lfg2000.controller;

import cn.lfg2000.pojo.Order;
import cn.lfg2000.pojo.User;
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;
import org.springframework.web.client.RestTemplate;

@RestController
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/order/{id}")
    public Order getOrder(@PathVariable("id") long id){
        String url = "http://service-user/user/"+id;
        User user = restTemplate.getForObject(url, User.class);
        return new Order(id,"一刀999",99.99,user);
    }
}

6、测试

在这里插入图片描述

在这里插入图片描述

七、Ribbon负载均衡算法

1、Ribbon内置算法

在这里插入图片描述

2、配置负载均衡算法

(1)注解全局配置

/**
 * 订单的启动类
 */
@SpringBootApplication
@EnableEurekaClient
public class OrderServerApplication1030
{

    //配置一个RestTemplate ,Spring封装的一个机遇Restful风格的http客户端 工具
    //@LoadBalanced :让RestTemplate有负载均衡的功能
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    //负载均衡算法
    @Bean
    public RandomRule randomRule(){
        return new RandomRule();
    }
    //省略...

(3)yml方式配置负载均衡算法

a.配置全局Ribbon算法

ribbon:
   NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

b.配置某个服务的Ribbon算法

service-user:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

八、Ribbon调优配置

1、超时配置

  • 使用Ribbon进行服务通信时为了防止网络波动造成服务调用超时,我们可以针对Ribbon配置超时时间以及重试机制

  • 也可以针对具体的服务进行超时配置:如"<服务名>.ribbon…"

ribbon:
  ReadTimeout: 3000					#读取超时时间
  ConnectTimeout: 3000				#链接超时时间
  MaxAutoRetries: 1 				#重试机制:同一台实例最大重试次数
  MaxAutoRetriesNextServer: 1 		#重试负载均衡其他的实例最大重试次数
  OkToRetryOnAllOperations: false  	#是否所有操作都重试,因为针对post请求如果没做幂等处理可能会造成数据多次添加/修改

2、饥饿加载

  • 我们在启动服务使用Ribbon发起服务调用的时候往往会出现找不到目标服务的情况,这是因为Ribbon在进行客户端负载均衡的时候并不是启动时就创建好的,而是在实际请求的时候才会去创建,所以往往我们在发起第一次调用的时候会出现超时导致服务调用失败,我们可以通过设置Ribbon的饥饿加载来改善此情况,即在服务启动时就把Ribbon相关内容创建好。
ribbon:
  eager-load:
    enabled: true #开启饥饿加载
    clients: user-server #针对于哪些服务需要饥饿加载

``

(3)yml方式配置负载均衡算法

a.配置全局Ribbon算法

ribbon:
   NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

b.配置某个服务的Ribbon算法

service-user:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

八、Ribbon调优配置

1、超时配置

  • 使用Ribbon进行服务通信时为了防止网络波动造成服务调用超时,我们可以针对Ribbon配置超时时间以及重试机制

  • 也可以针对具体的服务进行超时配置:如"<服务名>.ribbon…"

ribbon:
  ReadTimeout: 3000					#读取超时时间
  ConnectTimeout: 3000				#链接超时时间
  MaxAutoRetries: 1 				#重试机制:同一台实例最大重试次数
  MaxAutoRetriesNextServer: 1 		#重试负载均衡其他的实例最大重试次数
  OkToRetryOnAllOperations: false  	#是否所有操作都重试,因为针对post请求如果没做幂等处理可能会造成数据多次添加/修改

2、饥饿加载

  • 我们在启动服务使用Ribbon发起服务调用的时候往往会出现找不到目标服务的情况,这是因为Ribbon在进行客户端负载均衡的时候并不是启动时就创建好的,而是在实际请求的时候才会去创建,所以往往我们在发起第一次调用的时候会出现超时导致服务调用失败,我们可以通过设置Ribbon的饥饿加载来改善此情况,即在服务启动时就把Ribbon相关内容创建好。
ribbon:
  eager-load:
    enabled: true #开启饥饿加载
    clients: user-server #针对于哪些服务需要饥饿加载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/826100.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RB-Heparin罗丹明B-肝素偶联物的合成【星戈瑞】

罗丹明B标记肝素是一种荧光标记的肝素探针。在生物医学和生物化学研究中&#xff0c;研究人员常常需要将特定的生物分子或化合物进行标记&#xff0c;以便能够在实验中可视化或追踪它们的位置和相互作用。 合成Rhodamine B-Heparin罗丹明B-肝素偶联物需要将罗丹明B染料与肝素进…

20款奔驰S350升级原厂HUD抬头显示系统,提升您的行车安全

HUD是平视显示器的简称&#xff0c;它原先是运用在航空器上的飞行辅助仪器。指飞行员不需要低头&#xff0c;就能够看到他需要的重要资讯。由于HUD的方便性以及能够提高飞行安全&#xff0c;这项技术后来也发展到汽车行业。汽车搭载的HUD抬头数字显示功能&#xff0c;是利用光学…

使用Linux部署Jpress博客系统

环境要求 linux系统&#xff1a;我使用的操作系统是CentOS7 数据库&#xff1a;mysql&#xff0c;也可以使用mariadb jdk&#xff1a;与你的Linux操作系统能兼容的版本 tomcat&#xff1a;我使用的是tomcat8版本 如果没有数据库&#xff0c;请先自行下载 如果没有安装jdk…

MySQL内置函数使用说明

MySQL函数使用说明 MySQL 是一个流行的关系型数据库管理系统&#xff0c;它提供了许多内置函数来处理和操作数据。这些函数可以简化数据库查询和操作的过程&#xff0c;提高代码的可读性和效率。以下是一些常见的 MySQL 内置函数及其使用说明和示例。 数值函数 ABS() 函数原…

带 SPI 接口的独立 CAN 控制器 SIT2515

 芯片功能与 MCP2515 完全一致  适用 CAN2.0B 1.0Mb/s 的速度 0-8 字节长度数据场 支持标准帧扩展帧和远程帧  接收缓存、掩码与过滤码 两个带有存储优先级的接收缓存器 6 个 29 位过滤码 2 个 29 位掩码  采用前两个字节的数据进行报文过滤  三…

android 如何分析应用的内存(十五)——Visual Studio Code 调试Android应用

android 如何分析应用的内存&#xff08;十五&#xff09;——Visual Studio Code 调试Android 应用 在上一篇文章介绍了jdb调试java应用 接下来介绍用UI界面调试java应用&#xff0c;达到同jdb一样的效果。 同样的UI界面有很多选择&#xff0c;如Eclipse&#xff0c;Android …

Qt 中引入ffmpeg 动态库

1、前期准备 在qt引入ffmpeg动态库的时候&#xff0c;需要准备ffmpeg的动态库和头文件。 2、打开qt项目 在qt项目的.pro文件中添加以下几行代码 INCLUDEPATH $$PWD/thirtLib/ffmpeg4.2/include win32: LIBS -L$$PWD/thirtLib/ffmpeg4.2/lib/ -lavcodec -lavdevice -lavf…

亚马逊云科技与真格基金发起「AI超新星计划」,助力早期创业者快速启动项目

大模型创业热度仍旧在持续增加&#xff0c;“百模大战”中AI创业者们的机会更多是在应用层。为了尽可能降低AI创业者的启动门槛&#xff0c;亚马逊云科技携手头部早期投资机构真格基金共同发起了「AI超新星计划」&#xff0c;为心怀梦想的AI应用创业者们提供了从云资源、模型选…

[腾讯云Cloud Studio实战训练营]基于Cloud Studio完成图书管理系统

[腾讯云Cloud Studio实战训练营]基于Cloud Studio完成图书管理系统 ⭐前言&#x1f31c;Cloud Studio产品介绍1.登录2.创建工作空间3.工作空间界面简介4.环境的使用 ⭐实验实操&#x1f31c;Cloud Studio实现图书管理系统1.实验目的 2. 实验过程2.实验环境3.源码讲解3.1添加数据…

如何解决大量小文件传输慢的问题

在信息化社会的今天&#xff0c;大量小文件传输已经成为日常工作中不可或缺的需求。无论是云存储、大数据处理还是软件更新等场景&#xff0c;都需要快速高效地传输大量小文件。然而&#xff0c;传统的传输方式往往受到网络连接速度、传输协议和存储介质等方面的限制&#xff0…

【从零开始学习JAVA | 第三十六篇】IO流下的高级流

目录 前言&#xff1a; 1.缓冲流&#xff1a; 2.转换流&#xff1a; 3.序列化流&#xff1a; 4.打印流&#xff1a; 5.压缩流&#xff1a; 总结&#xff1a; 前言&#xff1a; 在前面我们从IO流体系出发&#xff0c;分别介绍了字节流和字符流&#xff0c;并且详细讲解了其…

推荐两款github敏感信息搜集工具(gsil、gshark)

推荐两款github敏感信息搜集工具&#xff08;gsil、gshark&#xff09; - 云社区 - 腾讯云 (tencent.com) github敏感信息泄露是很多企业时常忽视的一个问题&#xff0c;国外有一份研究报告显示&#xff0c;在超过24,000份的GitHub公开数据中&#xff0c;发现有数千个文件中可能…

python开发实战——ip池

前言 代理IP池是一组可用的代理IP地址&#xff0c;用于访问网站或执行其他网络请求。它可以帮助我们在网络请求时隐藏我们的真实IP地址&#xff0c;从而提高网络安全性、匿名性和稳定性。同时&#xff0c;代理IP池还可以通过定时更新和测试代理IP&#xff0c;保证代理IP的有效…

C#生成dll给c++调用 方法二COM方式 vs2022 NO Make Assembly COM-Visible选错了 不需要clr

有些C项目中也用了C语言.c,用方法一就无法使用【不能使用 /clr 选项编译 C 文件】。就用方法2。 方法二:COM方式 参考&#xff1a; https://www.5axxw.com/questions/content/2ozion 1.C# 生成dll using System; using System.Collections.Generic; using System.Linq; usin…

【Linux多线程】基于生产消费模型写的一个实例(附源代码+讲解)

生产消费模型 生产消费模型为何要使用生产者消费者模型生产者消费者模型优点 基于BlockingQueue的生产者消费者模型BlockQueue.cc代码解释 BlockQueue.hpp代码解释 Makefile代码解释 Task.hpp代码解释 生产消费模型 为何要使用生产者消费者模型 生产者消费者模式就是通过一个…

tdengine入门详解

TDengine是什么&#xff1f; TDengine 是一款开源、高性能、云原生的时序数据库&#xff08;Time Series Database, TSDB&#xff09;, 它专为物联网、车联网、工业互联网、金融、IT 运维等场景优化设计&#xff0c;基于C语言开发。 什么是时序数据库&#xff1f;时序数据产生…

三元运算符引发的自动拆装箱问题

文章目录 问题背景问题排查排查过程问题扩展总结 问题背景 生产环境上出现空指针异常&#xff0c;追踪报错位置得知以下代码报错 if (isNull(aiGroup)) {return null;}aiGroup.setNum(isNull(param.getNum()) ? aiGroup.getNum() : param.getNum().doubleValue());问题排查 …

1500-2000元预算性价比吉他推荐,雅马哈FG800和VEAZEN费森VZ90怎么选?评测对比哪一款更适合初学者入门选购!

在2000元价位入门进阶吉他圈里&#xff0c;可谓是群雄角逐&#xff0c;Yamaha 雅马哈入门级FG800系列和VEAZEN 费森VZ90系列是一直都很热销的面单吉他型号&#xff0c;初学者想要在其中挑选出一把合适自己的吉他还是有点难度的。 那么&#xff0c;今天就以它们为本期的评测主角…

企业级高负载web服务器-Tomcat小项目

目录 web静态动态页面区别安装java环境安装Tomcat安装Tomcat包到目录查看Tomcat主目录结构查看Tomcat配置目录结构Tomcat管理Tomcat web管理功能 部署jpress应用 web静态动态页面区别 静态页面&#xff1a; 在网站设计中&#xff0c;纯粹HTML格式的网页&#xff08;可以包含图…

后端整理(JVM、Redis、反射)

1. JVM 文章仅为自身笔记 详情查看一篇文章掌握整个JVM&#xff0c;JVM超详细解析&#xff01;&#xff01;&#xff01; 1.1 什么是JVM jvm是Java虚拟机 1.2 Java文件的编译过程 程序员编写代码形成.java文件经过javac编译成.class文件再通过JVM的类加载器进入运行时数据…