搭建微服务架构

一.新建父级工程

1.New—>Project
搭建微服务架构
2.选择对应的JDK, default——>Next
搭建微服务架构
3.输入项目组Group:com.xxx;组件名称Artifact:xxxx;Type:选择Maven Project;修改自动生成的Package——>Next
搭建微服务架构
4.选择你需要的Spring Boot版本,其他的先不选——>Next
搭建微服务架构
5.Project Name工程名称,和组件名称Artifact一样;Project location:设置项目文件存放目录——>Finish
搭建微服务架构
6.父级工程创建完成后,删除src目录
搭建微服务架构
7.修改pom文件

<?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>
    <!--申明此项目为springboot项目-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>microservice</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <name>microservice</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

二.搭建注册中心模块microservice-center(eureka server)

服务注册、发现模块。

1.microservice-center

(1)File—>New—>Module…
搭建微服务架构
(2)选择对应的JDK, default——>Next
搭建微服务架构
(3)输入项目组Group:com.xxx;组件名称Artifact:xxxx;Type:选择Maven Project;修改自动生成的Package——>Next
搭建微服务架构
(4)Dpendencies选择Spring Cloud Discovery—>Eureka Server,选择你需要的Spring Boot版本——>Next
搭建微服务架构
(5)Project Name工程名称一般不做修改,和组件名称Artifact一样;Content root、Module file location 均按自动生成,不做修改——>Finish
搭建微服务架构
(6)向MicroserviceCenterApplication添加注解@EnableEurekaServer表明是一个eureka服务
搭建微服务架构
(7)将application.properties修改为application.yml(重命名快捷键Shift+F6),修改完成后加入以下配置

server:
  port: 8101 #指定该Eureka实例的端口

eureka:
  instance:
    hostname: localhost #设置当前实例的主机名称
  client:
    registerWithEureka: false #禁止注册自身
    fetchRegistry: false  #因为该服务没有注册到其他注册中心,所以关闭从注册中心拉取服务列表。
    serviceUrl:  #服务注册中心地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

#eureka是一个高可用的组件,它没有后端缓存,每一个实例注册之后需要向注册中心发送心跳(因此可以在内存中完成)
#通过eureka.client.registerWithEureka:false和fetchRegistry:false来表明自己是一个eureka server.
#

(8)修改pom文件
使用父工程spring-cloud的spring boot依赖

<?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>

    <parent>
        <groupId>com.example</groupId>
        <artifactId>microservice</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>microservice-center</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>microservice-center</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.0</spring-cloud.version>
    </properties>

    <dependencies>
        <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>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

(9)启动microservice-center,运行,在浏览器访问:http://localhost:8101/,可以看到注册的服务。
搭建微服务架构

2.创建microservice-project(eureka-client)

(1)创建过程同上一样,只是第四步选择Eureka Discovery Client——>Next
搭建微服务架构
(2)MicroserviceProjectApplication中加入以下两个注解
@EnableEurekaClient
 @RestController

@SpringBootApplication
@EnableEurekaClient
@RestController
public class MicroserviceProjectApplication {

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

(3)application.yml配置

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8101/eureka/
server:
  port: 8102
spring:
  application:
    #    此处名称最好写项目名称,便于识别服务提供者
    name: microservice-project

(4)在启动类上写个接口作为测试

@SpringBootApplication
@EnableEurekaClient
@RestController
public class MicroserviceProjectApplication {

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

    @Value("${server.port}")
    String port;
    @RequestMapping("/chen")
    public String home(@RequestParam String name) {
        return "chen "+name+",i am from port:" +port;
    }

}

(5)启动microservice-center,在启动microservice-project,在浏览器上运行:http://localhost:8102/chen?name=forezp,返回接口访问内容
搭建微服务架构

三.ribbon+restTemplate-服务消费者

a.在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于http restful的。 Spring cloud有两种服务调用方式,一种是ribbon+restTemplate,另一种是feign。

b.ribbon是一个负载均衡客户端,可以很好的控制htt和tcp的一些行为。Feign默认集成了ribbon。

1.基于以上项目复制microservice-project创建microservice-project02并修改yml中端口为8103并启动

spring.application.name不修改,仍为microservice-project: 由于服务之间是根据此名称进行相互调用,所以此时表示 8102,8103对外提供一个服务,服务名为microservice-project=====>等同于一个小的集群
搭建微服务架构

2.创建一个服务消费者microservice-ribbon

1.创建步骤

