Eureka
1. Eureka简介
Eureka是Netflix开发的服务发现框架,是一个基于REST的服务
主要包含两个组件: Eureka Server和Eureka Client
主要有:
- Eureka Server(服务注册中心)
- 服务提供方
- 服务消费方
可以看这张图了解大概
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C0z9laYE-1570769790806)(BDB475AE408B4089B5B993F0A6FC85F3)]
2. Eureka Server搭建
2.1 依赖配置
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<!-- 在写版本的时候,不能像官网那样写 Greenwich SR2, -->
<version>Greenwich.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2.2 application.yml配置文件
server:
port: 7961
eureka:
instance:
hostname: localhosh #eureka的服务机器名
client:
fetch-registry: false
register-with-eureka: false
service-url:
defaultZone: http://localhost:${server.port}/eureka/
2.3 启动类代码
@SpringBootApplication
@EnableEurekaServer
public class SpringcloudMsEureka7961Application {
public static void main(String[] args) {
SpringApplication.run(SpringcloudMsEureka7961Application.class, args);
}
}
2.4 测试
访问访问http://localhost:7961/
3. 服务提供方搭建
3.1 依赖配置
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<!-- 在写版本的时候,不能像官网那样写 Greenwich SR2, -->
<version>Greenwich.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3.2 application.yml配置(阿里Durid 和 数据库读写分离)
server:
port: 6001
eureka:
client:
fetch-registry: false
register-with-eureka: true
service-url:
defaultZone: http://localhost:7961/eureka/
instance:
prefer-ip-address: true
logging:
level:
com.vip.weborder.mapper: debug
mybatis-plus:
mapper-locations: classpath:mappers/**/*.xml
spring:
datasource:
druid:
stat-view-servlet:
loginUsername: root
loginPassword: root
dynamic:
datasource:
master:
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://120.24.94.104:3316/aaaa?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
druid:
initial-size: 3
max-active: 8
min-idle: 2
max-wait: -1
min-evictable-idle-time-millis: 30000
max-evictable-idle-time-millis: 30000
time-between-eviction-runs-millis: 0
validation-query: select 1
validation-query-timeout: -1
test-on-borrow: false
test-on-return: false
test-while-idle: true
pool-prepared-statements: true
max-open-prepared-statements: 100
filters: stat,wall
share-prepared-statements: true
slave_1:
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://120.24.94.104:3317/aaaa?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
druid:
initial-size: 3
max-active: 8
min-idle: 2
max-wait: -1
min-evictable-idle-time-millis: 30000
max-evictable-idle-time-millis: 30000
time-between-eviction-runs-millis: 0
validation-query: select 1
validation-query-timeout: -1
test-on-borrow: false
test-on-return: false
test-while-idle: true
pool-prepared-statements: true
max-open-prepared-statements: 100
filters: stat,wall
share-prepared-statements: true
<!--注意最好是给名字方便消费层调用-->
application:
name: ms-provider
3.3 启动类代码
@SpringBootApplication
@EnableEurekaClient //启动Eureka客户端
public class ShopProviderApplication {
public static void main( String[] args){
SpringApplication.run(ShopProviderApplication.class, args);
}
}
4. 服务消费方搭建
4.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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.qf</groupId>
<artifactId>spring-cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.example</groupId>
<artifactId>springcloud-ms-consumer-8080</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-ms-consumer-8080</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>com.qf</groupId>
<artifactId>spring-cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</exclusion>
<exclusion>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<!-- 在写版本的时候,不能像官网那样写 Greenwich SR2, -->
<version>Greenwich.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
4.2 application.yml配置
spring:
application:
name: shop-consumer
server:
port: 8080
eureka:
client:
fetch-registry: true
register-with-eureka: false
service-url:
defaultZone: http://localhost:7961/eureka/
4.3 启动类代码
@SpringBootApplication
@EnableEurekaClient
public class SpringcloudMsConsumer8080Application {
public static void main(String[] args) {
SpringApplication.run(SpringcloudMsConsumer8080Application.class, args);
}
}
5 启动 Ribbon 负载均衡(单纯启动默认)
5.1 配置依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
5.2 实现负载均衡
Ribbon只是一个客户端的负载均衡器工具,实现起来非常的简单,我们只需要在注入RestTemplate的bean上加上@LoadBalanced就可以了。如下:
@Configuration
public class BeanConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
5.3 启动类配置
@SpringBootApplication
@EnableEurekaClient
public class ShopConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ShopConsumerApplication.class, args);
}
}
5.4 服务的调用
在服务的消费方,不再采用主机名+端口的形式进行调用,而是直接采用服务名的方式进行调用。
@RestController
@RequestMapping(value="/user")
public class UserController {
@Resource
private RestTemplate restTemplate;
@RequestMapping(value = "/ticket/{id}", method = RequestMethod.GET)
public Object getTicket(@PathVariable(value = "id") Integer id) {
Person person = new Person();
person.setId(23);
person.setName("张三三");
// shop-provider 是服务名,不需要使用ip:端口的形式进行调用
List<Ticket> ticketList = restTemplate.getForObject("http://shop-provier/ticket", List.class, person);
return ticketList;
}
}
5.5 负载均衡策略
Ribbon提供了一个很重要的接口叫做IRule,其中定义了很多的负载均衡策略,默认的是轮询的方式,以下是Ribbon的负载均衡策略:
类名 | 描述 |
---|---|
RoundRobbinRule | 轮询 |
RandomRule | 随机挑选 |
RetryRule | 按照轮询的方式去调用服务,如果其中某个服务不可用,但是还是会尝试几次,如果尝试过几次都没有成功,那么就不在调用该服务,会轮询调用其他的可用服务。 |
AvailabilityFilteringRule | 会先过滤掉因为多次访问不可达和并发超过阈值的服务,然后轮询调用其他的服务 |
WeightedResponseTimeRule | 根据平均响应时间计算权重,响应越快权重越大,越容易被选中。服务刚重启的时候,还未统计出权重会按照轮询的方式;当统计信息足够的时候,就会按照权重信息访问 |
ZoneAvoidanceRule | 判断server所在的区域性能和可用性选择服务器 |
BestAvailableRule | 会过滤掉多次访问都不可达的服务,然后选择并发量最小的服务进行调用,默认方式 |
改变Ribbon的负责均衡策略:
@Bean
public IRule getRule() {
return new RandomRule();
}
5.6 自定义负载均衡策略
我们自定义的负载均衡策略需要继承AbstractLoadBalancerRule这个类,然后重写choose方法,然后将其注入到容器中,如下所示:
public class Customize_Rule extends AbstractLoadBalancerRule {
private static Logger logger = LoggerFactory.getLogger(Customize_Rule.class);
private int currentIndex = 0; //当前调用的索引
private int num = 1; //次数
private int limit = 5;
/**
* 初始化工作
* @param iClientConfig
*/
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
@Override
public Server choose(Object key) {
ILoadBalancer balancer = getLoadBalancer();
return choose(balancer, key);
}
private Server choose(ILoadBalancer balancer, Object key) {
Server server = null;
while(null == server) {
//获取所有可用的服务
List<Server> reachableServers = balancer.getReachableServers();
if (0 == reachableServers.size()) {
logger.error("没有可用的服务");
return null; //退出while循环
}
int total = reachableServers.size(); //可用服务的数量
synchronized (this) {
/**
* 有种极端情况,当我们在使用最后一个服务的时候,其他的服务都不可用,可能导致索引越界异常
*/
if (currentIndex + 1 > total) {
currentIndex = 0;
server = reachableServers.get(currentIndex); //获取第一个服务
num = 0;
num++;
} else {
if(limit == num) {
currentIndex++;
num = 0;
if(currentIndex == total) {
currentIndex=0;
server = reachableServers.get(currentIndex); //获取第一个服务
num++;
}else{
server = reachableServers.get(currentIndex);
num++;
}
}else {
server = reachableServers.get(currentIndex);
num++;
}
}
}
}
return server;
}
}
将其注入到容器中,如下所示:
@Bean
public IRule getRule() {
return new Customize_Rule();
}
这种对Controller层的入侵太强而且,不方便观看,所以我们可以用下一个Feign 实现负载均衡
6. Feign 负载均衡
eign是基于Ribbon的另外一个负载均衡的客户端框架,只需要在接口上定义要调用的服务名即可,使用起来非常的简单。
6.1 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
6.2 启动类配置
需要在启动类上加上@EnableFeignClients注解即可开启feign,如下所示:
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class ShopConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ShopConsumerApplication.class, args);
}
}
6.3 service层 直接用注解调用其他模块
@Service
@FeignClient(name = "shop-provier")
public interface TicketService {
@RequestMapping(value = "ticket", method = RequestMethod.GET)
public List<Ticket> getAllTicket(Person person);
}
这样我们用起来在Controllor层就和平时用的写的一样,只是Service层有所不同,看上去也更加舒服
6.4 yml 配置
注意,有时候会遇到超时问题,可以配置一下设置时间
client:
config:
default:
connectTimeout: 160000000
readTimeout: 160000000