Eureka是Netfilx开源的服务发现组件,本身是一个基于REST的服务。它包含Eureka Server和Eureka Client两个部分。
Eureka Server提供服务注册功能,各个节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点。
Eureka Client是一个Java客户端,用于简化与Eureka Server的交互。主要用于消费服务。
CAP:CAP是一个经过证实的理论,一个分布式系统最多只能满足一致性(Consistency)/可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。
一致性:分布式环境中的一致性是指数据在多个副本之间是否能够保持一致的特性。如果一个节点A的数据被更新了,那么节点B的数据是否可以更新到和A节点一样的状态。
可用性:指系统提供的服务必须一直处于可用的状态,对于用户的每一个请求总是能够在有限的时间内返回结果,如果超过了这个时间范围,那么系统就被认为是不可用的。
分区容错性:所谓分区指在分布式系统中,节点组成的网络由于某些故障,导致节点之间网络不连通,整个分布式系统由于网络隔离就被划分为几个区块,数据散落在这些不连通的区域中。这样节点之间的数据就不可以相互访问,分区容错性是无法容忍的。
由于分区容错性是必须要解决,所以分布式系统就只有两中情况可以选择CP(一致性和分区容错性)和AP(可用性和分区容错性)
Zookeeper保证CP:当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。
Eureka保证AP:Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。
Spring cloud分布式应用是基于Spring boot框架搭建的,所以学习Spring cloud之前你应该对Spring boot有一定的了解和认识。如果没有学习过spirng boot可以参照下面的地址学习。对于企业开发中会用到的技术都有了基本的了解和认识即可。
快速构建spirng-boot项目:https://blog.csdn.net/sinat_32366329/article/details/82764483
Spring Boot替换启动Logo:https://blog.csdn.net/sinat_32366329/article/details/82766330
Spring-boot配置文件属性大全(2.0.5版本):https://blog.csdn.net/sinat_32366329/article/details/82833841
Spring boot整合mysql和druid:https://blog.csdn.net/sinat_32366329/article/details/84404944
Spring boot整合redis:https://blog.csdn.net/sinat_32366329/article/details/84455398
Spring boot整合mongodb:https://blog.csdn.net/sinat_32366329/article/details/84484776
Spring boot整合jpa:https://blog.csdn.net/sinat_32366329/article/details/84486406
Springboot整合filter和listener:https://blog.csdn.net/sinat_32366329/article/details/84575234
Spring boot整合mybatis:https://blog.csdn.net/sinat_32366329/article/details/86516124
Spring Boot整合ActiveMQ:https://blog.csdn.net/sinat_32366329/article/details/86616649
分布式首先要有服务注册中心,作用就是服务提供者注册自己提供的服务,服务消费者可在注册中心订阅自己需要的服务。所以我们开发分布式系统首先要搭建一个服务注册中心,spring cloud的服务注册中心是基于Eureka搭建的。
首先要使用spring boot创建要给eureka的spring boot应用。因为spring cloud都是基于spring boot创建的应用。
导入pom中的maven时候需要特别注意,spring cloud对spring boot的包版本是有指定的依赖的,可以说spring cloud的每个版本都有对应的spring boot版本,所以不懂的话可以去官网参考每个spring cloud版本说明。
Spring cloud的版本和其他框架的版本是有区别的,spring cloud的版本都是使用英国伦敦的地铁站名字命名的,后面另外带有版本。这个谷歌或百度就有版本介绍,这里不多说。
4.0.0
org.springframework.boot
spring-boot-starter-parent
1.5.2.RELEASE
com.example
eureka
0.0.1-SNAPSHOT
eureka
Demo project for Spring Boot
org.springframework.cloud
spring-cloud-dependencies
Camden.SR6
pom
import
1.8
org.springframework.cloud
spring-cloud-starter-eureka-server
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
server:
port: 8761
eureka:
client:
fetch-registry: false
register-with-eureka: false
service-url:
default-zone: http://localhost:8761/eureka/
简单介绍一下application.yml的配置属性:
package com.example.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
简单介绍EurekaApplication启动类:
@EnableEurekaServer:通过这个注解启动一个服务注册中心提供给其他应用进行对话。只需要在一个普通的spring boot应用中添加这个注解就可以开启此功能。
打开浏览器访问:http://localhost:8761/ 可以看到如下界面,这个就是注册中心的管理界面,由于我们还没有注册服务和订阅服务所以信息很多都是空的。
既然注册中心已经正常启动了,接下来我们就学习如何创建服务和将服务注册到Eureka Server注册中心。
为了节约时间成本,我们将刚才的注册中心eureka项目拷贝一份将名称和POM中的artifactId修改为provider-8762,8762主要是标记端口,这个服务我们使用8762端口。新的应用项目接口如下:
服务提供者和注册中心所依赖的spring cloud包不同具体区别就是将spring-cloud-starter-eureka-server包替换为spring-cloud-starter-eureka包即可。具体的pom.xml文件如下:
4.0.0
org.springframework.boot
spring-boot-starter-parent
1.5.2.RELEASE
com.example
provider-8762
0.0.1-SNAPSHOT
eureka
Demo project for Spring Boot
org.springframework.cloud
spring-cloud-dependencies
Camden.SR6
pom
import
1.8
org.springframework.cloud
spring-cloud-starter-eureka
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
server:
port: 8762
eureka:
client:
service-url:
default-zone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
spring:
application:
name: provider-8762
这里解释一下yml文件的配置意思:
package com.example.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class Provider8762Application {
public static void main(String[] args) {
SpringApplication.run(Provider8762Application.class, args);
}
}
对启动类的注解说明一下:
上一步我们已经成功将服务注册到注册中心,那么现在我们就需要消费注册到服务中心的服务。
Spring cloud的服务发现其中一个方式就是ribbon。Ribbon默认是轮询的方式去消费服务的,当然也可以自定义随机或者其他模式。为了提现ribbon的轮询消费服务,所以我们需要将provider-8762拷贝一份命名为provider-8763,其他可以不改变,但是端口需要修改为8763不然启动时候会提示端口冲突。
最后修改两个服务application.yml文件的spring.application.name属性的值为provider。因为spring cloud是根据名称判断是不是同一个服务的。具体如下:
spring:
application:
name: provider
我们上面创建的两个服务还没有提供任何的接口调用,所以我们创建一个ProviderController类,添加一个接口。这个展示的是provider-8762的代码,那么provider-8763的只需要将return的值8762修改为8763即可。这样是因为要显示ribbon的轮询功能。代码如下:
@RestController
public class ProviderController {
@GetMapping(value = "/hello")
public String hello() {
return "Hello 8762 World";
}
}
启动注册中心,再启动两个服务提供者,刷新注册中心页面就可以看到provider服务的数量是2个。接下来我们创建服务消费者。同样是一个spring boot功能。
4.0.0
org.springframework.boot
spring-boot-starter-parent
1.5.2.RELEASE
com.example
consumer-8862
0.0.1-SNAPSHOT
consumer-8862
Demo project for Spring Boot
org.springframework.cloud
spring-cloud-dependencies
Camden.SR6
pom
import
1.8
org.springframework.cloud
spring-cloud-starter-eureka
org.springframework.cloud
spring-cloud-starter-ribbon
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
server:
port: 8862
eureka:
client:
service-url:
default-zone: http://localhost:8761/eureka/
@LoadBalanced注解就表示使用ribbon的轮询功能,每次调用会分别调用provider-8762和provider-8763
@EnableDiscoveryClient
@SpringBootApplication
public class Consumer8862Application {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(Consumer8862Application.class, args);
}
}
这个类的功能主要是提供访问,这里通过ribbon调用PROVIDER服务的hello接口。
@RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping(value = "/consumer")
public String helloConsumer() {
return restTemplate.getForEntity("http://PROVIDER/hello", String.class).getBody();
}
}
刚才我们分别启动了注册中心和provider-8762/provider-8763两个服务。现在可以启动consumer服务消费者了。现在访问ConsumerController的consumer方法,这个时候不断刷新会分别返回Hello 8762 World和Hello 8763 World两个不同的字符串,就是ribbon的轮询功能分别访问了两个服务。
好了到这里你已经基本掌握了spring cloud的搭建注册中心/服务注册/服务消费功能。但是大家有没有思考一个问题,我们注册中心只有一个节点,如果生产的时候节点蹦了或者网络断开了,那不是新的服务无法注册和发现了吗?下一篇博客我会讲解如何搭建注册中心集群实现高可用。