前提:整个项目的微服务集群均写在顶级父工程(le-you)里:便于管理依赖及其版本
服务间调用存在的问题:服务间调用,servicer(提供方)对外提供服务,需要对外暴露自己的地址。而consumer(调用者)需要记录服务提供者的地址。将来地址出现变更,还需要及时更新。不仅开发困难,将来测试、发布上线都会非常麻烦。
Eureka:负责管理、记录服务提供者的信息。服务调用者无需自己寻找服务,而是把自己的需求告诉Eureka,然后Eureka会把符合你需求的服务告诉你。同时,服务提供方与Eureka之间通过“心跳”机制进行监控,当某个服务提供方出现问题,Eureka自然会把它从服务列表中剔除。这就实现了服务的自动注册、发现、状态监控。
这就实现了服务的自动注册、发现、状态监控。
架构图:
对于整个乐优项目,我们会在Eureka注册每个微服务,列表如下:
注册微服务(ly–registry)的配置:
server:
port: 10086
spring:
application:
name: ly--registry #应用名称,会在Eureka中显示
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
register-with-eureka: false
fetch-registry: false
注册与拉取服务
注册服务,就是在服务上添加Eureka的客户端依赖,客户端代码会自动把服务注册到EurekaServer中。
<!-- Eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
server:
port: 8081
spring:
application:
name: item-service #应用名称
datasource:
url: jdbc:mysql://localhost:3306/yun6
username: root
password: root
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
eureka:
client:
service-url: # EurekaServer地址
defaultZone: http://127.0.0.1:10086/eureka
instance:
prefer-ip-address: true # 当调用getHostname获取实例的hostname时,返回ip而不是host名称
ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找
注意:
@SpringBootApplication
@EnableDiscoveryClient // 开启EurekaClient功能
public class LyItemApplication{
public static void main(String[] args) {
SpringApplication.run(LyItemApplication.class, args);
}
}
消费者从Eureka获取服务
方法与注册类似,只需要在项目中添加EurekaClient依赖,就可以通过服务名称来获取信息了!
服务续约
在注册服务完成以后,服务提供者会维持一个心跳(定时向EurekaServer发起Rest请求),告诉EurekaServer:“我还活着”。这个我们称为服务的续约(renew);
有两个重要参数可以修改服务续约的行为:
eureka:
instance:
lease-expiration-duration-in-seconds: 90
lease-renewal-interval-in-seconds: 30
也就是说,默认情况下每个30秒服务会向注册中心发送一次心跳,证明自己还活着。如果超过90秒没有发送心跳,EurekaServer就会认为该服务宕机,会从服务列表中移除,这两个值在生产环境不要修改,默认即可。
在实际环境中,我们往往会开启很多个service的集群。此时我们获取的服务列表中就会有多个,一般采用Eureka中已经集成的Ribbon实现负载均衡,在多个实例列表中采用轮询方式进行选择,获取ip和端口来访问。
依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-ribbonartifactId>
<version>2.0.0.RC1version>
dependency>
Hystix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现服务间的调用级联失败(雪崩),在微服务中起保护作用。(注:Ribbon的超时时间一定要小于Hystix的超时时间。)
Hystix熔断机制(三种状态):
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMillisecond: 5000 # 熔断超时时长:5000ms
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix //开启Hystrix 功能
public class LyItemApplication{
public static void main(String[] args) {
SpringApplication.run(LyItemApplication.class, args);
}
}
Feign: Rest的远程请求进行隐藏,伪装成类似SpringMVC的Controller一样(类似本地请求)。
Feign 利用SpringMVC的注解来识别请求的信息(请求方式,路径,参数,返回值等)从而帮我们自动的进行一次远程调用,不需要我们再去手动写,一切都交给Feign去做。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
@EnableFeignClients // 开启Feign功能
public class LyItemApplication{
public static void main(String[] args) {
SpringApplication.run(LyItemApplication.class, args);
}
}
@FeignClient("user-service")
public interface UserFeignClient {
@GetMapping("/user/{id}")
User queryUserById(@PathVariable("id") Long id);
}
@Service
public class UserService {
@Autowired
private UserFeignClient userFeignClient;
@GetMapping("/user/{id}")
public User queryUserById(@PathVariable("id") Long id){
return userFeignClient.queryUserById(id));
}
}
我们看到的仅仅是feign调用了方法,但它的本质是做了一次远程调用。
注:
SpringCloud对Feign进行了增强,使Feign不仅支持SpringMVC的注解,并整合了Ribbon和Eureka,从而使Feign的使用更加方便。
feign:
hystrix:
enabled: true # 开启Feign的熔断功能