SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡

学习目标

  • 了解系统架构的演变
  • 知道什么是SpringCloud
  • 独立搭建Eureka注册中心
  • 独立配置Robbin负载均衡
系统架构演变 要学微服务,我们先来看看系统架构的演变史,从而对微服务架构进行更深层次的了解。
随着互联网的发展,网站应用的规模不断扩大,需求的剧增,带来了系统架构不断的演进、升级和迭代。
系统架构的演变,大体上划分为:传统架构、负载均衡架构,分布式服务架构,SOA架构,微服务架构。
传统架构:单一应用 当网站流量很小时,只需一个应用,将所有功能都部署在一起。
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

集群:负载均衡 随着访问量的变大,一个Tomcat服务器已经不能满足需求。
需要配置多个Tomcat,做Tomcat集群。通过负载均衡服务器访问不同的Tomcat服务器,每个Tomcat中部署完整项目即可。
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

分布式服务 每一个Tomcat存放完整项目,会存在部分业务模块长时间用不到,部分业务模块不够用的现象。
我们将按照功能模块拆分项目,每一台服务器仅存放某一个模块,通过多系统的配合完成整体业务逻辑,此种方式成为:分布式服务。
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

SOA架构:面向服务架构 SOA(Service Oriented Architecture)面向服务架构,就是将工程拆分成表现层和服务层两个工程。
服务层中包含业务逻辑,只需要对外提供服务即可。
表现层只需要处理和页面的交互,业务逻辑都是调用服务层的服务来实现。
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

微服务 微服务是SOA的一种实现,也可以说是微服务是去ESB(取中心)的SOA。
微服务架构是一种将单个应用程序作为一套小型服务开发的方法。每种应用程序都可以独立运行。应用程序之间远程调用进行通信。
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

  1. 微服务总结:(特性)
    1. 完全独立的一个最小个体。(可以独立运行)
    2. 个体与个体之间,通过远程调用进行访问。例如:基于RESTFul风格的。
    3. 通过注册中心,将不同个体可以进行整合。
通过网关,可以进行统一的入口访问。
初始SpringCloud 什么是微服务 微服务是一种架构风格,即将单体应用划分为小型的服务单元。
微服务的实现方式很多,但是最火的莫过于Spring Cloud了。为什么?
  • 后台硬:作为Spring家族的一员,有整个Spring全家桶靠山,背景十分强大。
  • 技术强:Spring作为Java领域的前辈,可以说是功力深厚。有强力的技术团队支撑,一般人还真比不了
  • 群众基础好:可以说大多数程序员的成长都伴随着Spring框架,试问:现在有几家公司开发不用Spring?SpringCloud与Spring的各个框架无缝整合,对大家来说一切都是熟悉的配方,熟悉的味道。
  • 使用方便:相信大家都体会到了SpringBoot给我们开发带来的便利,而SpringCloud完全支持SpringBoot的开发,用很少的配置就能完成微服务框架的搭建
什么是SpringCloud Spring Cloud 是一系列框架的集合,它利用Spring Boot的开发便利性,简化了分布式系统开发,如:服务注册、服务发现、配置中心。消息总线、负载均衡、熔断器、数据监控等。
Spring Cloud 主要贡献者是Netflix,也就是Spring Cloud是对Netflix贡献的框架的二次封装或优化。
通俗的讲,SpringCloud就是用于构建微服务开发和治理的框架集合。
SpringCloud常见模块 SpringCloud主要涉及的组件包括:
  • Eureka:服务注册中心,用于管理服务
  • Ribbon:负载均衡(集群)
  • Hystrix:熔断器,能够防止服务的雪崩效应。
  • Zuul:服务网关,提供路由转发、请求过滤等功能。
  • Feign:服务调用,简化Http接口的调用。
以上只是其中一部分,架构图:
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

版本 SpringCloud的版本命名比较特殊,因为它不是一个组件,而是许多组件的集合,它的命名是以A到Z的为首字母的一些单词组成:
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

我们的学习,将以Hoxton.SR9的版本。(最新版本,需要同步升级相关软件)
参考文档:Spring Cloud
入门案例 父项目 创建项目
创建父项目:cloud-parent-1007
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

pom配置文件
修改pom.xml,确定spring cloud的版本
4.0.0com.czxy.cloud cloud-parent-1007 1.0-SNAPSHOTorg.springframework.boot spring-boot-starter-parent 2.3.5.RELEASE UTF-8 1.8 Hoxton.SR9 org.springframework.cloud spring-cloud-dependencies ${spring-cloud-release.version} pom import

