Ribbon 跟 Eureka 的集成

Ribbon 和 Eureka 的集成
        Ribbon 是 Netflix 发布的云中间层服务开源项目,其主要功能是提供客户侧软件负载均衡算法,将 Netflix 的中间层服务连接在一起。Eureka 是一个 RESTful 服务,用来定位运行在 AWS 域(Region)中的中间层服务。本文介绍 Eureka 和 Ribbon 的集成,附带 Ribbon 自定义负载均衡算法示例。
        Ribbon 和 Eureka 的集成,其实也就是让 Ribbon 充当 Eureka 架构中的 Application Client 角色。本文示例基于前边相关博客中的 demo 而写。阅读本文最好参考一下《云中间层服务 - 区域感知负载均衡器 Ribbon》、《Eureka 的 Application Client 客户端的运行示例》。
        Why Eureka need Ribbon?
        Eureka 附带客户端库,为何还要 Ribbon 呢?
        Ribbon 的负载均衡算法、区域感知负载均衡器久经考验,可以直接拿来使用。
        Why Ribbon need Eureka?
        熟悉 Ribbon 的同学都知道,Ribbon 维护了一个服务器列表,如果服务器有宕机现象,Ribbon 能够自行将其剔除;但如果该服务器故障排除,重新启动,或者增加新的负载节点,我们需要手工调用 Ribbon 的接口将其动态添加进 Ribbon 的服务器列表。这样明显不够尽如人意。如何能够在服务节点启动时,自行添加服务列表?—— Eureka。Eureka 提供了 Application Service 客户端的自行注册的功能。此外,Eureka 的缓存机制能够防止大规模宕机带来的灾难性后果。
        下面开始我们的集成。进行以下操作之前,请确保 Eureka Server 已启动,Eureka Application Service 客户端已注册到 Server(参考《Eureka 的 Application Client 客户端的运行示例》)。
        1. 加入 ribbon-eureka 依赖包
        http://mvnrepository.com/artifact/com.netflix.ribbon/ribbon-eureka 选择合适的版本下载,作者下载的是 ribbon-eureka-0.3.12.jar。
        2. 配置的初始化

        配置文件基本采用《Eureka 的 Application Client 客户端的运行示例》Eureka Application Client 客户端配置。另外增添以下配置项:

  • 启用客户端负载均衡器并将其配置为 DynamicServerListLoadBalancer 或其子类(这个无须在配置中体现,因为这个是 Eureka 和 Ribbon 集成默认为 true 的)。
  • 将 ServerList 配置为 com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList。
  • 配置服务器(负载均衡节点)的刷新频率(可选。默认是为 30 秒)。
  • 为 Eureka 客户端配置服务器的虚拟地址(VIP 地址),并确保这个地址匹配到服务器(Application Service)注册 Eureka Server 时所用到的那个。
        总之就是在《Eureka 的 Application Client 客户端的运行示例》基础上添加了以下配置项:
myclient.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList


# refresh every minute 
myclient.ribbon.ServerListRefreshInterval=60000


# movieservice is the virtual address that the target server(s) uses to register with Eureka server
myclient.ribbon.DeploymentContextBasedVipAddresses=movieservice
        配置文件的初始化仍然采用《Eureka 的 Application Client 客户端的运行示例》中的配置初始化方法:
		// Register with Eureka
		DiscoveryManager.getInstance().initComponent(
				new MyDataCenterInstanceConfig(),
				new DefaultEurekaClientConfig());
		ApplicationInfoManager.getInstance().setInstanceStatus(
				InstanceStatus.UP);

        3. 自定义负载均衡算法
        负载均衡算法,简单 demo 起见,使用随机算法,就用 ribbon-core 类库里的 com.netflix.loadbalancer.RandomRule 所提供的随机负载算法,拿到侍服主机:
		// get LoadBalancer instance from configuration, properties file
		DynamicServerListLoadBalancer lb = (DynamicServerListLoadBalancer) ClientFactory.getNamedLoadBalancer("myclient");
		// use RandomRule 's RandomRule algorithm to get a random server from lb 's server list
		RandomRule randomRule = new RandomRule();
		Server randomAlgorithmServer = randomRule.choose(lb, null);
		logger.debug("random algorithm server host:" + randomAlgorithmServer.getHost() + ";port:" + randomAlgorithmServer.getPort());

        4. Application Client 网络请求
        请求代码和《Eureka 的 Application Client 客户端的运行示例》中的一般无二,在此不再赘述。
        5. Application Client 关闭时取消注册
        取消代码和《Eureka 的 Application Client 客户端的运行示例》中的一般无二,在此不再赘述。
        6. 运行 demo
        新建一个项目(不要和 Application Service 的 demo 跑在同一个项目下),现在我们把完整的 Eureka Application Client 和 Ribbon Client 集成的代码整理一下。
