一 布式服务必然要面临的问题
由上一章节的案例得出:
scloud-service-provider:对外提供了查询用户的接口
scloud-consumer:通过RestTemplate访问 http://locahost:9091/user/{id} 接口,查询用户数据
存在问题:
1.在consumer中,我们把url地址硬编码到了代码中,不方便后期维护
2.consumer需要记忆scloud-service-provider的地址,如果出现变更,可能得不到通知,地址将失效
3.consumer不清楚scloud-service-provider的状态,服务宕机也不知道
4.scloud-service-provider只有1台服务,不具备高可用性 即便scloud-service-provider形成集群,scloud-consumer还需自己实现负载均衡
通过上面的描述其实就是,是分布式服务必然要面临的问题:
由1.2描述得出:
1.如何自动注册和发现 2.如何实现状态监管;3.如何实现动态路由
由4得出:服务如何实现负载均衡
由3得出:服务如何解决容灾问题
二 eureka的作用
2.1作用
Eureka
就好比是打车平台,负责管理、记录服务提供者的信息。服务调用者无需自己寻找服务,而是把自己的需求告诉 Eureka,然后
Eureka会把符合你需求的服务告诉你。
同时,
服务提供方与Eureka之间通过 “心跳” 机制进行监控
,当某个服务提供方出现问题,
Eureka
自然会把它从服务
列表中剔除。这就是实现了服务的
自动注册、发现、状态监控。
Eureka
:就是服务注册中心(可以是一个集群),对外暴露自己的地址
提供者:启动后向
Eureka
注册自己信息(地址,提供什么服务)
消费者:向
Eureka
订阅服务,
Eureka
会将对应服务的所有提供者地址列表发送给消费者,并且定期更新
心跳
(
续约
)
:提供者定期通过
http
方式向
Eureka
刷新自己的状态
2.2实际案例
这就好比是 网约车出现以前,人们出门叫车只能叫出租车。一些私家车想做出租却没有资格,被称为黑车。而很多 人想要约车,但是无奈出租车太少,不方便。私家车很多却不敢拦,而且满大街的车,谁知道哪个才是愿意载人的。
一个想要,一个愿意给,就是缺少引子,缺乏管理啊。 此时滴滴这样的网约车平台出现了,所有想载客的私家车全部到滴滴注册,记录你的车型(服务类型),身份信息 (联系方式)。这样提供服务的私家车,在滴滴那里都能找到,一目了然。 此时要叫车的人,只需要打开APP
,输入你的目的地,选择车型(服务类型),滴滴自动安排一个符合需求的车到你面前,为你服务!
三 eureka的搭建
3.1 eureka注册中心的搭建
eureka是服务注册中心,只能做服务注册;自身并不提供服务也不消费服务。可以搭建web工程使用eureka,可以使用springboot方式搭建。
3.1.1 工程结构
3.1.2 依赖配置
<?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>
<groupId>com.scloud</groupId>
<artifactId>scloud-demo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.scloud.eureka</groupId>
<artifactId>scloue-eureka-center</artifactId>
<version>1.0-SNAPSHOT</version>
<name>scloue-eureka-center</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>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- eureka的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
</dependencies>
<build>
</build>
</project>
3.1.3 启动类 EurekaApp
package com.scloud.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* Hello world!
*
*/
//声明当前应用为eureka服务
@EnableEurekaServer
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class}) //配置文件没有配置数据源信息,排除掉,不然启动报错
public class EurekaApp
{
public static void main( String[] args )
{
SpringApplication.run(EurekaApp.class,args);
System.out.println( "EurekaHaApp 启动成功了!!!" );
}
}
3.1.4 配置文件
server:
port: ${port:10086}
spring:
application:
name: eureka-server
eureka:
client:
service-url:
# eureka 服务地址,如果是集群的话;需要指定其它集群eureka地址
defaultZone: http://127.0.0.1:10086/eureka
# 不注册自己
register-with-eureka: false
# 不拉取服务
fetch-registry: false
server:
# 服务失效剔除时间间隔,默认60秒
eviction-interval-timer-in-ms: 60000
# 关闭自我保护模式(默认是打开的)
enable-self-preservation: false
3.1.5 启动测试
3.2 服务者的配置
3.2.1 pom文件的配置
<!-- eureka 客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
3.2.2 启动文件
3.2.3 文件的配置
eureka: client: service-url: defaultZone: http://127.0.0.1:10086/eureka
这里我们添加了spring.application.name属性来指定应用名称,将来会作为服务的id使用。
3.2.4 启动服务端
3.2.5 访问注册中心
3.3 服务消费者
3.3.1 pom文件的配置
<!-- eureka 客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
3.3.2 启动类的配置
3.3.3 资源文件的配置
spring:
application:
name: scloud-consumer
server:
port: ${port:8080}
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
# 获取服务地址列表间隔时间,默认30秒
registry-fetch-interval-seconds: 10
3.3.4 调取服务
package com.scloud.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/{id}")
public String queryById(@PathVariable Long id){
String url = "http://localhost:9091/user/"+id;
//获取eureka中注册的user-service的实例
List<ServiceInstance> serviceInstances = discoveryClient.getInstances("user-service");
ServiceInstance serviceInstance = serviceInstances.get(0);
url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/user/" + id;
return restTemplate.getForObject(url, String.class);
}
}