1.Spring Cloud--Eureka项目集群之服务管理框架理解
紧跟上一篇博客,这里采用的也是上一篇博客的代码作为分析:《Spring Cloud 那些事之Spring Cloud 学习笔记二:SpringCloud之Eureka-Service集群搭建》。我们在搭建起了简单的单机模式Eureka项目之后,如果Eureka服务器和客户端不能满足高并发访问,项目需要集群部署,也可以利用Eureka做到这一点。我们这里创建两个Eureka服务器端,两个Eureka客户端(作为服务提供者),一个Eureka客户端(作为服务调用者),如图:
通过运行多个实例并让它们彼此注册,Eureka可以变得更有弹性和可用性。实际上,这是默认行为,所以需要做的就是将一个有效的serviceUrl添加到对等点。我们可以将多个对等点添加到一个系统中,只要它们之间至少有一条边连接,它们就会同步这些注册。如果对等体在物理上是分开的(在数据中心或多个数据中心之间),那么系统就可以在原则上生存下来,以避免“大脑分裂”。由于资源限制,这里让服务运行在同一个主机上,通过修改hosts文件配置,模仿两个不同的主机。
搜素Windows的“记事本”应用,以管理员身份运行,文件-->打开,找到C:\Windows\System32\drivers\etc目录,打开里面的“hosts”文件,在文件末尾为自己的主机添加两个虚拟的域名:
127.0.0.1 peer1 peer2
2.创建两个Eureka服务器端
找到我们上一篇博客编写的EurekaServiceA和EurekaServiceB项目,修改application.yml文件,配置如下:
---
server:
port: 8810
spring:
profiles: peerA
application:
name: eureka-server-A
eureka:
instance:
hostname: peer1
client:
serviceUrl:
defaultZone: http://peer2:8811/eureka/
---
server:
port: 8811
spring:
profiles: peerB
application:
name: eureka-server-B
eureka:
instance:
hostname: peer2
client:
instanceInfoReplicationIntervalSeconds: 10
serviceUrl:
defaultZone: http://peer1:8810/eureka/
由于需要启动的是两个项目,所以这里配置一下两个项目的名称。再配置启动环境,方便我们作为项目的启动条件,打开EurekaServiceA的class类和EurekaServiceB的class类,修改main方法。如下代码
package com.sn.springCloud101;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServiceA {
public static void main(String[] args) {
new SpringApplicationBuilder(EurekaServiceA.class).profiles("peerA").run(args);
}
}
package com.sn.springCloud101;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServiceB {
public static void main(String[] args) {
new SpringApplicationBuilder(EurekaServiceB.class).profiles("peerB").run(args);
}
}
之后分别运行EurekaServiceA和EurekaServiceB的main()方法,启动项目,项目EurekaServiceA启动过程中会报错,但是不影响我们启动项目,报错的原因是eureka-server-A会将自己的服务注册到eureka-server-B,但是eureka-server-B还未启动,我们可以在浏览器访问http://localhost:8810,能够进入Eureka的后台管理界面,说明项目已经启动成功。eureka-server-B项目是不会报错的,它能成功将自己注册到eureka-server-A。最后访问http://localhost:8811我们两个管理后台都能看见注册的服务信息:
3,创建两个Eureka客户端(提供者)
找到我们上一篇博客编写的EurekaProviderA再创建一个EurekaProviderB.java文件,代码如下:
package com.sn.springCloud102;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class EurekaProviderA {
public static void main(String[] args) {
// SpringApplication.run(EurekaProviderA.class, args);
new SpringApplicationBuilder(EurekaProviderA.class).properties("server.port="+8080).run(args);
}
}
package com.sn.springCloud102;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class EurekaProviderB {
public static void main(String[] args) {
// SpringApplication.run(EurekaProviderB.class, args);
new SpringApplicationBuilder(EurekaProviderB.class).properties("server.port="+8081).run(args);
}
}
然后修改application.yml文件,为服务提供者再提供一个服务器端的注册地址,让我们的服务提供者可以将自己的服务注册到两个服务器端,配置如下:
spring:
application:
name: eureka-provider
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8810/eureka/,http://localhost:8811/eureka/
为了能够让我们待会儿要创建的Eureka客户端(服务调用者)可以区分到底是从哪一个Eureka客户端(服务提供者)获取到返回值的,我们改造一下ApplicationProviderController类,设置UserName,用以展示对应请求的路径(包含端口号),用端口号来鉴别调用的是哪一个服务:如下代码:
package com.sn.springCloud102;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@RestController
public class ApplicationProviderController {
@RequestMapping(value = "/search/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public User searchUser(@PathVariable String id, HttpServletRequest sr){
User user = new User();
user.setId(id);
user.setAge(20);
user.setPassWord("123");
user.setUserName("EurekaProvider--"+sr.getRequestURL().toString());
return user;
}
}
运行EurekaProviderA和EurekaProviderB类的main()方法,启动两个项目;项目成功启动之后,我们在浏览器分别访问http://localhost:8080/search/A和http://localhost:8081/search/B,能够得到对应的响应结果,如下:
然后访问我们的Eureka服务器端,http://localhost:8810或者http://localhost:8811,也能够看到服务被注册到了服务器端。
4.创建一个Eureka客户端(服务调用者)
找到我们上一篇博客编写的EurekaConsumer,修改application.yml文件,为服务调用者再提供一个服务器端的注册地址,让我们的服务调用者可以将自己的服务注册到两个服务器端,再将端口修改了,避免冲突导致的不能启动项目,配置如下:
server:
port: 8888
spring:
application:
name: eureka-consumer
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8810/eureka/,http://localhost:8811/eureka/
为了让结果更加明显,我们对applicationConsumerController.java进行简单的修改,代码如下
package com.sn.springCloud103;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import javax.servlet.http.HttpServletRequest;
import java.security.PrivateKey;
import java.util.List;
@RestController
public class applicationConsumerController {
@Autowired
private DiscoveryClient discoveryClient;
//添加负载均衡配置
@Bean
@LoadBalanced
public org.springframework.web.client.RestTemplate getRestTemplate(){
return new RestTemplate();
}
@RequestMapping(value = "/consumer/{id}",method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public String testConsumer(@PathVariable String id, HttpServletRequest request) {
List<ServiceInstance> list = discoveryClient.getInstances("STORES");
System.out.println(discoveryClient.description());
System.out.println("discoveryClient.getServices().size()+" + discoveryClient.getServices().size());
//打印EurekaProvider客户端的服务信息
for (String str : discoveryClient.getServices()) {
System.out.println("services " + str);
List<ServiceInstance> serviceInstances = discoveryClient.getInstances(str);
for (ServiceInstance si : serviceInstances) {
System.out.println(" services:" + str + ":getHost()=" + si.getHost());
System.out.println(" services:" + str + ":getPort()=" + si.getPort());
System.out.println(" services:" + str + ":getServiceId()=" + si.getServiceId());
System.out.println(" services:" + str + ":getUrl()=" + si.getUri());
System.out.println(" services:" + str + ":getMetadata()=" + si.getMetadata());
}
}
String string = "";
System.out.println(id);
String flag =id;
if (id.equals("A")) {
System.out.println(id);
RestTemplate rt = new RestTemplate();
// RestTemplate rt = getRestTemplate();
string= rt.getForObject("http://localhost:8080/search/A", String.class);
return string;
// return rt.getForObject("http://EUREKA-PROVIDER/search/A", String.class);
}
if (id.equals("B")) {
System.out.println(id);
RestTemplate rt = new RestTemplate();
// RestTemplate rt = getRestTemplate();
string= rt.getForObject("http://localhost:8081/search/B", String.class);
return string;
}
// RestTemplate rt = getRestTemplate();
// return rt1.getForObject("http://localhost:8081/search/A", String.class);
return string;
}
}
服务消费者需要的配置就完成了,然后我们运行EurekaConsumer类的main()方法,成功启动之后,访问http://localhost:8888/consumer/A和http://localhost:8888/consumer/B可以看到,我们的服务调用者是依次去调用了8080和8081的服务。
这时刷新eureka-service-A和eureka-service-B页面可以发现也有变化
至此搭建完成!!!
完整代码地址如下:(三个项目分别对应三个服务,1.0.1对应EurekaService;1.0.2对应EurekaProvider;1.0.3对应EurekaConsumer)
https://github.com/ZFCC/springCloud1.0.1
https://github.com/ZFCC/springCloud1.0.2
https://github.com/ZFCC/springCloud1.0.3
精彩内容,请见下回分解
有关springCloud的更多更新内容,请移步:个人博客 https://zfcc.github.io/ (Spring Cloud 技术标签)