分布式系统开发---高可用业务服务器SpringCloud(五)
本节我们将把我们的项目改造成一个高可用的业务服务器,这里使用SpringCloud中的Eureka
,首先,我们来认识下Eureka
:
Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。
针对我们之前做好的服务分离实例,遗留了一个问题,那就是如果我新增了一个服务,或者商品服务
的服务端IP或者域名改变了,是不是我还要再次修改订单服务
中获取商品信息的逻辑(IP地址)来达到我们的目的,但是随之而来的就是各种配置。
上面介绍了Eureka的功能,最终实现后的应用场景就是我们不用再关心商品服务
服务器的IP地址或域名,只需要从Eureka中注册的各种服务中找到商品服务
,从中获取我们需要的数据即可,下面,我们来编写Eureka这个服务中心。
在我们的项目中创建新的模块eureka
,这里要注意下,我们这次在选择依赖的时候选择Cloud Discovery
,勾选Eureka Server
如图:

创建好的
eureka
模块如图
这里,我们把
eureka
中的application.properties
修改为application.yml
,同时指定服务端的端口号为7000
注:为了避免以后的端口冲突,我们把
order
的端口从8001改变成8100![]()
接下来回到eureka
模块中,修改eureka
模块中的EurekaApplication
代码如下
package com.felix;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
配置eureka
模块中的application.yml
server:
port: 7000
eureka:
client:
register-with-eureka: false #是否注册到Eureka服务中
fetch-registry: false #是否从Eureka服务中获取注册信息
service-url: #Eureka客户端与服务端进行交互的地址
defaultZone: http://127.0.0.1:${server.port}/eureka/
到了这里,我们的服务中心已经搭建完毕,启动eureka
服务器后访问http://127.0.0.1:7000
就会看到如下界面

当然,出于安全性考虑,这个界面一定不能任何人都可以访问,所以,我们需要添加用户认证。在
eureka
的pom.xml
添加spring-boot-starer-security
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starer-security</artifactId>
</dependency>
修改配置文件application.yml
,设置eureka
页面的用户名和密码,同时修改默认的service-url
:
server:
port: 7000
spring:
security:
user:
name: felix
password: 123456
eureka:
client:
register-with-eureka: false #是否注册到Eureka服务中
fetch-registry: false #是否从Eureka服务中获取注册信息
service-url: #Eureka客户端与服务端进行交互的地址
defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@127.0.0.1:7000/eureka/
然后在程序入口启用安全认证,EurekaApplication
修改如下
package com.felix;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
@EnableWebSecurity
public class WebSecurityConfigure extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
super.configure(http);
}
}
}
重新启动eureka
服务,这次会弹出登录窗口,我们填写之前设置的用户名和密码后就可以顺利登录了

登录后,因为没有服务注册到服务中心,所以
Instances currently registered with Eureka
中的内容为空。我们需要订单服务
从商品服务
中获取商品信息,所以,需要把商品服务
注册到服务中心
去,同时订单服务
需要从服务中心
中发现服务,并且使用,所以,下一步,我们开始注册商品服务
到服务中心
。修改
goods
模块的pom.xml
,添加Eureka
的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.felix</groupId>
<artifactId>goods</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>goods</name>
<description>A service of goods for mall</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RC2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>
然后修改goods
中的配置文件application.yml
server:
port: 8000
spring:
application:
name: goods-service #指定服务名称
eureka:
client:
register-with-eureka: true #是否注册到Eureka服务中
fetch-registry: false #是否从Eureka服务中获取注册信息
service-url: #Eureka客户端与服务端进行交互的地址
defaultZone: http://felix:123456@127.0.0.1:7000/eureka/
instance:
prefer-ip-address: true #把ip地址注册到Eureka服务中
这里,我们指定商品服务
的服务名为goods-service
,然后配置Eureka
,因为商品服务
需要注册到服务中心
,所以register-with-eureka
设置为true
现在,我们启动商品服务
(没有启动服务中心
的也要启动服务中心),等到启动完毕后,再次访问http://127.0.0.1:7000/
页面如下

可以看到,
商品服务
的服务名称goods-service
已经成功注册到服务中心
了(显示的是大写)接下来我们来改造
订单服务
,让它从服务中心发现服务,利用发现的服务请求对应的数据。首先,和商品服务
类似,我们先修改order
模块的pom.xml
的依赖如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.felix</groupId>
<artifactId>order</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>order</name>
<description>A service of order for mall</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RC2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<exclusions>
<exclusion>
<!--排除Eureka自带的数据格式转换,否则返回的结果会被转成XML格式的数据-->
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>
这里一定要在Eureka
依赖中排除<groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId>
否则订单信息的返回结果将会被转换成XML格式。
添加好依赖以后,我们修改订单服务
中的配置文件application.yml
server:
port: 8100
#port: 8001
spring:
application:
name: order-service #指定服务名称
eureka:
client:
register-with-eureka: false #是否注册到Eureka服务中
fetch-registry: true #是否从Eureka服务中获取注册信息
service-url: #Eureka客户端与服务端进行交互的地址
defaultZone: http://felix:123456@127.0.0.1:7000/eureka/
这里,订单服务
无需注册到服务中心
,但是需要从服务中心
获取注册的服务信息,所以上面的配置需要按照我们的需求进行调整。
最后,修改OrderApplication
中的代码
package com.felix;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableDiscoveryClient
@SpringBootApplication
public class OrderApplication {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
大功告成,我们启动订单服务
(确认商品服务
、服务中心
都已经启动),然后访问订单服务
的接口http://127.0.0.1:8100/order/6
,结果如下

现在,我们已经有了三台服务端了
商品服务
、订单服务
、服务中心
,为了展示目前的效果,我们再启动一个商品服务
。首先我们修改goods
中的application.yml
的端口号为8081,然后点击顶部的模块选择,点击Eidt Configurations

在弹出的窗口中点击加号,选择
Spring Boot

依次修改名称为
GoodsApplication01
,MainClass
选择GoodsApplication
,Use classpath of module
选择goods
,点击Apply
后选择OK
完成
然后,在顶部选择刚才创建的
GoodsApplication01
并启动,现在,我们可以看到,已经启动了四个服务:
等到启动完成后,
GoodsApplication01
会在服务中心
注册一个新的商品服务
,我们现在打开http://127.0.0.1:7000/
会发现服务中心
已经有两个注册的服务了,此时访问订单服务
,一切正常
现在,我们模拟单台服务故障,我们手动关闭
GoodsApplication01
现在,再次访问订单服务
仍然没有问题,实际上,提供商品服务
的一台服务器已经故障了,我们看下Eureka
界面

注册的服务中也只剩下一个了,但是并没有影响我们的业务访问。
截止目前,我们已经初步搭建了一个分布式系统了,实现了业务服务器的高可用,系统中提供业务的某台服务器即使Down机,也不会影响我们业务的正常访问。
结束之前,留下一个问题,虽然业务服务器达到了高可用,但是,它是基于服务中心
的,那么如果服务中心
Down掉了,岂不是仍然会影响业务吗?是的,下节我们就来解决这个问题。
分布式系统开发---高可用服务中心SpringCloud(六)
以上内容转载请注明出处,同时也请大家不吝你的关注和下面的赞赏
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