原理分析 基本架构:
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

  • Eureka:就是服务注册中心,用于管理所有注册服务。
  • 班级服务,服务的提供者,启动后向Eureka注册自己地址,方便服务调用方获取。
  • 学生服务,服务的调用者,定期从eureka注册中心中获得服务列表。
  • 心跳(续约):提供者定期通过http方式向Eureka刷新自己的状态。
Eureka注册中心(服务端) 认识Eureka 当开发大型项目时,服务的提供方和服务的调用方,将会非常庞大,管理服务的成本将几何倍的增长。
Eureka将负责服务的注册、发现、状态监控。
注册:Eureka负责管理、记录服务提供者的信息
发现:服务调用者无需自己寻找服务,而是把自己的需求告诉Eureka,然后Eureka会把符合你需求的服务告诉你
监控:服务提供方与Eureka之间通过“心跳”机制进行监控,当某个服务提供方出现问题,Eureka自然会把它从服务列表中剔除
编写注册服务中心(10086) 步骤一:创建注册中心项目(服务),cloud-eureka-1007
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

步骤二:修改pom.xml文件,添加依赖(web项目、eureka服务)
org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-netflix-eureka-server

  1. 步骤三:创建application.yml,配置注册中心
    1. register-with-eureka: false # 是否注册自己的信息到注册中心,默认是true
    2. fetch-registry: false # 是否拉取其它服务的信息,默认是true
    3. service-url: # 注册中心的地址,现在是自己的地址。如果是集群,需要加上其它Server的地址。
# 端口号 server: port: 10086 # 服务名称 spring: application: name: cloud-eureka-1007 # eureka的配置 eureka: client: service-url: defaultZone: http://localhost:${server.port}/eureka/# 注册中心的地址 register-with-eureka: false# 是否注册自己的信息到注册中心,默认是true fetch-registry: false# 是否拉取其它服务的信息,默认是true

步骤四:编写启动类,添加注解 @EnableEurekaServer
package com.czxy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; /** * Created by liangtong. */ @SpringBootApplication @EnableEurekaServer public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args ); } }

步骤五:访问
http://localhost:10086
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片
编写服务(客户端) 编写班级服务 服务提供方(9010) 步骤一:编写项目(服务),cloud-classes-service-1007
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

步骤二:修改pom.xml文件,添加 eureka client依赖
org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-netflix-eureka-client org.springframework.boot spring-boot-starter-actuator

步骤三:创建yml文件,确定eureka注册中心的位置
server: port: 9010 spring: application: name: classes-service eureka: client: service-url: #注册中心位置 defaultZone: http://localhost:10086/eureka/ instance: #web页面显示效果和访问路径 instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port} prefer-ip-address: true

步骤四:编写启动类,添加注解
【SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡】SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片


package com.czxy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class ClassesApplication { public static void main(String[] args) { SpringApplication.run(ClassesApplication.class,args); } }

步骤五:启动项目,并测试
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

步骤六:提供查询所有班级
package com.czxy.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("/classes") public class ClassesController {@GetMapping public List findAll(){ List list = new ArrayList<>(); list.add("Java12班"); list.add("Java34班"); return list; } }

SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

编写学生服务 服务调用方(9020) 步骤一:编写项目(服务),cloud-student-service-1007
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

步骤二:修改pom.xml文件, (和eureka_service一样)
org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-netflix-eureka-client org.springframework.boot spring-boot-starter-actuator

步骤三:创建yml文件
server: port: 9020 spring: application: name: student-service eureka: client: service-url: #注册中心位置 defaultZone: http://localhost:10086/eureka/ instance: #web页面显示效果和访问路径 instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port} prefer-ip-address: true

步骤四:编写启动类
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

package com.czxy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class StudentApplication { public static void main(String[] args) { SpringApplication.run(StudentApplication.class,args); } }

步骤五:启动,并测试
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

功能:学生服务调用班级服务 步骤一:编写HttpConfig,用于配置RestTemplate
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

package com.czxy.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class HttpConfig {@Bean public RestTemplate restTemplate() { return new RestTemplate(); } }

步骤二:编写ClassesDao,完成远程调用
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

package com.czxy.dao; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Repository; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; import java.util.List; @Repository public class ClassesDao {@Resource private RestTemplate restTemplate; @GetMapping public List findAll(){ ResponseEntity entity = restTemplate.getForEntity("http://localhost:8082/classes", List.class); List list = entity.getBody(); return list; }}

步骤三:编写StudentService,调用ClassesDao
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

