本系列介紹的配置均基於 Spring Boot 2.0.1.RELEASE 版本和 Spring Cloud Finchley.SR1git
pom.xml文件以下github
<?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>spring-cloud-manage</artifactId> <groupId>org.springcloudmanage</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>producer-service</artifactId> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <build> <finalName>producer-service</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Finchley版本已經不須要添加@EnableDiscoveryClient註解,Spring Cloud會自動識別。web
@SpringBootApplication public class ProducerServiceApplication { public static void main(String[] args) { SpringApplication.run(ProducerServiceApplication.class, args); } }
spring.application.name=producer-service server.port=9001 #eureka eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/
多節點eureka服務註冊以下:spring
eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/,http://localhost:8002/eureka/
@RestController @RequestMapping(value = "/test") public class ProducerAction { @RequestMapping(value = "", method = RequestMethod.GET) public String test(String param) { return "param is " + param; } }
服務啓動後,訪問eureka主頁http://localhost:8001/,便可看到以下頁面,說明服務已經註冊到eureka上了 apache
訪問http://localhost:9001/test?param=test,看到返回結果以下app
param is test
Ribbon 了,它是一個基於 HTTP 和 TCP 的客戶端負載均衡器。它能夠經過在客戶端中配置ribbonServerList 來設置服務端列表去輪詢訪問以達到均衡負載的做用。負載均衡
當 Ribbon 與 Eureka聯合使用時,ribbonServerList會被DiscoveryEnabledNIWSServerList 重寫,擴展成從 Eureka 註冊中心中獲取服務實例列表。同時它也會用 NIWSDiscoveryPing 來取代 IPing,它將職責委託給 Eureka 來肯定服務端是否已經啓動。maven
pom.xml文件以下ide
<?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>spring-cloud-manage</artifactId> <groupId>org.springcloudmanage</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>consumer-service</artifactId> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
spring-cloud-starter-netflix-eureka-client中已經引用了ribbon先關的jar,所需不須要再引入了spring-boot
@SpringBootApplication public class ConsumerServiceApplication { @LoadBalanced @Bean public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(ConsumerServiceApplication.class, args); } }
spring.application.name=consumer-service server.port=9002 #eureka eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/
這裏注入restTemplate,Spring Cloud Ribbon 本身有攔截器會對 服務名producer-service作解析,自動的去選取服務實例負載均衡調用,並將服務名替換成實際要請求的IP地址和端口
@RestController @RequestMapping(value = "/ribbon/test") public class ConsumerAction { @Autowired private RestTemplate restTemplate; @RequestMapping(value = "", method = RequestMethod.GET) public String test(String param) { String url = "http://producer-service/test/?param=" + param; return restTemplate.getForObject(url, String.class); } }
消費端服務啓動成功後,能夠看到erueka時已經顯示註冊成功了
訪問http://localhost:9002/ribbon/test?param=ribbon-test ,能夠看到以下結果,說明消費端服務接收到參數後,經過ribbon負載均衡,調用到producer-service的接口。
param is ribbon-test
控制檯日誌
2018-08-28 16:25:23.397 INFO 3791 --- [nio-9002-exec-1] c.netflix.config.ChainedDynamicProperty : Flipping property: producer-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647 2018-08-28 16:25:23.414 INFO 3791 --- [nio-9002-exec-1] c.n.u.concurrent.ShutdownEnabledTimer : Shutdown hook installed for: NFLoadBalancer-PingTimer-producer-service 2018-08-28 16:25:23.433 INFO 3791 --- [nio-9002-exec-1] c.netflix.loadbalancer.BaseLoadBalancer : Client: producer-service instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=producer-service,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null 2018-08-28 16:25:23.440 INFO 3791 --- [nio-9002-exec-1] c.n.l.DynamicServerListLoadBalancer : Using serverListUpdater PollingServerListUpdater 2018-08-28 16:25:23.462 INFO 3791 --- [nio-9002-exec-1] c.netflix.config.ChainedDynamicProperty : Flipping property: producer-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647 2018-08-28 16:25:23.463 INFO 3791 --- [nio-9002-exec-1] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client producer-service initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=producer-service,current list of Servers=[192.168.101.238:9001],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:1; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;] },Server stats: [[Server:192.168.101.238:9001; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0] ]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@12e48993 2018-08-28 16:25:24.447 INFO 3791 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty : Flipping property: producer-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
能夠啓動多個producer-service服務測試下實際的負載均衡效果。
Feign是一個聲明式的Web Service客戶端,它使得編寫Web Serivce客戶端變得更加簡單。咱們只須要使用Feign來建立一個接口並用註解來配置它既可完成。它具有可插拔的註解支持,包括Feign註解和JAX-RS註解。Feign也支持可插拔的編碼和解碼。Spring Cloud爲Feign增長了對Spring MVC註解的支持,還整合了Ribbon和Eureka來提供均衡負載的HTTP客戶端實現。
在實際工做中,咱們基本上都是使用Feign來完成調用的。咱們經過一個例子來展示 Feign 如何方便的聲明對 eureka-producer 服務的定義和調用。
<?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>spring-cloud-manage</artifactId> <groupId>org.springcloudmanage</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>consumer-service</artifactId> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
@EnableFeignClients @SpringBootApplication public class ConsumerServiceApplication { public static void main(String[] args) { SpringApplication.run(ConsumerServiceApplication.class, args); } }
spring.application.name=consumer-service server.port=9002 #eureka eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/ #開啓Hystrix斷路器 feign.hystrix.enabled=true #斷路器的超時時間須要大於ribbon的超時時間,否則不會觸發重試,缺省爲1000 hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
建立feign客戶端調用類,其中name爲所需調用的服務名,fallback使用Hystrix,當producer-service不可用時,對服務作降級,並返回友好提示
@FeignClient(name = "producer-service", fallback = ProducerServiceFeignClientHystrix.class) public interface ProducerServiceFeignClient { @RequestMapping(value = "/test", method = RequestMethod.GET) String test(@RequestParam("param") String param); }
==注意@RequestParam("param")中name必需要和producer-service服務中的參數名一致==
@Component public class ProducerServiceFeignClientHystrix implements ProducerServiceFeignClient { @Override public String test(String param) { return "服務[producer-service]沒法訪問"; } }
訪問http://localhost:9002/feign/test?param=feign-test,能夠看到以下結果
param is feign-test
中止producer-service,再次訪問http://localhost:9002/feign/test?param=feign-test,能夠看到以下結果,說明fallback已經生效了
服務[producer-service]沒法訪問