Spring Boot 微服务(未完)

Spring Boot 微服务

微服务指提供一个或多个 Rest 接口的小 Spring Boot 项目,创建过程和一般 Spring Boot 项目相同

一、使用 Spring Boot Actuator 来监视 Spring Boot 项目

在创建初始化项目中,在 Ops 下选择 Spring Boot Actuator,将浏览器指向 localhost:8080/actuator,可以看到 Actuator 返回的监视信息

通过 Jconsole 查看监视信息

在 jdk 安装目录 bin 下,单击 jconsole.exe 打开 Jconsole

配置 actuator

配置 info 节点

info.app.name=Boot actuator
info.app.description=My Greeting Service
info.app.version=1.0.0

例如:

默认情况下 actuator 只暴露 info 和 health ,如果想暴露其他的需要进行配置

management.endpoints.web.exposure.include=info,health,metrics

更多请看教程https://www.jianshu.com/p/8bfac9289c7e

官方文档https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-endpoints

添加自定义运行状况模块

系统默认的运行状况可以通过 http://localhost:8082/actuator/health来查看,默认只有 updown 两种状态,我们可以通过实现 HealthIndicator接口来自定义运行状况

先定义一个系统运行状态类

用来保存计数信息和判断系统状态

package com.zolmk.ms.actuator.config.actuator;

import java.util.Calendar;
import java.util.concurrent.atomic.LongAdder;

/**
 * @author : Administrator
 * @project : MiscoServices
 * @date : 2020/11/11 11:22
 **/

public class TPSCounter
{
    public LongAdder longAdder;
    int threshold = 2;

    Calendar expiry = null;

    public TPSCounter ()
    {
        this.longAdder = new LongAdder();
        this.expiry = Calendar.getInstance();
        this.expiry.add(Calendar.MINUTE,1); // 一分钟的检测期
    }
    // expired 过期
    public boolean isExpired()
    {
        return Calendar.getInstance().after(expiry);
    }

    public boolean isWeak()
    {
        return (longAdder.intValue() > threshold);
    }
    public void increment()
    {
        this.longAdder.increment();
    }


}
实现HealthIndicator接口并注册成为 Spring Boot 组件
package com.zolmk.ms.actuator.service;

import com.zolmk.ms.actuator.config.actuator.TPSCounter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;


/**
 * @author : Administrator
 * @project : MiscoServices
 * @date : 2020/11/11 16:00
 **/

