编写不易,转载请注明(http://shihlei.iteye.com/blog/2400190)!
一 服务注册与发现
(1)概述
服务调用基本两端:
服务提供者(Service Provider)、服务消费者(Service Client)
调用方式:
(a)简单版:
直接调用
优点:
简单,快速完成
缺点:
服务消费者感知服务端IP、Port,任何这二者修改,都可能引起客户端都需要修改,极端可能需要重新发布上线。
不利于服务HA。
(b)反向代理版:
在中间增加反向代理,服务消费者依赖反向代理服务器,屏蔽服务提供者后端物理架构。
特点:
客户端,服务器端无入侵性
传统反向代理定位HA和负载均衡,不具备自动注册新服务,添加服务新机能力,可以通过扩展反向代理服务器解决。
(c)服务注册中心版:
服务注册到中心中,服务消费者从中心获取服务IP、Port,再进行请求。
特点:
将核心的服务注册发现能力,已独立中间件形式提供。其实和反向代理的解决方案差不多。
(2)服务注册中心定位
解决:
服务物理设备变动(ip,端口变动),造成客户端需要修改的问题。
目前业界大部分使用基于Docker云架构,提供弹性扩展能力,服务提供者IP,Port无法在发布时就给定,引入服务注册中心,可以适应这种变化。
主要提供功能:
1)服务注册发现
2)心跳同步
3)负载均衡
二 服务注册中心:Eureka
(1)概述:
Eureka:Netflix公司开发的服务发现中间件,用于服务的负载均衡和服务故障转移
SpringCloud 集成了EurekaSever,让我们通过简单配置即可启动
git:https://github.com/Netflix/eureka
wiki:https://github.com/Netflix/eureka/wiki
架构:
(2)基于SpringCloud搭建EurekaServer:
搭建过程重用了《 SpringCloud(一): SpringBoot 创建简单的微服务》中的项目,项目环境可点击查看。
第一步:创建项目,添加依赖:见pom
<?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> <artifactId>spring-cloud-eureka-server</artifactId> <packaging>jar</packaging> <name>spring-cloud-eureka-server</name> <description>Demo project for Spring Boot</description> <parent> <groupId>x.demo.springcloud</groupId> <artifactId>spring-cloud</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
第二步:创建SpringCloud启动类,添加@EnableEurekaServer
package x.demo.springcloud.eureka.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class SpringCloudEurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudEurekaServerApplication.class, args);
}
}
第三步:配置EurekaServer相关信息:application.yml
spring: profiles: Standalone application: name: eureka-server-standalone server: port: 8761 eureka: # 每个EurekaServer 都包含一个EurekaClient,用于请求其他节同步 client: service-url: defaultZone: http://localhost:8761/eureka # 单机版不注册到Eureka registerWithEureka: false fetchRegistry: false instance: # 指定实例名称,默认:${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}} instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
第四步:访问查看是否成功
(3)Eureka Server集群搭建
Eureka Server 集群主要是各个实例通过EurekaClieint 注册到其他实例(对等体Pear)中,保证服务注册表冗余。
注意:由于要操作必须在所有对等体上生效,服务修改才生效,所以有时候会慢。
规划:启动三个实例,互相注册对等体
Peer1:5001
Peer2:5002
Peer3:5003
第一步:项目如上
第二步:修改application.yml指定各个Peer配置,主要是端口及对等体
特别注意:我将多个Profile写在同一个文件中,咋样yml中约定“---”标识一个Profile
--- #HA 版: 通过运行多个实例并请求他们相互注册, 通过defaultZone 注定本实例要注册到哪些其他的节点 spring: profiles: Peer1 application: name: eureka-server server: port: 50001 eureka: client: service-url: defaultZone: http://localhost:50002/eureka/,http://localhost:50003/eureka/ instance: instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}} --- spring: profiles: Peer2 application: name: eureka-server server: port: 50002 eureka: client: serviceUrl: defaultZone: http://localhost:50001/eureka/,http://localhost:50003/eureka/ instance: instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}} --- spring: profiles: Peer3 application: name: eureka-server server: port: 50003 eureka: client: serviceUrl: defaultZone: http://localhost:50001/eureka/,http://localhost:50002/eureka/ instance: instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
第三步:配置启动,idea添加启动操作,以Peer1为例,Peer2,Peer3同
注:第一个Peer启动的时候注册对等体报错正常,因为其他对等体还没启动
异常:com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused
第四步:访问页面验证
三 服务提供者,服务消费者集成EurekaClient
重用前面的项目:见《 SpringCloud(一): SpringBoot 创建简单的微服务》,《SpringCloud(二):声明式RestClient—Feign》
1)spring-cloud-microservice:微服务项目,实现获取当前时间服务
2)spring-cloud-webfront:前端项目,根据业务调用各种微服务,这里只是获取时间。
(1)服务提供者
第一步:依赖
<?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> <artifactId>spring-cloud-microservice</artifactId> <packaging>jar</packaging> <name>spring-cloud-microservice</name> <description>Demo project for Spring Boot</description> <parent> <groupId>x.demo.springcloud</groupId> <artifactId>spring-cloud</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--服务注册--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <!--监控数据--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- utils --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
第二步:application.yml 配置 EurekaClient,做服务注册
server: port: 10001 # 服务名称 spring: application: name: microservice-time eureka: client: service-url: defaultZone: http://localhost:50001/eureka/,http://localhost:50002/eureka/,http://localhost:50003/eureka/ instance: instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}} prefer-ip-address: true
第三步:启动集成@EnableDiscoveryClient (可以用@EnableEurekaClient 替代)
package x.demo.springcloud.microservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudServiceApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudServiceApplication.class, args);
}
}
第四步:页面查看注册
(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>
<artifactId>spring-cloud-webfront</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-cloud-webfront</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>x.demo.springcloud</groupId>
<artifactId>spring-cloud</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- spring -->
<!-- spring boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--rest client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<!-- utils -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
第二步:application.yml 配置 EurekaClient,做服务发现
server: port: 20001 spring: application: name: webfront eureka: client: service-url: defaultZone: http://localhost:50001/eureka/,http://localhost:50002/eureka/,http://localhost:50003/eureka/ instance: instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}} prefer-ip-address: true
第三步:基于Feign的服务Client
package x.demo.springcloud.webfront.service.impl.feign;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import x.demo.springcloud.webfront.service.impl.ProtocolResult;
//name为服务提供者应用名称
@FeignClient(name = "microservice-time")
public interface TimeV1MicroServiceDiscoveryClient {
@RequestMapping(method = RequestMethod.GET, value = "/time/v1/now", consumes = MediaType.APPLICATION_JSON_VALUE)
ProtocolResult<String> now(@RequestParam(name = "format", required = false) String format);
}
第四步:Service,Controller
package x.demo.springcloud.webfront.service;
public interface TimeService {
/**
* 获取当前时间
* @return 当前时间,格式:yyyy-MM-dd HH:mm:ss
*/
String now();
}
@Service("timeV1FeignImpl")
public class TimeV1FeignImpl implements TimeService {
@Resource
private TimeV1MicroServiceDiscoveryClient timeV1MicroServiceDiscoveryClient;
/**
* 获取当前时间
*
* @return 当前时间,格式:yyyy-MM-dd HH:mm:ss
*/
@Override
public String now() {
ProtocolResult<String> result = timeV1MicroServiceDiscoveryClient.now(null);
return result.getBody();
}
}
package x.demo.springcloud.webfront.web;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import x.demo.springcloud.webfront.service.TimeService;
@RestController
@RequestMapping("/time")
public class TimeController {
@Resource(name = "timeV1FeignImpl")
private TimeService timeService;
@GetMapping("/now")
public String now() {
return timeService.now();
}
}
第五步:启动集成@EnableDiscoveryClient (可以用@EnableEurekaClient 替代)
package x.demo.springcloud.webfront;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class SpringCloudWebfrontApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudWebfrontApplication.class, args);
}
}
第六步:验证
四 参考
https://springcloud.cc/spring-cloud-dalston.html