注册中心环境搭建
Maven依赖信息
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> </parent> <!-- 管理依赖 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.M7</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!--SpringCloud eureka-server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies> <!-- 注意: 这里必须要添加, 否者各种依赖有问题 --> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/libs-milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
application.yml
###服务端口号 server: port: 8100 ###eureka 基本信息配置 eureka: instance: ###注册到eurekaip地址 hostname: 127.0.0.1 client: serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ ###因为自己是为注册中心,不需要自己注册自己 register-with-eureka: false ###因为自己是为注册中心,不需要检索服务 fetch-registry: false
启动Eureka服务
@EnableEurekaServer @SpringBootApplication public class AppEureka { public static void main(String[] args) { SpringApplication.run(AppEureka.class, args); } }
注册服务提供者
Maven依赖信息
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> </parent> <!-- 管理依赖 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.M7</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- SpringBoot整合Web组件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- SpringBoot整合eureka客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <!-- 注意: 这里必须要添加, 否者各种依赖有问题 --> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/libs-milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
application.yml
###服务启动端口号 server: port: 8000 ###服务名称(服务注册到eureka名称) spring: application: name: app-itmayiedu-member ###服务注册到eureka地址 eureka: client: service-url: defaultZone: http://localhost:8100/eureka ###因为该应用为注册中心,不会注册自己 register-with-eureka: true ###是否需要从eureka上获取注册信息 fetch-registry: true
服务接口
@RestController public class MemberController { @RequestMapping("/getMember") public String getMember() { return "this is getMember"; } }
启动会员服务
@SpringBootApplication @EnableEurekaClient public class AppMember { public static void main(String[] args) { SpringApplication.run(AppMember.class, args); } }
服务消费者
Maven依赖信息
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> </parent> <!-- 管理依赖 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.M7</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- SpringBoot整合Web组件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- SpringBoot整合eureka客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <!-- 注意: 这里必须要添加, 否者各种依赖有问题 --> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/libs-milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
Application.yml配置
###服务启动端口号 server: port: 8001 ###服务名称(服务注册到eureka名称) spring: application: name: app-itmayiedu-order ###服务注册到eureka地址 eureka: client: service-url: defaultZone: http://localhost:8100/eureka ###因为该应用为注册中心,不会注册自己 register-with-eureka: true ###是否需要从eureka上获取注册信息 fetch-registry: true
使用rest方式调用服务
@RestController public class OrderController { @Autowired private RestTemplate restTemplate; @RequestMapping("/getorder") public String getOrder() { // order 使用rpc 远程调用技术 调用 会员服务 String memberUrl = "http://app-itmayiedu-member/getMember"; String result = restTemplate.getForObject(memberUrl, String.class); System.out.println("会员服务调用订单服务,result:" + result); return result; } }
启动消费者服务
@SpringBootApplication @EnableEurekaClient public class AppOrder { public static void main(String[] args) { SpringApplication.run(AppOrder.class, args); } @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } }
@LoadBalanced就能让这个RestTemplate在请求时拥有客户端负载均衡的能力
高可用注册中心
在微服务中,注册中心非常核心,可以实现服务治理,如果一旦注册出现故障的时候,可能会导致整个微服务无法访问,在这时候就需要对注册中心实现高可用集群模式。
Eureka高可用原理
默认情况下Eureka是让服务注册中心,不注册自己
###注册自己 register-with-eureka: true ###需要去注册中心上检索服务 fetch-registry: true
Eureka高可用实际上将自己作为服务向其他服务注册中心注册自己,这样就可以形成一组相互注册的服务注册中心,从而实现服务清单的互相同步,达到高可用效果。
客户端集成Eureka集群
server: port: 8000 spring: application: name: app-itmayiedu-member #eureka: # client: # service-url: # defaultZone: http://localhost:8100/eureka ###集群地址 eureka: client: service-url: defaultZone: http://localhost:8100/eureka,http://localhost:8200/eureka register-with-eureka: true fetch-registry: true
Eureka详解
服务消费者模式
获取服务
消费者启动的时候,使用服务别名,会发送一个rest请求到服务注册中心获取对应的服务信息,让后会缓存到本地jvm客户端中,同时客户端每隔30秒从服务器上更新一次。
可以通过 fetch-inte vall-seconds=30参数进行修以通过eureka.client .registry该参数默认值为30, 单位为秒。
服务下线
在系统运行过程中必然会面临关闭或重启服务的某个实例的情况,在服务关闭期有我们自然不希望客户端会继续调用关闭了的实例。所以在客户端程序中,当服务实例过正常的关闭操作时,它会触发一个服务下线的REST请求给Eureka Server, 告诉服务日中心:“我要下线了”。服务端在接收到请求之后,将该服务状态置为下线(DOWN),井该下线事件传播出去。
服务注册模式
失效剔除
有些时候,我们的服务实例并不一定会正常下线,可能由于内存溢出、网络故障气因使得服务不能正常工作,而服务注册中心并未收到“服务下线”的请求。为了从服务表中将这些无法提供服务的实例剔除,Eureka Server 在启动的时候会创建一个定时任多默认每隔一一段时间(默认为60秒)将当前清单中超时(默认为90秒)没有续约的服务除出去
自我保护
默认情况下,EurekaClient会定时向EurekaServer端发送心跳,如果EurekaServer在一定时间内没有收到EurekaClient发送的心跳,便会把该实例从注册服务列表中剔除(默认是90秒),但是在短时间内丢失大量的实例心跳,这时候EurekaServer会开启自我保护机制,Eureka不会踢出该服务。
产生的原因:
在开发测试时,需要频繁地重启微服务实例,但是我们很少会把eureka server一起重启(因为在开发过程中不会修改eureka注册中心),当一分钟内收到的心跳数大量减少时,会触发该保护机制。可以在eureka管理界面看到Renews threshold和Renews(last min),当后者(最后一分钟收到的心跳数)小于前者(心跳阈值)的时候,触发保护机制,会出现红色的警告:
EMERGENCY!EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT.RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEGING EXPIRED JUST TO BE SAFE. |
从警告中可以看到,eureka认为虽然收不到实例的心跳,但它认为实例还是健康的,eureka会保护这些实例,不会把它们从注册表中删掉。
该保护机制的目的是避免网络连接故障,在发生网络故障时,微服务和注册中心之间无法正常通信,但服务本身是健康的,不应该注销该服务,如果eureka因网络故障而把微服务误删了,那即使网络恢复了,该微服务也不会重新注册到eureka server了,因为只有在微服务启动的时候才会发起注册请求,后面只会发送心跳和服务列表请求,这样的话,该实例虽然是运行着,但永远不会被其它服务所感知。所以,eureka server在短时间内丢失过多的客户端心跳时,会进入自我保护模式,该模式下,eureka会保护注册表中的信息,不在注销任何微服务,当网络故障恢复后,eureka会自动退出保护模式。自我保护模式可以让集群更加健壮。
但是我们在开发测试阶段,需要频繁地重启发布,如果触发了保护机制,则旧的服务实例没有被删除,这时请求有可能跑到旧的实例中,而该实例已经关闭了,这就导致请求错误,影响开发测试。所以,在开发测试阶段,我们可以把自我保护模式关闭,只需在eureka server配置文件中加上如下配置即可:
但在生产环境,不会频繁重启,所以,一定要把自我保护机制打开,否则网络一旦终端,就无法恢复。
当然关于自我保护还有很多个性化配置,这里不详细说明。
注意考虑网络不可达情况下:调用接口幂等、重试、补偿等。
关闭服务保护
Eureka服务器端配置
###服务端口号 server: port: 8100 ##定义服务名称 spring: application: name: app-itmayiedu-eureka eureka: instance: ###注册中心ip地址 hostname: 127.0.0.1 client: serviceUrl: ##注册地址 defaultZone: http://${eureka.instance.hostname}:8100/eureka/ ####因为自己是注册中心,是否需要将自己注册给自己的注册中心(集群的时候是需要是为true) register-with-eureka: false ###因为自己是注册中心, 不需要去检索服务信息 fetch-registry: false server: # 测试时关闭自我保护机制,保证不可用服务及时踢出 enable-self-preservation: false eviction-interval-timer-in-ms: 2000
Eureka客户端配置
###订单服务的端口号 server: port: 8001 ###服务别名----服务注册到注册中心名称 spring: application: name: app-itmayiedu-order eureka: client: service-url: ##### 当前会员服务注册到eureka服务地址 # defaultZone: http://localhost:8100/eureka,http://localhost:9100/eureka defaultZone: http://localhost:8100/eureka ### 需要将我的服务注册到eureka上 register-with-eureka: true ####需要检索服务 fetch-registry: true registry-fetch-interval-seconds: 30 # 心跳检测检测与续约时间 # 测试时将值设置设置小些,保证服务关闭后注册中心能及时踢出服务 instance: ###Eureka客户端向服务端发送心跳的时间间隔,单位为秒(客户端告诉服务端自己会按照该规则) lease-renewal-interval-in-seconds: 1 ####Eureka服务端在收到最后一次心跳之后等待的时间上限,单位为秒,超过则剔除(客户端告诉服务端按照此规则等待自己) lease-expiration-duration-in-seconds: 2
声明式服务调用SpringCloud Feign 主流
feign介绍
Feign客户端是一个web声明式http远程调用工具,提供了接口和注解方式进行调用。
环境搭建
Maven依赖信息
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
feign客户端接口
// name 指定服务名称 @FeignClient(name = "app-itmayiedu-member") public interface MemberApifeign { @RequestMapping("/getMember") public String getMember(); }
controller
@Autowired private MemberApifeign memberApifeign; @RequestMapping("/feignMember") public String feignMember() { return memberApifeign.getMember(); }
项目启动加上@EnableFeignClients
@SpringBootApplication @EnableEurekaClient @EnableFeignClients public class AppOrder { public static void main(String[] args) { SpringApplication.run(AppOrder.class, args); }
Ribbon配置
SpringCloud Feign客户端Http调用工具,默认已经整合了Ribbon负载均衡客户端。
配置Feign客户端超时时间
###设置feign客户端超时时间 ribbon: ###指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间。 ReadTimeout: 5000 ###指的是建立连接后从服务器读取到可用资源所用的时间。 ConnectTimeout: 5000
@RestController publicclass OrderController { @Autowired private RestTemplate restTemplate;
@RequestMapping("/getorder") public String getOrder() { // order 使用rpc远程调用技术 调用 会员服务 String memberUrl = "http://app-itmayiedu-member/getMember"; String result = restTemplate.getForObject(memberUrl, String.class); System.out.println("会员服务调用订单服务,result:" + result); returnresult; }
}
|