基于springboot构建微服务项目开发的方案复习总结(一)

/ 默认分类 / 0 条评论 / 950浏览

基于springboot构建微服务项目开发的方案复习总结(一)

一.构建微服务项目常用基本技术栈

springboot系列

数据库操作

mybatis-spring springdata-jpa

缓存操作

springdata-redis

数据源

Alibaba Druid

日志

spring-boot-starter-logging spring集成log4j

开发接口文档

springboot集成swagger

权限安全

springboot集成security(权限控制)

消息队列服务

springboot集成rabbitmq等

全文检索

Spring Data Elasticsearch

springcloud

springcloudstarts

基于Spring Boot的微服务初始化项目,为Spring Cloud提供开箱即用的依赖管理。

Eureka

云端服务发现,一个基于 REST 的服务,用于定位服务,以实现云端中间层服务发现和故障转移。

Hystrix

熔断器,服务降级

Zuul

提供路由网关

Ribbon

云端的负载均衡的实现

Feign

Feign是一种声明式、模板化的HTTP客户端。简化了Http客户端调用.

spring cloud security

基于spring security的安全工具包,为应用程序添加安全控制。

我的学习文档

二.springcloud微服务架构

2.1 整体架构结构图

2.2 微服务开发环境搭建

2.2.1 初始化项目

使用idea插件spring-assistantspring.io初始化一个springboot项目,作为一个项目管理的顶级父工程

    <groupId>cn.wondershare</groupId>
	<artifactId>microserver</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<name>microserverproject</name>
	<packaging>pom</packaging>

注意:父项目打包方式为pom

2.2.2 platform-bom与spring-cloud-dependencies维护依赖版本

platform-bom集成了Spring Boot常见的依赖spring-cloud-dependencies则是对Spring Cloud的依赖进行管理,使用它们的好处是我们不需要关心各种依赖的版本号,因为它们管理的依赖都是经过测试的,不会发生各依赖间的兼容性问题,我们只需要在使用的地方引入需要的依赖即可

注:引入依赖时,不用填写版本号

示例代码:

   <dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>io.spring.platform</groupId>
				<artifactId>platform-bom</artifactId>
				<version>Brussels-SR4</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Dalston.SR2</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

注意:platform-bom与spring-cloud-dependencies这两个之间的兼容性问题,这个兼容性问题同样是Spring Boot 与 Spring Cloud间的兼容性问题,具体的版本适配如下:

graph LR
id[Spring Boot 2.1.0以下]-->d[Spring Cloud-Finchley]

graph LR
id[Spring Boot 2.1.0以上]-->d[Spring Cloud-Greenwich]

2.2.3 建立父工程项目

注意:父项目需要设置为pom,作为项目管理的功能

<packaging>pom</packaging>

2.2.4 构建注册中心模块

1. 注册中心介绍:

在微服务项目中,会将很多细小的功能模块作为一个单独的项目服务分离出来,这样就会出现服务间的相互调用的情况,那么就会出现一个问题,调用者怎样去找到服务提供者呢,这里就是通过注册中心这样的组件来完成类似的一系列的工作的

Eureka官方文档链接

2. 注册中心详细解析
server:
  port: 10086
spring:
  application:
    name: Eureka-Server
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1
@SpringBootApplication
@EnableEurekaServer
public class EurekaSpringbootStarter {
    public static void main(String[] args) {
        SpringApplication.run(EurekaSpringbootStarter.class);
    }
}
    <dependencies>
        <!--springcloud依赖,版本信息继承自父工程-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
        </dependency>
        <!-- Eureka服务端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

3.网关

网关是一个网络整体系统中的前置门户入口。请求首先通过网关,进行路径的路由,定位到具体的服务节点上. Zuul是一个微服务网关,首先是一个微服务。也是会在Eureka注册中心中进行服务的注册和发现。也是一个网关,请求应该通过Zuul来进行路由。

zuul网关的作用:

maven依赖

<dependencies>
    <!--引入Zuul的依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        <version>2.0.0.RELEASE</version>
    </dependency>
    <!--将Zuul作为服务注册到eureka-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
    </dependency>
</dependencies>

服务启动类

@EnableDiscoveryClient
@EnableZuulProxy
@SpringBootApplication
public class ZuulSpringBoot {
    public static void main(String[] args) {
        SpringApplication.run(ZuulSpringBoot.class,args);
    }
}

配置信息:

server:
  port: 10088  #配置微服务的端口号
