https://blog.csdn.net/weixin_43591980/article/details/106255122#t4
Spring Cloud 五大组件
- 服务注册与发现——Netflix Eureka
负载均衡:
客户端负载均衡——Netflix Ribbon<br /> 服务端负载均衡:——Feign(其也是依赖于Ribbon,只是将调用方式RestTemplete 更改成Service 接口)
断路器——Netflix Hystrix
- 服务网关——Netflix Zuul
-
什么是微服务?
微服务是一种架构风格
- 一个应用拆分为一组小型服务
- 每个服务运行在自己的进程内,也就是可独立部署和升级
- 服务之间使用轻量级HTTP交互
- 服务围绕业务功能拆分
- 可以由全自动部署机制独立部署
-
微服务优缺点
优点
单一职责原则;
- 每个服务足够内聚,足够小,代码容易理解,这样能聚焦一个指定的业务功能或业务需求;
- 开发简单,开发效率高,一个服务可能就是专一的只干一件事;
- 微服务能够被小团队单独开发,这个团队只需2-5个开发人员组成;
- 微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的;
- 微服务能使用不同的语言开发;
- 易于和第三方集成,微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如jenkins,Hudson,bamboo;
- 微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果,无需通过合作才能体现价值;
- 微服务允许利用和融合最新技术;
- 微服务只是业务逻辑的代码,不会和HTML,CSS,或其他的界面混合;
每个微服务都有自己的存储能力,可以有自己的数据库,也可以有统一的数据库
缺点
开发人员要处理分布式系统的复杂性;
- 多服务运维难度,随着服务的增加,运维的压力也在增大;
- 系统部署依赖问题;
- 服务间通信成本问题;
- 数据一致性问题;
- 系统集成测试问题;
- 性能和监控问题
微服务技术栈
| 微服务技术条目 | 落地技术 | | —- | —- | | 服务开发 | SpringBoot、Spring、SpringMVC等 | | 服务配置与管理 | Netfix公司的Archaius、阿里的Diamond等 | | 服务注册与发现 | Eureka、Consul、Zookeeper等 | | 服务调用 | Rest、PRC、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等 |
为什么选择SpringCloud作为微服务架构
- SpringBoot专注于开苏方便的开发单个个体微服务;
- SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务,整合并管理起来,为各个微服务之间提供:配置管理、服务发现、断路器、路由、为代理、事件总栈、全局锁、决策竞选、分布式会话等等集成服务;
- SpringBoot可以离开SpringCloud独立使用,开发项目,但SpringCloud离不开SpringBoot,属于依赖关系;
- SpringBoot专注于快速、方便的开发单个个体微服务,SpringCloud关注全局的服务治理框架
Dubbo 和 SpringCloud技术选型
1. 分布式+服务治理Dubbo
目前成熟的互联网架构,应用服务化拆分 + 消息中间件2. Dubbo 和 SpringCloud对比
| | Dubbo | SpringCloud | | —- | —- | —- | | 服务注册中心 | Zookeeper | Spring Cloud Netfilx Eureka | | 服务调用方式 | RPC | REST API | | 服务监控 | Dubbo-monitor | Spring Boot Admin | | 断路器 | 不完善 | Spring Cloud Netfilx Hystrix | | 服务网关 | 无 | Spring Cloud Netfilx Zuul | | 分布式配置 | 无 | Spring Cloud Config | | 服务跟踪 | 无 | Spring Cloud Sleuth | | 消息总栈 | 无 | Spring Cloud Bus | | 数据流 | 无 | Spring Cloud Stream | | 批量任务 | 无 | Spring Cloud Task |
最大区别:Spring Cloud 抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式
Dubbo的定位是一款RPC框架,而SpringCloud的目标是微服务架构下的一站式解决方案。
SpringCloud能干嘛
- Distributed/versioned configuration 分布式/版本控制配置
- Service registration and discovery 服务注册与发现
- Routing 路由
- Service-to-service calls 服务到服务的调用
- Load balancing 负载均衡配置
- Circuit Breakers 断路器
-
SpringCloud Rest学习环境搭建:服务提供者
介绍
我们会使用一个Dept部门模块做一个微服务通用案例Consumer消费者(Client)通过REST调用Provider提供者(Server)提供的服务。
- 回顾Spring,SpringMVC,Mybatis等以往学习的知识。
- Maven的分包分模块架构复习 ```xml 一个简单的Maven模块结构是这样的:
— app-parent: 一个父项目(app-parent)聚合了很多子项目(app-util\app-dao\app-web…) |— pom.xml | |— app-core ||—— pom.xml | |— app-web ||—— pom.xml
一个父工程带着多个Moudule子模块<br />MicroServiceCloud父工程(Project)下初次带着3个子模块(Module)- microservicecloud-api 【封装的整体entity/接口/公共配置等】- microservicecloud-consumer-dept-80 【服务提供者】- microservicecloud-provider-dept-8001 【服务消费者】<a name="wiCPi"></a>#### 创建父工程- 新建父工程项目springcloud,切记**Packageing是pom模式**- 主要是定义POM文件,将后续各个子模块公用的jar包等统一提取出来,类似一个抽象父类<a name="HSmLL"></a>#### pom.xml```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"><modelVersion>4.0.0</modelVersion><groupId>com.haust</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><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--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.1.4.RELEASE</version><type>pom</type><scope>import</scope></dependency><!--数据库--><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><!--SpringBoot 启动器--><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>
父工程为springcloud,其下有多个子mudule,详情参考完整代码了解
springcloud-consumer-dept-80访问springcloud-provider-dept-8001下的controller使用REST方式
如DeptConsumerController.java
/*** @Auther: csp1999* @Date: 2020/05/17/22:44* @Description:*/@RestControllerpublic class DeptConsumerController {/*** 理解:消费者,不应该有service层~* RestTemplate .... 供我们直接调用就可以了! 注册到Spring中* (地址:url, 实体:Map ,Class<T> responseType)* <p>* 提供多种便捷访问远程http服务的方法,简单的Restful服务模板~*/@Autowiredprivate RestTemplate restTemplate;/*** 服务提供方地址前缀* <p>* Ribbon:我们这里的地址,应该是一个变量,通过服务名来访问*/private static final String REST_URL_PREFIX = "http://localhost:8001";//private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";/*** 消费方添加部门信息* @param dept* @return*/@RequestMapping("/consumer/dept/add")public boolean add(Dept dept) {// postForObject(服务提供方地址(接口),参数实体,返回类型.class)return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);}/*** 消费方根据id查询部门信息* @param id* @return*/@RequestMapping("/consumer/dept/get/{id}")public Dept get(@PathVariable("id") Long id) {// getForObject(服务提供方地址(接口),返回类型.class)return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);}/*** 消费方查询部门信息列表* @return*/@RequestMapping("/consumer/dept/list")public List<Dept> list() {return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);}}
使用RestTemplete先需要放入Spring容器中
ConfigBean.java
@Configurationpublic class ConfigBean {//@Configuration -- spring applicationContext.xml//配置负载均衡实现RestTemplate// IRule// RoundRobinRule 轮询// RandomRule 随机// AvailabilityFilteringRule : 会先过滤掉,跳闸,访问故障的服务~,对剩下的进行轮询~// RetryRule : 会先按照轮询获取服务~,如果服务获取失败,则会在指定的时间内进行,重试@Beanpublic RestTemplate getRestTemplate(){return new RestTemplate();}}
springcloud-provider-dept-8001的dao接口调用springcloud-api模块下的pojo,可使用在springcloud-provider-dept-8001的pom文件导入springcloud-api模块依赖的方式
<!--我们需要拿到实体类,所以要配置api module--><dependency><groupId>com.haust</groupId><artifactId>springcloud-api</artifactId><version>1.0-SNAPSHOT</version></dependency>
Eureka服务注册中心
什么是Eureka
- Netflix在涉及Eureka时,遵循的就是API原则.
- Eureka是Netflix的有个子模块,也是核心模块之一
Eureka是基于REST的服务,用于定位服务,以实现云端中间件层服务发现和故障转移,服务注册与发现对于微服务来说是非常重要的,有了服务注册与发现,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Dubbo的注册中心,比如Zookeeper
原理理解
Eureka基本的架构
Springcloud 封装了Netflix公司开发的Eureka模块来实现服务注册与发现 (对比Zookeeper).
- Eureka采用了C-S的架构设计,EurekaServer作为服务注册功能的服务器,他是服务注册中心.
- 而系统中的其他微服务,使用Eureka的客户端连接到EurekaServer并维持心跳连接

- 和Dubbo架构对比

- Eureka 包含两个组件:Eureka Server 和 Eureka Client.
- Eureka Server 提供服务注册,各个节点启动后,回在EurekaServer中进行注册,这样Eureka Server中的服务注册表中将会储存所有课用服务节点的信息,服务节点的信息可以在界面中直观的看到.
- Eureka Client 是一个Java客户端,用于简化EurekaServer的交互,客户端同时也具备一个内置的,使用轮询负载算法的负载均衡器
- 三大角色
- springcloud-eureka-7001 模块建立
pom.xml 配置
<!--导包~--><dependencies><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server --><!--导入Eureka Server依赖--><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>
application.yml ```yaml server: port: 7001
Eureka配置
eureka: instance:
# Eureka服务端的实例名字hostname: 127.0.0.1
client:
# 表示是否向 Eureka 注册中心注册自己(这个模块本身是服务器,所以不需要)register-with-eureka: false# fetch-registry如果为false,则表示自己为注册中心,客户端的化为 turefetch-registry: false# Eureka监控页面~service-url:defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
源码中Eureka的默认端口以及访问路径:<br />
4. 主启动类
```java
/**
* @Auther: csp1999
* @Date: 2020/05/18/10:26
* @Description: 启动之后,访问 http://127.0.0.1:7001/
*/
@SpringBootApplication
// @EnableEurekaServer 服务端的启动类,可以接受别人注册进来~
@EnableEurekaServer
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class,args);
}
}
- 启动成功后访问 http://localhost:7001/ 得到以下页面
2. eureka-client
调整之前创建的springlouc-provider-dept-8001
导入Eureca依赖
<!--Eureka依赖--> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency>application中新增Eureca配置
# Eureka配置:配置服务注册中心地址 eureka: client: service-url: defaultZone: http://localhost:7001/eureka/为主启动类添加@EnableEurekaClient注解
/** * @Auther: csp1999 * @Date: 2020/05/17/22:09 * @Description: 启动类 */ @SpringBootApplication // @EnableEurekaClient 开启Eureka客户端注解,在服务启动后自动向注册中心注册服务 @EnableEurekaClient public class DeptProvider_8001 { public static void main(String[] args) { SpringApplication.run(DeptProvider_8001.class,args); } }先启动7001服务端后启动8001客户端进行测试,然后访问监控页http://localhost:7001/ 产看结果如图

