参考文章:1.eureka的详细配置:https://www.cnblogs.com/tiancai/p/9593648.html
2.eureka注册中心,服务提供者,服务消费者详解:https://blog.csdn.net/chengqiuming/article/details/81040822
一.eureka服务治理思想简介
1.服务注册中心:eureka提供服务端,提供服务的注册与发现功能。
注:在配置注册中心时,记得避免注册中心向自己注册,需要在配置文件中添加:
eureka.client.register-with-eureka=false(这个是避免eureka向自己进行注册)
eureka.client.fetch-registry=false(这个是避免eureka查找服务列表)
2.服务提供者:提供服务的应用,可以是springboot应用,也可以是其他技术平台且遵循Eureka通信机制的应用,可以将自己的服务注册到Eureka上。
3.服务消费者:消费者应用从服务注册中心获取服务列表,从而使消费者知道去哪调用所需要的服务。
二.eureka注册中心,提供服务注册与发现功能
编写服务注册中心eureka-server
1.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">
<parent>
<artifactId>supper-cloud</artifactId>
<groupId>com.zhourui</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka-server</artifactId>
<dependencies>
<!-- eureka server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- eureka client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>
2.配置文件
# 指令接收服务监听的端口号
server.port=9999
# 应用名
spring.application.name=eureka-server
# 注册中心相关配置
#eureka.instance.hostname=localhost
eureka.instance.hostname=127.0.0.1
#避免注册中心向自己注册
###a.避免eureka向自己进行注册
eureka.client.register-with-eureka=false
###b.避免eureka查找服务列表
eureka.client.fetch-registry=false
#在本地开发时,关闭保护机制
eureka.server.enable-self-preservation=false
#eureka 客户端注册地址
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
# 暴露管理节点
#management.endpoints.web.exposure.include=["*"]
3.编写启动类,只需加上@EnableEurekaServer表明是eureka服务注册中心
package com.zhourui.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* 类名称: EurekaServerApplication
* 功能简介: 注册中心启动类
* 功能详解: 使用eureka作为微服务的注册中心
*
* @author zhourui
* @date 2019/6/3
*/
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
eureka服务端提供服务注册与发现,启动eureka-server可在127.0.0.1:9999查看服务的监控页面
三.服务提供者,在启动的时候会发送REST请求将自己注册到Eureka Server上,并带上一些元信息
服务提供者编写
1.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">
<parent>
<artifactId>supper-cloud</artifactId>
<groupId>com.zhourui</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service-provider</artifactId>
<dependencies>
<dependency>
<groupId>com.zhourui</groupId>
<artifactId>service-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- spring boot web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- eureka client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<!-- feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- swagger2 的依赖 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<!-- swagger 文档导出的依赖 -->
<!--
<dependency>
<groupId>io.github.swagger2markup</groupId>
<artifactId>swagger2markup</artifactId>
<optional>true</optional>
<scope>test</scope>
</dependency>
-->
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
<optional>true</optional>
</dependency>
<!-- spring boot test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<optional>true</optional>
<scope>test</scope>
</dependency>
<!-- mybatis starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!-- pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
</dependency>
<!--hibernate validator-->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
</dependencies>
</project>
2.配置文件
# 指令接收服务监听的端口号
server.port=9001
# 应用名
spring.application.name=service-provider
# 注册中心相关配置
eureka.client.service-url.defaultZone=http://127.0.0.1:9999/eureka
#每隔30秒拉取一次服务注册信息
eureka.client.fetch-registry=true
eureka.client.registry-fetch-interval-seconds=30
# 暴露管理节点
management.endpoints.web.exposure.include=["*"]
########
3.启动类编写,加上@EnableDiscoveryClient将服务注册到注册中心
package com.zhourui;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* 类名称: InstructionReceptionApplication
* 功能简介: 指令接收模块启动类
* 功能详解: 启动指令接收模块,它要做的事情有:
* <ul>
* <li>向注册中心注册自己的服务</li>
* <li>从注册中心拉去服务</li>
* <li>加载Ribbon配置,做客户端负载均衡</li>
* <li>启用Feign,以接口的方式调用服务</li>
* <li>启用Hystrix熔断器</li>
* </ul>
*
* @author zhourui
* @date 2019/6/3
*/
@EnableDiscoveryClient
@SpringBootApplication
public class ServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceProviderApplication.class, args);
}
}
4.提供服务接口controller
package com.zhourui.business.controller.test;
import com.zhourui.common.ExceptionEnum;
import com.zhourui.common.GlobalException;
import com.zhourui.common.bean.Student;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
@RequestMapping("/provide")
@Api(tags = "测试接口", description = "by zhourui")
public class TestProviderController {
@ApiOperation(value = "查询学生", notes = "根据学生id查询学生")
@GetMapping("/getStudentById/{id}")
public ResponseEntity<Student> getStudent(@ApiParam(value = "学生id", name = "id", required = true)
@PathVariable("id") String id){
if (id==null){
throw new GlobalException(ExceptionEnum.ID_NULL);
}
Student student=new Student();
student.setId("1");
student.setName("张三");
student.setNation("汉族");
student.setAge(18);
student.setSex("男");
return ResponseEntity.ok().body(student);
}
}
服务提供者
服务注册:
“服务提供者”在启动的时候会发送REST请求将自己注册到Eureka Server上,并带上一些元信息。
Eureka Server接收到REST请求,将元信息存储在一个双层Map中,第一层key是服务名,第二层key是具体服务的实例名。
注:在服务注册时,需要确认一下eureka.client.register-with-eureka=true是否正确,如果为false是禁止向Eureka Server注册的。
服务同步:
不同的服务提供者分别注册到了一个注册中心集群上的不同的注册中心上。他们的信息被不同的注册中心维护。
由于在集群中,一个注册中心互为其他注册中心的服务,当服务提供者请求到一个服务注册中心后,它会将请求转发到其他服务注册中心,实现注册中心之间的服务同步。
通过服务同步,服务提供者的服务信息可以通过集群中的任何一个注册中心获取。
服务续约:
在注册完成后。服务提供者会维护一个心跳告诉注册中心服务政策,防止注册中心剔除服务,该过程称为服务续约。
eureka.instance.lease-renewal-interval-in-seconds参数用于定义:服务续约任务的调用间隔时间,默认30s。
eureka.instance.lease-expiration-duration-in-seconds参数用于定义:服务失效时间,默认30s。
四.服务消费者,可从注册中心获取服务列表调用服务,这里会用到feign进行服务调用,之后会介绍
1.pom文件
# 指令接收服务监听的端口号
server.port=8001
# 应用名
spring.application.name=service-consumer
# 注册中心相关配置
eureka.client.service-url.defaultZone=http://127.0.0.1:9999/eureka
#每隔30秒拉取一次服务注册信息
eureka.client.fetch-registry=true
eureka.client.registry-fetch-interval-seconds=30
#请求异常时feign的容错处理 fallback(指定一个feign客户端接口的实现类)
feign.hystrix.enabled=true
#设置feign的超时时间,不设置默认是1000毫秒
feign.client.config.default.connect-timeout=10000
feign.client.config.default.read-timeout=10000
#其中“service-provider”指明对哪个微服务的调用进行配置,当前配置使用随机策略,修改策略修改最后的类名即可
service-provider.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
# 暴露管理节点
management.endpoints.web.exposure.include=["*"]
# 修改feign默认的通信方式,解决401状态码无法获取responseBody的问题
feign.httpclient.enabled=true
2.启动类
package com.zhourui;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableHystrix
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class ServiceConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceConsumerApplication.class,args);
}
}
4.使用feign调用提供者
package com.zhourui.controller;
import com.zhourui.common.bean.Student;
import com.zhourui.service.ProviderAdapterFeign;
import org.springframework.http.ResponseEntity;
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 javax.annotation.Resource;
@RestController
@RequestMapping("/consumer")
public class TestConsumerController {
@Resource
private ProviderAdapterFeign providerAdapterFeign;
@GetMapping("/{id}")
public ResponseEntity getProviderByFeign(@PathVariable("id") String id){
Student student = providerAdapterFeign.getStudentById(id);
return ResponseEntity.ok().body(student);
}
@GetMapping("/zuul")
public ResponseEntity testZuul(){
return ResponseEntity.ok().body("zuul success!");
}
}
5.feign编写
package com.zhourui.service;
import com.zhourui.common.bean.Student;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "service-provider",fallback = ProviderAdapterFeignFallback.class)
public interface ProviderAdapterFeign {
@GetMapping(value = "/provide/getStudentById/{id}")
Student getStudentById(@PathVariable("id")String id/*, @RequestHeader("X-Subject-Token") String token*/);
}
6.请求异常时的容错处理
package com.zhourui.service;
import com.zhourui.common.bean.Student;
import org.springframework.stereotype.Component;
/***
* 异常时熔断处理
*/
@Component
public class ProviderAdapterFeignFallback implements ProviderAdapterFeign {
@Override
public Student getStudentById(String id) {
Student student=new Student();
student.setName("xx");
student.setAge(1);
return student;
}
}
6.feign默认ribbo的负载均衡配置
package com.zhourui.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* 类名称: RibbonConfig
* 功能简介: Ribbon配置类
* 功能详解: 通过spring boot的配置类,来配置Ribbon,
* 实例化一个RestTemplate实例,并加上@LoadBalanced注解
*
* @author zhourui
* @date 2019/6/3
*/
@Configuration
public class RibbonConfiguration {
/**
* 加上Ribbon的提供的负载均衡注解{@link LoadBalanced @LoadBalanced}
*
* @return
*/
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
启动服务消费者后,会发送一个REST请求给服务注册中心,来获取上面注册的服务清单。消费者获取服务清单后,可以通过服务名获取到具体服务实例与实例的元数据信息。在Ribbon中默认采用轮询的方式进行调用,从而实现负载均衡。