eureka:
  client:
    registry-fetch-interval-seconds: 5 # 获拉取服务列表到本地的周期为5s
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka  #注册自己的路径
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1
zuul:
  retryable: true   #在Zuul中开启Ribbon的超时重试机制
  routes:
    userservice: /user/**  #请求路由配置(表示匹配到/user/**路径会抓到userservice服务)

spring:
  application:
    name: gateway
4.Ribbon服务端负载均衡

Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于NetflixRibbon实现。通过SpringCloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。SpringCloudRibbon虽然只是一个工具类框架,它不像服务注册中心、配置中心、API网关那样需要独立部署,但是它几乎存在于每一个SpringCloud构建的微服务和基础设施。因为微服务间的调用,API网关的请求转发等内容,实际上都是通过Ribbon来实现的,包括后续我们将要介绍的Feign,它也是基于Ribbon实现的工具。

Zuul中已经集成了Ribbon和Hytrix(后面介绍,这是一种服务熔断机制),在微服务项目开发中,我们一般部署服务的时候,都会部署一个网关服务,内部所有的其他微服务的调用,都将通过网关路由过去,不对外直接暴露,对外只暴露网关服务。而且一般内部服务会部署多个实例,zuul集成了ribbon,所以会以自动负载均衡的方式去调用内部服务。假如当内部服务滚动重启的时候,通过网关的一个请求刚好路由到重启的那个服务实例的话,因为默认没有开启zuul的请求重试策略,该请求将会报错,其实理想的方式可以通过重试路由到另外一个活动的服务实例上去。

所以这里我们需要先在Zuul中配置好重试机制,这就需要引入spring-retry

   <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
    </dependency>

配置开启重试机制:

zuul:
  retryable: true   #是否在Zuul中开启Ribbon的超时重试机制

这里为什么是开启Ribbon的重试机制,是因为Zuul中已经集成了Ribbon,重试机制需要使用spring-retry,但是重试之后还是走的Zuul网关,这样就还是来到了Ribbon,因为集成了Ribbon所以需要做负载均衡,所以最终走的还是通过Ribbon选择的服务实例,并且超时机制的一些属性的设置还是通过Ribbon来设置的

#有的时候我们可能不需要设置所有的服务进行重试机制,所以下面的方式就是可以单独设置指定的服务进行重试
zuul.routes.<服务名称>.retryable=true

按照上面介绍的,我们知道zuul请求也是通过Ribbon负载均衡客户端去调用其他服务的,所以我们的重试策略也是在具体的ribbon配置中指定

ribbon:
  ConnectTimeout: 100 # ribbon连接超时时间(ms)  重试机制
  ReadTimeout: 900 # ribbon通信超时时间(ms)  重试机制
4.hystrix服务熔断

Hystrix是一个为服务关于服务保护的框架,是Netflix开源的一款针对分布式系统的延迟和容错解决框架,目的是用来隔离分布式服务故障.它提供线程和信号隔离,以减少不同服务之间的资源竞争带来的相互影响;提供熔断机制使得服务可以快速失败,而不是一直阻塞等待服务响应,并能从中快速恢复.Hystrix通过这些机制来阻止级联失败并保证系统弹性,可用.

zuul作为网关服务,用来分配调度其他服务的,那么难免就会出现调用的服务出现问题的请求,或者用户访问急剧增多的情况,那么此时我们的网关服务就应该具有容错能力,zuul本身也考虑到了这点,所以默认集成的有Hystrix。(也就是说请求)

所以下面是配置在Zuul网关服务中的Hytrix

hystrix:
  command:
    userservice:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000
        timeout:
          enabled: true
5.微服务提供者

我这边设置的是一个提供学生信息查询的接口作为服务的提供者

spring:
  application:
    name: userservice
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://左左的ECS:3306/springboot?serverTimezone=PRC
    username: root
    password: 密码
mybatis:
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mybatis-mapper/studentMapper.xml
  type-aliases-package: zuo.pojo
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1
server:
  port: 8081

接口代码

@RestController
public class StudentController {

    @Autowired
    StudentService studentService;

    @GetMapping("/getStudentById/{id}")
    public Student getStudentById(@PathVariable("id") String id)
    {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Student student = studentService.getStudentById(Integer.parseInt(id));
        System.out.println("===========");
        System.out.println("这是调用userservice中的controller的方法");
        System.out.println("===========");
        System.out.println("查询出的信息:"+student);
        return student;
    }
}
6.调用测试

目前除了Eureka自己作为一个服务(这里我取消了在只有一个Eureka实例时注册自己),剩下的服务包括一个学生查询的微服务和一个网关服务

  1. 直接访问服务:

请求路径:

http://localhost:10088/user/getStudentById/1

返回结果:

{"id":1,"name":"左左"}