Spring Cloud 学习之旅 --- 随机端口启动多实例

本文内容很简单,就是使用随机端口来启动多个实例。

还记得之前我们在 Spring Cloud 学习之旅 — 服务注册与发现(二) 学习创建服务提供者的时候,我们写了个配置文件吗?在配置文件中,我们指定了一个 2222 端口作为我们的监听端口,但是往往我们的服务提供者是多实例的,因此如果在单台机器中启动多个实例,不修改监听端口,势必会造成端口冲突,导致启动一个实例后,后续实例无法正常启动。

那么这里有两种解决方法:
(一)配置多个配置文件,通过不同的启动参数设置不同的端口进行实例的运行。
(二)采用随机端口的方式,每次启动时获取一个随机端口进行启动。

第一个方法其实很有效,但是在本文中,介绍的是第二种方法。

.properties / .yml 文件中,设置 server.port 属性的值为 ${random.int} 或者设置其值为 0 即可。

下面我们来做一个实验。


我们先启动我们的注册中心和服务消费者,以观察我们的最终结果。(由于注册中心会定时刷新可使用的服务提供者名单,所以修改了服务提供者后,无需等待服务提供者注册后再重启消费者)


实验(一)

采用 ${random.int} 的方式取随机值

修改配置文件,使 server.port 配置的值为 ${random.int} ,具体如下图:
这里写图片描述

随后将其启动,我们看看控制台的输出。

2017-06-19 19:33:57.321  INFO 10512 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 14572 (http)
2017-06-19 19:33:57.322  INFO 10512 --- [           main] .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 14572

可以看到其中一条,我们的tomcat监听了14572端口。接着我们打开注册中心看看,具体如下图:
这里写图片描述

可以看到服务的确正常注册进来了。我们通过上一节的消费者调用一下该服务,看看效果。具体如下图:
这里写图片描述

但是好像有点事与愿违。我们为什么会调用不到呢?

我们查看一下注册中心中的simple-service的实例情况。我们通过访问注册中心的 /eureka/apps 查看所有注册到注册中心的实例的信息。

<applications>
    <versions__delta>1</versions__delta>
    <apps__hashcode>UP_5_</apps__hashcode>
    <application>
        <name>SIMPLE-SERVICE</name>
        <instance>
            <instanceId>simple-service:-87414967</instanceId>
            <hostName>localhost</hostName>
            <app>SIMPLE-SERVICE</app>
            <ipAddr>172.30.0.177</ipAddr>
            <status>UP</status>
            <overriddenstatus>UNKNOWN</overriddenstatus>
            <port enabled="true">14258</port>
            <securePort enabled="false">443</securePort>
            <countryId>1</countryId>
            <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
                <name>MyOwn</name>
            </dataCenterInfo>
            <leaseInfo>
                <renewalIntervalInSecs>5</renewalIntervalInSecs>
                <durationInSecs>10</durationInSecs>
                <registrationTimestamp>1497872037342</registrationTimestamp>
                <lastRenewalTimestamp>1497872287304</lastRenewalTimestamp>
                <evictionTimestamp>0</evictionTimestamp>
                <serviceUpTimestamp>1497872037342</serviceUpTimestamp>
            </leaseInfo>
            <metadata class="java.util.Collections$EmptyMap"/>
            <homePageUrl>http://localhost:14258/</homePageUrl>
            <statusPageUrl>http://localhost:14258/info</statusPageUrl>
            <healthCheckUrl>http://localhost:14258/health</healthCheckUrl>
            <vipAddress>simple-service</vipAddress>
            <secureVipAddress>simple-service</secureVipAddress>
            <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
            <lastUpdatedTimestamp>1497872037342</lastUpdatedTimestamp>
            <lastDirtyTimestamp>1497872037172</lastDirtyTimestamp>
            <actionType>ADDED</actionType>
        </instance>
    </application>
</applications>