package com.czxy.service; import com.czxy.dao.ClassesDao; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; @Service public class StudentService {@Resource private ClassesDao classesDao; public List findAll() { return classesDao.findAll(); } }

步骤四:编写StudentController,调用StudentService直接显示数据
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

package com.czxy.controller; import com.czxy.service.StudentService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.List; @RestController @RequestMapping("/student") public class StudentController {@Resource private StudentService studentService; @GetMapping public List findAll(){ return studentService.findAll(); } }

步骤五:测试
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片
优化:服务调用 修改HttpConfig类,使RestTemplate支持通过服务名调用
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

修改Dao,使用服务名调用
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

@GetMapping public List findAll(){ ResponseEntity entity = restTemplate.getForEntity("http://classes-service/classes", List.class); List list = entity.getBody(); return list; }

Eureka高级 优化集群:高可用的Eureka Server Eureka Server即服务的注册中心,在刚才的案例中,我们只有一个Eureka Server,事实上Eureka Server也可以是一个集群,形成高可用的Eureka中心。
  1. 服务同步
多个Eureka Server之间也会互相注册为服务,当服务提供者注册到Eureka Server集群中的某个节点时,该节点会把服务的信息同步给集群中的每个节点,从而实现数据同步。因此,无论客户端访问到Eureka Server集群中的任意一个节点,都可以获取到完整的服务列表信息。

  1. 动手搭建高可用的EurekaServer
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

我们假设要搭建两条EurekaServer的集群,端口分别为:10086和10087
步骤一:分别为两个端口配置yml文件
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

application-10086.yml 配置
# 端口号 server: port: 10086 # 服务名称 spring: application: name: cloud-eureka-1007 # eureka的配置 eureka: client: service-url: defaultZone: http://localhost:10087/eureka/# 注册中心的地址 register-with-eureka: true# 是否注册自己的信息到注册中心,默认是true fetch-registry: true# 是否拉取其它服务的信息,默认是true

application-10087.yml 配置
# 端口号 server: port: 10087 # 服务名称 spring: application: name: cloud-eureka-1007 # eureka的配置 eureka: client: service-url: defaultZone: http://localhost:10086/eureka/# 注册中心的地址 register-with-eureka: true# 是否注册自己的信息到注册中心,默认是true fetch-registry: true# 是否拉取其它服务的信息,默认是true

所谓的高可用注册中心,其实就是把EurekaServer自己也作为一个服务进行注册,这样多个EurekaServer之间就能互相发现对方,从而形成集群。因此我们做了以下修改:
  • 删除了register-with-eureka=false和fetch-registry=false两个配置。因为默认值是true,这样就会吧自己注册到注册中心了。
  • 把service-url的值改成了另外一台EurekaServer的地址,而不是自己

  1. 步骤二:配置启动器
-Dspring.profiles.active=10086
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

步骤三:测试
注意:10086端口启动后,将一直报错,再等待10087端口,10087启动后错误消失
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

步骤四:将“classes-service”注册到10086,将自动同步到10087
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

步骤七:手动将服务注册到Eureka集群
因为EurekaServer不止一个,可以通过service-url设置多个注册地址
eureka: client: service-url: #注册中心位置,多个地址以','隔开 defaultZone: http://localhost:10086/eureka/,http://localhost:10087/eureka

SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片
优化:服务提供者配置 服务提供者要向EurekaServer注册服务,并且完成服务续约等工作。
  1. 服务注册
服务提供者在启动时,会检测配置属性中的:eureka.client.register-with-erueka=true参数是否正确,事实上默认就是true。如果值确实为true,则会向EurekaServer发起一个Rest请求,并携带自己的元数据信息,完成注册操作。
  1. 服务续约
在注册服务完成以后,服务提供者会维持一个心跳(定时向EurekaServer发起Rest请求),告诉EurekaServer:“我还活着”。这个我们称为服务的续约(renew);
有两个重要参数可以修改服务续约的行为:
eureka: client: lease-renewal-interval-in-seconds: 5#服务续约(renew)的间隔,默认值90秒 lease-expiration-duration-in-seconds: 10#服务失效时间,默认为30秒

  • lease-expiration-duration-in-seconds:服务失效时间,默认值90秒
  • lease-renewal-interval-in-seconds:服务续约(renew)的间隔,默认为30秒
