一: Ribbon 是什么?
Ribbon 是 Netflix 发布的开源项目, 主要功能是提供客户端的软件负载均衡算法, 将 Netflix 的中间层服务连接在一起. Ribbon 客户端组件提供一系列完善的配置项如连接超时, 重试等. 简单的说, 就是在配置文件中列出 Load Balancer(简称 LB)后面所有的机器, Ribbon 会自动的帮助你基于某种规则 (如简单轮询, 随即连接等) 去连接这些机器. 我们也很容易使用 Ribbon 实现自定义的负载均衡算法.
二: LB 方案分类
目前主流的 LB 方案可分成两类: 一种是集中式 LB, 即在服务的消费方和提供方之间使用独立的 LB 设施(可以是硬件, 如 F5, 也可以是软件, 如 nginx), 由该设施负责把访问请求通过某种策略转发至服务的提供方; 另一种是进程内 LB, 将 LB 逻辑集成到消费方, 消费方从服务注册中心获知有哪些地址可用, 然后自己再从这些地址中选择出一个合适的服务器. Ribbon 就属于后者, 它只是一个类库, 集成于消费方进程, 消费方通过它来获取到服务提供方的地址.
三: Ribbon 的主要组件与工作流程
Ribbon 的核心组件 (均为接口类型) 有以下几个:
ServerList
用于获取地址列表. 它既可以是静态的(提供一组固定的地址), 也可以是动态的(从注册中心中定期查询地址列表).
ServerListFilter
仅当使用动态 ServerList 时使用, 用于在原始的服务列表中使用一定策略过虑掉一部分地址.
IRule
选择一个最终的服务地址作为 LB 结果. 选择策略有轮询, 根据响应时间加权, 断路器 (当 Hystrix 可用时) 等.
Ribbon 在工作时首选会通过 ServerList 来获取所有可用的服务列表, 然后通过 ServerListFilter 过虑掉一部分地址, 最后在剩下的地址中通过 IRule 选择出一台服务器作为最终结果.
四: Ribbon 提供的主要负载均衡策略介绍
1: 简单轮询负载均衡(RoundRobin)
以轮询的方式依次将请求调度不同的服务器, 即每次调度执行 i = (i + 1) mod n, 并选出第 i 台服务器.
2: 随机负载均衡 (Random)
随机选择状态为 UP 的 Server
3: 加权响应时间负载均衡 (WeightedResponseTime)
根据相应时间分配一个 weight, 相应时间越长, weight 越小, 被选中的可能性越低.
4: 区域感知轮询负载均衡(ZoneAvoidanceRule)
复合判断 server 所在区域的性能和 server 的可用性选择 server
Ribbon 自带负载均衡策略比较
五: Ribbon 单独使用
创建一个 maven 工程 名称 ribbon_client
pom 内容
- com.netflix.ribbon
- ribbon-core
- 2.2.0
- com.netflix.ribbon
- ribbon-httpclient
- 2.2.0
sample-client.properties 配置文件
- # Max number of retries
- sample-client.ribbon.MaxAutoRetries=1
- # Max number of next servers to retry (excluding the first server)
- sample-client.ribbon.MaxAutoRetriesNextServer=1
- # Whether all operations can be retried for this client
- sample-client.ribbon.OkToRetryOnAllOperations=true
- # Interval to refresh the server list from the source
- sample-client.ribbon.ServerListRefreshInterval=2000
- # Connect timeout used by Apache HttpClient
- sample-client.ribbon.ConnectTimeout=3000
- # Read timeout used by Apache HttpClient
- sample-client.ribbon.ReadTimeout=3000
- # Initial list of servers, can be changed via Archaius dynamic property at runtime
- sample-client.ribbon.listOfServers=www.sohu.com:80,www.163.com:80,www.sina.com.cn:80
- sample-client.ribbon.EnablePrimeConnections=true
RibbonMain 代码
- import java.NET.URI;
- import com.netflix.client.ClientFactory;
- import com.netflix.client.http.HttpRequest;
- import com.netflix.client.http.HttpResponse;
- import com.netflix.config.ConfigurationManager;
- import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
- import com.netflix.niws.client.http.RestClient;
- public class RibbonMain {
- public static void main( String[] args ) throws Exception {
- ConfigurationManager.loadPropertiesFromResources("sample-client.properties");
- System.out.println(ConfigurationManager.getConfigInstance().getProperty("sample-client.ribbon.listOfServers"));
- RestClient client = (RestClient)ClientFactory.getNamedClient("sample-client");
- HttpRequest request = HttpRequest.newBuilder().uri(new URI("/")).build();
- for(int i = 0; i < 4; i ++) {
- HttpResponse response = client.executeWithLoadBalancer(request);
- System.out.println("Status for URI:" + response.getRequestedURI() + "is :" + response.getStatus());
- }
- ZoneAwareLoadBalancer lb = (ZoneAwareLoadBalancer) client.getLoadBalancer();
- System.out.println(lb.getLoadBalancerStats());
- ConfigurationManager.getConfigInstance().setProperty("sample-client.ribbon.listOfServers", "ccblog.cn:80,www.linkedin.com:80");
- System.out.println("changing servers ...");
- Thread.sleep(3000);
- for(int i = 0; i < 3; i ++) {
- HttpResponse response = client.executeWithLoadBalancer(request);
- System.out.println("Status for URI:" + response.getRequestedURI() + "is :" + response.getStatus());
- }
- System.out.println(lb.getLoadBalancerStats());
- }
- }
代码解析
使用 Archaius ConfigurationManager 加载属性;
使用 ClientFactory 创建客户端和负载均衡器;
使用 builder 构建 http 请求. 注意我们只支持 URI 的 "/" 部分的路径, 一旦服务器被负载均衡器选中, 会由客户端计算出完整的 URI;
调用 API client.executeWithLoadBalancer(), 不是 exeucte() API;
动态修正配置中的服务器池;
等待服务器列表刷新(配置文件中定义的刷新间隔是为 3 秒钟);
打印出负载均衡器记录的服务器统计信息.
六: Ribbon 结合 eureka 使用
先要启动 eureka_register_service 工程 (注册中心) 和 biz-service-0 工程(服务生产者)
创建 maven 工程 eureka_ribbon_client 该工程启动和相关配置依赖 eureka_register_service 和 biz-service-0
pom 加入
- org.springframework.boot
- spring-boot-starter-parent
- 1.4.3.RELEASE
- org.springframework.cloud
- spring-cloud-starter-ribbon
- org.springframework.cloud
- spring-cloud-starter-eureka
- org.springframework.boot
- spring-boot-starter-web
- org.springframework.boot
- spring-boot-starter-test
- test
- org.springframework.cloud
- spring-cloud-dependencies
- Brixton.RELEASE
- pom
- import
在应用主类中, 通过 @EnableDiscoveryClient 注解来添加发现服务能力. 创建 RestTemplate 实例, 并通过 @LoadBalanced 注解开启均衡负载能力.
- @SpringBootApplication
- @EnableDiscoveryClient
- public class RibbonApplication {
- @Bean
- @LoadBalanced
- RestTemplate restTemplate() {
- return new RestTemplate();
- }
- public static void main(String[] args) {
- SpringApplication.run(RibbonApplication.class, args);
- }
- }
创建 ConsumerController 来消费 biz-service-0 的 getuser 服务. 通过直接 RestTemplate 来调用服务
- @RestController
- public class ConsumerController {
- @Autowired
- RestTemplate restTemplate;
- @RequestMapping(value = "/getuserinfo", method = RequestMethod.GET)
- public String add() {
- return restTemplate.getForEntity("http://biz-service-0/getuser", String.class).getBody();
- }
- }
application.properties 中配置 eureka 服务注册中心
- spring.application.name=ribbon-consumer
- server.port=8003
- eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/
完成后可以打开 http://localhost:8003/getuserinfo 可以看到结果
总结
Ribbon 其实就是一个软负载均衡的客户端组件, 他可以和其他所需请求的客户端结合使用, 和 eureka 结合只是其中的一个实例.
最后
如果你是 Java 程序员, 对技术提升很感兴趣, 可以加入我的 Java 进阶之路来交流学习: 878249276, 里面都是同行, 有资源共享. 欢迎一到五年的工程师加入, 合理利用自己每一分每一秒的时间来学习提升自己, 不要再用 "没有时间" 来掩饰自己思想上的懒惰! 趁年轻, 使劲拼, 给未来的自己一个交代!
来源: http://www.jianshu.com/p/bd2b7bbda50e