一 概念
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具。
LB,即负载均衡(Load Balance),在微服务或分布式集群中经常用的一种应用。 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA。 常见的负载均衡有软件Nginx,LVS,硬件 F5等。 相应的在中间件,例如:dubbo和SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义。
Ribbon概述
是 Netflixfa 发布的一个负载均衡器,有助于控制 HTTP 和 TCP客户端行为。在 SpringCloud 中,
Eureka一般配合Ribbon进行使用,Ribbon提供了客户端负载均衡的功能,Ribbon利用从Eureka中读
取到的服务信息,在调用服务节点提供的服务时,会合理的进行负载。
在SpringCloud中可以将注册中心和Ribbon配合使用,Ribbon自动的从注册中心中获取服务提供者的
列表信息,并基于内置的负载均衡算法,请求服务
Ribbon的主要作用
(1)服务调用
基于Ribbon实现服务调用, 是通过拉取到的所有服务列表组成(服务名-请求路径的)映射关系。借助
RestTemplate 最终进行调用
(2)负载均衡
当有多个服务提供者时,Ribbon可以根据负载均衡的算法自动的选择需要调用的服务地址
二 Ribbon配置初步
-
启动一中的eureka-server项目和producer-service项目,然后再改producer-service的端口,启动2个客户端
-
修改producer-service的类
1 @RestController 2 @RequestMapping("/api/v1/product") 3 public class ProductController { 4 5 6 7 @Value("${server.port}") 8 private String port; 9 10 @Autowired 11 private ProductService productService; 12 13 /** 14 * 获取所有商品列表 15 * @return 16 */ 17 @RequestMapping("list") 18 public Object list(){ 19 return productService.listProduct(); 20 } 21 22 23 /** 24 * 根据id查找商品详情 25 * @param id 26 * @return 27 */ 28 @RequestMapping("find") 29 public Object findById(int id){ 30 31 Product product = productService.findById(id); 32 33 Product result = new Product(); 34 BeanUtils.copyProperties(product,result); 35 result.setName( result.getName() + " data from port="+port ); 36 return result; 37 }
-
-
创建order-serveice项目
-
pom.xml
<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> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
注:在springcloud的新版本中提供的服务发现的jar中以及包含了Ribbon的依赖。所以这里不需要导入任何额外的坐标(spring-cloud-starter-netflix-ribbon)
-
启动类
1 @SpringBootApplication 2 public class OrderServiceApplication { 3 4 public static void main(String[] args) { 5 SpringApplication.run(OrderServiceApplication.class, args); 6 } 7 8 9 @Bean 10 @LoadBalanced 11 public RestTemplate restTemplate() { 12 return new RestTemplate(); 13 } 14 15 16 }
-
Web层
@RestController @RequestMapping("/api/v1/order") public class OrderController { @Autowired(required = false) private ProductOrderServiceImpl productOrderService; @RequestMapping("/save") public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId){ return productOrderService.save(userId, productId); } }
-
Service层
@Service public class ProductOrderServiceImpl { @Autowired private RestTemplate restTemplate; public ProductOrder save(int userId, int productId) { System.out.println("123"); Object obj = restTemplate.getForObject("http://product-service/api/v1/product/find?id="+productId, Object.class); System.out.println(obj); ProductOrder productOrder = new ProductOrder(); productOrder.setCreateTime(new Date()); productOrder.setUserId(userId); productOrder.setTradeNo(UUID.randomUUID().toString()); return productOrder; } }
-
Bo类
/** * 商品订单实体类 */ public class ProductOrder implements Serializable { private int id; /** * 商品名称 */ private String productName; /** * 订单号 */ private String tradeNo; /** * 价格,分 */ private int price; private Date createTime; private int userId; private String userName; public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getProductName() { return productName; } public void setProductName(String productName) { this.productName = productName; } public String getTradeNo() { return tradeNo; } public void setTradeNo(String tradeNo) { this.tradeNo = tradeNo; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } }
-
配置文件
server: port: 8781 #指定注册中心地址 eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ #服务的名称 spring: application: name: order-service
-
结果:2个结果在轮询
-
{id=1, name=iphonex data from port=8772, price=9999, store=10} {id=1, name=iphonex data from port=8771, price=9999, store=10} {id=1, name=iphonex data from port=8772, price=9999, store=10} {id=1, name=iphonex data from port=8771, price=9999, store=10} {id=1, name=iphonex data from port=8772, price=9999, store=10} {id=1, name=iphonex data from port=8771, price=9999, store=10}
如要修改它的负载均衡策略:
service-product:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule