文档章节

Spring Cloud 服务消费(Ribbon)

TurboSanil
 TurboSanil
发布于 2019/05/05 17:46
字数 1556
阅读 78
收藏 2

之前介绍了使用 Eureka 作为服务发现组件,构建了 Eureka Server 作为服务注册中心,使用 Eureka Client 去注册服务 Spring Cloud 服务注册与发现、高可用(Eureka),那服务间又是怎样相互调用的呢?这里介绍使用 Ribbon 实现负载均衡

准备

构建一个 Eureka Server 服务注册中心 eureka-server 和两个注册服务 product-service (用来提供服务) 和 order-service-ribbon (消费服务者) 参考,这里我们启动两个 product-service 实例

这里分别给出配置信息

spring:
  application:
    name: eureka-server
server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

我们启动两个 product-service 服务实例,在 idea 中的 Edit Configurations 中复制一个 product-service 改变端口为 8072

spring:
  application:
    name: product-service
server:
  port: 8071
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

spring-cloud-consumer-ribbon-1-1.jpg

order-service-ribbon 需要添加 Ribbon 的依赖,如下:

spring:
  application:
    name: order-service-ribbon
server:
  port: 8081
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

启动服务注册中心 eureka-server 和两个注册服务,打开 http://localhost:8761/eureka/ 查看服务注册情况

spring-cloud-consumer-ribbon-1-2.jpg

Ribbon 实现负载均衡

实际生产中,基本上每个服务都会部署多个实例,那么服务消费者的请求该怎么分配到多个服务提供者实例上呢?

Ribbon 简介

Ribbon 是 Netflix 发布的负载均衡器,是在客户端实现负载均衡,对客户端的HTTP和TCP行为有很好的控制。它可以在客户端为其配置服务提供者地址列表 ribbonServerList,然后基于某种负载均衡算法(轮询、随机等),自动帮助客户端去请求

当 Eureka 与 Ribbon 结合使用时,ribbonServerList 将被扩展为DiscoveryEnabledNIWSServerList,扩展为 Eureka 的服务器注册实例列表。同时还会用 NIWSDiscoveryPing 替换 IPing 接口,让 Eureka 来确定服务端是否启动

RestTemplate 作为负载均衡客户端

RestTemplate 可以自动配置为使用 ribbon,要创建一个负载均衡的 RestTemplate ,需要加上注解 @LoadBalanced

@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceRibbonApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderServiceRibbonApplication.class, args);
    }

    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

创建一个 Controller 来测试请求

@RestController
public class ProductController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/product/{id}")
    public Product getProduct(@PathVariable Long id){
        return restTemplate.getForObject("http://product-service/product/" + id, Product.class);
    }
}

重新启动服务,访问路径 http://localhost:8081/product/1 得到如下结果

{"id":1,"name":"秋裤","descriptionl":"花秋裤","price":9.9,"count":99}

有上面的代码我们可以看到请求的地址为 http://product-service/product/1,其中的 product-service 就是我们要请求的服务的虚拟主机名,Ribbon 会自动把这个虚拟主机名映射成要请求的服务网络地址

LoadBalancerClient

LoadBalancerClient 是 Spring Cloud Commons 中提供的一个抽象接口,可以使用它来调用 Ribbon API

@RestController
@Log4j2
public class ProductController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @GetMapping("/product/{id}")
    public Product getProduct(@PathVariable Long id){
        return restTemplate.getForObject("http://product-service/product/" + id, Product.class);
    }

    @GetMapping("/product/log/{id}")
    public void logProduct(@PathVariable Long id){
        ServiceInstance serviceInstance = loadBalancerClient.choose("product-service");
        // URI storesUri = URI.create(String.format("https://%s:%s/"+ id, serviceInstance.getHost(), serviceInstance.getPort()));
        log.info("{}:{}:{}", serviceInstance.getHost(), serviceInstance.getPort());
    }
}

现在我们重新启动服务,访问 http://localhost:8081/product/log/1 ,上面代码可以看到我们会打印查询日志,会记录下请求服务的实例id、主机名、端口,多次访问上面的地址