对比和Zookeeper区别
回顾CAP原则
- RDBMS (MySQL\Oracle\sqlServer) ===> ACID
NoSQL (Redis\MongoDB) ===> CAP
ACID是什么?
A (Atomicity) 原子性
- C (Consistency) 一致性
- I (Isolation) 隔离性
-
CAP是什么?
C (Consistency) 强一致性
- A (Availability) 可用性
-
CAP理论的核心
一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求
根据CAP原理,将NoSQL数据库分成了满足CA原则,满足CP原则和满足AP原则三大类 CA:单点集群,满足一致性,可用性的系统,通常可扩展性较差
- CP:满足一致性,分区容错的系统,通常性能不是特别高
AP:满足可用性,分区容错的系统,通常可能对一致性要求低一些
Eureka比Zookeeper好在哪
著名的CAP理论指出,一个分布式系统不可能同时满足C (一致性) 、A (可用性) 、P (容错性)
由于分区容错性P再分布式系统中是必须要保证的,因此我们只能再A和C之间进行权衡Zookeeper 保证的是 CP —> 满足一致性,分区容错的系统,通常性能不是特别高
Eureka 保证的是 AP —> 满足可用性,分区容错的系统,通常可能对一致性要求低一些
Ribbon:负载均衡(基于客户端)
负载均衡以及Ribbon
Ribbon是什么?
Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具
Ribbon能干嘛?
负载均衡 (LoadBalancer) ,在微服务或分布式集群中经常用的一种应用
负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA (高用)
负载均衡简单分类:集中式LB
即在服务的提供方和消费方之间使用独立的LB设施,如Nginx(反向代理服务器),由该设施负责把访问请求通过某种策略转发至服务的提供方
- 进程式 LB
将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。
Ribbon 就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址
集成Ribbon
springcloud-consumer-dept-80向pom.xml中添加Ribbon和Eureka依赖
<!--Ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--Eureka: Ribbon需要从Eureka服务中心获取要拿什么-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
在application.yml文件中配置Eureka
# 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/
主启动类加上@EnableEurekaClient注解,开启Eureka
//Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心IP地址和端口号
@SpringBootApplication
@EnableEurekaClient //开启Eureka 客户端
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class, args);
自定义Spring配置类:ConfigBean.java 配置负载均衡实现RestTemplate
@Configuration
public class ConfigBean {//@Configuration -- spring applicationContext.xml
@LoadBalanced //配置负载均衡实现RestTemplate
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
修改conroller:DeptConsumerController.java
//Ribbon:我们这里的地址,应该是一个变量,通过服务名来访问
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
使用Ribbon实现负载均衡

每次访问http://localhost/consumer/dept/list随机访问集群中某个服务提供者,这种情况叫做轮询,轮询算法在SpringCloud中可以自定义
@Configuration
public class ConfigBean {//@Configuration -- spring applicationContext.xml
/**
* IRule:
* RoundRobinRule 轮询策略
* RandomRule 随机策略
* AvailabilityFilteringRule : 会先过滤掉,跳闸,访问故障的服务~,对剩下的进行轮询~
* RetryRule : 会先按照轮询获取服务~,如果服务获取失败,则会在指定的时间内进行,重试
*/
@Bean
public IRule myRule() {
return new RandomRule();//使用随机策略
//return new RoundRobinRule();//使用轮询策略
//return new AvailabilityFilteringRule();//使用轮询策略
//return new RetryRule();//使用轮询策略
}
}
也可以自定义规则,在myRule包下自定义一个配置类MyRule.java,注意:该包不要和主启动类所在的包同级,要跟启动类所在包同级:
MyRule.java
/**
* @Auther: csp1999
* @Date: 2020/05/19/11:58
* @Description: 自定义规则
*/
@Configuration
public class MyRule {
@Bean
public IRule myRule(){
return new MyRandomRule();//默认是轮询RandomRule,现在自定义为自己的
}
}
主启动类开启负载均衡并指定自定义的MyRule配置类
//Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心IP地址和端口号
@SpringBootApplication
@EnableEurekaClient
//在微服务启动的时候就能加载自定义的Ribbon类(自定义的规则会覆盖原有默认的规则)
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRule.class)//开启负载均衡,并指定自定义的规则
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class, args);
}
}
Feign:负载均衡(基于服务端)
Feign简介
Feign是声明式Web Service客户端,它让微服务之间的调用变得更简单,类似controller调用service。SpringCloud集成了Ribbon和Eureka,可以使用Feigin提供负载均衡的http客户端
只需要创建一个接口,然后添加注解即可~
Feign能干什么?
- Feign旨在使编写Java Http客户端变得更容易
前面在使用Ribbon + RestTemplate时,利用RestTemplate对Http请求的封装处理,形成了一套模板化的调用方法
Feign默认集成了Ribbon
利用Ribbon维护了MicroServiceCloud-Dept的服务列表信息,并且通过轮询实现了客户端的负载均衡
- 而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用
Feign和Ribbon二者对比
前者显现出面向接口编程特点,代码看起来更清爽
Feign调用方式更符合我们之前在做SSM或者SprngBoot项目时,Controller层调用Service层的编程习惯
