SpringCloud使用手册
本文最后更新于:2021年1月25日 晚上
一、常见面试题
1.1 什么是微服务?
1.2 微服务之间是如何独立通讯的?
1.3 SpringCloud 和 Dubbo有那些区别?
1.4 SpringBoot 和 SpringCloud,请谈谈你对他们的理解
1.5 什么是服务熔断?什么是服务降级?
1.6 微服务的优缺点分别是什么?说下你在项目开发中遇到的坑
1.7 你所知道的微服务技术栈有哪些?列举一二
1.8 Eureka和Zookeeper都可以提供服务注册与发现的功能,请说说两者的区别
1.9 SpringCloud的五大组件
- 服务注册与发现:Netflix Eureka
- 负载均衡:
- 客户端负载均衡:Netflix Ribbon
- 服务端负载均衡:Feign(其也是基于Ribbon,只是将调用方式Rest Templete更改成Service 接口)
- 断路器:Netflix Hystrix
- 服务网关:Netflix Zuul
- 此外,分布式配置可以使用Spring Cloud Config实现
…
二、微服务概述
1)什么是微服务
微服务架构是一种架构模式,它将单一应用程序划分成一组小的服务,服务之间相互协调,互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务之间采用轻量级的通信机制(如HTTP)互相协作,每个服务都围绕着具体的业务进行构建,并且能够被独立的部署到生产环境中,另外,应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具(如Maven)对其进行构建。
微服务化的核心就是将传统的一站式应用,根据业务拆分为一个一个的服务,彻底的解耦,每一个微服务提供单个业务功能的服务,一个服务做一件事情。从技术角度看就是一种小而独立的处理过程,类似进程的概念,能够自行单独启动或者销毁,拥有自己独立的数据库
2)优缺点
- 优点:开发简单,开发效率高,一个服务可能就是专一的只干一件事;微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的;每个微服务都有自己的存储能力,可以有自己的数据库,也可以有统一的数据库;微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果,无需通过合作才能体现价值
- 缺点:开发人员要处理分布式系统的复杂性,处理系统部署依赖、服务间通信成本、数据一致性、系统集成测试、性能和监控问题等等;多服务运维难度,随着服务的增加,运维的压力也在增大
3)微服务的技术栈
微服务技术条目 | 落地技术 |
---|---|
服务开发 | SpringBoot、Spring、SpringMVC等 |
服务配置与管理 | Netfix公司的Archaius、阿里的Diamond等 |
服务注册与发现 | Eureka、Consul、Zookeeper等 |
服务调用 | Rest、RPC、gRPC |
服务熔断器 | Hystrix、Envoy等 |
负载均衡 | Ribbon、Nginx等 |
服务接口调用(客户端调用服务的简化工具) | Fegin等 |
消息队列 | Kafka、RabbitMQ、ActiveMQ等 |
服务配置中心管理 | SpringCloudConfig、Chef等 |
服务路由(API网关) | Zuul等 |
服务监控 | Zabbix、Nagios、Metrics、Specatator等 |
全链路追踪 | Zipkin、Brave、Dapper等 |
数据流操作开发包 | SpringCloud Stream(封装与Redis,Rabbit,Kafka等发送接收消息) |
时间消息总栈 | SpringCloud Bus |
服务部署 | Docker、OpenStack、Kubernetes等 |
4)各微服务框架对比
功能点/服务框架 | Netflix/SpringCloud | Motan | gRPC | Thri t | Dubbo/DubboX |
---|---|---|---|---|---|
功能定位 | 完整的微服务框架 | RPC框架,但整合了ZK或Consul,实现集群环境的基本服务注册发现 | RPC框架 | RPC框架 | 服务框架 |
支持Rest | 是,Ribbon支持多种可拔插的序列号选择 | 否 | 否 | 否 | 否 |
支持RPC | 否 | 是(Hession2) | 是 | 是 | 是 |
支持多语言 | 是(Rest形式) | 否 | 是 | 是 | 否 |
负载均衡 | 是(服务端zuul+客户端Ribbon),zuul-服务,动态路由,云端负载均衡Eureka(针对中间层服务器) | 是(客户端) | 否 | 否 | 是(客户端) |
配置服务 | Netfix Archaius,Spring Cloud Config Server 集中配置 | 是(Zookeeper提供) | 否 | 否 | 否 |
服务调用链监控 | 是(zuul),zuul提供边缘服务,API网关 | 否 | 否 | 否 | 否 |
高可用/容错 | 是(服务端Hystrix+客户端Ribbon) | 是(客户端) | 否 | 否 | 是(客户端) |
典型应用案例 | Netflix | Sina | |||
社区活跃程度 | 高 | 一般 | 高 | 一般 | 2017年后重新开始维护,之前中断了5年 |
学习难度 | 中等 | 低 | 高 | 高 | 低 |
文档丰富程度 | 高 | 一般 | 一般 | 一般 | 高 |
其他 | Spring Cloud Bus为我们的应用程序带来了更多管理端点 | 支持降级 | Netflix内部在开发集成gRPC | IDL定义 | 实践的公司比较多 |
三、SpringCloud概述
1)SpringCloud 和 SpringBoot间的联系
- SpringBoot专注于开发单个个体微服务
- SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务,整合并管理起来,为各个微服务之间提供:配置管理、服务发现、断路器、路由、为代理、事件总栈、全局锁、决策竞选、分布式会话等等集成服务;
- SpringBoot可以离开SpringCloud独立使用,开发项目,但SpringCloud离不开SpringBoot,属于依赖关系;
- SpringBoot专注于快速、方便的开发单个个体微服务,SpringCloud关注全局的服务治理框架;
2)SpringCloud 和 Dubbo间的区别
Dubbo | SpringCloud | |
---|---|---|
服务注册中心 | Zookeeper | Spring Cloud Netflix Eureka |
服务调用方式 | RPC | REST API |
服务监控 | Dubbo-monitor | Spring Boot Admin |
断路器 | 不完善 | Spring Cloud Netflix Hystrix |
服务网关 | 无 | Spring Cloud Netflix Zuul |
分布式配置 | 无 | Spring Cloud Config |
服务跟踪 | 无 | Spring Cloud Sleuth |
消息总栈 | 无 | Spring Cloud Bus |
数据流 | 无 | Spring Cloud Stream |
批量任务 | 无 | Spring Cloud Task |
最大区别是:SpringCloud抛弃了Dubbo的RPC通信,改为采用基于HTTP的REST方式调用服务,虽然在一定程度上来说,后者牺牲了服务调用的性能,但REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这个优点在当下强调快速演化的微服务环境下,显得更加合适。
Dubbo断更了五年,重新维护后开始定位为一款专业的RPC框架,而SpringCloud的目标是微服务架构下的一站式解决方案
3)版本概述
官网:http://projects.spring.io/spring-cloud/
SpringCloud没有采用数字编号的方式命名版本号,而是采用了伦敦地铁站的名称,同时根据字母表的顺序来对应版本时间顺序,比如最早的Release版本:Angel,第二个Release版本:Brixton,然后是Camden、Dalston、Edgware,目前最新的是Hoxton.SR9
- SpringCloud Netflix 中文文档:https://springcloud.cc/spring-cloud-netflix.html
- SpringCloud 中文API文档(官方文档翻译版):https://springcloud.cc/spring-cloud-dalston.html
四、SpringCloud 基础环境构建
1)任务概述
我们会使用一个Dept部门模块做一个微服务通用案例:Consumer消费者(Client)通过REST调用Provider提供者(Server)提供的服务
2)创建父工程
新建父工程springcloud,导入相关依赖
<?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.kuang</groupId>
<artifactId>springcloud</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 包含的各个子模块 -->
<modules>
<module>springcloud-api</module>
<module>springcloud-provider-dept-8001</module>
<module>springcloud-consumer-dept-80</module>
<module>springcloud-eureka-7001</module>
<module>springcloud-eureka-7002</module>
<module>springcloud-eureka-7003</module>
<module>springcloud-provider-dept-8002</module>
<module>springcloud-provider-dept-8003</module>
<module>springcloud-consumer-dept-feign</module>
<module>springcloud-provider-dept-hystrix-8001</module>
<module>springcloud-consumer-hystrix-dashboard</module>
<module>springcloud-zuul-9527</module>
<module>springcloud-config-server-3344</module>
<module>springcloud-config-client-3355</module>
<module>springcloud-config-eureka-7001</module>
<module>springcloud-config-dept-8001</module>
</modules>
<!-- 打包方式为 pom-->
<packaging>pom</packaging>
<!-- 项目编码方式为UTF-8,java版本1.8
可以在此处指定一些包的版本,下面直接调用该值即可-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
</properties>
<!-- 各个依赖项 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--springCloud的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--SpringBoot依赖项(直接创建Springboot工程时的父依赖)-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.4.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--数据库驱动、连接池、Mybatis-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--日志及测试-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
3)创建实体类Dept
4)服务提供方
导入相关依赖,如实体类的api module、spring相关、数据库相关等等。由于子模块会集成父项目,因此,此处无需指定Spring这类包的版本号。
<dependency>
<groupId>com.kuang</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
编写dao接口及其实现,编写service接口及其实现(调用dao接口),更新配置文件application.yml
server:
port: 8001
#mybatis配置
mybatis:
type-aliases-package: com.kuang.springcloud.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
#spring的配置
spring:
application:
name: springcloud-provider-dept # 该名字对应Eureka监控界面中的application name
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/db01?serverTimezone=UTC&useUnicode=true&useSSL=false&characterEncoding=utf-8
username: root
password: root
5)服务消费方
DeptConsumerController.java
package com.kuang.springcloud.controller;
import com.kuang.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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 java.util.List;
@RestController
public class DeptConsumerController {
// 消费者,其调用生成者的服务,因此其本身无需创建service层
// RestTemplate 提供多种便捷访问远程http服务的方法,简单的Restful服务模板!
@Autowired
private RestTemplate restTemplate;
// 服务提供方的地址
//private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
private static final String REST_URL_PREFIX = "http://localhost:8001";
// 通过url+实体 +响应类型 调用服务提供者的对应方法
// 提交用postForObject,获取用getForObject
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
}
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list(){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);
}
}
采用RestTemplete前,需将其添加到Spring容器中。创建config/ConfigBean.java文件
package com.kuang.springcloud.config;
import com.netflix.loadbalancer.IRule;
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 ConfigBean {
// 配置负载均衡实现RestTemplate
// 可以通过重写IRule类,自定义负载均衡的规则,默认为轮询
// RoundRobinRule 轮询;RandomRule 随机;AvailabilityFilteringRule 先过滤掉跳闸、访问故障的服务,再对剩下的进行轮询;RetryRule 先按照轮询获取服务,如果服务获取失败,则会在指定的时间内进行,重试
@Bean // 将Restful服务模板注册到Spring容器中
@LoadBalanced // 开启Ribbon的负载均衡
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
此时,按理说此时就可以启动springcloud-provider-dept-8001和springcloud-consumer-dept-80的启动类,然后通过
http://localhost:8001/consumer/dept/list
调用相关方法了。
五、Eureka:服务注册中心
1)概述
Eureka是Netflix开发的一款服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。
Eureka包含两个组件:Eureka Server和Eureka Client。
Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client 是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的,使用轮询负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳 (默认周期为30秒) 。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除掉 (默认周期为90s).
- Eureka Server:提供服务的注册与发行
- Service Provider:服务提供方,将自身服务注册到Eureka中,从而使服务消费方可以找到并调用
- Service Consumer:服务消费方,从Eureka中获取注册服务列表,从而找到所需要的服务
基础环境中搭配完毕,只要再构建好服务注册中心,就可以…(Eureka的好处体现在哪呢。。)
2)构建步骤
基本可以分为三步:导入依赖、配置yaml文件、开启注解
🌏 服务器端:创建子maven模块springcloud-eureka-7001,导入eureka依赖,编写配置文件修改服务器端实例名称、监控界面地址等等,最后在主启动类中开启注解
<dependencies>
<!-- 注册中心Eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!-- 热部署工具 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
server:
port: 7001
#Eureka配置
eureka:
instance:
hostname: eureka7001.com # Eureka服务端的实例名称,一般为127.0.0.1或者localhost(此处修改了host文件)
client:
register-with-eureka: false # 是否在eureka注册中心中进行注册,此处为服务器端,无需注册
fetch-registry: false # 注册中心端为false,客户端为true
service-url: # 监控界面
# 单机:
#defaultZone: http://${eureka.instance.hostname}:${server.port}/
# 集群(关联):
defaultZone: http://eureka7002.com:7002/,http://eureka7003.com:7003/
package com.kuang.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer // 开启注解,使客户端可以注册进来
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class,args);
}
}
若要构建注册中心集群,可以按照子maven模块springcloud-eureka-7001中的文件,新建7002和7003子模块,然后仅修改两个新的子模块中的yaml配置文件即可
server:
port: 7002
#Eureka配置
eureka:
instance:
hostname: eureka7002.com #Eureka服务端的实例名称
client:
register-with-eureka: false # 是否在eureka注册中心中进行注册,此处为服务器端,无需注册
fetch-registry: false # 注册中心端为false,客户端为true
service-url: # 监控界面,端口号后面没有Eureka!!
defaultZone: http://eureka7001.com:7001/,http://eureka7003.com:7003/
server:
port: 7003
#Eureka配置
eureka:
instance:
hostname: eureka7003.com #Eureka服务端的实例名称
client:
register-with-eureka: false # 表示是否向eureka注册中心注册自己
fetch-registry: false #fetch-registry如果为false,则表示自己为注册中心
service-url: # 监控页面
defaultZone: http://eureka7001.com:7001/,http://eureka7002.com:7002/
🌏 客户端1:修改之前的 服务提供端子模块springcloud-provider-dept-8001
,将其在注册中心中注册服务。依旧是导入eureka依赖、更新yaml文件、开启注解三步
# Eureka的配置,服务注册到哪里
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
instance:
instance-id: springcloud-provider-dept8001 # 修改eureka上的默认描述信息!
prefer-ip-address: true # 是否在eurake监控界面显示服务的IP地址
package com.kuang.springcloud;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
//启动类
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到Eureka中!
public class DeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class,args);
}
}
此时,启动这两个子模块,访问http://eureka7001.com:7001/ 或者 http://localhost:7001/即可进入Spring Eureka的监控界面。
🌏 客户端2:修改之前的 服务消费端子模块springcloud-consumer-dept-80
,导入eureka依赖,并在yaml文件中配置注册中心的地址,主启动类开启注解
server:
port: 80
#Eureka配置
eureka:
client:
register-with-eureka: false # 不向Eureka注册自己
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
package com.kuang.springcloud;
import com.kuang.myrule.KuangRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
@SpringBootApplication
@EnableEurekaClient
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class,args);
}
}
此时启动该子模块,即可通过http://localhost:80/consumer/dept/list执行相应的服务
3)Eureka 和 ZooKeeper
- ACID原则:Atomicity 原子性、Consistency 一致性、Isolation 隔离性、Durability 持久性
- CAP原则:Consistency 一致性、Availability 可用性、Partition tolerance 分区容错性
- 一个分布式系统不可能同时很好的满足CAP原则,只能三选二;但分区容错性对分布式系统是非常重要的,因此,只能最终只能在一致性和可用性间抉择。
- 两者的区别在于:
- Zookeeper保证的是一致性和分区容错性,CP:当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但zookeeper会出现这样一种情况,当主节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。而leader选举的时间一般可能会持续30-120s,且选举期间整个zookeeper集群是不可用的,这就会导致选举期间的整个注册服务瘫痪。在云部署的环境下,因为网络问题使得zookeeper集群失去master节点是较大概率发生的事件,虽然服务最终能够恢复,但是,漫长的选举时间导致注册长期不可用,是不可容忍的。
- Eureka保证的是可用性和分区容错性,AP:各个节点是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册时,如果发现连接失败,则会自动切换至其他节点,只要有一台Eureka还在,就能保住注册服务的可用性,只不过查到的信息可能不是最新的,除此之外,Eureka还有之中自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
- Eureka不在从注册列表中,移除因为长时间没收到心跳而应该过期的服务
- Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上 (即保证当前节点依然可用)
- 当网络稳定时,当前实例新的注册信息会被同步到其他节点中
- Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪
六、Ribbon:基于客户端的负载均衡
1)概述
Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具。
负载均衡(LoadBalancer,LB)就是将用户的请求分配到多个服务器上,从而达到系统的HA (高用)。
常见的负载均衡软件有 Nginx、Lvs等等。Dubbo、SpringCloud等也支持负载均衡,
分类:
- 集中式LB:在服务的提供方和消费方之间使用独立的负载均衡设施,如反向代理服务器Nginx,由该设施负责将访问请求通过某种策略转发至服务提供方
- 进程式LB:将负载均衡集成到消费方,消费方从服务注册中心获取可用的服务地址,然后自己再从这些地址选取一个使用,如Ribbon
- 没太懂啊…
2)集成Ribbon
黄金三步,导入依赖,配置yaml文件,开启注释
由于Ribbon是集成于消费方的负载均衡应用,因此我们对之前的子模块springcloud-consumer-dept-80
进行升级改造
导入Eureka和Ribbon依赖
<?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>com.kuang</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>springcloud-consumer-dept-80</artifactId> <dependencies> <!-- 实体类、web、热部署 --> <dependency> <groupId>com.kuang</groupId> <artifactId>springcloud-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <!-- 注册中心erueka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!-- 负载均衡Ribbon --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.6.RELEASE</version> </dependency> </dependencies> </project>
配置yaml
server: port: 80 #Eureka配置 eureka: client: register-with-eureka: false # 不向Eureka注册自己 service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
开启注释
在配置类
src/main/java/com/kuang/springcloud/config/ConfigBean.java
加入注释@LoadBalanced
开启负载均衡package com.kuang.springcloud.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 ConfigBean { @Bean @LoadBalanced // 开启负载均衡 public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
修改Controller这的远程路径:之前只有一个服务提供者,我们可以采用某个端口号来访问,但目前多个服务提供者时采用固定的地址和端口就不现实了。此时,我们可以将控制器类
DeptConsumerController.java
的restful地址修改为应用程序名。//private static final String REST_URL_PREFIX = "http://localhost:8001"; private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
此时,多次访问
http://localhost/consumer/dept/list
,便会发现数据来源从db01-db03直接切换。这是因为Ribbon负载均衡已成功启用,每次访问时按照轮询算法
访问服务器
如何改变或者自定义Ribbon的负载均衡规则呢?
创建文件src/mian/java/com/kuang/myrule/KuangRule.java
,重写Irule方法即可。
- myrule文件夹不可与主启动类同一级目录
package com.kuang.myrule;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class KuangRule {
@Bean
public IRule myRule(){
return new RoundRobinRule(); // 默认是轮询
//return new RandomRule(); // 随机
//return new AvailabilityFilteringRule(); // 会先过滤掉,跳闸,访问故障的服务,对剩下的进行轮询
//return new RetryRule(); // 会先按照轮询获取服务,如果服务获取失败,则会在指定的时间内进行,重试
//return new MyCustomRule() // 我们自定义的规则
}
}
之后,还需将该配置文件绑定到主启动类上
package com.kuang.springcloud;
import com.kuang.myrule.KuangRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
//Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心IP地址和端口号~
@SpringBootApplication
@EnableEurekaClient
//在微服务启动的时候就能去加载我们自定义Ribbon类;该类不要和主启动类放在同一目录下
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = KuangRule.class)
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class,args);
}
}
七、Feign:基于服务端的负载均衡
1)Feign概述
2)使用步骤
3)Feign与Ribbon区别
八、Hystrix:服务熔断
1)概述
服务雪崩
Hystrix
2)采用服务熔断
3)服务降级
九、Zuul:路由网关
1)Zuul概述
Zull包含了对请求的路由(用来跳转的)和过滤两个最主要功能:
- 路由功能:负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础,
- 过滤器功能:负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础。
Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。
2)入门案例
新建
springcloud-zuul-9527
,导入依赖<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> <version>1.4.6.RELEASE</version> </dependency>
编写配置文件
server: port: 9527 spring: application: name: springcloud-zuul #微服务名称 # eureka 注册中心配置 eureka: client: service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ instance: #实例的id instance-id: zuul9527.com prefer-ip-address: true # 显示ip info: app.name: haust.springcloud # 项目名称 company.name: 河南科技大学西苑校区 # 公司名称 # zull 路由网关配置 zuul: # 路由相关配置 # 原来访问路由 eg:http://www.cspStudy.com:9527/springcloud-provider-dept/dept/get/1 # zull路由配置后访问路由 eg:http://www.cspstudy.com:9527/haust/mydept/dept/get/1 routes: mydept.serviceId: springcloud-provider-dept # eureka注册中心的服务提供方路由名称 mydept.path: /mydept/** # 将eureka注册中心的服务提供方路由名称 改为自定义路由名称 # 不能再使用这个路径访问了,*: 忽略,隐藏全部的服务名称~ ignored-services: "*" # 设置公共的前缀 prefix: /haust
十、SpringCloud Config分布式配置
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!