2019-04-30 09:19:01.437  INFO 22024 --- [nio-8081-exec-3] c.t.order.controller.ProductController   : DESKTOP-G11TC44.mshome.net:8071
2019-04-30 09:19:01.687  INFO 22024 --- [nio-8081-exec-4] c.t.order.controller.ProductController   : DESKTOP-G11TC44.mshome.net:8072
2019-04-30 09:19:01.843  INFO 22024 --- [nio-8081-exec-5] c.t.order.controller.ProductController   : DESKTOP-G11TC44.mshome.net:8071
2019-04-30 09:19:01.984  INFO 22024 --- [nio-8081-exec-6] c.t.order.controller.ProductController   : DESKTOP-G11TC44.mshome.net:8072
2019-04-30 09:19:02.140  INFO 22024 --- [nio-8081-exec-7] c.t.order.controller.ProductController   : DESKTOP-G11TC44.mshome.net:8071
2019-04-30 09:19:02.297  INFO 22024 --- [nio-8081-exec-8] c.t.order.controller.ProductController   : DESKTOP-G11TC44.mshome.net:8072

可以看到请求的各个服务节点依次交替,说明已经实现负载均衡

restTemplate.getForObject() 不能和 loadBalancerClient.choose() 同时使用,因为注释了 @LoadBalanced 的 restTemplate 实际上就是一个 Ribbon 客户端,包含了 choose 的功能

自定义 Ribbon 客户端

在某些场景下,可能会需要自定义 Ribbon 的配置,如修改 Ribbon 的负载均衡规则。可以使用 @RibbonClient 声明自定义的配置,或者使用 <clientName>.Ribbon.* 中的外部属性配置 Ribbon 客户端

代码自定义 Ribbon 客户端