  1. File—>New—>Module…
  2. 选择Spring Initializr,选择对应的JDK, default——>Next
  3. 输入项目组Group:com.xxx;组件名称Artifact:xxxx;Type:选择Maven Project;修改自动生成的Package——>Next
  4. Dpendencies选择Spring Cloud Discovery—>Eureka Server,选择你需要的Spring Boot版本——>Next
  5. Project Name工程名称一般不做修改,和组件名称Artifact一样;Content root、Module file location 均按自动生成,不做修改——>Finish

2.启动类中添加注解和方法

  1. @EnableDiscoveryClient
  2. 通过LoadBalanced注解表明这个restRemplate开启负载均衡的功能
@SpringBootApplication
@EnableDiscoveryClient
public class MicroserviceRibbonApplication {

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

   @Bean
   @LoadBalanced
   RestTemplate restTemplate() {
       return new RestTemplate();
   }
}
  1. 编写测试类controller和service,主要调用是因为service中的RestTemplate
    microservice-ribbon结构如下:
    搭建微服务架构
    HelloRibbonService
package com.example.microserviceribbon.service;
public interface HelloRibbonService {

    public String chenService(String name);

}

HelloRibbonServiceImpl

package com.example.microserviceribbon.service.impl;

import com.example.microserviceribbon.service.HelloRibbonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class HelloRibbonServiceImpl implements HelloRibbonService {

    @Autowired
    RestTemplate restTemplate;

    @Override
    public String chenService(String name) {
        //使用注册到Eureka服务中心的客户端,由客户端分配具体调用哪个服务
        return restTemplate.getForObject("http://microservice-project/chen?name="+name,String.class);
    }
}

HelloRibbonController

package com.example.microserviceribbon.controller;

import com.example.microserviceribbon.service.impl.HelloRibbonServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloRibbonController {

    @Autowired
    HelloRibbonServiceImpl helloRibbonService;

    @RequestMapping(value = "/chen")
    public String hi(@RequestParam String name){
        return helloRibbonService.chenService(name);
    }

}

  1. 一次运行center、project、project02、ribbon,在浏览器上多次访问http://localhost:8104/陈?name=Chen Houbo,浏览器交替显示:“chen Chen Houbo,i am from port:8102”,“chen Chen Houbo,i am from port:8103”;这说明我们通过调用restTemplate.getForObject(“http://microservice-project/chen?name=”+name,String.class)方法时,已经做了负载均衡,访问了不同端口的服务实例

场景总结:

1.一个服务注册中心,microservice-center端口为8101
2.向服务注册中心microservice-center注册两个客户端服务:名称为microservice-project包含服务:8102/8103
3.向服务之策中心microservice-center注册消费者服务:microservice-ribbon端口:8104
4.当microservice-ribbon通过restTemplate调用microservice-project的chen接口时,因为用了ribbon负载均衡,会轮流的调用microservice-project:8102和8103两个端口的chen接口;

四.Feign-服务消费者

a.Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单。
使用Feign,只需要创建一个接口并注解。它具有可插拔的注解特性,可使用Feign 注解和JAX-RS注解。
Feign支持可插拔的编码器和解码器。Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果

b.简单理解:
Feign 采用的是基于接口的注解
Feign 整合了ribbon

1.创建一个服务消费者microservice-feign

(1)指定端口
搭建微服务架构
(2)pom文件中加入feign依赖入

<?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>
    <parent>
        <groupId>com.example</groupId>
        <artifactId>microservice</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>microservice-feign</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>microservice-feign</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.0</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>
        <!--高版本feign依赖============================-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</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>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

(3)启动类中加入@EnableFeignClients注解开启Feign的功能(@EnableDiscoveryClient和@EnableFeignClients)

package com.example.microservicefeign;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class MicroserviceFeignApplication {

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

}

(4)编写测试类service和controller,feign基于接口——创建serviceTest
microservice-feign解构如下:
搭建微服务架构
HelloFeignService

package com.example.microservicefeign.service;

import com.example.microservicefeign.service.impl.HelloFeignServiceImpl;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(value = "eureka-client-01", fallback = HelloFeignServiceImpl.class)
public interface HelloFeignService {

    @GetMapping(value = "/chen")
    String sayHiFromClientOne(@RequestParam(value = "name") String name);
    
}

HelloFeignServiceImpl

package com.example.microservicefeign.service.impl;

import com.example.microservicefeign.service.HelloFeignService;

public class HelloFeignServiceImpl implements HelloFeignService {