@Component
public class TPSHealth implements HealthIndicator
{
    TPSCounter tpsCounter;
    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public Health health ()
    {
        boolean health = tpsCounter != null && tpsCounter.isWeak();
        if(health)
        {
            return Health.outOfService().withDetail("To Many Request","OutOfService").build();
        }
        return Health.up().build();
    }
	// 在每个 request 中调用该方法
    public void updateTx()
    {
        if(tpsCounter==null || tpsCounter.isExpired())
        {
            tpsCounter = new TPSCounter();
        }
        else
        {
            tpsCounter.increment();
        }
    }

需要在每个 Request 中调用该组件的 updateTx() 方法,该自定义运行状态的实现结果是,当请求超过三次时,请求http://localhost:8082/actuator/health接口时,将返回

{
    "status": "OUT_OF_SERVICE"
}

如果需要更详细的信息,必须在 application.properties 中配置

management.endpoint.health.show-details=always

这时,你将得到下面的结果

{
    "status": "OUT_OF_SERVICE",
    "components": {
        "TPSHealth": {
            "status": "OUT_OF_SERVICE",
            "details": {
                "To Many Request": "OutOfService"
            }
        },
        "diskSpace": {
            "status": "UP",
            "details": {
                "total": 4000785100800,
                "free": 3920117735424,
                "threshold": 10485760,
                "exists": true
            }
        },
        "ping": {
            "status": "UP"
        }
    }
}

二、记录微服务

使用 SpringFox 来自动生成 REST API 文档。

添加依赖

因为 SpringFox 不是SpringBoot套件下的,所有需要单独添加 SpringFox Swagger 依赖。

<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger2</artifactId>
	<version>2.9.2</version>
</dependency>

<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger-ui</artifactId>
	<version>2.9.2</version>
</dependency>

开启 SpringFox Swagger

在 application.java 中添加 @EnableSwagger2 注解

查看结果

在浏览器中输入 http://localhost:8082/swagger-ui.html,你将看到如下的页面

在该页面中可以查看相关的 REST API 接口。

三、微服务概念的应用

微服务虽然很优秀,但也不是所有的场景都适合去使用它,我们应该学会分析微服务的边界,更好的去使用它。

模式和常见设计决策

一般来说,对于开发一个轻量级的、模块化的、可扩展的分布式系统而言,微服务是一个很好的选择。

确定合适的微服务边界

领域驱动设计(DDD)定义了有界上下文(bounded context)概念。一个有界上下文是一个负责执行特定功能的大的领域,或者系统的子领域或子系统。

一个有界上下文是确定微服务边界的有效方式。每个有界上下文能够映射到单个微服务。

设计微服务边界最实用的方法是通过一系列可能的选项来把手边的工作运行起来,就像是一个服务的“试金石”。

自治功能

自治服务通常很少依赖外部功能,它们接收输入,通过内部的逻辑和数据进行计算,然后产生结果进行输出。

可部署单元的大小

服务的大小随着它实现的功能密度的增加而增加。

好的微服务应该确保它可部署的单元的大小始终保持在可控范围内。

最合适的功能或者子域

分析如何从一个整体应用上分离出一个最有用的组件是非常重要的,这个特别适用于将整块的应用切分成一个个微服务。这种分析可以基于资源密度程度、所有权成本、商业利益以及灵活性等因素。

多语言结构

微服务一个很重要的特点就是它对多语言架构的支持。为了满足不同的非功能性和功能性的需求,不同组件可能需要区别对待。它们可能采用不同的架构,不同的技术,不同的部署和拓扑等。当组件一旦确定,需要考虑对语言的要求。

选择性缩放

选择性缩放与前面提到的多语言结构是相关联的,与前面提到的例子类似,并非所有的功能性模块都需要同样等级的可扩展性。有时候,根据可扩展性需求来决定边界是比较合适的。

选择性缩放就是有目的有选择的去适当放大或缩小微服务的边界,对于可扩展性要求不高的子系统,可以适当放大它们的边界。

小而灵活的团队

微服务允许小且集中的团队分别开发系统的不同模块。

单一职责

指单个业务能力或者单个技术能力。一般来说,任何单个职责都不能由多个微服务来承担,单个微服务也不能承担多个职责。

存在单个业务项被切分到不同服务这种特殊情况,比如管理客户资料时,为了达到好的工作效率,采用两个不同的微服务去管理读和写。

可复制性或变性

在定义微服务边界的时候,需要使得每个微服务都能很顺畅的从整个应用中分离出来,而不用再次去重复编写它的代码。如果系统的某个部分符合这种特征,那么它就很适合去作为一个微服务。

耦合和内聚

耦合和内聚是决定服务边界最重要的两个因素。必须很认真地评估微服务之间的依赖以避免高耦合的接口。将功能进行依赖分解有助于确定微服务边界。避免服务间的频繁通信过多的同步请求—响应调用同步循环和依赖是3个很重要的关键点。在微服务内部保持高内聚,微服务之间保持低耦合是一种比较成功的设计方式。

设计通信方式

微服务之间的通信方式可以设计成为同步(请求—响应)或者异步(即发即弃)的通信方式。

该如何选择通信方式?

如果使用异步方式进行建模没有任何优点,那么就使用同步方式。使用异步通信方式对用户驱动请求进行建模会带来很多复杂性,使用反应式编程框架可以避免这一点。

微服务的编制

可组合性是服务设计的原则之一。谁对服务组合负责?

第一种方法是编制

在编制方法中,多个服务组合在一起,共同实现一个完整的功能。在 SOA 中, ESB 担任编制的角色。编制服务由 ESB 作为混合服务暴露出来。

第二种方法是编排

一个事件,由一个生产者发布,一系列消费者等待这个事件,并且在事件到来后互相独立地实施不同的逻辑处理。在 SOA 中,请求方推送消息到 ESB ,下游流向由消费服务方自动决定。

设置事务边界

事务在一个操作型系统中是通过把一系列操作组合成一个原子块来保证在一个 RDBMS 中存储的数据的一致性,它们要么提交要么回滚整个操作。

分布式事务场景

如果需要,理想的场景是在微服务中使用本地事务,并且完全避免分布式事务。

服务版本控制的考虑

语义版本被广泛应用于服务版本控制。一个语义版本有3个组成部分:主版本号、次版本号及补丁版本号、当有一个突破性改变时,需要更新主版本号,当有向后兼容改变发生时使用次版本号,当有向后兼容 bug 修复时使用补丁版本号。

URI 版本控制

在 URI 版本控制中,版本号包含在 URL 本身。把最新的版本命名为一个非版本的 URL 是一个不错的方式。

微服务和块操作

由于我们已经把整块的应用切分成了更小的、目标明确的服务,也就不再可能在微服务数据存储之间使用 join 查询。此时可能导致一种情况,一个服务可能需要很多来自其他服务的记录来完成自己的功能。

有两个解决方案:第一个是当数据创建时预聚合数据。第二个是当预聚合数据不太现实,就使用批量 API(Spring Batch)。

微服务的挑战

数据孤岛

将一个整体的应用划分成一个个微服务,如果也将数据进行划分,就会造成数据孤岛,解决办法是创建一个数据仓库或者数据库,将微服务的所有数据(选择性托管)托管到数据仓库中去。

日志和监控

当实现微服务时,我们需要一个将日志从每个服务传输到中央托管入职存储库的功能。好处主要有两个:一是不再需要依赖本地硬盘或者本地 I/O、二是日志文件是由中央托管的,可供所有类型的分析。

依赖管理
  • 通过合理地设计服务边界减少依赖。
  • 通过设计依赖时尽量低地耦合来减少影响。同样,通过异步通信风格设计服务交互。
  • 使用类似断路器的设计模式来解决依赖问题。
  • 使用可视化依赖图监控依赖。

四、微服务的演变

微服务能力模型:

微服务迁移的优先级

