博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringCloud——简介,5大组件
阅读量:5308 次
发布时间:2019-06-14

本文共 23226 字,大约阅读时间需要 77 分钟。

一、SpringCloud简介

微服务

微服务化的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底地去解耦合,每一个微服务提供单个业务功能也服务,一个服务做一件事,从技术角度看就是一种小而独立的处理过程,类似进程概念,能够自行单独启动或销毀,拥有自己独立的数据库。

SpringCloud与Dubbo对比

  Dubbo SpringCloud
服务注册中心 Zookeeper Eureka
服务调用方式 RPC RestAPI
服务监控 Dubbo-monitor Spring Boot Admin
断路器 不完善 Hystrix
服务网关 Zuul
分布式配置 Spring Cloud Config
服务跟踪 Spring Cloud Sleuth
消息总线 Spring Cloud Bus
数据流 Spring Cloud Stream
批量任务 Spring Cloud Task

最大区别:SpringCloud抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式。 严格来说,这两种方式各有优劣,虽然从一定程度上来说,后者牺牲了服务调用的性能,但也避免了上面提到的原生RPC带来的问题。而且REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这在强调快速演化的微服务环境下,显得更加合适。

一、Rest微服务构建

项目结构

microservicecloud  // 父项目   |- microservicecloud-api  // 存放公共接口、实体类。。   |- microservicecloud-provider-dept-8081  // 部门服务提供者   |- microservicecloud-consumer-dept-80  // 部门服务消费者

1、创建maven父项目

书写pom.xml文件

1 
2
5
4.0.0
6 7
cn.x5456
8
microservicecloud
9
pom
10
1.0-SNAPSHOT
11
12
microservicecloud-api
13
14 15
16
UTF-8
17
1.8
18
1.8
19
4.12
20
1.2.17
21
1.16.18
22
23 24
25
26
27
org.springframework.cloud
28
spring-cloud-dependencies
29
Dalston.SR1
30
pom
31
import
32
33
34
org.springframework.boot
35
spring-boot-dependencies
36
1.5.9.RELEASE
37
pom
38
import
39
40
41
mysql
42
mysql-connector-java
43
5.0.4
44
45
46
com.alibaba
47
druid
48
1.0.31
49
50
51
org.mybatis.spring.boot
52
mybatis-spring-boot-starter
53
1.3.0
54
55
56
ch.qos.logback
57
logback-core
58
1.2.3
59
60
61
junit
62
junit
63
${junit.version}
64
test
65
66
67
log4j
68
log4j
69
${log4j.version}
70
71
72
73 74
75
microservicecloud
76
77
78
src/main/resources
79
true
80
81
82
83
84
org.apache.maven.plugins
85
maven-resources-plugin
86
87
88
$
89
90
91
92
93
94 95
View Code

2、创建microservicecloud-api项目

和上面一样

1)书写pom.xml文件

1 
2
5
6
microservicecloud
7
cn.x5456
8
1.0-SNAPSHOT
9
10
4.0.0
11 12
microservicecloud-api
13 14
15
16
org.springframework.cloud
17
spring-cloud-starter-feign
18
19
20
org.springframework.boot
21
spring-boot-starter-data-jpa
22
23
24
View Code

2)书写实体类

// 在api中这样写,有一点问题@Entity // 告诉JPA这是一个实体类(对应数据表),不是普通的javabean@Table(name = "tb_dept")   // 不写这个注解,默认为这个类的小写作为名字public class Dept implements Serializable {    @Id // 标识这是主键    @GeneratedValue(strategy = GenerationType.AUTO) // 根据数据库自动选则主键自增类型    private Long 	deptno; // 主键    private String 	dname; // 部门名称    private String 	dbSource;// 来自那个数据库,因为微服务架构可以一个服务对应一个数据库,同一个信息被存储到不同数据库

3、创建microservicecloudproviderdept8081(提供者)

1)书写pom.xml文件

1 
2
5
6
microservicecloud
7
cn.x5456
8
1.0-SNAPSHOT
9
10
4.0.0
11 12
microservicecloud-provider-dept-8081
13
14
15
16
cn.x5456
17
microservicecloud-api
18
${project.version}
19
20
21
22
org.springframework.boot
23
spring-boot-starter-actuator
24
25
26
27
org.springframework.cloud
28
spring-cloud-starter-eureka
29
30
31
org.springframework.cloud
32
spring-cloud-starter-config
33
34
35
junit
36
junit
37
38
39
40
41
42
43
com.oracle
44
ojdbc14
45
10.2.0.4.0
46
47
48
com.alibaba
49
druid
50
51
52
ch.qos.logback
53
logback-core
54
55
56
org.mybatis.spring.boot
57
mybatis-spring-boot-starter
58
59
60
org.springframework.boot
61
spring-boot-starter-jetty
62
63
64
org.springframework.boot
65
spring-boot-starter-web
66
67
68
org.springframework.boot
69
spring-boot-starter-test
70
71
72
73
org.springframework
74
springloaded
75
76
77
org.springframework.boot
78
spring-boot-devtools
79
80
81 82
View Code

