初识微服务

微服务概念

把一个大型的单个应用程序和服务拆分为数个甚至数十个的支持微服务,它可扩展单个组件而不
是整个的应用程序堆栈

微服务架构

image.png

微服务主流框架

  • Dubbo(阿里) :目前开源于Apache ;2012年推出;2014年停更;2015年恢复更新
  • DubboX(当当基于Dubbo的更新)
  • JD-hydra(京东基于Dubbo的更新)
  • ServiceComb/CSE(华为2017)
  • SpringCloud (Spring推出)官网有自己的组件,但是部分没人用

image.png

Spring Cloud Netflix

Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。
SpringCloud版本和Springboot版本兼容不同的springboot版本,配套支持SpringCloud的版本;如果使用Hoxton版本,Boot版本必须要2.2.x或者以上.
image.png

组件介绍

Eureka

服务注册和发现,它提供了一个服务注册中心、服务发现客户端,还有一个方便的查看所有注
册的服务的界面。所有的服务使用Eureka的服务发现客户端来将自己注册到Eureka的服务器上。

Eureka是基于REST(Representational State Transfer)服务,提供服务发现并实现负载均衡和
故障转移。我们称此服务为Eureka服务。Eureka提供了Java客户端组件,Eureka Client,方便与
服务端的交互。客户端内置了基于round-robin实现的简单负载均衡。在Netflix,为Eureka提供
更为复杂的负载均衡方案进行封装,以实现高可用,它包括基于流量、资源利用率以及请求返回
状态的加权负载均衡。
image.png

Ribbon

负载均衡,一个请求发送给某一个服务的应用的时候,如果一个服务启动了多个实例,就会通过
Ribbon来通过一定的负载均衡策略来发送给某一个服务实例。

Feign

服务客户端,服务之间如果需要相互访问,可以使用RestTemplate,也可以使用Feign客户端访
问。它默认会使用Ribbon来实现负载均衡。

Hystrix

监控和熔断器。只需要在服务接口上添加Hystrix标签,就可以实现对这个接口的监控和断路
器功能。
Hystrix Dashboard,监控面板,他提供了一个界面,可以监控各个服务上的服务调用所消耗的时
间等。
Turbine,监控聚合,使用Hystrix监控,我们需要打开每一个服务实例的监控信息来查看。

  • 服务降级:调用远程服务时,如果一定时间内远程服务没有返回结果,调用者自行返回结果(如:返回服务繁忙等),称为服务降级
  • 服务熔断:满足一定条件出发服务熔断机制(比如1min种内1000条服务请求均无答复),触发服务熔断后,在一定周期内(自定义,比如10min等)不会去调用远程服务,而是有调用者自行答复。周期时间到了会尝试去调用远程服务,如果此时远程服务正常返回结果,服务熔断关闭。
  • Hystrix Dashboard:监控页面,可用来监控服务降级、服务熔断等

image.png

Zuul

网关,所有的客户端请求通过这个网关访问后台的服务。他可以使用一定的路由配置来判断某一个
URL由哪个服务来处理。并从Eureka获取注册的服务来转发请求。

示例

示例项目Demo规划

项目名称: ldx-demo
项目环境:jdk1.8、maven 3.6.3、springboot 2.3.7.RELEASE、Spring-cloud Hoxton.SR9
项目模块:

  • ldx-dependency
    • pom方式;项目总依赖包;通用的依赖版本;总体父项目
  • ldx-commons
    • jar包方式;项目公共包;包含通用实体类、工具类、结果码等
  • ldx-eureka
    • 项目注册中心;可做集群;默认端口8761;
    • 应用名称(spring.application.name) : ldx-eureka
    • 端口规划: 7000 ;集群规划7000,7001,7002;
  • ldx-order
    • 订单服务接口:可做集群:默认端口8000
    • 应用名称(spring.application.name) : ldx-order
    • 端口规划: 8000 - 8199
  • ldx-order-api
    • 订单服务;实际调用ldx-order ;可做集群;默认端口8200
    • 应用名称(spring.application.name) : ldx-order-api
    • 端口规划: 8200 - 8399
  • ldx-goods
    • 商品服务接口;可做集群;默认端口8400
    • 应用名称(spring.application.name) : ldx-goods
    • 端口规划: 8400 - 8599
  • ldx-goods-api
    • 商品服务;实际调用ldx-goods;可做集群;默认端口8600
    • 应用名称(spring.application.name) : ldx-goods-api
    • 端口规划: 8600 - 8799

00 Spring Cloud Netflix 基础使用 - 图6

Eureka 的使用

Eureka-server 注册中心
  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-web</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.springframework.cloud</groupId>
  12. <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
  13. </dependency>
  14. </dependencies>