    @Override
    public String sayHiFromClientOne(String name) {
        return "hello"+name;
    }
    
}

HelloFeignController

package com.example.microservicefeign.controller;

import com.example.microservicefeign.service.HelloFeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloFeignController {

    @Autowired
    private HelloFeignService helloFeignService;

    @GetMapping(value = "chen")
    public String sayHi(@RequestParam String name){
        return helloFeignService.sayHiFromClientOne(name);
    }

}

(5)浏览器上多次访问http://localhost:8105/chen?name=Feign,浏览器交替显示:“chen Feign,i am from port:8102”,“chen Feign,i am from port:8103”;

五.断路器(Hystrix)

1.微服务架构中,根据业务分析来拆分一个个的服务,服务与服务之间可以相互调用(RPC)在Spring Cloud可以用RestTemplate+Ribbon和Feign来调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。为了解决这个问题,业界提出了断路器模型。
2.Netflix开源了Hystrix组件,实现了断路模式,SpringCloud对这一组件进行了整合。

在微服务架构中,一个请求需要调用多个服务是非常常见的,较底层的服务如果出现故障,会导致连锁故障。当对特定的服务调用的不可用达到一个阈值(Hystrix是5秒20次断路器将会被打开。断路打开后,可用避免连锁故障,fallback方法可以直接返回一个固定值)。

3.Ribbon使用断路器

(1)添加断路器依赖:spring-cloud-starter-netflix-hystrix如果springboot是2.0及以上的新版本还需要加入一个依赖
搭建微服务架构

(2)启动类加注解@EnableHystrix开启Hystrix(@EnableDiscoveryClient和@EnableHystrix)
搭建微服务架构
(3)改造HelloRibbonServiceImpl类,在chenService方法上加上@HystrixCommand注解
注意: 该注解对该方法创建了熔断器的功能,并指定了fallbackMethod熔断方法, 熔断方法直接返回了一个字符串,字符串为“chen,”+name+“,sorry,error!”,

package com.example.microserviceribbon.service.impl;

import com.example.microserviceribbon.service.HelloRibbonService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class HelloRibbonServiceImpl implements HelloRibbonService {

    @Autowired
    RestTemplate restTemplate;

    @Override
    @HystrixCommand(fallbackMethod="chenError")
    public String chenService(String name) {
        //使用注册到Eureka服务中心的客户端,由客户端分配具体调用哪个服务
        return restTemplate.getForObject("http://microservice-project/chen?name="+name,String.class);
    }

    public String chenError(String name){
        return "chen," + name +"sorry,error!";
    }
}

(4)断路测试

  • 启动ribben访问
  • 关闭microservice-project,再访问,会得到短路由返回值
  • microservice-project工程不可用的时候,microservice-ribbon调用 microservice-chen的API接口时,会执行快速失败,直接返回一组字符串,而不是等待响应超时,这很好的控制了容器的线程阻塞
    搭建微服务架构
4.Feign中使用断路器

(1)Feign是自带断路器的,在D版本的Spring Cloud中,它没有默认打开。需要在配置文件中配置打开:feign.hystrix.enabled=true
搭建微服务架构
(2)在@FeignClient接口的注解中加上fallback的指定类HelloFeignServiceImpl
搭建微服务架构
(3)HelloFeignServiceImpl需要实现HelloFeignService接口,并注入到Ioc容器中(组件注解)
搭建微服务架构
(4)断路测试-同上

5.Hystrix Dashboard (断路器:Hystrix 仪表盘)

–仪表盘添加+ribbon和feign相同
–以ribbon为例:
(1)添加依赖

<!--添加断路器-仪表盘依赖==========-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

(2)主程序启动类中

  • 加入@EnableHystrixDashboard注解,开启hystrixDashboard
  • 在spring版本2.0以上需要注入一个servlet(启动类中)
//仪表盘注解@EnableHystrixDashboard

搭建微服务架构

@Bean
    public ServletRegistrationBean hystrixMetricsStreamServlet() {
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        registrationBean.addUrlMappings("/actuator/hystrix.stream");//访问该页面就是监控页面
        return registrationBean;
    }

(3)访问http://localhost:8104/hystrix

上一篇:微服务:整合 Spring Boot Admin - 开启Security安全认证


下一篇:Ribbon负载均衡及Feign消费者调用服务