2)目录结构

DeptProvider8081_App

@SpringBootApplicationpublic class DeptProvider8001_App {	public static void main(String[] args) {		SpringApplication.run(DeptProvider8001_App.class, args);	}}

controller

@RestControllerpublic class DeptController {	@Autowired	private DeptService service;	@RequestMapping(value = "/dept/add", method = RequestMethod.POST)	public Dept add(Dept dept){		return service.addDept(dept);	}	@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)	public Dept get(@PathVariable("id") Long id)	{		return service.findById(id);	}	@RequestMapping(value = "/dept/list", method = RequestMethod.GET)	public List
list(){ return service.findAll(); }}

service

@Servicepublic class DeptServiceImpl implements DeptService {    @Resource    private DeptRepository deptRepository;    @Override    public Dept addDept(Dept dept) {        return deptRepository.save(dept);    }    @Override    public Dept findById(Long id) {        return deptRepository.findOne(id);    }    @Override    public List
findAll() { return deptRepository.findAll(); }}

repository

public interface DeptRepository extends JpaRepository
{}

3)书写配置文件

spring:  application:      name: microservicecloud-dept  datasource:    url: jdbc:oracle:thin:@127.0.0.1:1521:orcl    username: scott    password: tiger    driver-class-name: oracle.jdbc.OracleDriver  jpa:    hibernate:      # 更新或创建数据表      ddl-auto: update    # 控制台打印sql    show-sql: trueserver:  context-path: /DeptProvider8001_App  port: 8001

4、创建microservicecloudconsumerdept80

1)书写pom.xml文件

1 
2
5
6
microservicecloud
7
cn.x5456
8
1.0-SNAPSHOT
9
10
4.0.0
11 12
microservicecloud-consumer-dept-80
13 14
15
16
cn.x5456
17
microservicecloud-api
18
${project.version}
19
20
21
22
org.springframework.cloud
23
spring-cloud-starter-eureka
24
25
26
org.springframework.cloud
27
spring-cloud-starter-ribbon
28
29
30
org.springframework.cloud
31
spring-cloud-starter-config
32
33
34
org.springframework.boot
35
spring-boot-starter-web
36
37
38
39
org.springframework
40
springloaded
41
42
43
org.springframework.boot
44
spring-boot-devtools
45
46
47
com.oracle
48
ojdbc14
49
10.2.0.4.0
50
51
52 53
View Code

2)目录结构

DeptConsumer80_App

@SpringBootApplicationpublic class DeptConsumer80_App {	public static void main(String[] args) {		SpringApplication.run(DeptConsumer80_App.class, args);	}}

书写配置类

@Configurationpublic class ConfigBean //boot -->spring   applicationContext.xml --- @Configuration配置   ConfigBean = applicationContext.xml{ 	@Bean	public RestTemplate getRestTemplate(){		return new RestTemplate();	}}

controller

@RestControllerpublic class DeptController_Consumer{	private static final String REST_URL_PREFIX = "http://localhost:8001/DeptProvider8001_App";	/**	 * 使用 使用restTemplate访问restful接口非常的简单粗暴无脑。 (url, requestMap,	 * ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。	 */	@Autowired	private RestTemplate restTemplate;	@RequestMapping(value = "/consumer/dept/add")	public boolean add(Dept dept)	{		return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);	}	@RequestMapping(value = "/consumer/dept/get/{id}")	public Dept get(@PathVariable("id") Long id)	{		return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);	}	@RequestMapping(value = "/consumer/dept/list")	public List
list() { return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class); }}

3)配置文件

### 理论上这部分不应该有 ###spring:  datasource:    url: jdbc:oracle:thin:@127.0.0.1:1521:orcl    username: scott    password: tiger    driver-class-name: oracle.jdbc.OracleDriver  jpa:    hibernate:      # 更新或创建数据表      ddl-auto: update    # 控制台打印sql    show-sql: true################## server:  port: 80  context-path: /DeptConsumer80_App

二、Eureka

 

简介

 

Eureka是Spring Cloud Netflix的一个子模块,也是核心模块之一。用于云端服务发现,一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务的注册与发现对应微服务架构来说是非常重要的,有了服务的发现与注册,只需要使用服务标识符,就可以访问到服务,而不需要修改服务调用的配置文件了。

 

其功能类似与dubbo的注册中心(zookeeper)。

 

基本架构

 

SpringCloud封装了Netflix公司开发的Eureka模块来实现服务的注册与发现

 

