一、学习前闲聊~
所需知识
- JavaSE
- 数据库
- 前端
- Servlet
- Http
- Mybatis
- Spring
- SpringMVC
- SpringBoot
- Dubbo\Zookeeper
- Maven
- Git
- Ajax\Json
这个阶段该如何学
- 三层架构 + MVC
- 框架:
- Spring(IOC、AOP)解决开发的复杂性
- SpringBoot (新一代JavaEE开发标准,Spring的升级,自动装配)
- 微服务核心:模块化,不同模块存放在不同电脑上
- 微服务架构四个核心问题:
-
- 客户端如何访问?
-
- 服务之间如何通信?HTTP、RPC
-
- 服务如何治理?服务注册与发现
-
- 服务挂了怎么办?熔断机制
-
- 解决方案:
SpringCloud 是解决上述四个问题的一种生态,成熟的解决方案有如下:
Spring Cloud NetFlix (一站式解决方案) 如何访问:api网关、Zuul组件 如何通信:Feign基于HTTP通信,可以进行负载均衡,同步、阻塞 服务注册与发现:Eureka 熔断机制:Hystrix
Apache Dubbo+Zookeeper (半自动,需要整合别人) 如何访问:没有,找第三方组件,或者自己实现 如何通信:Dubbo基于Java的RPC通信框架 服务注册与发现:Zookeeper 熔断机制:没有,找第三方 方案并不完善,就是想单一做RPC通信框架
Spring Cloud Alibaba (最新的一站式解决方案,因为NetFlix停更) 更简单
-
万变不离其宗(归其本质分布式网络不可靠)
-
- API
-
- HTTP、RPC
-
- 注册和发现
-
- 熔断机制
-
-
带着一下问题去学习:
- 什么是微服务?
- 微服务之间是如何独立通讯的?
- SpringCloud和Dubbo有哪些区别?
- 请谈谈SpringBoot和SpringCloud的理解
- 什么是服务熔断?什么是服务降级?
- 微服务的优缺点分别是什么,说一下你在项目中遇到的坑
- 你所知道的微服务技术栈?
- Eureka和Zookeeper都可以提供服务注册与发现,有什么区别
二、微服务概述
1. 什么是微服务
微服务(Microservice Architecture)是近几年流行的一种架构思想,引用ThoughtWorks公司首席科学家Martin Fowler于2014年提出的一段话:
- 就目前而言,对于微服务,业界没有统一标准的定义
- 通常而言,微服务架构是一种架构模式,或是一种架构风格,提倡单一的应用程序划分成一组小的服务,每个服务运行在其独立的进程中,服务之间相互协调,相互配置,为用户提供最终价值。服务之间采用轻量级的通信机制,每个服务围绕具体业务进行构建,能够被独立部署在生产环境中。另外,应尽量避免统一集中的服务管理制度,对具体一个服务,应根据业务上下文, 选择合适的语言、工具对其进行构建,可以有一个轻量级集中式管理来协调服务,可以使用不同语言编写,不同数据存储。
从技术维度来理解:
- 微服务化的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底的解耦合,每个服务提供单个业务功能,从技术角度看就是一种小而独立的处理过程,类似进程的概念,能够自行单独启动和销毁,拥有自己独立的数据库。
2. 微服务与微服务架构
(1)微服务 强调的是服务的大小,他关注的是某一个点,是具体解决一个问题、提供落地对应服务的一个服务应用,狭义的看可以是IDEA中一个个微服务工程,或者Model (2)微服务架构 一种新的架构形式,Martin Fowler于2014年提出,是要处理开头提出的四个问题。
3. 微服务优缺点
(1)优点
- 单一职责原则
- 每个服务足够内聚,代码容易理解,聚焦一个指定的业务功能或业务需求
- 开发简单,一个服务可能就是专一只干一件事
- 微服务能够被小团队单独开发
- 微服务是松耦合的,是有功能意义的服务
- 微服务能使用不同语言开发
- 易于和第三方集成,容易且灵活的方式继承自动部署,如Jenkins、Hudson、Bamboo
- 微服务易于被一个开发人员理解,修改和维护
- 微服务允许你利用融合最新技术
- 微服务只是业务逻辑代码,不会和HTML、CSS界面混合
- 每个微服务都有自己的存储能力,有自己的数据库
(2)缺点
- 开发人员要处理分布式系统的复杂性
- 多服务运维难度,随着服务的增加,运维压力也增加
- 系统部署依赖
- 服务间通信成本
- 数据一致性
- 系统集成测试
- 性能监控
4. 微服务技术栈有哪些
| 微服务条目 | 落地技术 |
|---|---|
| 服务开发 | SpringBoot、Spring、SpringMVC |
| 服务配置与管理 | Netflix公司的Archaius、阿里的Diamond等 |
| 服务注册与发现 | Eureka、Consul、Zookeeper |
| 服务调用 | Rest、RPC、gRPC |
| 服务熔断 | Hystrix、Envoy等 |
| 负载均衡 | Ribbon、Nginx等 |
| 服务接口调用 | Feign等 |
| 消息队列 | Kafka、RabbitMQ、ActiveMQ等 |
| 服务配置中心管理 | SpringCloudConfig、Chef等 |
| 服务路由(API网关) | Zuul等 |
| 服务监控 | Zabbix、Nagios、Metrics、Specatator等 |
| 全链路追踪 | Zipkin、Brave、Dapper等 |
| 服务部署 | Docker、OpenStack、K8s等 |
| 数据库操作开发包 | SpringCloud Stream(封装与Redis、Rabbit、Kafka等发送接收消息) |
| 事件消息总线 | SpringCloud Bus |
5. 为什么选择SpringCloud作为微服务架构
(1)选型依据
- 整体解决方案和框架成熟度
- 社区热度
- 可维护性
- 学习曲线
(2)当前各大IT公司用微服务架构有哪些?
- 阿里:dubbo+HFS
- 京东:JSF
- 新浪:Motan
- 当当网:DubboX
(3)微服务框架对比
| 功能点 | Netflix/SpringCloud | Motan | gRPC | Thrift | Dubbo/DubboX |
|---|---|---|---|---|---|
| 功能定位 | 完成的微服务框架 | RPC框架,但整合Zookeeper或Consul,实现集群环境基本服务注册发现 | RPC框架 | RPC框架 | 服务框架 |
| 支持Rest | 是,Ribbon支持多种可插拔序列化选择 | 否 | 否 | 否 | 否 |
| 支持RPC | 否 | 是(Hession2) | 是 | 是 | 是 |
| 支持多语言 | 是 | 否 | 是 | 是 | 否 |
| 负载均衡 | 是,服务端Zuul+客户端Ribbon,Eureka针对中间层服务器 | 是(客户端) | 否 | 否 | 是(客户端) |
| 配置服务 | NetfixArchaius,SpringCloudConfigServer | 是(Zookeeper提供) | 否 | 否 | 否 |
| 服务调用链监控 | 是(Zuul),提供边缘服务,API网关 | 否 | 否 | 否 | 否 |
| 高可用/容错 | 是(服务端Hystrix+客户端Ribbon) | 是(客户端) | 否 | 否 | 是(客户端) |
| 典型应用案例 | Netfilx | Sina |
三、SpringCloud入门概述
1. SpringCloud是什么
SpringCloud是基于SpringBoot提供了一套微服务解决方案,包括服务注册与发现、配置中心、全链路监控、服务网关、负载均衡、熔断器等组件,除了基于NetFlix的开源组件做高抽象封装之外,还有一些选型中立的开源组件。
Springcloud利用Springboot的开发便利,巧妙地简化分布式系统基础设施开发,SpringCloud为开发人员提供快速构建分布式系统的工具,包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式回话等,都可以用SpringBoot开发风格做到一键启动和部署。
2. SpringCloud和SpringBoot关系
- SpringBoot专注于快速方便的开发单个个体微服务
- SpringCloud是关注全局微服务协调整理框架,将SpringBoot开发的一个个单体微服务整合并管理起来,为各个微服务之间提供:配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等
3. Dubbo和SpringCloud技术选型
(1)分布式+服务治理Dubbo
目前成熟的互联网架构:应用服务化拆分+消息中间件
(2)Dubbo+SpringCloud
| Dubbo(组装机) | Spring(品牌机) | |
|---|---|---|
| 服务注册中心 | 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方式。 严格来说,二者各有优劣,后者牺牲了服务调用性能,也避免了原生RPC带来的问题。而且REST比RPC更灵活,服务提供方和调用方依赖只依靠一纸契约,不存在代码级别的强依赖。
四、创建项目
1. 主项目搭建
- 创建一个普通的Maven项目
- 设置父级POM文件导包
<!--打包方式 pom-->
<packaging>pom</packaging>
<properties>
<junit.version>4.13.2</junit.version>
<lombok.version>1.18.20</lombok.version>
<log4j.version>1.2.17</log4j.version>
<logback.version>1.2.6</logback.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-core -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
2. 实体模块--API
- 添加依赖
<!-- 当前Model自己要是用的依赖,父依赖已经配置了版本 -->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
- 创建实体
/**
* @author wangwk-a
* @date 2021/9/24 17:09
* @description 在网络传输中,所有实体类务必实现序列化
*/
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class Dept implements Serializable {
private Long deptno;
private String dname;
/**
* 看这个数据存在哪个数据库,微服务一个服务对应一个数据库
*/
private String db_source;
public Dept(String dname) {
this.dname = dname;
}
}
3. 生产者模块--springcloud-provider-dept-8001
- 添加依赖
首先通过POM引入API模块所提供的实体
<!-- 我们需要拿到实体类,所以需要配置api Module-->
<dependency>
<groupId>com.nick</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
然后添加测试、数据库、springBoot、热部署等依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--jetty-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<!--热部署工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
- 配置文件
使用yml格式,配置端口号、Mybatis、和spring
server:
port: 8001
# Mybatis配置
mybatis:
type-aliases-package: com.nick.springcloud.pojo
config-locations: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
spring:
application:
name: springcloud-provider-dept
datasource:
# 数据源 org.gjt.mm.mysql.Driver
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/nick_database?useUnicode=true&characterEncoding=utf8&useSSL=false
username: 数据库名称
password: 数据库密码
- dao层
@Mapper
@Repository
public interface DeptDao {
public boolean addDept(Dept dept);
public Dept queryById(Long id);
public List<Dept> queryAll();
}
- Service层
接口类
public interface DeptService {
public boolean addDept(Dept dept);
public Dept queryById(Long id);
public List<Dept> queryAll();
}
实现类
@Service
public class DeptServiceImpl implements DeptService{
@Autowired
private DeptDao deptDao;
@Override
public boolean addDept(Dept dept) {
return deptDao.addDept(dept);
}
@Override
public Dept queryById(Long id) {
return deptDao.queryById(id);
}
@Override
public List<Dept> queryAll() {
return deptDao.queryAll();
}
}
- controller层
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@PostMapping("/dept/add")
public boolean addDept(Dept dept) {
return deptService.addDept(dept);
}
@GetMapping("/dept/get/{id}")
public Dept get(@PathVariable("id") Long id) {
return deptService.queryById(id);
}
@GetMapping("/dept/list")
public List<Dept> queryAll() {
return deptService.queryAll();
}
}
- 启动类
@SpringBootApplication
public class DeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class, args);
}
}
- 效果
4. 消费者模块--springcloud-consumerdept-8080
- 添加依赖
<dependency>
<groupId>com.nick</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>
- Configration类
@Configuration
public class ConfigBean {
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
- controller层
@RestController
public class DeptConsumerController {
/**
* 消费者不应该有Service层
* RestTemplate 直接调用就可以
* (url, 实体Map, responseType)
* 提供多种便捷访问远程HTTP的方法,简单的RestFul服务模板
*/
@Autowired
private RestTemplate restTemplate;
private static final String REST_URL_PREFIX = "http://localhost:8001";
/**
* http://localhost:8001/dept/get/{id}
* @param id
* @return
*/
@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/add")
public boolean add(Dept dept) {
return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list() {
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
}
}
- 启动类
@SpringBootApplication
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class, args);
}
}
- 效果
先启动成产者,再启动消费者
访问8080
五、Eureka服务注册与发现
1. 什么是Eureka
- Netflix在设计Eureka时,遵循AP原则
- Eureka是Netflix的一个子模块,是基于REST服务,用于定位服务,已实现云端中间层服务发现和故障转移,服务注册与发现,只需要使用服务的标识符,就可以访问到服务,功能类似于Dubbo的注册中心,比如Zookeeper。
2. 原理讲解
- SpringCloud封装了NetFlex模块来实现服务注册与发现(对比Zookeeper)
- Eureka采用C-S架构设计,EurekaServer作为服务注册功能的服务器,是服务注册中心
- 系统中其他微服务,使用Eureka客户端连接到EurekaServer并维持心跳连接,这样维护人员就可以通过EurekaServer来监控微服务
两个组件
Eureka Server: 提供服务注册服务,各个节点启动后,会在EurekaServer中注册,这样其中的服务注册表中将会有所有的可用服务节点可被外界看到Eureka Client: Java客户端,用于简化EurekaServer的交互,客户端同时也具备一个内置轮训负载均衡器,应用启动后,将会向EurekaServer发送心跳,如果多个心跳周期内没有心跳,EurekaServer将会从服务注册表中移除该服务
三大角色
EurekaServer:提供服务的注册与发现ServiceProvider: 将自身服务注册到Eureka中,从而使消费者能够找到ServiceConsumer: 消费从Eureka中获取注册服务列表,从而找到消费服务
3. EurekaServer创建
- 配置Eureka
server:
port: 7001
# Eureka配置
eureka:
instance:
# Eureka服务端的实例名称
hostname: localhost
client:
# 表示是否向Eureka注册中心注册自己,因为服务器不需要注册自己
register-with-eureka: false
# 如果为false,则表示自己为注册中心
fetch-registry: false
service-url:
# 监控页面
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
- 创建启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class, args);
}
}
- 访问7001端口
4. 服务注册至EurekaServer
将之前实现的生产模块
springcloud-provider-dept-8001注册至EurekaServer
- 在
8001模块的POM中添加Eureka依赖
<!-- 添加Eureka依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 添加配置
# 配置Eureka 服务注册到哪里
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
instance:
# 修改Eureka上的默认描述信息
instance-id: springcloud-provider-dept-8001
其中
defaultZone的链接就是在EurekaServer配置文件中监控页面的路径
- 开启服务
在启动类中开启
EurekaClient,服务启动后会自动注册到Eureka服务中
@SpringBootApplication
@EnableEurekaClient
public class DeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class, args);
}
}
- 查看效果
这个默认描述信息点击是一个网址,是一些监控信息,目前是没有信息的,如果要添加,进行如下操作:
8001模块POM添加依赖
<!-- 完善Eureka监控信息 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
8001配置Info
# Info监控服务
info:
app.name: nick-springcloud
company.name: https://juejin.cn/user/4117012877420045/posts
- 点击配置信息查看效果
5. Eureka自我保护机制
好死不如赖活着
某一时刻某个微服务挂了,Eureka不会立刻清理,依旧会对该微服务的信息进行保存。
- 默认情况,如果EurekaServer在一定时间没有接收到某微服务实例的心跳,EurekaServer会注销该实例,但是如果是因为网络问题,微服务无法和Server通信,但是其本身是好的,就不应该注销该服务。因此Eureka通过自我保护机制来解决这个问题,当Server短时间内丢失客户端心跳,该节点会进入自我保护模式,Server会保护服务注册表中的信息,网路恢复后自动退出自我保护模式
- 在EurekaCloud中,可以使用
eureka.server.enable-self-preservation=false禁用自我保护模式(不推荐关闭)
6. 通过Controller获取配置信息
- 在Controller注入
DiscoveryClient对象
@Autowired
private DiscoveryClient client;
注意DiscoveryClient要引下图的包,引错了无法调用其方法
- 接口编写
@GetMapping("/dept/discovery")
public Object discovery() {
// 获取微服务列表清单
List<String> services = client.getServices();
System.out.println("discovery=>service: " + services);
// 得到一个具体的微服务信息,通过具体的微服务id,applicationName
List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
instances.forEach(item->{
System.out.println(
item.getHost() + "\t" +
item.getPort() + "\t" +
item.getUri() + "\t" +
item.getServiceId()
);
});
return this.client;
}
-
网页访问
-
控制台输出
六、Eureka集群
- 创建集群
其中7002、7003是复制7001,并修改配置文件端口号和启动类中类名
- host域名映射(注意备份)
改域名映射只是为了方便后续理解,命名不同易于看出效果,实际访问的还是localhost
-
集群互联
-
配置生产服务
springcloud-provider-dept-8001 -
效果测试
查看7001(7002和7003同样的效果,这里补贴图了)
-
将服务
springcloud-provider-dept-8001启动,注册到集群 -
查看效果
六、对比Zookeeper
1. 回顾CAP原则
RDBMS(MySQL、Oracle、sqlServer)--> ACID NoSQL(redis、mongdb)--> CAP
- ACID是什么
- A(Atomicity)原子性
- C(Consistency)一致性
- I(Isolation)隔离性
- D(Durability)持久性
- CAP是什么
- C(Consistency)强一致性
- A(Availability)可用性
- P(Partition Tolerance)分区容错性
2. Eureka比Zookeeper好在哪里
CAP理论指出,一个分布式系统不能同时满足CAP,由于分区容错性P在分布式系统是是必须要保证的,因此我们需要在C、A中进行权衡。
- Zookeeper保证了
CP - Eureka保证了
AP
Zookeeper保证了CP
当向注册中心查询服务列表是,可以容忍注册中心返回几分钟前的注册信息,但不能接收服务直接down掉。也就是说,服务注册功能对可用性要求高于一致性。Zookeeper会有这种情况,master节点因为网络故障down掉,剩余节点会重新选举leader,数据量越大选举时间越长,选举过程中,服务不可用。(可用性低了)
Eureka保证的是AP
因此设计时优先保证可用性,Eureka各个节点时平等的,几个节点挂了,剩余节点立马提供注册和查询服务,只不过查到的信息可能不是最新的。此外Eureka有自我保护机制,如果在15分钟内超过85%节点都没有正常的心跳,那么Eureka认为客户端与注册中心出现了网络故障,会出现:
- Eureka不在从注册列表中移除因为长时间没有收到心跳的过期服务
- Eureka任然能能够接收新服务的注册和查询,但是不会被同步到其他节点(即保证当前节点可用)
- 网络稳定时,当前实例新的注册信息会被同步到其他节点
因此,Eureka可以很好应对因网络故障导致部分节点失去联系的情况,不会像Zookeeper那样使整个注册服务瘫痪。
七、Ribbon实现负载均衡
(之后有时间会更新这部分...)