默认情况下,Ribbon 客户端已经实现了以下的 bean (BeanType beanName:ClassName

  • IClientConfig ribbonClientConfig: DefaultClientConfigImpl
  • IRule ribbonRule: ZoneAvoidanceRule
  • IPing ribbonPing: DummyPing
  • ServerList<Server> ribbonServerList: ConfigurationBasedServerList
  • ServerListFilter<Server> ribbonServerListFilter: ZonePreferenceServerListFilter
  • ILoadBalancer ribbonLoadBalancer: ZoneAwareLoadBalancer
  • ServerListUpdater ribbonServerListUpdater: PollingServerListUpdater

可通过自定义配置覆盖默认配置

@Configuration
public class RibbonConfiguration {

    @Bean
    public IPing ribbonPing() {
        return new PingUrl();
    }

    @Bean
    public IRule ribbonRule() {
        // 负载均衡规则:随机
        return new RandomRule();
    }
}
@Configuration
@RibbonClient(name = "product-service", configuration = RibbonConfiguration.class)
public class TestConfiguration {
}

这种配置是细粒度的,不同的 Ribbon 客户端可以使用不同的配置,使用 @RibbonClient 的 configuration 属性,就可以自定义 指定名称的 Ribbon 客户端的配置

这里的 RibbonConfiguration 类不能包含在主应用程序的上下文中的 @ComponentScan 中,否则该类的配置会被所有的 @RibbonClient 共享。因此只想自定义某一个 Ribbon 客户端的配置,必须防止 @Configuration 的注解的类所在包和 @ComponentScan 扫描的包重合,或显示指定 @ComponentScan 不扫描 @Configuration 类所在包

为所有Ribbon客户端自定义默认值

通过使用 @RibbonClients 注释并注册一个默认配置,可以为所有 Ribbon 客户端提供一个默认配置

@RibbonClients(defaultConfiguration = DefaultRibbonConfig.class)
public class RibbonClientDefaultConfigurationTestsConfig {

	public static class BazServiceList extends ConfigurationBasedServerList {

		public BazServiceList(IClientConfig config) {
			super.initWithNiwsConfig(config);
		}

	}

}

@Configuration
class DefaultRibbonConfig {

	@Bean
	public IRule ribbonRule() {
		return new BestAvailableRule();
	}

	@Bean
	public IPing ribbonPing() {
		return new PingUrl();
	}

	@Bean
	public ServerList<Server> ribbonServerList(IClientConfig config) {
		return new RibbonClientDefaultConfigurationTestsConfig.BazServiceList(config);
	}

	@Bean
	public ServerListSubsetFilter serverListFilter() {
		ServerListSubsetFilter filter = new ServerListSubsetFilter();
		return filter;
	}
}

属性自定义 Ribbon 客户端

使用属性自定义 Ribbon 客户端会比代码自定义更加方便。属性配置的前缀为 <clientName>.Ribbon.*

  • NFLoadBalancerClassName: 实现 ILoadBalancer
  • NFLoadBalancerRuleClassName: 实现 IRule
  • NFLoadBalancerPingClassName: 实现 IPing
  • NIWSServerListClassName: 实现 ServerList
  • NIWSServerListFilterClassName: 实现 ServerListFilter

这些属性中定义的类优先于使用 @RibbonClient(configuration=MyRibbonConfig.class) 定义的 bean 和Spring Cloud Netflix 提供的默认值定义的 bean。

product-service:
  ribbon:
    NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule

参考代码:demo

© 著作权归作者所有

TurboSanil
粉丝 2
博文 48
码字总数 98648
作品 0
广州
程序员
私信 提问
加载中

评论(0)

SpringCloud系列第05节之服务消费Ribbon和Feign

Ribbon Ribbon 是一个基于 HTTP 和 TCP 客户端的负载均衡器 它可以在客户端配置 ribbonServerList(服务端列表),然后轮询请求以实现均衡负载 它在联合 Eureka 使用时 ribbonServerList 会被...

吴伟祥
2019/03/20
42
0
Spring Cloud 实战之服务提供与调用

eureka注册续约流程 启动注册中心 服务提供者生产服务并注册到服务中心中 消费者从服务中心中获取服务并执行 服务提供 1.在spring-cloud-manage下创建一个子项目producer-service pom.xml文件...

技术小能手
2018/10/26
0
0
企业级java b2bc商城系统开源源码二次开发:服务消费(Ribbon)

Spring Cloud Ribbon Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。它是一个基于HTTP和TCP的客户端负载均衡器。它可以通过在客户端中配置ribbonServerList来设置...

park
2019/01/21
0
0
Spring Cloud 服务消费(Feign)

在使用 RestTemplate 实现 Rest API 调用的时候,是通过拼接字符串的方式构造 URL,向具体服务实例发起 Http 请求。在定义 RestTemplate 的时候,还可以增加 注解,在调用服务接口的时候,原...

TurboSanil
2019/05/05
97
0
Spring Cloud构建微服务架构:服务消费(Ribbon)

Spring Cloud Ribbon Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。它是一个基于HTTP和TCP的客户端负载均衡器。它可以通过在客户端中配置ribbonServerList来设置...

itcloud
2019/03/01
45
1

没有更多内容

加载失败,请刷新页面

加载更多

MySQL字符串截取的4个函数

1、从左开始截取字符串 left(str, length) 说明: left(被截取字段,截取长度) 例如: select left(content,200) as abstract from my_content_t 从左边(字符串开始位置)截取指定长...

fairy1674
48分钟前
92
0
Fedora 31 - 查杀木马

使用chkrootkit和rkhunter检查系统 #安装工具sudo dnf install chkrootkit rkhunter#修改配置##使用管理员邮箱地址sudo sed -i 's/^MAILTO=.*/MAILTO=admin@server.com/' /etc/sy......

wffger
56分钟前
68
0
检查目录是否存在,如果不存在则创建

我经常发现自己写的R脚本会产生大量输出。 我发现它更干净,可以将此输出放到自己的目录中。 我在下面编写的内容将检查目录是否存在并移入该目录,或者创建目录然后移入该目录。 有没有更好的...

javail
59分钟前
97
0
让你相见恨晚的Photoshop 使用技巧——用ps做后期渲染

无论是面对客户汇报方案还是在设计竞赛中脱颖而出,通过PS来渲染平面图都是至关重要的工作。无论何时,你的平面设计的出图质量便也是你的能力说明。 今天小编给大家带来真正的对建筑 / 规划/...

mac小叮当
今天
80
0
推荐VSCode12个比较实用的插件

1、Auto Rename Tag ——自动重命名成对的HTML标记。假如你创建了一个<p>标记。现在你想更改它。有了这个软件,你只需要更改一个就行,另一个会自动修改。从理论上来说,使用这个软件可以把...

IT技术分享社区
今天
102
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部