Eureka采用了C-S的设计架构。Eureka Server作为服务注册功能的服务器,它是服务的注册中心。而系统中其他的微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接,这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。SpringCloud的一些其他模块(Zuul)就可以通过Eureka来发现系统中的其他微服务,并执行相关的逻辑。

Eureka包含两个组件:Eureka Server和Eureka Client

 

Eureka Server提供服务注册服务,在各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务阶段的信息可以在界面中直观的看到。

 

EurekaClient是一个Java客户端,用于简化EurekaServer的交互,客户端同时也具备一个内置的、使用轮询负载算法的负载均衡器。在应用启动后,将会EurekaServer发送心跳(默认周期是30s)。如果EurekaServer在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中吧这个服务节点移除(默认30s)。

 

SpringCloud中三大角色

 

  • EurekaServer:提供服务的注册和发现

  • Server Provider服务提供方将自身服务注册到Eureka,从而使服务消费方可以找到

  • Service Consumer服务消费方从Eureka获取注册服务列表,从而可以消费服务

Euraka的自我保护模式

 

默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络分区发生故障时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端时(可能网络分区发生故障),那么这个节点就会进入自我保护模式。一旦进入改模式,EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,改Eureka节点会自动退出自我保护模式。

综上自我保护模式是一种应对网络异常的安全保护措施。他的架构哲学是宁可保留所有微服务(不管它健不健康都会保留),也不盲目注销任何微服务。使用自我保护模式,可以让Eureka集群更加健壮、稳定。

作为服务注册中心,Eureka比Zookeeper好在哪

分布式系统的CAP理论

● 一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)

● 可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)

● 分区容错性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

Zookeeper保证的是CP

当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟前的注册信息,但不能接受直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是Zookeeper会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s,且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。

Eureka保证的是AP

Eureka看明白了这一点,因此在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作 ,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分祌内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:

  1. Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务

  2. Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)

  3. 当网络稳定时,当前实例新的注册信息会被同步到其它节点中

因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像Zookeeper那样是整个注册服务瘫痪。

 

项目中引入Eureka

1、新建Eureka项目microservicecloud-eureka-7001

1)新建项目

2)目录结构

MicroservicecloudEureka7001Application

@SpringBootApplication@EnableEurekaServer		// 代表eureka服务端public class MicroservicecloudEureka7001Application {	public static void main(String[] args) {		SpringApplication.run(MicroservicecloudEureka7001Application.class, args);	}}

书写配置文件

# 端口号server.port=7001# 主机名eureka.instance.hostname=localhost# 是否向服务注册中心注册自己eureka.client.register-with-eureka=false# 是否检索服务,false表示自己就是注册中心,不需要去检索服务eureka.client.fetch-registry=false# 服务注册中心的配置内容,指定服务注册中心的位置eureka.client.service-url.defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

2、修改提供者和消费者部分配置

1)修改服务提供者与消费者的主方法

@SpringBootApplication @EnableEurekaClient       // eureka客户端 public class DeptProvider8001_App {
public static void main(String[] args) {
SpringApplication.run(DeptProvider8001_App.class, args); } }

2)为服务提供者与消费者配置文件中添加配置

eureka:   client:     service-url:       defaultZone: http://localhost:7001/eureka/

3)还要在restTemplate上添加负载均衡注解,客户端才可以调用

此时url可以改为提供者在Eureka中注册的名字

Eureka集群的搭建

1、再创建2个Eureka项目

2、修改系统hosts文件的映射(为了防止名字冲突)

3、书写配置文件

4、修改服务提供者的配置文件

将这个服务注册到每一个eureka上

5、成功页面

三、Ribbon

简介

Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。

Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载衡算法,将Netflix的中间层服务连接在一起。 Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer (负载均衡)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。

基本架构

Ribbon在工作时分成两步

第一步先选择EurekaServer,他优先选则在同一个区域内负载较少的server

第二步在根据用户指定的策略,从server渠道的服务注册列表中选则一个地址。

Ribbon的irule组件

Ribbon默认是采用轮询的方式进行负载均衡,我们可以使用irule进行指定。

Ribbon的使用

首先要在(消费者)pom.xml文件中引入jar包

org.springframework.cloud
spring-cloud-starter-eureka
org.springframework.cloud
spring-cloud-starter-ribbon
org.springframework.cloud
spring-cloud-starter-config

之前为了能够使用微服务名称来调用服务时,我们已经使用过ribbon了,没错就是这个:

Robbon默认使用的是轮询算法,总共有以下几种算法:

可以使用以下方法进行修改算法

四、Feign

 

简介

 

Feign是一个声明式WebService客户端。使得编写Web服务客户端变得非常容易,我们只需要创建一个接口,然后在上面添加注解即可。

 