从上方的 <applications> 节点中的 <application> 中,有一个 <port> 断点,看到端口是 14258,与我们启动时控制台的 14572 有点不符,那么到底是什么原因导致这样的情况呢?
其实是每次在读取 server.port 属性时,都会获取到 ${random.int} ,然后对其进行解析,即每次读取该属性时都会重新获取一次随机值。因此会出现服务成功注册,但是缺无法调用的情况,根本原因是端口不对。


实验(二)

修改配置文件,使 server.port 配置的值为 0 ,具体如下图:

这里写图片描述

跟上一个实验相同进行启动,看到控制台的输出,监听端口为 57239 (以本人本机启动为例)

2017-06-19 19:48:04.433  INFO 9380 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 57239 (http)
2017-06-19 19:48:04.434  INFO 9380 --- [           main] .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 57239

同样的,我们先不调用,直接看注册信息。访问注册中心IP端口的 /eureka/apps 查看信息。(此次截取的是部分信息)

<instance>
    <instanceId>simple-service:663939329</instanceId>
    <hostName>localhost</hostName>
    <app>SIMPLE-SERVICE</app>
    <ipAddr>172.30.0.177</ipAddr>
    <status>UP</status>
    <overriddenstatus>UNKNOWN</overriddenstatus>
    <port enabled="true">57239</port>
    <securePort enabled="false">443</securePort>
    <countryId>1</countryId>
    <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
        <name>MyOwn</name>
    </dataCenterInfo>
    <leaseInfo>
        <renewalIntervalInSecs>5</renewalIntervalInSecs>
        <durationInSecs>10</durationInSecs>
        <registrationTimestamp>1497872885163</registrationTimestamp>
        <lastRenewalTimestamp>1497872915123</lastRenewalTimestamp>
        <evictionTimestamp>0</evictionTimestamp>
        <serviceUpTimestamp>1497872885163</serviceUpTimestamp>
    </leaseInfo>
    <metadata class="java.util.Collections$EmptyMap"/>
    <homePageUrl>http://localhost:57239/</homePageUrl>
    <statusPageUrl>http://localhost:57239/info</statusPageUrl>
    <healthCheckUrl>http://localhost:57239/health</healthCheckUrl>
    <vipAddress>simple-service</vipAddress>
    <secureVipAddress>simple-service</secureVipAddress>
    <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
    <lastUpdatedTimestamp>1497872885163</lastUpdatedTimestamp>
    <lastDirtyTimestamp>1497872885130</lastDirtyTimestamp>
    <actionType>ADDED</actionType>
</instance>

此次实例的端口是57239 ,与控制台启动的端口相同。我们再调用一下消费者,看看效果。具体如下图:
这里写图片描述

