搭建一个简单的Eureka应用

搭建一个简单的Eureka应用

Eureka提供基于REST的服务,在集群中主要用于服务管理。Eureka提供了基于Java语言的客户端组件,客户端组件实现了负载均很的功能,为业务组件的集群部署创建了条件。使用该框架,可以将业务组件注册到Eureka容器中,这些组件可进行集群部署,Eureka主要维护这些服务的列表并自动检查他们的状态。

简单的Eureka集群应用

一个简单的Eureka应用,需要包括一个Eureka服务器和若干个服务提供者。我们可以将业务组件注册到Eureka服务器中,其他客户端组件可以向服务器获取服务器并且进行远程调用。

简单的Eureka应用架构

接下来,搭建一个简单的Eureka应用。

搭建服务器

新建一个first-ek-server的maven,在pom文件中加入如下依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
</dependencies>

加入的spring-cloud-started-eureka-server会自动引入spring-boot-start-web。

接下来,写一个启动类

1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableEurekaServer
public class FirstServer {
public static void main(String[] arsg) {
new SpringApplicationBuilder(FirstServer.class).run(arsg);
}
}

注解@EnableEurekaServer说明当前是一个Eureka的服务器。执行当前的main方法,待应用启动完全之后,就可以在本地的8080端口,看到启动后的页面了。

Eureka启动后的页面

如果要修改默认的8080端口的话,在resource目录下,新建一个配置application.yml或者application.properties文件,在里面设置即可。这里以yml文件为例:

1
2
3
4
5
6
eureka:
client:
register-with-eureka: false
fetch-registry: false
server:
port: 8761

这里还有两个配置register-with-eureka和fetch-registry。

  • register-with-eureka:表示是否将自己的信息注册到Eureka服务器。默认为true。这里的Eureka仅作为服务器使用,不做客户端,因此设置为false
  • fetch-registry:表示是否到Eureka服务器中抓取注册信息。这里的Eureka仅作为服务器使用,不做客户端,因此设置为false

搭建服务提供者

新建一个first-ek-service-provider的maven项目,在pom文件中添加如下依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>

启动类代码如下:

1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableEurekaClient
public class FirstServiceProvider {

public static void main(String[] args) {
new SpringApplicationBuilder(FirstServiceProvider.class).run(args);
}
}

这个类中使用了EnableEurekaClient注解,表示这个工程是一个Eureka客户端应用。启动配置项如下:

1
2
3
4
5
6
7
8
9
10
11
12
spring:
application:
name: first-service-provider
eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
logging:
level:
com.netflix: INFO

以上配置,通过application.name字段,将应用的名称设置为first-service-provider,通过eureka.instance.hostname配置应用的主机名称。通过eureck.client.serviceUrl.defaultZone配置服务需要注册到的服务器。

通过上面的配置,first-service-provider启动之后就可以注册在启动的Eureka服务器中了。

注册在Eureka服务器上的服务

为了演示用,再提供一个REST接口做服务调用演示用。

1
2
3
4
5
6
7
8
9
10
@RestController
public class FirstController {

@RequestMapping(value = "/person/{personId}", method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public Person findPerson(@PathVariable("personId") Integer personId) {
Person person = new Person(personId, "Crazyit", 30);
return person;
}
}

Person Bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class Person {

private Integer id;

private String name;

private Integer age;

public Person() {
super();
}

public Person(Integer id, String name, Integer age) {
super();
this.id = id;
this.name = name;
this.age = age;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

}

搭建服务调用者

服务被注册、发布到Eureka服务器后,需要有程序去发现它,并且进行调用。此处所说的调用者,是指同样注册到Eureka的客户端,来调用其他客户端发布的任务。

新建名为first-ek-service-invoker项目,它的pom依赖如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
</dependencies>

配置文件配置如下,同样将其注册到Eureka的服务器上:

1
2
3
4
5
6
7
8
9
10
11
server:
port: 9000
spring:
application:
name: first-service-invoker
eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka

而后,对外提供一个REST服务供客户端调用,这个REST服务又通过Eureka服务器,获取要调用的服务的地址,产生调用。调用流程如下:

调用流程

Invoker对外提供的REST服务代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@RestController
@Configuration
public class InvokerController {

@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}

@RequestMapping(value = "/router", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String router() {
RestTemplate template = getRestTemplate();
String json = template.getForObject("http://first-service-provider/person/1", String.class);
return json;
}
}

启动类:

1
2
3
4
5
6
7
8
9
@SpringBootApplication
@EnableDiscoveryClient
public class FirstInvoker {

public static void main(String[] args) {
SpringApplication.run(FirstInvoker.class, args);
}

}

注解EnableDiscoveryClient使服务有能力去Eureka中发现服务。需要注意的是EnableEurekaClient注解已经包含了EnableDiscoveryClient的功能,也就是说,一个Eureka客户端,本身就具有发现服务的能力。

启动invoker后,就能在Eureka的控制台页面上看到,注册的invoker了。

调用流程

然后,在浏览器中打开如下接口http://localhost:9000/router,可以看到,成功返回了数据。

调用

再看看invoker的日志,

1
2
3
2020-04-23 16:40:42.456  INFO 16740 --- [nio-9000-exec-3] c.n.l.DynamicServerListLoadBalancer      : DynamicServerListLoadBalancer for client first-service-provider initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=first-service-provider,current list of Servers=[localhost:8080],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone;	Instance count:1;	Active connections count: 0;	Circuit breaker tripped count: 0;	Active connections per server: 0.0;]
},Server stats: [[Server:localhost:8080; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@6ee6facf

可以看到,它是通过服务名称first-service-provider来获取服务列表current list of Servers=[localhost:8080],然后再发起调用的。

参考资料

疯狂Spring Cloud微服务架构实战

0%