上篇以一个 demo 示例介绍了 Eureka 的 Application Service 客户端角色。今天我们继续了解 Eureka 的 Application Client 客户端,以一个简单的交互示例,介绍 Application Client 是如何使用 Eureka 获取 Application Service 实例并发送请求的。
上篇《Eureka 的 Application Service 客户端的注册以及运行示例》使用了一个 Socket 服务做为 demo,本文示例配合该文,将以一个 Socket 客户端对该服务进行请求。
1. Eureka 服务器启动
本文 demo 要求 Eureka Server 已经部署好,并已经启动。关于架设步骤参考博客《Linux 下 Eureka 服务器的部署》。
2. Application Service 服务启动
直接将《Eureka 的 Application Service 客户端的注册以及运行示例》中的小 demo 跑起来(Socket Server 启动,开始侍服网络请求)。
3. Application Client 配置文件的编写
我们的 Application Client 就用官方提供 demo 里的 sampleclient 下的 sample-eureka-client.properties 即可,当然还要根据实际情况修正一下,比如把 eureka.serviceUrl.default(默认情况下本客户端将要注册到的 Eureka 服务器):http://serverIP:8080/eureka/v2/:
###Eureka Client configuration for Sample Eureka Client #Properties based configuration for eureka client. The properties specified here is mostly what the users #need to change. All of these can be specified as a java system property with -D option (eg)-Deureka.region=us-east-1 #For additional tuning options refer <url to go here> #Region where eureka is deployed -For AWS specify one of the AWS regions, for other datacenters specify a arbitrary string #indicating the region.This is normally specified as a -D option (eg) -Deureka.region=us-east-1 eureka.region=default #Name of the application to be identified by other services eureka.name=sampleEurekaClient #Virtual host name by which the clients identifies this service #eureka.vipAddress=eureka.mydomain.net #The port where the service will be running and servicing requests #eureka.port=80 #For eureka clients running in eureka server, it needs to connect to servers in other zones eureka.preferSameZone=true #Change this if you want to use a DNS based lookup for determining other eureka servers. For example #of specifying the DNS entries, check the eureka-client-test.properties, eureka-client-prod.properties eureka.shouldUseDns=false eureka.us-east-1.availabilityZones=default eureka.serviceUrl.default=http://serverIP:8080/eureka/v2/
4. 日志配置
就用官方提供 demo 里的 sampleclient 下的 log4j.properties 即可,当然还要根据实际需要修正一下,比如给 com.netflix.eureka 包的输出级别设置为 DEBUG(log4j.properties 追加 log4j.logger.com.netflix.eureka=DEBUG),以方便我们研发期跟踪调试。
log4j.rootCategory=INFO,stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %-5p %C:%L [%t] [%M] %m%n log4j.logger.com.netflix.eureka=DEBUG
5. 寻找本次请求的 Application Service 实例
客户端在向 Application Service 请求之前得先从 Eureka Server 拿到侍服本次请求的 Application Service 实例。寻找本次请求的 Application Service 实例的代码如下:
// Register with Eureka DiscoveryManager.getInstance().initComponent( new MyDataCenterInstanceConfig(), new DefaultEurekaClientConfig()); ApplicationInfoManager.getInstance().setInstanceStatus( InstanceStatus.UP); String vipAddress = configInstance.getStringProperty( "eureka.vipAddress", "sampleservice.mydomain.net").get(); InstanceInfo nextServerInfo = DiscoveryManager.getInstance() .getDiscoveryClient() .getNextServerFromEureka(vipAddress, false);
第一句初始化本客户端,第二句告诉 Eureka 本客户端处于就绪状态,接下来两句是使用 Eureka 找到对本次请求进行侍服的 Application Service 实例。
6. Application Client 网络请求
Application Client 拿到 Application Service 之后立马进行网络 Socket 请求,进行数据信息交互。
Socket s = new Socket(); int serverPort = nextServerInfo.getPort(); try { s.connect(new InetSocketAddress(nextServerInfo.getHostName(), serverPort)); } catch (IOException e) { System.err.println("Could not connect to the server :" + nextServerInfo.getHostName() + " at port " + serverPort); } try { System.out.println("Connected to server. Sending a sample request"); PrintStream out = new PrintStream(s.getOutputStream()); out.println("Sample request " + new Date()); String str = null; System.out.println("Waiting for server response.."); BufferedReader rd = new BufferedReader(new InputStreamReader( s.getInputStream())); str = rd.readLine(); if (str != null) { System.out .println("Received response from server. Communication all fine using Eureka :"); System.out.println("Exiting the client. Demo over.."); } rd.close(); } catch (IOException e) { e.printStackTrace(); }
7. Application Client 关闭时取消注册
Application Client 在关闭时要将自己在 Eureka 的注册取消掉。
public void unRegisterWithEureka() { // Un register from eureka. DiscoveryManager.getInstance().shutdownComponent(); }
8. 运行 demo
新建一个项目(不要和 Application Service 的 demo 跑在同一个项目下),现在我们把完整的 Application 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 org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.netflix.appinfo.ApplicationInfoManager; import com.netflix.appinfo.InstanceInfo; import com.netflix.appinfo.InstanceInfo.InstanceStatus; import com.netflix.appinfo.MyDataCenterInstanceConfig; import com.netflix.config.DynamicPropertyFactory; import com.netflix.discovery.DefaultEurekaClientConfig; import com.netflix.discovery.DiscoveryManager; /** * Sample Eureka client that discovers the service using Eureka and sends * requests. * * @author Karthik Ranganathan * */ public class SampleEurekaClient { private static final DynamicPropertyFactory configInstance = com.netflix.config.DynamicPropertyFactory .getInstance(); private static final Logger logger = LoggerFactory .getLogger(SampleEurekaClient.class); public void sendRequestToServiceUsingEureka() { // Register with Eureka DiscoveryManager.getInstance().initComponent( new MyDataCenterInstanceConfig(), new DefaultEurekaClientConfig()); ApplicationInfoManager.getInstance().setInstanceStatus( InstanceStatus.UP); String vipAddress = configInstance.getStringProperty( "eureka.vipAddress", "sampleservice.mydomain.net").get(); InstanceInfo nextServerInfo = DiscoveryManager.getInstance() .getDiscoveryClient() .getNextServerFromEureka(vipAddress, false); Socket s = new Socket(); int serverPort = nextServerInfo.getPort(); try { s.connect(new InetSocketAddress(nextServerInfo.getHostName(), serverPort)); } catch (IOException e) { System.err.println("Could not connect to the server :" + nextServerInfo.getHostName() + " at port " + serverPort); } try { System.out.println("Connected to server. Sending a sample request"); PrintStream out = new PrintStream(s.getOutputStream()); out.println("Sample request " + new Date()); String str = null; System.out.println("Waiting for server response.."); BufferedReader rd = new BufferedReader(new InputStreamReader( s.getInputStream())); str = rd.readLine(); if (str != null) { System.out .println("Received response from server. Communication all fine using Eureka :"); System.out.println("Exiting the client. Demo over.."); } rd.close(); } catch (IOException e) { e.printStackTrace(); } this.unRegisterWithEureka(); } public void unRegisterWithEureka() { // Un register from eureka. DiscoveryManager.getInstance().shutdownComponent(); } public static void main(String[] args) { SampleEurekaClient sampleEurekaService = new SampleEurekaClient(); sampleEurekaService.sendRequestToServiceUsingEureka(); } }
如上篇博客所述一样把各种依赖包加进本文 demo 的 CLASSPATH,然后把第三、四步写好的 sample-eureka-client.properties、log4j.properties 也拷贝进 CLASSPATH,并将 sample-eureka-client.properties 重命名为 config.properties(原因参考上篇博客),接下来就可以运行本文 demo 了。run SampleEurekaClient,日志结果如下:
2014-07-10 11:02:51,860 INFO com.netflix.config.sources.URLConfigurationSource:125 [main] [<init>] URLs to be used as dynamic configuration source: [file:/D:/javaprojects/test2/bin/config.properties]
2014-07-10 11:02:51,927 INFO com.netflix.config.DynamicPropertyFactory:281 [main] [getInstance] DynamicPropertyFactory is initialized with configuration sources: [email protected]
2014-07-10 11:02:52,060 WARN com.netflix.appinfo.PropertiesInstanceConfig:349 [main] [init] Cannot find the properties specified : eureka-client. This may be okay if there are other environment specific properties or the configuration is installed with a different mechanism.
2014-07-10 11:02:52,065 WARN com.netflix.discovery.DefaultEurekaClientConfig:95 [main] [init] Cannot find the properties specified : eureka-client. This may be okay if there are other environment specific properties or the configuration is installed with a different mechanism.
2014-07-10 11:02:52,103 INFO com.netflix.appinfo.providers.EurekaConfigBasedInstanceInfoProvider:79 [main] [get] Setting initial instance status as: STARTING
2014-07-10 11:02:53,667 INFO com.netflix.discovery.DiscoveryClient:646 [main] [fetchRegistry] Disable delta property : false
2014-07-10 11:02:53,667 INFO com.netflix.discovery.DiscoveryClient:647 [main] [fetchRegistry] Single vip registry refresh property : null
2014-07-10 11:02:53,667 INFO com.netflix.discovery.DiscoveryClient:648 [main] [fetchRegistry] Force full registry fetch : false
2014-07-10 11:02:53,667 INFO com.netflix.discovery.DiscoveryClient:649 [main] [fetchRegistry] Application is null : false
2014-07-10 11:02:53,667 INFO com.netflix.discovery.DiscoveryClient:650 [main] [fetchRegistry] Registered Applications size is zero : true
2014-07-10 11:02:53,668 INFO com.netflix.discovery.DiscoveryClient:652 [main] [fetchRegistry] Application version is -1: true
2014-07-10 11:02:54,061 INFO com.netflix.discovery.DiscoveryClient:992 [main] [makeRemoteCall] Finished a call to service url http://serverIP:8080/eureka/v2/ and url path apps/ with status code 200.
2014-07-10 11:02:54,061 INFO com.netflix.discovery.DiscoveryClient:758 [main] [getAndStoreFullRegistry] Getting all instance registry info from the eureka server
2014-07-10 11:02:54,568 INFO com.netflix.discovery.DiscoveryClient:765 [main] [getAndStoreFullRegistry] The response status is 200
2014-07-10 11:02:54,578 INFO com.netflix.discovery.DiscoveryClient:1056 [main] [initScheduledTasks] Starting heartbeat executor: renew interval is: 30
Connected to server. Sending a sample request
Waiting for server response..
Received response from server. Communication all fine using Eureka :
Exiting the client. Demo over..
证明 demo 获取 Application Service 实例并请求成功。
可以看出,Application Service 实例的信息都封装在了 com.netflix.appinfo.InstanceInfo 下,那么我们还能从中获取哪些信息?SampleEurekaClient 类加入以下代码:
logger.debug("nextServerInfo.getAppGroupName()-" + nextServerInfo.getAppGroupName()); logger.debug("nextServerInfo.getAppName()-" + nextServerInfo.getAppName()); logger.debug("nextServerInfo.getASGName()-" + nextServerInfo.getASGName()); logger.debug("nextServerInfo.getHomePageUrl()-" + nextServerInfo.getHomePageUrl()); logger.debug("nextServerInfo.getHostName()-" + nextServerInfo.getHostName()); logger.debug("nextServerInfo.getId()-" + nextServerInfo.getId()); logger.debug("nextServerInfo.getIPAddr()-" + nextServerInfo.getIPAddr()); logger.debug("nextServerInfo.getLastUpdatedTimestamp()-" + nextServerInfo.getLastUpdatedTimestamp()); logger.debug("nextServerInfo.getPort()-" + nextServerInfo.getPort()); logger.debug("nextServerInfo.getSecureVipAddress()-" + nextServerInfo.getSecureVipAddress()); logger.debug("nextServerInfo.getStatusPageUrl()-" + nextServerInfo.getStatusPageUrl()); logger.debug("nextServerInfo.getVIPAddress()-" + nextServerInfo.getVIPAddress()); logger.debug("nextServerInfo.getLastDirtyTimestamp()-" + nextServerInfo.getLastDirtyTimestamp()); logger.debug("nextServerInfo.getHealthCheckUrls()-" + nextServerInfo.getHealthCheckUrls()); logger.debug("nextServerInfo.getStatus()-" + nextServerInfo.getStatus());
然后重新运行本文 demo,以上语句打印结果如下:
2014-07-10 11:02:54,619 DEBUG com.netflix.eureka.SampleEurekaClient:69 [main] [sendRequestToServiceUsingEureka] nextServerInfo.getAppGroupName()-UNKNOWN
2014-07-10 11:02:54,619 DEBUG com.netflix.eureka.SampleEurekaClient:70 [main] [sendRequestToServiceUsingEureka] nextServerInfo.getAppName()-SAMPLESERVICE
2014-07-10 11:02:54,619 DEBUG com.netflix.eureka.SampleEurekaClient:71 [main] [sendRequestToServiceUsingEureka] nextServerInfo.getASGName()-null
2014-07-10 11:02:54,619 DEBUG com.netflix.eureka.SampleEurekaClient:72 [main] [sendRequestToServiceUsingEureka] nextServerInfo.getHomePageUrl()-http://defonds-win7:1935/
2014-07-10 11:02:54,620 DEBUG com.netflix.eureka.SampleEurekaClient:73 [main] [sendRequestToServiceUsingEureka] nextServerInfo.getHostName()-defonds-win7
2014-07-10 11:02:54,620 DEBUG com.netflix.eureka.SampleEurekaClient:74 [main] [sendRequestToServiceUsingEureka] nextServerInfo.getId()-defonds-win7
2014-07-10 11:02:54,620 DEBUG com.netflix.eureka.SampleEurekaClient:75 [main] [sendRequestToServiceUsingEureka] nextServerInfo.getIPAddr()-172.21.40.134
2014-07-10 11:02:54,620 DEBUG com.netflix.eureka.SampleEurekaClient:76 [main] [sendRequestToServiceUsingEureka] nextServerInfo.getLastUpdatedTimestamp()-1404961202884
2014-07-10 11:02:54,620 DEBUG com.netflix.eureka.SampleEurekaClient:77 [main] [sendRequestToServiceUsingEureka] nextServerInfo.getPort()-1935
2014-07-10 11:02:54,620 DEBUG com.netflix.eureka.SampleEurekaClient:78 [main] [sendRequestToServiceUsingEureka] nextServerInfo.getSecureVipAddress()-null
2014-07-10 11:02:54,620 DEBUG com.netflix.eureka.SampleEurekaClient:79 [main] [sendRequestToServiceUsingEureka] nextServerInfo.getStatusPageUrl()-http://defonds-win7:1935/Status
2014-07-10 11:02:54,620 DEBUG com.netflix.eureka.SampleEurekaClient:80 [main] [sendRequestToServiceUsingEureka] nextServerInfo.getVIPAddress()-sampleservice.mydomain.net
2014-07-10 11:02:54,620 DEBUG com.netflix.eureka.SampleEurekaClient:81 [main] [sendRequestToServiceUsingEureka] nextServerInfo.getLastDirtyTimestamp()-1404961230856
2014-07-10 11:02:54,620 DEBUG com.netflix.eureka.SampleEurekaClient:82 [main] [sendRequestToServiceUsingEureka] nextServerInfo.getHealthCheckUrls()-[http://defonds-win7:1935/healthcheck]
2014-07-10 11:02:54,621 DEBUG com.netflix.eureka.SampleEurekaClient:83 [main] [sendRequestToServiceUsingEureka] nextServerInfo.getStatus()-UP
这些信息都和 http://serverIP:8080/eureka/v2/apps/ 显示的 SAMPLESERVICE 实例的 各个属性一一对应。
参考资料
Eureka 的 Application Client 客户端的运行示例