Feign旨在使编写JavaHttp客户端变得更容易。前面在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模板化的调用方法,但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服努的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在 Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它,即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。

 

Feign集成了Ribbon,使用它来进行负载均衡。

 

Feign的使用

1、创建消费者microservicecloud-consumer-dept-feign

pom.xml导入相应依赖

org.springframework.cloud
spring-cloud-starter-feign

2、在microservicecloud-api中添加接口

@FeignClient(value = "MICROSERVICECLOUD-DEPT/DeptConsumerDeptFeign_App")    // 这个是我们要调用的提供者在eureka中注册的名字public interface DeptClientService{	@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)  // 要请求 提供者 的url	public Dept get(@PathVariable("id") long id);	@RequestMapping(value = "/dept/list", method = RequestMethod.GET)	public List
list(); @RequestMapping(value = "/dept/add", method = RequestMethod.POST) public boolean add(Dept dept);}

3、microservicecloudconsumerdeptfeign中的一些操作

DeptConsumerDeptFeign_App

@SpringBootApplication@EnableEurekaClient@EnableFeignClients(basePackages= {"cn.x5456.microservicecloud"})	// 扫描所有Feign的接口@ComponentScan("cn.x5456.springcloud")	// 扫描我们调用的controllerpublic class DeptConsumerDeptFeign_App {	public static void main(String[] args) {		SpringApplication.run(DeptConsumerDeptFeign_App.class, args);	}}

DeptController_Consumer(变得和我们面向接口编程一样了)

@RestControllerpublic class DeptController_Consumer {	@Autowired	private DeptClientService service;	@RequestMapping(value = "/consumer/dept/get/{id}")	public Dept get(@PathVariable("id") Long id)	{		return this.service.get(id);	}	@RequestMapping(value = "/consumer/dept/list")	public List
list() { return this.service.list(); } @RequestMapping(value = "/consumer/dept/add") public Object add(Dept dept) { return this.service.add(dept); }}

配置文件和以前一样

五、Hystrix(断路器)

简介

Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。 "断路器"本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

服务熔断

1、概念

一般处某个服务故障异常引起,类似现实世界中的“保险丝“,当某个异常条件被触发,直接熔断整个服务,而不是一直等到此服务超时。

2、使用

1)(提供者端)导入依赖

org.springframework.cloud
spring-cloud-starter-hystrix

2)在需要进行熔断处理的方法上添加注解,书写熔断方法

@RestControllerpublic class DeptController {	@Autowired	private DeptService service = null;	@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)	//一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法	@HystrixCommand(fallbackMethod = "processHystrix_Get")	public Dept get(@PathVariable("id") Long id) {		Dept dept = this.service.get(id);				if (null == dept) {			throw new RuntimeException("该ID:" + id + "没有没有对应的信息");		}				return dept;	}	public Dept processHystrix_Get(@PathVariable("id") Long id) {		return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息,null--@HystrixCommand")				.setDb_source("no this database in MySQL");	}}

3)在主方法上添加@EnableCircuitBreaker注解

@SpringBootApplication@EnableEurekaClient //本服务启动后会自动注册进eureka服务中@EnableCircuitBreaker//对hystrixR熔断机制的支持public class DeptProvider8001_Hystrix_App{	public static void main(String[] args)	{		SpringApplication.run(DeptProvider8001_Hystrix_App.class, args);	}}

3、问题

  • 没有实现解耦的思想
  • 方法膨胀(每有一个方法就要有一个对应的断路器方法)
  • 服务降级

服务降级

1、概念

降级,一般是从整体负荷考虑。就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的fallback回调,返回—个缺省值。这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强。

2、使用

1)在microservicecloud-api项目,根据刚刚写的DeptClientService接口新建一个实现了FallbackFactory接口的类DeptClientServiceFallbackFactory

@Component // 不要忘记添加public class DeptClientServiceFallbackFactory implements FallbackFactory
{ @Override public DeptClientService create(Throwable throwable) { return new DeptClientService() { @Override public Dept get(long id) { Dept dept = new Dept(); dept.setDname("yyy"); return dept; } @Override public List
list() { return null; } @Override public boolean add(Dept dept) { return false; } }; }}

2)为DeptClientService的注解中添加参数

@FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClientServiceFallbackFactory.class)

3)在消费者端的配置文件中添加下面配置:

feign:   hystrix:     enabled: true

4)测试

  • 启动enreka,启动提供者,启动消费者
  • 故意关闭服务提供者
  • 再次进行访问,查看效果

六、Zuul(路由网关)

简介

Zuul包含了对请求的路由和过滤两个最主要的功能: 其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。

Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。

 

转载于:https://www.cnblogs.com/x54256/p/9517146.html

你可能感兴趣的文章