Release Train | Boot Version |
---|---|
Hoxton | 2.2.x, 2.3.x (Starting with SR5) |
Greenwich | 2.1.x |
Finchley | 2.0.x |
Edgware | 1.5.x |
Dalston | 1.5.x |
Netflix在涉及Eureka时,遵循的就是AP原则
Eureka时Netflix的一个子模块,也是核心模块之一。Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移,服务注册于发现对于微服务来说是非常重要的,有了服务发现于注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Dubbo的注册中心,比如Zookeeper。
Eureka的基本架构
- Spring Cloud封装了Netflix公司开发的Eureka模块来实现注册 和发现(对比zookeeper)
- Eureka采用了C/S的架构涉及,EurekaServer作为服务注册功能的服务器,它是服务注册中心
- 而系统中的其他微服务。使用Eureka的客户端连接到EurekaServer并维持心跳连接。这样系统的维护人员就可以通过EurekaServer来监控系统中各个微服务是否正常运行,Spring Cloud的一些其他模块(比如Zuul)就可以通过EurekaServer来发现系统中的其他微服务,并执行相关的逻辑。
- 和Dubbo相比
Eureka包含两个组件:Eureka Server 和 Eureka Client
Eureka启动后,服务提供者会通过REST请求将自己注册在Eureka Server中,并维护一个心跳(默认30秒发送一次心跳)进行服务续约,告诉Eureka Server “ 我还活着 ”,防止Eureka Server将该服务从服务列表中剔除。
用于获取Eureka Server注册的服务清单,并且该服务清单默认每隔30秒更新一次。服务消费者获取到服务清单后,能够根据自己的需求决定调用哪个服务,默认采用轮询方式调用,从而实现Eureka Client的负载均衡。
服务提供者和服务消费者是可以相互转换的,因为一个服务既可能是服务消费者,同时有可能是服务提供者。
Spring Cloud的版本名称,通常是由 ”版本号 + 小版本名称 “ 组成的。这样设计的目的是为了更好地管理每个Spring Cloud子项目的清单,避免自己的版本号于子项目的版本号混淆。
例如 Finchley M1版本中,Finchley代表的是版本号,M1是小版本的名称。
| 核心组件 | Dubbo | Spring Cloud |
| - | - | - |
| 服务注册方式 | Zookeeper | Eureka |
| 服务通信方式 | RPC | REST API |
| 服务网关 | 无 | Zuul |
| 熔断器 | 不完善 | Hystrix |
| 分布式配置中心 | 无 | Spring Cloud Config |
| 服务追踪框架 | 无 | Spring Cloud Sleuth |
创建maven父工程
<?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>
<!--继承springboot-starter-parent依赖-->
<!--使用继承方式,实现复用,符合继承的都快可以被使用-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
</parent>
<groupId>org.example</groupId>
<artifactId>01-eureka-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>eureka-server</module>
</modules>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring-cloud.version>Hoxton.SR1</spring-cloud.version>
</properties>
<!--项目依赖管理,父项目只是声明依赖,子项目需要写明需要的依赖(可以省略版本信息)-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
从该父工程创建一个module ,可以是一个maven工程
<?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>
<parent>
<artifactId>01-eureka-demo</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>eureka-server</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>eureka-server</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<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>
</properties>
<dependencies>
<!--netflix eureka server 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!--spring boot web 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring -boot 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
创建springboot 启动类
package org.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @author gitsilence
* @version 1.0
* @date 2020/12/9 15:20
* @mail gitsilence@lacknb.cn
*/
@SpringBootApplication
@EnableEurekaServer // 开启eureka server 注册中心
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
创建spring boot配置文件
application.yml
server:
port: 8761
spring:
application:
name: eureka-server
# 配置eureka server 注册中心
eureka:
instance:
hostname: localhost # 主机名,不配置的时候将根据操作系统的主机名来获取
client:
# 如果单个eureka server 是要关闭该选项的,如果是集群eureka,需要将自身注册到 注册中心
register-with-eureka: false # 是否将自己注册到注册中心,默认是true
fetch-registry: false # 是否从注册中心获取服务注册信息 默认为true
service-url: # 注册中心对外暴露的注册地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
创建一个新的module ,可以是一个maven工程。为eureka-server02
pom和上一个项目的一样。
创建启动类、和配置文件
将将上一个项目的配置文件改成如下:
server:
port: 8761
spring:
application:
name: eureka-server
# 配置eureka server 注册中心
eureka:
instance:
hostname: eureka01 # 主机名,不配置的时候将根据操作系统的主机名来获取
prefer-ip-address: true # 是否使用ip地址注册
instance-id: ${spring.cloud.client.ip-address}:${server.port}
client:
# 如果单个eureka server 是要关闭该选项的,如果是集群eureka,需要将自身注册到 注册中心
register-with-eureka: true # 是否将自己注册到注册中心,默认是true
fetch-registry: true # 是否从注册中心获取服务注册信息 默认为true
service-url: # 注册中心对外暴露的注册地址
defaultZone: http://localhost:8762/eureka/ # 互相注册
将当前项目的配置文件 改为:
server:
port: 8762
spring:
application:
name: eureka-server
# 配置eureka server 注册中心
eureka:
instance:
hostname: eureka02 # 主机名,不配置的时候将根据操作系统的主机名来获取
prefer-ip-address: true # 是否使用ip地址注册
instance-id: ${spring.cloud.client.ip-address}:${server.port}
client:
# 如果单个eureka server 是要关闭该选项的,如果是集群eureka,需要将自身注册到 注册中心
register-with-eureka: true # 是否将自己注册到注册中心,默认是true
fetch-registry: true # 是否从注册中心获取服务注册信息 默认为true
service-url: # 注册中心对外暴露的注册地址
defaultZone: http://localhost:8761/eureka/ # 互相注册
重启两个项目,即可。
pom.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">
<parent>
<artifactId>01-eureka-demo</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service-provider</artifactId>
<name>service-provider</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<!--netflix eureka server 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--spring boot web 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring -boot 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
启动类
package org.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @author gitsilence
* @version 1.0
* @date 2020/12/9 16:40
* @mail gitsilence@lacknb.cn
*/
@SpringBootApplication
@EnableEurekaClient
public class ServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceProviderApplication.class, args);
}
}
配置文件application.yml
server:
port: 7070
spring:
application:
name: service-provider
# 配置eureka 注册中心
eureka:
instance:
prefer-ip-address: true # 是否使用ip注册
instance-id: ${spring.cloud.client.ip-address}:${server.port}
client:
service-url:
# 有多少个集群eureka,就写多少个。
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
register-with-eureka: true
fetch-registry: true
Product.java
package org.example.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author gitsilence
* @version 1.0
* @date 2020/12/9 16:42
* @mail gitsilence@lacknb.cn
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
private int id;
private String productName;
private int productNum;
private double productPrice;
}
ProductService.java
package org.example.service;
import org.example.pojo.Product;
import java.util.List;
/**
* @author gitsilence
* @version 1.0
* @date 2020/12/9 16:44
* @mail gitsilence@lacknb.cn
*/
public interface ProductService {
List<Product> selectProductList();
}
ProductServiceImpl.java
package org.example.service.impl;
import org.example.pojo.Product;
import org.example.service.ProductService;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
/**
* @author gitsilence
* @version 1.0
* @date 2020/12/9 16:45
* @mail gitsilence@lacknb.cn
*/
@Service
public class ProductServiceImpl implements ProductService {
@Override
public List<Product> selectProductList() {
return Arrays.asList(
new Product(1, "华为手机", 2, 5888d),
new Product(2, "联想笔记本", 1, 6888d),
new Product(3, "小米平板", 5, 2666d)
);
}
}
ProductController.java
package org.example.controller;
import org.example.pojo.Product;
import org.example.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author gitsilence
* @version 1.0
* @date 2020/12/9 16:44
* @mail gitsilence@lacknb.cn
*/
@RestController
public class ProductController {
@Autowired
private ProductService productService;
@RequestMapping("/list")
public List<Product> selectProductList () {
return productService.selectProductList();
}
}
Ribbon属于后者,它是一个类库,集成于consumer进程, consumer通过它来获取provider的地址。
服务之间,拍好队,每个服务器访问一下。
策略对应类名: WeightedResponseTimeRule
实现原理:
策略对应类名:RandomRule
实现原理:从provider列表中随机选择一个。
策略对应类名:BestAvaliableRule
实现原理:选择正在请求中的并发数最小的provider,除非这个provider在熔断中(即该provider当前不可用)。
策略对应类名:RetryRule
实现原理:其实就是轮询策略的增强版,轮询策略服务不可用时不做处理,重试策略服务不可用时会重新尝试集群中的其他节点。
策略对应类名:AvailabilityFilteringRule
实现原理:过滤性能差的 provider
策略对应类名:ZoneAvoidanceRule
实现原理: