您现在的位置是:首页 > 文章详情

Spring Cloud Netflix Ribbon核心接口

日期:2019-03-23点击:317

Spring Cloud Netflix Ribbon核心接口

LoadBalancerClient

主要职责

  • 转化URI:将含应用名称URI转化成具体主机+端口形式
  • 选择服务实例:通过负载算法,选择指定服务中的一台机器实例
  • 请求执行回调:针对选择后服务实例,执行具体的请求回调操作
    默认实现:RibbonLoadBalancerClient

自动装配源:RibbonAutoConfiguration#loadBalancerClient(...)

负载均衡器上下文

LoadBalancerContext

主要职责

  • 转化URI:将含应用名称URI转化成具体主机+端口的形式
  • 组件关联:关联RetryHandler、ILoadBalancer等
  • 记录服务统计信息:记录请求响应时间、错误数量等
  • 默认实现:RibbonLoadBalancerContext
  • 自动装配源:RibbonClientConfiguration#ribbonLoadBalancerContext(...)

负载均衡器

ILoadBalancer

主要职责

  • 增加服务器
  • 获取服务器:通过关联Key获取、获取所有服务列表、获取可用服务器列表
  • 服务器状态:标记服务器宕机
  • 默认实现:ZoneAwareLoadBalancer
  • 自动装配源:RibbonClientConfiguration#ribbonLoadBalancer(...)

规则接口

IRule

主要职责

  • 选择服务器:根据负载均衡器以及关联Key获取候选的服务器
  • 默认实现:ZoneAvoidanceRule
  • 自动装配源:RibbonClientConfiguration#ribbonRule(...)

PING策略

IPing

主要职责

  • 活动检测:根据指定的服务器,检测其是否活动
  • 默认实现:DummyPing
  • 自动装配源:RibbonClientConfiguration#ribbonPing(...)

服务器列表

ServerList

主要职责

  • 获取初始化服务器列表
  • 获取更新服务器列表
  • 默认实现:ConfigurationBasedServerList或DiscoveryEnabledNIWSServerList
  • 自动装配源:RibbonClientConfiguration#ribbonPing(...)

我的项目版本信息Maven配置

<?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> <modules> <module>user-api</module> </modules> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>spring-cloud-lesson-7</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>pom</packaging> <name>spring-cloud-lesson-7</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <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-eureka-server</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> <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> </project>

idea多工程配置

pom.xml文件中
m1

然后删除之前src文件夹,然后new个项目,效果如图

m2

三个模块:

  • user-api:公用 API
  • user-ribbon-client:客户端应用
  • user-service-provider:服务端应用

实现 user-robbon-client

配置信息
application.properties:

## 用户 Ribbon 客户端应用 spring.application.name = user-ribbon-client ## 服务端口 server.port = 8080 ## 提供方服务名称 provider.service.name = user-service-provider ## 提供方服务主机 provider.service.host = localhost ## 提供方服务端口 provider.service.port = 9090 ## 关闭 Eureka Client,显示地通过配置方式注册 Ribbon 服务地址 eureka.client.enabled = false ## 定义 user-service-provider Ribbon 的服务器地址 ## 为 RibbonLoadBalancerClient 提供服务列表 user-service-provider.ribbon.listOfServers = \ http://${provider.service.host}:${provider.service.port}

2.编写客户端调用

package com.segumentfault.spring.cloud.lesson7.user.ribbon.client.web.controller; import com.segumentfault.spring.cloud.lesson7.domain.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import javax.ws.rs.GET; import java.io.IOException; /** * 用户 Ribbon Controller * */ @RestController public class UserRibbonController { /** * 负载均衡器客户端 */ @Autowired private LoadBalancerClient loadBalancerClient; @Value("${provider.service.name}") private String providerServiceName; @GetMapping("") public String index() throws IOException { User user = new User(); user.setId(1L); user.setName("ssss"); // 选择指定的 service Id ServiceInstance serviceInstance = loadBalancerClient.choose(providerServiceName); return loadBalancerClient.execute(providerServiceName, serviceInstance, instance -> { //服务器实例,获取 主机名(IP) 和 端口 String host = instance.getHost(); int port = instance.getPort(); String url = "http://" + host + ":" + port + "/user/save"; RestTemplate restTemplate = new RestTemplate(); return restTemplate.postForObject(url, user, String.class); }); } }

3.编写引导类

package com.segumentfault.spring.cloud.lesson7.user.ribbon.client; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.ribbon.RibbonClient; /** * 引导类 * */ @SpringBootApplication @RibbonClient("user-service-provider") // 指定目标应用名称 public class UserRibbonClientApplication { public static void main(String[] args) { SpringApplication.run(UserRibbonClientApplication.class, args); } } 

实现user-service-provider

1.配置信息
application.properties

## 用户服务提供方应用信息 spring.application.name = user-service-provider ## 服务端口 server.port = 9090 ## 关闭 Eureka Client,显示地通过配置方式注册 Ribbon 服务地址 eureka.client.enabled = false

2.实现UserService

package com.segumentfault.spring.cloud.lesson7.user.service.provider.service; import com.segumentfault.spring.cloud.lesson7.api.UserService; import com.segumentfault.spring.cloud.lesson7.domain.User; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * 内存实现{@link UserService} * */ @Service public class InMemoryUserService implements UserService { private Map<Long, User> repository = new ConcurrentHashMap<>(); @Override public boolean saveUser(User user) { return repository.put(user.getId(), user) == null; } @Override public List<User> findAll() { return new ArrayList(repository.values()); } } 

3.实现Web服务

package com.segumentfault.spring.cloud.lesson7.user.service.web.controller; import com.segumentfault.spring.cloud.lesson7.api.UserService; import com.segumentfault.spring.cloud.lesson7.domain.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; /** * 用户服务提供方 Controller * */ @RestController public class UserServiceProviderController { @Autowired private UserService userService; @PostMapping("/user/save") public boolean user(@RequestBody User user){ return userService.saveUser(user); } }

4.编写引导类

package com.segumentfault.spring.cloud.lesson7.user.service; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.ribbon.RibbonClient; /** * 引导类 * */ @SpringBootApplication public class UserServiceProviderApplication { public static void main(String[] args) { SpringApplication.run(UserServiceProviderApplication.class, args); } } 

下面知识点是拓展源码练习,只做了解


分析调用链路
选择服务器逻辑
LoadBalancerClient(LoadBalancerClient) -> ILoadBalancer(ZoneAwareLoadBalancer) -> IRule (ZoneAvoidanceRule)

自定义实现IRule

扩展AbstractLoadBalancerRule:MyRule

package com.segumentfault.spring.cloud.lesson7.user.ribbon.client.rule; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.Server; import java.util.List; /** * 自定义{@link IRule} 实现,永远选择最后一台可达服务器 * */ public class MyRule extends AbstractLoadBalancerRule { @Override public void initWithNiwsConfig(IClientConfig clientConfig) { } @Override public Server choose(Object key) { ILoadBalancer loadBalancer = getLoadBalancer(); //获取所有可达服务器列表 List<Server> servers = loadBalancer.getReachableServers(); if (servers.isEmpty()) { return null; } // 永远选择最后一台可达服务器 Server targetServer = servers.get(servers.size() - 1); return targetServer; } } 

将MyRule暴露成Bean
通过ribbonClientConfiguration学习源码

@Bean @ConditionalOnMissingBean public IRule ribbonRule(IClientConfig config) { if (this.propertiesFactory.isSet(IRule.class, name)) { return this.propertiesFactory.get(IRule.class, config, name); } ZoneAvoidanceRule rule = new ZoneAvoidanceRule(); rule.initWithNiwsConfig(config); return rule; }

然后将其暴露成Bean

/** * 将 {@link MyRule} 暴露成 {@link Bean} * * @return {@link MyRule} */ @Bean public IRule myRule() { return new MyRule(); }

配置化实现组件
通过学习PropertiesFactory源码

public PropertiesFactory() { classToProperty.put(ILoadBalancer.class, "NFLoadBalancerClassName"); classToProperty.put(IPing.class, "NFLoadBalancerPingClassName"); classToProperty.put(IRule.class, "NFLoadBalancerRuleClassName"); classToProperty.put(ServerList.class, "NIWSServerListClassName"); classToProperty.put(ServerListFilter.class, "NIWSServerListFilterClassName"); } 

可知NFLoadBalancerClassName等是可以配置的
实现IPing:MyPing

package com.segumentfault.spring.cloud.lesson7.user.ribbon.client.ping; import com.netflix.loadbalancer.IPing; import com.netflix.loadbalancer.Server; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; import java.net.URI; /** * 实现 {@link IPing} 接口:检查对象 /health 是否正常状态码:200 * */ public class MyPing implements IPing { @Override public boolean isAlive(Server server) { String host = server.getHost(); int port = server.getPort(); // /health endpoint // 通过 Spring 组件来实现URL 拼装 UriComponentsBuilder builder = UriComponentsBuilder.newInstance(); builder.scheme("http"); builder.host(host); builder.port(port); builder.path("/health"); URI uri = builder.build().toUri(); RestTemplate restTemplate = new RestTemplate(); ResponseEntity responseEntity = restTemplate.getForEntity(uri, String.class); // 当响应状态等于 200 时,返回 true ,否则 false return HttpStatus.OK.equals(responseEntity.getStatusCode()); } }

增加配置
application.properties

## 扩展 IPing 实现 user-service-provider.ribbon.NFLoadBalancerPingClassName = \ com.segumentfault.spring.cloud.lesson7.user.ribbon.client.ping.MyPing
原文链接:https://yq.aliyun.com/articles/695067
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章