Java后端爱上SpringCloud 第二节:内部负载均衡 Ribbon和Feign
Java后端爱上SpringCloud 第一节:内部负载均衡 Ribbon和Feign
PS:为什么说是内部负载均衡?因为Ribbon和Feign都是在SpringClodu服务间的调用做的,之后会讲到在外部请求做负载均衡。至于负载均衡是啥,大家可以自行搜索一下,老规矩先贴一些连接,让大家明确概念,在进行实现。
这里先简单的贴一下负载均衡的概念:
负载均衡:英文名称为Load Balance, 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。
一些链接
- 微服务之间的调用(Ribbon与Feign)
- Spring Cloud 客服端负载均衡 Ribbon
- 轻松搞定SpringCloud微服务-负载均衡Ribbon
- git上feign的项目
- git上ribbon的项目
- 详解 RestTemplate 操作
Ribbon和Feign的区别和比较
Ribbon | Feign |
---|---|
软负载 | 软负载 |
支持TCP,HTTP,UPU | 支持HTTP |
支持容错 | 支持容错 |
和RestTemplate结合起来实现负载均衡 | 简单的HTTP生命调用 |
当前架构
之前有个工程起名为spring-first,太low了,我把它改名为My-Cloud-First虽然也很low。贴一下现在的架构图:
下面开始实现正题。
创建My-Spring-Ribbon
创建一个My-Spring-Ribbon工程。
pom文件如下:
<?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"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.1.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.hyn</groupId> <artifactId>My-Spring-Ribbon</artifactId> <version>0.0.1-SNAPSHOT</version> <name>My-Spring-Ribbon</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.RC1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <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-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </repository> </repositories> </project>
注册到Eureka上面:
spring: application: name: spring-boot-ribbo server: port: 8765 # tag::configuration-eureka[] management: endpoints: web: exposure: include: "*" #<2> endpoint: health: show-details: ALWAYS # end::configuration-eureka[] eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/
记得在启动类上加上:@EnableEurekaClient
写一个controller:RibbonControler
package com.hyn.cloud.ribbon.controler; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/ribbon") public class RibbonControler { @RequestMapping(value = "/name",method=RequestMethod.GET) @ResponseBody public String ribbon(@RequestParam String name){ String respResult="I am ribbon,My name is "+name; return respResult; } }
依次启动Eureka,Admin,Ribbon,测试一下:http://127.0.0.1:8765/ribbon/name?name=hyn
创建My-Spring-Feign
创建一个My-Spring-Feign工程。
pom文件如下:
<?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"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.hyn</groupId> <artifactId>My-Spring-Feign</artifactId> <version>0.0.1-SNAPSHOT</version> <name>My-Cloud-Feign</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.RC2</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <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-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </repository> </repositories> </project>
注册到Eureka上面:
spring: application: name: spring-boot-feign server: port: 8763 # tag::configuration-eureka[] management: endpoints: web: exposure: include: "*" #<2> endpoint: health: show-details: ALWAYS # end::configuration-eureka[] eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/
记得在启动类上加上:@EnableEurekaClient
写一个controller:RibbonControler
package com.hyn.cloud.feign.controler; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/feign") public class FeignControler { @RequestMapping(value = "/name",method=RequestMethod.GET) @ResponseBody public String feign(@RequestParam String name){ String respResult="I am feign,My name is "+name; return respResult; } }
依次启动Feign,测试一下:http://127.0.0.1:8763/feign/name?name=hyn
现在可以看到,在SpringBootAdmin上如下结构:
Ribbon调用
说明一下RestTemplate:
- RestTemplate是Spring提供的用于访问Rest服务的客户端。
- RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
- 调用RestTemplate的默认构造函数,RestTemplate对象在底层通过使用java.net包下的实现创建HTTP 请求,可以通过使用ClientHttpRequestFactory指定不同的HTTP请求方式。
- ClientHttpRequestFactory接口主要提供了两种实现方式,一种是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)创建底层的Http请求连接,还有一种方式是使用HttpComponentsClientHttpRequestFactory方式,底层使用HttpClient访问远程的Http服务,使用HttpClient可以配置连接池和证书等信息。
启动类修改:
package com.hyn.cloud.ribbon; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableEurekaClient @EnableDiscoveryClient public class MyCloudRibbonApplication { public static void main(String[] args) { SpringApplication.run(MyCloudRibbonApplication.class, args); } /** * Spring提供的用于访问Rest服务的客户端 * @return */ @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } }
controller 类修改
package com.hyn.cloud.ribbon.controler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController @RequestMapping("/ribbon") public class RibbonControler { /** * 注入RestTemplate */ @Autowired RestTemplate restTemplate; @RequestMapping(value = "/name",method=RequestMethod.GET) @ResponseBody public String ribbon(@RequestParam String name){ String respResult="I am ribbon,My name is "+name; String url="http://SPRING-BOOT-FEIGN/feign/name?name="; return restTemplate.getForObject(url+respResult, String.class); } }
在调用一下:
可以看到通过Ribbon去调用了Feign,虽然栗子举的有些生硬。哈哈哈哈
Feign调用
启动类修改:
package com.hyn.cloud.feign; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableEurekaClient @EnableFeignClients //开启spring cloud feign的支持 public class MyCloudFeignApplication { public static void main(String[] args) { SpringApplication.run(MyCloudFeignApplication.class, args); } }
controller修改:
package com.hyn.cloud.feign.controler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.hyn.cloud.feign.service.FeignService; @RestController @RequestMapping("/feign") public class FeignControler { @Autowired FeignService feignService; @RequestMapping(value = "/name",method=RequestMethod.GET) public String feign(@RequestParam String name){ return feignService.getName(name); } }
添加一个service:
package com.hyn.cloud.feign.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; @FeignClient(value = "SPRING-BOOT-RIBBO") public interface FeignService { @RequestMapping(value = "/ribbon/name",method = RequestMethod.GET) String getName(@RequestParam("name")String name); }
然后我掉了一下http://127.0.0.1:8763/feign/name?name=hyn,然后feign去调了ribbon,ribbon又去调了feign,然后就没有然后了,会报一大堆错,没有仔细分析。
这里我们在ribbon项目Controller里面再添加一个Request,
package com.hyn.cloud.ribbon.controler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController @RequestMapping("/ribbon") public class RibbonControler { /** * 注入RestTemplate */ @Autowired RestTemplate restTemplate; @RequestMapping(value = "/name",method=RequestMethod.GET) @ResponseBody public String ribbon(@RequestParam String name){ String respResult="I am ribbon,My name is "+name; String url="http://SPRING-BOOT-FEIGN/feign/name?name="; return restTemplate.getForObject(url+respResult, String.class); } @RequestMapping(value = "/name2",method=RequestMethod.GET) @ResponseBody public String ribbon2(@RequestParam String name){ String respResult="I am ribbon,My name2 is "+name; return respResult; } }
修改FeignService调用的url
package com.hyn.cloud.feign.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; @FeignClient(value = "SPRING-BOOT-RIBBO") public interface FeignService { @RequestMapping(value = "/ribbon/name2",method = RequestMethod.GET) String getName(@RequestParam("name")String name); }
然后请求feign项目:
可以看到feign工程去调用了ribbon工程的name2的controller
- SpringCloud | Feign如何整合Ribbon进行负载均衡的?
- springcloud服务调用其它服务接口实例及ribbon均衡负载
- 负载均衡之feign与ribbon的比较
- java B2B2C Springcloud电子商城系统-Ribbon负载均衡策略配置
- SpringCloud(第 007 篇)电影微服务,使用定制化 Ribbon 在客户端进行负载均衡,使用 RibbonClient 不同服务不同配置策略
- Java后端爱上SpringCloud 第四节:路由网关Zuul和Gateway
- springCloud(8):Ribbon实现客户端侧负载均衡-自定义Ribbon配置
- [java]微服务架构连载No3 Ribbon+Retry服务实现负载均衡和服务请求重试
- Java后端爱上SpringCloud 第三节:熔断器 Hystrix
- SpringCloud(第 007 篇)电影微服务,使用定制化 Ribbon 在客户端进行负载均衡,使用 RibbonClient 不同服务不同配置策略
- SpringCloud客户端的负载均衡Ribbon的实现
- SpringCloud 入门 | 负载均衡之rest+ribbon
- springCloud(7):Ribbon实现客户端侧负载均衡-消费者整合Ribbon
- SpringCloud Finchley 实战入门(基于springBoot 2.0.3)【四 Ribbon 服务负载均衡】
- SpringCloud(第 006 篇)电影微服务,使用 Ribbon 在客户端进行负载均衡
- 搭建nginx+tomcat+Java的负载均衡环境
- nginx做前端反代负载均衡,后端httpd+tomcat
- 客户端负载均衡 Spring Cloud Ribbon
- [分布式会话]zuul通过Ribbon配置负载均衡策略实现粘性会话(sticky session)
- 浅谈SpringCloud (三) Ribbon负载均衡