/*
 * Copyright 2012 Netflix, Inc.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */


package com.netflix.eureka;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Date;
import java.util.Iterator;
import java.util.List;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
import com.netflix.appinfo.MyDataCenterInstanceConfig;
import com.netflix.client.ClientFactory;
import com.netflix.discovery.DefaultEurekaClientConfig;
import com.netflix.discovery.DiscoveryManager;
import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.Server;


/**
 * Sample Eureka client that discovers the service using Eureka and sends
 * requests.
 *
 * @author Karthik Ranganathan
 *
 */
public class SampleEurekaRibbonClient {
	private static final Logger logger = LoggerFactory
			.getLogger(SampleEurekaRibbonClient.class);


	public void sendRequestToServiceUsingEureka() {


		// Register with Eureka
		DiscoveryManager.getInstance().initComponent(
				new MyDataCenterInstanceConfig(),
				new DefaultEurekaClientConfig());
		ApplicationInfoManager.getInstance().setInstanceStatus(
				InstanceStatus.UP);
		// get LoadBalancer instance from configuration, properties file
		DynamicServerListLoadBalancer lb = (DynamicServerListLoadBalancer) ClientFactory.getNamedLoadBalancer("myclient");
		// show all servers in the list
		List<Server> list = lb.getServerList(false);
		Iterator<Server> it = list.iterator();
		while (it.hasNext()) {
			Server server = it.next();
			logger.debug("application service host:" + server.getHost() + ";port=" + server.getPort());
		}
		// use RandomRule 's RandomRule algorithm to get a random server from lb 's server list
		RandomRule randomRule = new RandomRule();
		Server randomAlgorithmServer = randomRule.choose(lb, null);
		logger.debug("random algorithm server host:" + randomAlgorithmServer.getHost() + ";port:" + randomAlgorithmServer.getPort());
		// communicate with the server
		Socket s = new Socket();
		try {
			s.connect(new InetSocketAddress(randomAlgorithmServer.getHost(), randomAlgorithmServer.getPort()));
		} catch (IOException e) {
			logger.error("Could not connect to the server :"
					+ randomAlgorithmServer.getHost() + " at port " + randomAlgorithmServer.getPort());
		}
		try {
			logger.debug("Connected to server. Sending a sample request");
			PrintStream out = new PrintStream(s.getOutputStream());
			out.println("Sample request " + new Date());
			String str = null;
			logger.debug("Waiting for server response..");
			BufferedReader rd = new BufferedReader(new InputStreamReader(
					s.getInputStream()));
			str = rd.readLine();
			if (str != null) {
				logger.debug("Received response from server. Communication all fine using Eureka :");
				logger.debug("Exiting the client. Demo over..");
			}
			rd.close();
		} catch (IOException e) {
			e.printStackTrace();
			logger.error(e.getMessage(), e);
		}
		this.unRegisterWithEureka();
	}


	public void unRegisterWithEureka() {
		// Un register from eureka.
		DiscoveryManager.getInstance().shutdownComponent();
	}


	public static void main(String[] args) {
		SampleEurekaRibbonClient sampleEurekaRibbonClient = new SampleEurekaRibbonClient();
		sampleEurekaRibbonClient.sendRequestToServiceUsingEureka();


	}
}

        之后是把配置文件、log4j 文件整理一下,运行 SampleEurekaRibbonClient,日志显示 demo 成功。
        参考资料
  • https://github.com/Netflix/ribbon/wiki/Programmers-Guide
1楼soledadzz11小时前
您的文章已被推荐到博客首页和个人页侧边栏推荐文章,感谢您的分享。