也就是说,默认情况下每个30秒服务会向注册中心发送一次心跳,证明自己还活着。如果超过90秒没有发送心跳,EurekaServer就会认为该服务宕机,会从服务列表中移除,这两个值在生产环境不要修改,默认即可。
但是在开发时,这个值有点太长了,经常我们关掉一个服务,会发现Eureka依然认为服务在活着。所以我们在开发阶段可以适当调小。
server: port: 8080 spring: application: name: service eureka: client: service-url: #注册中心位置 defaultZone: http://localhost:10086/eureka/ instance: #web页面显示效果和访问路径 instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port} prefer-ip-address: true lease-renewal-interval-in-seconds: 5#5秒一次心跳 lease-expiration-duration-in-seconds: 10#10秒及过期

SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片
优化:服务消费者配置
  1. 获取服务列表
当服务消费者启动是,会检测eureka.client.fetch-registry=true参数的值,如果为true,则会从Eureka Server服务的列表只读备份,然后缓存在本地。并且每隔30秒会重新获取并更新数据。我们可以通过下面的参数来修改:
eureka: client: registry-fetch-interval-seconds: 5

server: port: 9090 spring: application: name: client eureka: client: service-url: #注册中心位置 defaultZone: http://localhost:10087/eureka/ registry-fetch-interval-seconds: 5 #从注册中心,获得列表的间隔时间 instance: #web页面显示效果和访问路径 instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port} prefer-ip-address: true

SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片
生产环境中,我们不需要修改这个值。
但是为了开发环境下,能够快速得到服务的最新状态,我们可以将其设置小一点。
注册中心优化:失效剔除和自我保护 服务端配置
eureka.server.enable-self-preservation ,是否开启自我保护模式,默认为true。
eureka.server.eviction-interval-timer-in-ms, 清理无效节点的时间间隔,默认60000毫秒
# eureka的配置 eureka: server: enable-self-preservation: true #是否开启自我保护模式 eviction-interval-timer-in-ms: 4000 # 清理无效节点的时间间隔

SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

  1. 失效剔除
有些时候,我们的服务提供方并不一定会正常下线,可能因为内存溢出、网络故障等原因导致服务无法正常工作。Eureka Server需要将这样的服务剔除出服务列表。因此它会开启一个定时任务,每隔60秒对所有失效的服务(超过90秒未响应)进行剔除。
可以通过eureka.server.eviction-interval-timer-in-ms参数对其进行修改,单位是毫秒,生成环境不要修改。
这个会对我们开发带来极大的不变,你对服务重启,隔了60秒Eureka才反应过来。开发阶段可以适当调整,比如10S
# eureka的配置 eureka: server: eviction-interval-timer-in-ms: 4000 # 清理无效节点的时间间隔(缺省为60*1000ms)

自我保护
我们关停一个服务,就会在Eureka面板看到一条警告:
这是触发了Eureka的自我保护机制。当一个服务未按时进行心跳续约时,Eureka会统计最近15分钟心跳失败的服务实例的比例是否超过了85%。在生产环境下,因为网络延迟等原因,心跳失败实例的比例很有可能超标,但是此时就把服务剔除列表并不妥当,因为服务可能没有宕机。Eureka就会把当前实例的注册信息保护起来,不予剔除。生产环境下这很有效,保证了大多数服务依然可用。
但是这给我们的开发带来了麻烦, 因此开发阶段我们都会关闭自我保护模式:
# eureka的配置 eureka: server: enable-self-preservation: true #是否开启自我保护模式(缺省为true)

优化总结
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

负载均衡 在刚才的案例中,我们启动了一个classes-service,然后通过DiscoveryClient来获取服务实例信息,然后获取ip和端口来访问。
但是实际环境中,我们往往会开启很多个eureka-service的集群。此时我们获取的服务列表中就会有多个,到底该访问哪一个呢?
一般这种情况下我们就需要编写负载均衡算法,在多个实例列表中进行选择。
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

不过Eureka中已经帮我们集成了负载均衡组件:Ribbon,简单修改代码即可使用。
什么是Ribbon:
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

接下来,我们就来使用Ribbon实现负载均衡。
启动两个服务实例 首先我们启动两个classes-service实例,一个9010,一个9011。
步骤一:为两个端口号配置yml文件
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

application-9010.yml
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片


application-9011.yml
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

步骤二:配置两个启动项
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

测试
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片
开启负债均衡 因为Eureka中已经集成了Ribbon,所以我们无需引入新的依赖。直接修改代码:
在RestTemplate的方法上添加@LoadBalanced注解即可
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