我们可以看到消费者调用服务恢复正常,因此正确的随机多端口启动实例的方式应该是采用 server.port0 的方式。当然,如果读者能够重写配置文件的解析方法,将实验一中的问题排除掉,那么您当我没说这句话23333


  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Spring Cloud LoadBalancer 是 Spring Cloud 中的一个组件,用于提供负载均衡功能,可以帮助开发者在微服务架构中轻松地实现服务发现和负载均衡。 Spring Cloud LoadBalancer 提供了一套简单的 API 接口,允许开发者自定义负载均衡策略,并且支持多种负载均衡算法,例如轮询、随机等。它与 Spring Cloud 的服务注册与发现组件集成得很好,能够自动地将服务实例注册到负载均衡器中,并根据需要对服务实例进行负载均衡。 使用 Spring Cloud LoadBalancer 的好处是它可以帮助开发者快速实现服务发现和负载均衡功能,而无需手动编写繁琐的负载均衡算法和服务发现代码。此外,Spring Cloud LoadBalancer 还具有高度可扩展性和灵活性,可以与不同的负载均衡器集成,并且支持自定义的负载均衡算法。 总之,如果您正在使用 Spring Cloud 构建微服务架构,那么使用 Spring Cloud LoadBalancer 可以帮助您更轻松地实现服务发现和负载均衡功能,并且可以提高系统的可扩展性和灵活性。 ### 回答2: Spring Cloud Loadbalancer是Spring Cloud提供的一个负载均衡器,用于在微服务架构中实现服务的负载均衡。以下是使用Spring Cloud Loadbalancer的步骤: 1. 引入依赖:在项目的pom.xml文件中添加Spring Cloud Loadbalancer的依赖。 ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> ``` 2. 创建服务调用类:首先,我们需要创建一个ServiceInstanceListSupplier的实现,以提供要进行负载均衡的服务实例列表。 ```java import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.ServiceInstanceListSupplier; public class CustomServiceInstanceListSupplier implements ServiceInstanceListSupplier { // 实现ServiceInstanceListSupplier接口的方法 // 返回要进行负载均衡的服务实例列表 } ``` 3. 注册服务调用类:将自定义的ServiceInstanceListSupplier注册到Spring容器。 ```java @Configuration public class LoadBalancerConfig { @Bean public ServiceInstanceListSupplier serviceInstanceListSupplier() { return new CustomServiceInstanceListSupplier(); } } ``` 4. 使用负载均衡器:在需要进行服务调用的地方,可以使用@LoadBalanced注解将RestTemplate、WebClient等进行负载均衡代理。 ```java @Autowired @LoadBalanced private RestTemplate restTemplate; // 在需要进行服务调用的地方,可以直接使用RestTemplate进行调用 ResponseEntity<String> response = restTemplate.getForEntity("http://service-provider/api/endpoint", String.class); ``` 5. 配置负载均衡策略:可以通过配置文件(application.yml或application.properties)来配置负载均衡器的策略。 ```yaml spring: cloud: loadbalancer: ribbon: enabled: false # 禁用默认的Ribbon负载均衡器 ``` 通过以上步骤,我们可以在Spring Cloud项目中使用Spring Cloud Loadbalancer来实现服务的负载均衡。 ### 回答3: spring-cloud-loadbalancer是Spring Cloud提供的一个负载均衡器,用于在微服务架构中实现服务的负载均衡。我们可以通过以下步骤来使用spring-cloud-loadbalancer: 1. 在pom.xml文件中,添加spring-cloud-loadbalancer的依赖: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> ``` 2. 创建一个自定义的负载均衡器配置类,实现LoadBalancerClient接口,并注入LoadBalancerProperties对象: ```java @Configuration public class MyLoadBalancerConfig { @Autowired private LoadBalancerProperties loadBalancerProperties; @Bean public LoadBalancerClient loadBalancerClient() { return new LoadBalancerClient() { // 实现接口方法,使用具体的负载均衡算法进行服务的选择 @Override public ServiceInstance choose(String serviceId) { // 在这里选择一个可用的服务实例并返回 } }; } } ``` 3. 创建一个服务消费者类,通过@LoadBalanced注解启用负载均衡能力: ```java @Service public class ConsumerService { @Autowired @LoadBalanced private RestTemplate restTemplate; public void consumeService() { // 发起对服务提供者的请求 ResponseEntity<String> response = restTemplate.getForEntity("http://service-provider/service", String.class); String result = response.getBody(); // 处理返回结果 } } ``` 4. 在应用启动类上添加@EnableDiscoveryClient注解,开启服务注册和发现的能力。 5. 在服务提供者的配置文件中,设置应用的名称和端口号。 6. 运行服务提供者和服务消费者,观察服务消费者通过负载均衡器调用服务提供者的效果。 总结起来,使用spring-cloud-loadbalancer,首先需要添加依赖,然后实现一个自定义的负载均衡器配置类,再在服务消费者中注入负载均衡的RestTemplate,并通过@LoadBalanced注解启用负载均衡能力。最后,通过@EnableDiscoveryClient注解开启服务注册和发现的能力。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值