文章目录
二、Eureka注册中心
1、初始Eureka
- Eureka:服务注册中心(可以是一个集群),对外暴露自己的地址。
- Provider:启动之后向Eureka注册中心注册自己的相关信息(地址以及提供什么服务)
- Consumer:从Eureka获取注册服务列表,从而能够消费服务。
- 心跳:提供者定期通过http方式向Eureka刷新自己的状态
2、搭建环境
在之前的父工程下创建一个maven工程,成为注册中心
添加如下依赖:
<dependencies>
<!--eureka-server服务端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
在resources中的application.yml中配置Eureka
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服务端的实例名称
client:
register-with-eureka: false # 表示不向注册中心注册自己
fetch-registry: false # 表示自己就是注册中心,职责就是维护服务实例,不需要去检索服务
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置Eureka Server交互的地址查询和注册服务都要依赖这个地址
只需要编写一个启动类即可
package springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer //注册中心
public class EurekaServer7001_App {
public static void main(String[] args) {
SpringApplication.run(EurekaServer7001_App.class, args);
}
}
3、调试
<1>、修改EurekaServer
运行,来到7001端口
我们发现注册Eureka的地址名称是unknown,是因为我们没有设置访问Eureka的Application Name,就是微服务的名称,所以我们这里来到配置文件中手动进行修改:
spring:
application:
name: miscroservicecloud-dept
eureka:
client: # 客户端注册进eureka服务列表内
service-url:
defaultZone: http://localhost:7001/eureka
重新运行,发现我们的微服务名称不再是unknown了,而是我们自己写的名称。
<2>、修改生产者
消费者就是要在Eureka上注册自己的相关信息,因此要对消费者做一些配置上的修改,让其能够成功注册。
首先添加如下依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
和之前一样,配置了Eureka就要开启这项集群服务来到启动类,进行启动Eureka
,加上一个注解@EnableDiscoveryClient即可,之后和以上相同,如果我们这个时候重新运行了miscroservicecloudproviderdept8001是无法被检测到注册了的,所以还需要稍微修改一下配置
server:
port: 8001
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml # mybatis配置文件所在路径
type-aliases-package: springcloud.entities # 所有Entity别名类所在包
mapper-locations: # mapper映射文件
- classpath:mybatis/mapper/**/*.xml
spring:
application:
name: miscroservicecloud-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
url: jdbc:mysql://localhost:3306/cloudDB01 # 数据库名称
username: root
password: 123456
dbcp2:
min-idle: 5 # 数据库连接池的最小维持连接数
initial-size: 5 # 初始化连接数
max-total: 5 # 最大连接数
max-wait-millis: 200 # 等待连接获取的最大超时时间
eureka:
client: # 客户端注册进eureka服务列表内
service-url:
defaultZone: http://localhost:7001/eureka
重新运行之后,显示成功。
<3>、修改消费者
首先添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
在application.yml中进行相关配置
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://localhost:7001/eureka
使用Eureka的目的就是动态获取到地址,所以要对url的获取方式进行修改
package springcloud.controller;
import org.springframework.beans.factory.annotation.Autowired;
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 springcloud.entities.Dept;
import java.util.List;
@RestController
public class DeptController_Consumer {
//misroservicecloud-dept
// private static final String REST_URL_PREFIX = "http://localhost:8081";
private static final String REST_URL_PREFIX = "http://MISROSERVICECLOUD-DEPT";
/**
* 使用RestTemplate访问restful接口
* (url,requestMap,ResponseBean.class)
* REST请求地址、请求参数、HTTP响应转换被转换成的对象类型
*/
@Autowired
RestTemplate restTemplate;
@RequestMapping(value = "/consumer/dept/add")
public boolean add(Dept dept){
return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add", dept, boolean.class);
}
@RequestMapping(value = "/consumer/dept/get/{id}")
public Dept get(@PathVariable("id")Long id){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get"+id, Dept.class);
}
@SuppressWarnings("unchecked")
@RequestMapping(value = "/consumer/dept/list")
public List<Dept> list(){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);
}
//测试@EnableDiscoveryClient,消费端可以调用服务发现
@RequestMapping(value = "/consumer/dept/discovery")
public Object discovery(){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/discovery", Object.class);
}
}
4、Eureka HA
<1>、基本架构
Eureka中三大核心角色:
Eureka Server:
Eureka的服务端应用,提供服务注册和发现功能,就是刚刚我们建立的Eureka-Server
Service Provider:
提供服务的应用,可以是SpringBoot应用,也可以是其它任意技术实现,只要对外提供的是Rest风格的服务即可。本例中就是我们实现的miscroservicecloudproviderdept8001
Service Consumer:
消费应用从注册中心获取服务列表,从而得知每个服务方的信息,知道去哪里调用服务方。就是在本例中实现的miscroservicecloudconsumerdept80
<2>、Eureka Server HA
Eureka Server:服务注册中心,刚才我们只创建了一个Eureka Server,事实上Eureka Server也可以是一个集群,从而形成高可用的注册中心。
服务同步:
多个Eureka Server之间也会互相注册为服务,当服务提供者注册到Eureka Server集群中的某个节点时,该节点会把服务的信息同步给集群中的每个节点,从而实现数据同步。因此,无论客户端访问到Eureka Server集群中的任意一个节点,都可以获取到完整的服务列表信息。
(1)、搭建环境
server:
port: 7001
eureka:
instance:
# hostname: localhost #eureka服务端的实例名称
hostname: eureka7001.com
client:
register-with-eureka: false # 表示不向注册中心注册自己
fetch-registry: false # 表示自己就是注册中心,职责就是维护服务实例,不需要去检索服务
service-url:
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置Eureka Server交互的地址查询和注册服务都要依赖这个地址
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
将defaultZone的地址改变成为其他相邻的地址,做到相互连通。
然后将EurekaServer进行复制,让复制出来的也指向Eureka这项服务
创建第二个注册中心,修改相关的配置
server:
port: 7002
eureka:
instance:
# hostname: localhost #eureka服务端的实例名称
hostname: eureka7002.com
client:
register-with-eureka: false # 表示不向注册中心注册自己
fetch-registry: false # 表示自己就是注册中心,职责就是维护服务实例,不需要去检索服务
service-url:
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置Eureka Server交互的地址查询和注册服务都要依赖这个地址
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/
同理创建第三个注册中心,记得修改defaultZone让其指向其相邻的地址。
由于我们对于Eureka进行了高可用的注册,所以也必须要对miscroservicecloudproviderdept8001和miscroservicecloudconsumerdept80进行两个Eureka的注册,而不只是7001端口的了,只需要在yml文件中给defaultZone加上域名即可
加了此注册信息主要就是防止其中一个节点挂了,另外的节点还可以继续工作。
(2)、调试
运行之后,发现我们现在的微服务是有三个Eureka Server。
5、Eureka Server的Register
<1>、Register
平时启动Eureka的时候还是先会报错,然后才能正常启动,现在我们的Eureka一启动首先就会注册自己,但是并不是所有情况下一开始就会注册自己,然后先报错的,这取决于一个设置register-with-eureka: false只要设置为false就不注册了,默认都是注册的。
平时注册的时候,都是以Map形式注册的,Key就是微服务的名字,Value就是InstanceID。
<2>、续约
心跳续约的默认时间是30s,每隔30s进行一次心跳的续约,但是时间也是可以配置的,超出时间范围就会被默认为宕机了。
默认配置是这样的:
eureka:
instance:
lease-expiration-duration-in-seconds: 90
lease-renewal-interval-in-seconds: 30
每隔三十秒发送一次心跳,一共90秒也就是三次,如果都没有发送心跳相应,就是宕机了。
但是也不能心跳发送的太快,Eureka也会宕机的,设置默认就好,一般情况下是不会更改这个值的。
<3>、拉取列表
服务的提供方会注册自己,而消费方则会拉取服务列表,拉取也是有一定周期的:
eureka:
client:
registry-fetch-interval-seconds: 30
<4>、失效剔除和自我保护
一般情况下,当我们关闭某一项服务时,会触发一个服务下线的REST的请求给EurekaServer,告诉服务中心下线的请求,然后服务中心接收到请求之后就会下线。
- 失效剔除:
有时我们的服务提供方并不一定会正常下线,可能因为内存溢出、网络故障等原因导致服务无法正常工作。Eureka Server需要将这样的服务剔除出服务列表。因此它会开启一个定时任务,每隔60秒对所有失效的服务(超过90秒未响应)进行剔除。
eureka:
server:
eviction-interval-timer-in-ms: 30000
- 自我保护:
触发了Eureka的自我保护机制。当一个服务未按时进行心跳续约时,Eureka会统计最近15分钟心跳失败的服务实例的比例是否超过了85%。在生产环境下,因为网络延迟等原因,心跳失败实例的比例很有可能超标,但是此时就把服务剔除列表并不妥当,因为服务可能没有宕机。Eureka就会把当前实例的注册信息保护起来,不予剔除。生产环境下这很有效,保证了大多数服务依然可用。
我们可以手动关闭掉自我保护:
eureka:
server:
enable-self-preservation: false # 关闭自我保护模式(缺省为打开)
eviction-interval-timer-in-ms: 1000 # 扫描失效服务的间隔时间(缺省为60*1000ms)
三、Ribbon负载均衡
1、概述
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。Spring Cloud Ribbon虽然只是一个工具类框架,它不像服务注册中心、配置中心、API网关那样需要独立部署,但是它几乎存在于每一个Spring Cloud构建的微服务和基础设施中。因为微服务间的调用,API网关的请求转发等内容,实际上都是通过Ribbon来实现的,包括后续我们将要介绍的Feign,它也是基于Ribbon实现的工具。所以,对Spring Cloud Ribbon的理解和使用,对于我们使用Spring Cloud来构建微服务非常重要。
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。
2、环境搭建
首先导入maven的相关依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
3、开启负载均衡
修改miscroservicecloudconsumerdept80的cfgbeans包里面的配置类
package springcloud.cfgbeans;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
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;
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced //spring cloud ribbon基于netfix实现的一套客户端 负载均衡的工具
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
总结:Ribbon默认是使用轮询来达到负载均衡,但是我们也可以去手动修改负载均衡机制,比如说随机
只需要在配置类里面写上
@Bean
public IRule myRule(){
return new RandomRule(); //目的:用重新选择的随机算法替代默认的轮询
}
即可。