SpringCloud是一系列框架的集合,目的是将业务系统拆分成一个个微服务,服务于服务之间相互独立,支持水平扩展,高可用,微服务架构主要的功能有服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,Netflix虽然已经过时了,但是他框架集和其他微服务框架集作用差不多
微服务整体架构如下图,看看就好:
Netflix主要使用下面的组件:
组件 | 描述 |
---|---|
Eureka | 服务注册中心、服务发现中心 |
Ribbon | 负载均衡,服务如果是一个集群,会通过Ribbon实现负载均衡 |
Feign | 服务于服务之间的调用 |
Hystrix | 监控和熔断器,服务降级与数据统计 |
Zuul | 网关,所有请求由网关转发到具体的服务 |
一、项目搭建
首先搭建一个聚合项目,结构如下:
1. commons模块
commons
模块是一个普通的Maven
项目,存放JavaBean
和工具类
2. dependency模块
其他模块都依赖于dependency
模块,主要做SpringBoot的版本控制:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<groupId>com.aruba</groupId>
<artifactId>dependency</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>dependency</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.7.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
3. eureka模块
eureka
模块就是我们首先使用的组件,用于服务注册和发现
二、Eureka
1. eureka服务端
eureka模块单独启动,作为服务端
1.1 依赖
导入eureka服务依赖:
代码语言:javascript复制 <parent>
<artifactId>dependency</artifactId>
<groupId>com.aruba</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../dependency/pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--eureka服务-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
1.2 @EnableEurekaServer
SpringBoot启动类上添加@EnableEurekaServer
注解开启Eureka:
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
启动后可以访问到eureka界面:
1.3 配置Eureka服务地址
此时虽然可以访问页面,但是eureka服务并没有真正的启动,yml文件需要配置,需要注意的是application.name
将会作为服务名注册到eureka中,后续调用方会使用该名称:
spring:
application:
name: aruba-eureka
server:
port: 7000
eureka:
instance:
hostname: aruba-eureka
client:
service-url:
# 指定eureka服务的地址
defaultZone: http://127.0.0.1:7000/eureka
# 当前项目关闭注册服务
register-with-eureka: false
# 当前项目关闭获取服务
fetch-registry: false
2. eureka客户端
再次新建一个dept
模块作为eureka的客户端,用于注册服务到eureka服务器
2.1 依赖
导入eureka客户端依赖:
代码语言:javascript复制 <parent>
<artifactId>dependency</artifactId>
<groupId>com.aruba</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../dependency/pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.aruba</groupId>
<artifactId>commons</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
2.2 @EnableEurekaClient
使用@EnableEurekaClient
注解开启Eureka客户端
@SpringBootApplication
@EnableEurekaClient
public class DeptApplication {
public static void main(String[] args) {
SpringApplication.run(DeptApplication.class, args);
}
}
2.3 配置Eureka服务地址
代码语言:javascript复制spring:
application:
name: aruba-dept
server:
port: 8000
eureka:
client:
service-url:
# 指定eureka服务的地址
defaultZone: http://127.0.0.1:7000/eureka
2.4 启动客户端服务
启动服务后,再次访问Eureka管理页面,可以看到新注册的服务:
三、Feign
有了服务提供者,注册中心,消费者就可以通过Feign
调用提供者
1. 完善dept模块
1.1 Javabean
commons
模块中创建实体类:WDept
,用于服务与服务之间传输
@AllArgsConstructor
@NoArgsConstructor
@Data
public class WDept implements Serializable {
/**
* 部门编号
*/
private Integer deptId;
/**
* 部门名称
*/
private String dName;
}
1.2 service层
dept
模块中编写相应的service层代码
接口:
代码语言:javascript复制public interface DeptService {
String insertDept(WDept dept);
}
实现:
代码语言:javascript复制@Service
public class DeptServiceImpl implements DeptService {
@Override
public String insertDept(WDept dept) {
return "收到:" dept.toString();
}
}
1.3 提供Controller
Feign本质上是通过http进行调用的,controller层对外提供接口:
代码语言:javascript复制@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@RequestMapping("/insertDept")
public String insertDept(@RequestBody WDept wDept) {
return deptService.insertDept(wDept);
}
}
2. 调用方模块
新建模块,作为调用方:
2.1 依赖
导入eureka客户端和openFeign依赖:
代码语言:javascript复制 <parent>
<artifactId>dependency</artifactId>
<groupId>com.aruba</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../dependency/pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.aruba</groupId>
<artifactId>commons</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
2.2 yml文件配置
需要配置的和dept
模块差不多:
spring:
application:
name: aruba-dept-api
server:
port: 8001
eureka:
client:
service-url:
# 指定eureka服务的地址
defaultZone: http://127.0.0.1:7000/eureka
2.3 @EnableFeignClients
使用@EnableFeignClients
注解配置启动类,表示作为服务调用方
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class DeptApiApplication {
public static void main(String[] args) {
SpringApplication.run(DeptApiApplication.class, args);
}
}
2.4 @FeignClient
使用@FeignClient
注解接口,并指定调用服务名,对应application.name
,定义一个和调用方接口一样的方法
@FeignClient("aruba-dept")
public interface DeptFeignClient {
@RequestMapping("/insertDept")
String insertDept(WDept dept);
}
2.5 使用Feign
在调用方controller层中,注入刚刚的接口,并调用,需要注意的是加上@CrossOrigin
注解支持跨域
:
@RestController
@CrossOrigin
public class DeptController {
@Autowired
private DeptFeignClient deptFeignClient;
@RequestMapping("/insertDept")
public String insertDept(@RequestParam("deptId") Integer id) {
return deptFeignClient.insertDept(new WDept(id, "Feign"));
}
}
尝试调用:
四、Robbin
Feign集成了Robbin,默认就支持负载均衡,默认使用轮询策略,一旦遇上服务集群就会触发
1. 配置多个yml
修改端口为:
代码语言:javascript复制server:
port: 8010
代码语言:javascript复制server:
port: 8011
代码语言:javascript复制server:
port: 8012
2. 配置启动
配置多个启动项,并指定使用yml文件:--spring.profiles.active=xxx
,这边对应就是1,2,3:
3. 调用接口
启动多个服务,并调用消费者接口:
效果:
五、Hystrix
hystrix作为保证整体服务可用的组件,拥有服务降级和服务熔断功能,当一个微服务无法访问或长时间无响应,hystrix会自动帮助调用方进行处理,防止出现服务雪崩,因为hystrix是集成在服务调用方
1. 依赖
dept-api
模块导入hystrix依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
2. yml配置
添加hystrix相关配置:
代码语言:javascript复制spring:
application:
name: aruba-dept-api
server:
port: 8001
eureka:
client:
service-url:
# 指定eureka服务的地址
defaultZone: http://127.0.0.1:7000/eureka
# 开启hystrix
feign:
hystrix:
enabled: true
# 请求超时时间
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 2000
3. @EnableHystrix
启动类添加@EnableHystrix
注解:
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrix
public class DeptApiApplication {
public static void main(String[] args) {
SpringApplication.run(DeptApiApplication.class, args);
}
}
此时为服务提供方接口调用添加一个睡眠:
代码语言:javascript复制@Service
public class DeptServiceImpl implements DeptService {
@Override
public String insertDept(WDept dept) {
System.out.println(dept);
try {
Thread.sleep(13000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "收到:" dept.toString();
}
}
再次调用接口,2秒后会出现500错误
,表示hystrix生效了:
4. 失败处理
接下来就要指定hystrix服务降级后,进行自己的业务处理,实际上feign与hystrix已经结合,我们之前定义了DeptFeignClient
接口,需要实现一个该接口的类作为降级回调处理类:
@Component
public class DeptFeignFallCallback implements DeptFeignClient {
@Override
public String insertDept(WDept dept) {
return "服务发生错误";
}
}
接口类的@FeignClient
注解添加fallback
属性值,指定为处理类:
@FeignClient(value = "aruba-dept", fallback = DeptFeignFallCallback.class)
public interface DeptFeignClient {
@RequestMapping("/insertDept")
String insertDept(WDept dept);
}
再次调用接口,会返回自定义回调处理的结果:
六、Hystrix仪表盘
Hystrix仪表盘是监测触发熔断数据统计的管理页面,配置好后可以方便查看信息
新建模块:
1. 导入依赖
除了web
外,还需要actuator
和hystrix-dashboard
依赖
<parent>
<artifactId>dependency</artifactId>
<groupId>com.aruba</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../dependency/pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
</dependencies>
2. yml配置
代码语言:javascript复制spring:
application:
name: aruba-hystrix-client
server:
port: 9000
hystrix:
dashboard:
proxy-stream-allow-list: "localhost"
3. @EnableHystrixDashboard
使用@EnableHystrixDashboard
注解在启动类上:
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixClientApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixClientApplication.class, args);
}
}
启动后访问localhost:9000/hystrix
,就可以看到管理界面了:
4. 模块中配置
仅仅有上面的配置是不够的,还需要指定监测服务的一些配置,我们监测的是使用hystrix的dept-api
模块,所以在该模块中添加配置类:
配置类提供ServletRegistrationBean
的注入,内容为:
@Configuration
public class DeptActuator {
@Bean
public ServletRegistrationBean getServletRegistrationBean(){
HystrixMetricsStreamServlet mss = new HystrixMetricsStreamServlet();
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(mss);
servletRegistrationBean.setName("servletRegistrationBean");
servletRegistrationBean.setLoadOnStartup(1);
servletRegistrationBean.addUrlMappings("/hystrix.stream");
return servletRegistrationBean;
}
}
5. 输入具体监测地址
管理中输入:http://localhost:8001/hystrix.stream
,对应提供配置的dept-api
模块的端口和配置的url
进入后,尝试访问服务接口后,有了数据,才会出现数据统计:
七、Zuul
Zuul是微服务中的网关,在所有微服务内部,所有请求都应该由网关进行转发请求,网关提供统一的对外接口,功能概念和nginx差不多,但是nginx处于更上的接入层,性能方面没有可比较性,而微服务的网关组件都和SpringBoot有着较好的融合,使用方便
新建模块:
1. 依赖
导入zuul
依赖以及eureka客户端依赖:
<parent>
<artifactId>dependency</artifactId>
<groupId>com.aruba</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../dependency/pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>
2. yml配置
争对对外的微服务配置路由,可以配置多条,一般使用服务的application.name
作为配置名,path
为反向代理后的访问前缀,serviceId
为服务的application.name
:
spring:
application:
name: aruba-zuul
server:
port: 8080
#配置一个路由器
zuul:
routes:
dept-api:
path: /oapi/**
serviceId: aruba-dept-api
#从eureka获取我们的服务器的真实ip地址
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:7000/eureka
instance:
prefer-ip-address: true
instance-id: ${spring.cloud.client.ip-address}:${server.port}
3. @EnableZuulProxy
使用@EnableZuulProxy
注解在启动类上:
@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
启动后,可以通过http://localhost:8080/oapi/xxx
进行对dept-api
模块的访问:
项目地址:
https://gitee.com/aruba/netflix-study.git