Eureka 是 RESTful 服务。用于定位执行 AWS 域(Region)中的中间层服务。本文介绍 Eureka 和 Ribbon 的集成,附带 Ribbon 自己定义负载均衡算法演示样例。
Ribbon 和 Eureka 的集成,事实上也就是让 Ribbon 充当 Eureka 架构中的 Application Client 角色。本文演示样例基于前边相关博客中的 demo 而写。阅读本文最好參考一下《云中间层服务 - 区域感知负载均衡器 Ribbon》、《Eureka 的 Application Client client的执行演示样例》。
Why Eureka need Ribbon?
Eureka 附带client库,为何还要 Ribbon 呢?
Ribbon 的负载均衡算法、区域感知负载均衡器久经考验,可以直接拿来使用。
Why Ribbon need Eureka?
熟悉 Ribbon 的同学都知道,Ribbon 维护了一个服务器列表,假设服务器有宕机现象,Ribbon 可以自行将其剔除;但假设该服务器故障排除,又一次启动,或者添加新的负载节点。我们须要手工调用 Ribbon 的接口将其动态加入进 Ribbon 的服务器列表。这样明显不够尽如人意。怎样可以在服务节点启动时,自行加入服务列表?—— Eureka。Eureka 提供了 Application Service client的自行注冊的功能。此外。Eureka 的缓存机制可以防止大规模宕机带来的灾难性后果。
下面開始我们的集成。进行下面操作之前,请确保 Eureka Server 已启动,Eureka Application Service client已注冊到 Server(參考《Eureka 的 Application Client client的执行演示样例》)。
1. 加入 ribbon-eureka 依赖包
http://mvnrepository.com/artifact/com.netflix.ribbon/ribbon-eureka 选择合适的版本号下载,作者下载的是 ribbon-eureka-0.3.12.jar。
2. 配置的初始化
配置文件基本採用《Eureka 的 Application Client client的执行演示样例》Eureka Application Client client配置。另外增添下面配置项:
- 启用client负载均衡器并将其配置为 DynamicServerListLoadBalancer 或其子类(这个无须在配置中体现。由于这个是 Eureka 和 Ribbon 集成默觉得 true 的)。
- 将 ServerList 配置为 com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList。
- 配置服务器(负载均衡节点)的刷新频率(可选。默认是为 30 秒)。
- 为 Eureka client配置服务器的虚拟地址(VIP 地址),并确保这个地址匹配到服务器(Application Service)注冊 Eureka Server 时所用到的那个。
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 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 client的执行演示样例》中的一般无二,在此不再赘述。
5. Application Client 关闭时取消注冊
取消代码和《Eureka 的 Application Client 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 成功。
參考资料
版权声明:本文博客原创文章。博客,未经同意,不得转载。