# eureka 服务端口 7000
server:
  port: 7000

# eureka服务名称 eureka
spring:
  application:
    name: eureka

# eureka 服务设置
eureka:
  instance:
    hostname: eureka
  client:
    service-url:
      defaultZone: http://127.0.0.1:7000/eureka
    register-with-eureka: false
    fetch-registry: false
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class,args);
    }
}

使用Eureka-client向注册中心注册服务

以goods(服务提供方)、goods-api(服务调用方)为例

<dependencies>
      <!--eureka客户端-->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <!--mysql connector-->
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
      </dependency>
      <!--druid数据源-->
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid-spring-boot-starter</artifactId>
          <version>1.2.8</version>
      </dependency>
      <!--jpa 数据查找封装-->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-jpa</artifactId>
      </dependency>
      <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
      </dependency>
      <dependency>
          <groupId>com.msb</groupId>
          <artifactId>commons</artifactId>
          <version>1.0.0</version>
      </dependency>
  </dependencies>
server:
  port: 8400

spring:
  application:
    name: goods
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://127.0.0.1:3306/goods?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowRetrivePublicKey=true
    username: root
    password: root
    druid:
      min-idle: 10
      max-active: 10
      initial-size: 10

# 指定注册中心服务
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:7000/eureka
@SpringBootApplication
@EnableEurekaClient // 启用eureka 客户端
public class GoodsApplication {
    public static void main(String[] args) {
        SpringApplication.run(GoodsApplication.class,args);
    }
}
@Configuration
public class CrossOriginConfig {

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildCrossConfig());
        return new CorsFilter(source);
    }

    private CorsConfiguration buildCrossConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("http://127.0.0.1:*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.setAllowCredentials(true);
        return corsConfiguration;
    }
}

<dependencies>

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


  <!--netflix feign 远程调用组件-->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
  </dependency>
  <!--netflix hytrix 熔断、降级组件-->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  </dependency>

  <!--actuator 监控服务状态 向httrix上报-->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
  </dependency>
  <dependency>
    <groupId>com.msb</groupId>
    <artifactId>commons</artifactId>
    <version>1.0.0</version>
  </dependency>
</dependencies>
server:
  port: 8600

# 服务名称
spring:
  application:
    name: goods-api

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:7000/eureka
# feign远程调用 开启熔断
feign:
  hystrix:
    enabled: true
# 服务响应时间 2000ms
hystrix:
  metrics:
    polling-interval-ms: 2000
@SpringBootApplication
@EnableFeignClients // 启用远程调用
@EnableHystrix  // 启用熔断机制
public class GoodsApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(GoodsApiApplication.class,args);
    }
}

远程调用feign

// 远程调用goods服务                    熔断、降级服务 GoodsApiClientFallback
@FeignClient(name = "goods",fallback = GoodsApiClientFallback.class)
@Qualifier("goodsFeignClient")
public interface GoodsFeignClient {

    @PostMapping("/goods/add")
    GoodsInfo addGood(GoodsInfo goodsInfo);

    @RequestMapping("/goods/all")
    List<GoodsInfo> all();
}

Hytrix配置

@Component
public class GoodsApiClientFallback implements GoodsFeignClient {
    @Override
    public GoodsInfo addGood(GoodsInfo goodsInfo) {
        System.out.println("服务降级");
        return null;
    }

    @Override
    public List<GoodsInfo> all() {
        System.out.println("服务降级");
        return null;
    }
}

Hytrix Dashboard
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  <!--actuator 依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
   <!--hystrix-dashboard依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    </dependency>
</dependencies>
server:
  port: 9000
spring:
  application:
    name: hystrix
hystrix:
  dashboard:
    proxy-stream-allow-list: localhost
@SpringBootApplication
@EnableHystrixDashboard // 启动HtrixDashboard
public class HystrixDashboardApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixDashboardApplication.class,args);
    }
}
@Configuration
public class GoodsActuator {
    @Bean
    public ServletRegistrationBean getServletRegistrationBean() {

        HystrixMetricsStreamServlet mss = new HystrixMetricsStreamServlet();

        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(mss);

        servletRegistrationBean.setName("servletRegistrationBean");
        servletRegistrationBean.setLoadOnStartup(1);
        servletRegistrationBean.addUrlMappings("/goods.stream");
        return servletRegistrationBean;
    }
}

Zuul

<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>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
spring:
  application:
    name: zuul
server:
  port: 8080

# 配置路由规则
zuul:
  routes:
    goods-api:
      path: /gApi/**
      serviceId: goods-api

# 指定注册中心
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}
@SpringBootApplication
@EnableZuulProxy  // 开启zuul 代理
@EnableEurekaClient // 开启euraka 客户端
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }
}