  • 依赖:从服务依赖图来看,拥有少量或者没有依赖的服务更容易迁移。
  • 事务量:在 IT 支持和维护的角度看,迁移高事务量的服务更有价值。
  • 资源利用率:迁移资源密集型服务可以释放资源供其他服务使用,这有助于更好的运行剩下的模块。
  • 复杂度:与复杂模块相比,简单模块更加容易进行迁移。
  • 业务关键性:越关键服务能够带来更高的商业价值。

Sring Cloud 组件

分布式配置:开发、测试和生产等不同的环境中运行多个微服务实例,配置属性将会很难管理。因此,有一个配置中心去管理这些配置属性是非常重要的。分布式配置管理模块可以中心化和具体化微服务配置参数。

路由:路由是一个 API 网关组件,主要用于反向代理转发消费者发送请求到服务提供接口。

负载均衡:负载均衡功能要求实现一个基于软件的负载均衡模块,该模块可以利用负载均衡算法将请求路由给可用的服务器。

服务注册和发现:服务注册和发现模块的作用是,当一个服务可用并且能够接受通信流的时候,使其注册到一个注册中心,通知它们的存在且可以被发现。

服务到服务的请求:Spring Cloud Feign 子项目提供了声明式的方法,可以同步实现 RESTful 风格的服务到服务的请求。

熔断机制:这个子项目使用了保险丝熔断的设计模式。当主服务失败的时候,系统就把流量切到另一个临时的”保底“服务上去,从而切断回路。当主服务恢复正常,它也可以自动切回主服务上去,最终它提供一个监控服务状态变化的仪表盘。

全局锁、内部选举和集群状态:Spring Cloud 集群可以通过 Redis、ZooKeeper 和 Consul 等实现这些功能。

安全:使用 OAuth2 实现 SSO 功能。

大数据支持

分布式追踪:分布式追踪能力帮助我们在多个微服务实例之间实现线程和关联服务的转换。

分布式消息:Spring Cloud Stream 在如 Kafka、Redis 和 RabbitMQ 等可靠消息解决方案中提供了消息整合。

Spring Cloud Config

Spring Cloud Config 服务器是一个统一管理分布式系统的配置中心。通过其中的应用和服务,可以部署、访问和管理所有的运行时配置属性项。Spring Config 服务器也支持配置属性的版本控制。

Spring Config 将属性值储存在一个有版本控制的仓库中,如 Git 或 SVN。Git 库可以是本地或者远程的。

创建 Spring Config 服务器
  • 创建新的 Spring 启动项目,选择 Config Server 和 Actuator。

  • 创建 Git 库。

  • 修改 Spring 启动项目的 application.properties 内容

    spring.application.name=configServer
    spring.cloud.config.server.git.uri=https://gitee.com/zolmk/train-ms-spring-config-server.git
    spring.cloud.config.server.git.username=username
    spring.cloud.config.server.git.password=password
    

    配置 Git Uri 和 用户名、密码。

  • 添加开启服务注解

    @SpringBootApplication
    @EnableConfigServer
    public class ConfigserverApplication
    {
    
        public static void main (String[] args)
        {
            SpringApplication.run(ConfigserverApplication.class, args);
        }
    
    }
    
    
  • Spring Config 服务器就配置完成,点击启动就可以了。

Spring Config 特性(自解)

当 Git 仓库的文件被修改时, Spring Config Server 会监听到修改,然后自动从 Git 仓库拉取最新的文件(怀疑是一直在监听 Git 仓库内容变化,有时间了可以研究一下)。

从客户端连接 Config 服务器
posted @ 2020-12-02 15:37  zolmk  阅读(108)  评论(0编辑  收藏  举报