修改 ClassesController ,添加标识内容
package com.czxy.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.List; /** * @author 桐叔 * @email liangtong@itcast.cn */ @RestController @RequestMapping("/classes") public class ClassesController {@Resource private HttpServletRequest request; @GetMapping public List findAll(){ List list = new ArrayList<>(); list.add("Java12班"); list.add("Java34班"); list.add("服务端端口:" + request.getServerPort()); return list; } }

访问“学生服务”进行测试:
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片
扩展:源码追踪 为什么我们只输入了service名称就可以访问了呢?之前还要获取ip和端口。
显然有人帮我们根据service名称,获取到了服务实例的ip和端口。它就是LoadBalancerInterceptor
我们进行源码跟踪:
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

继续跟入execute方法:发现获取了8082端口的服务
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

再跟下一次,发现获取的是8081:
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

优化:负载均衡策略 为什么我们只输入了service名称就可以访问了呢? 显然有人帮我们根据service名称,获取到了服务实例的ip和端口。
通过对底层原理的分析,Ribbon采用是负载均衡策略进行的处理。
负载均衡策略初体验
第一步】添加整合Junit的坐标
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

org.springframework.boot spring-boot-starter-test

【第二步】编写测试类
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

package com.czxy; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; /** * @author 桐叔 * @email liangtong@itcast.cn */ @RunWith(SpringRunner.class) @SpringBootTest(classes = StudentApplication.class) public class TestRibbon { @Resource private RibbonLoadBalancerClient client; @Test public void test(){ for (int i = 0; i < 100; i++) { ServiceInstance instance = this.client.choose("classes-service"); System.out.println(instance.getHost() + ":" + instance.getPort()); } }}

SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

结果:
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

负载均衡的配置
SpringBoot提供了修改负载均衡规则的配置入口:
{服务名称}.ribbon.NFLoadBalancerRuleClassName=具体策略
例如:
# 指定服务设置负载均衡策略 classes-service: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

再次测试,发现结果变成了随机:
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

常见策略的配置(注意:下面提供了3个策略,同时只能使用一个。)
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

优化:重试机制 CAP原则
注册中心通常需要遵循CAP原则,CAP指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),往往三者不可兼得。
Eureka的服务治理主要强调是AP:即可用性和可靠性。
Eureka为了实现更高的服务可用性,牺牲了一定的一致性,极端情况下它宁愿接收故障实例也不愿丢掉健康实例,正如我们上面所说的自我保护机制。
但是,此时如果我们调用了这些不正常的服务,调用就会失败,从而导致其它服务不能正常工作!这显然不是我们愿意看到的。
效果演示
【第一步】我们现在关闭一个classes-service 9011实例:

【第二步】因为服务剔除的延迟,student-service并不会立即得到最新的服务列表,此时再次访问你会得到错误提示SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

【第三步】整合Spring Retry
此时,9010服务其实是正常的。
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

重试机制:Retry
因此Spring Cloud 整合了Spring Retry 来增强RestTemplate的重试能力,当一次服务调用失败后,不会立即抛出一次,而是再次重试另一个服务。
引入spring-retry依赖
SpringCloud|SpringCloud之Eureka注册中心与Robbin负载均衡
文章图片

org.springframework.retry spring-retry

只需要简单配置即可实现Ribbon的重试:
server: port: 9020 spring: application: name: student-service cloud: loadbalancer: retry: enabled: true eureka: client: service-url: #注册中心位置,多个地址以','隔开 defaultZone: http://localhost:10086/eureka/,http://localhost:10087/eureka registry-fetch-interval-seconds: 5 #从注册中心,获得列表的间隔时间 instance: #web页面显示效果和访问路径 instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port} prefer-ip-address: true lease-renewal-interval-in-seconds: 5#服务续约(renew)的间隔,默认值90秒 lease-expiration-duration-in-seconds: 10#服务失效时间,默认为30秒 # 指定服务设置负载均衡策略 #classes-service: #ribbon: #NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #NFLoadBalancerRuleClassName : com.netflix.loadbalancer.BestAvailableRule#并发最少 #NFLoadBalancerRuleClassName : com.netflix.loadbalancer.WeightedResponseTimeRule#请求时间权重classes-service: ribbon: ConnectTimeout: 250# Ribbon的连接超时时间 ReadTimeout: 1000# Ribbon的数据读取超时时间 OkToRetryOnAllOperations: true# 是否对所有操作都进行重试 MaxAutoRetriesNextServer: 1# 切换实例的重试次数 MaxAutoRetries: 1# 对当前实例的重试次数

【第四步】我们重启eureka_client,测试,发现即使user-service2宕机,也能通过另一台服务实例获取到结果!

    推荐阅读