在微服务领域Spring Boot自动伸缩如何实现

自动伸缩是每个人都想要的,尤其是在微服务领域。让我们看看如何在基于Spring Boot的应用程序中实现。

我们决定使用 Kubernetes 、 Pivotal Cloud Foundry 或 HashiCorp‘s Nomad 等工具的一个更重要的原因是为了让系统可以自动伸缩。当然,这些工具也提供了许多其他有用的功能,在这里,我们只是用它们来实现系统的自动伸缩。乍一看,这似乎很困难,但是,如果我们使用 Spring Boot 来构建应用程序,并使用 Jenkins 来实现 CI ,那么就用不了太多工作。

今天,我将向您展示如何使用以下框架/工具实现这样的解决方案:

Spring Boot
Spring Boot Actuator
Spring Cloud Netflix Eureka
Jenkins CI
它是如何工作的

每一个包含 Spring Boot Actuator 库的 Spring Boot 应用程序都可以在 /actuator/metrics端点下公开 metric 。许多有价值的 metric 都可以提供应用程序运行状态的详细信息。在讨论自动伸缩时,其中一些 metric 可能特别重要: JVM 、CPU metric 、正在运行的线程数和HTTP请求数。有专门的 Jenkins 流水线通过按一定频率轮询 /actuator/metrics 端点来获取应用程序的指标。如果监控的任何 metric 【指标】低于或高于目标范围,则它会启动新实例或使用另一个 Actuator 端点 /actuator/shutdown 来关闭一些正在运行的实例。在此之前,我们需要知道当前有那些实践在提供服务,只有这样我们才能在需要的时候关闭空闲的实例或启动新的新例。

图片描述(最多50字)

在讨论了系统架构之后,我们就可以继续开发了。这个应用程序需要满足以下要求:它必须有公开的可以优雅地关闭应用程序和用来获取应用程序运行状态 metric 【指标】的端点,它需要在启动完成的同时就完成在Eureka的注册,在关闭时取消注册,最后,它还应该能够从空闲端口池中随机获取一个可用的端口。感谢 Spring Boot ,只需要约五分钟,我们可以轻松地实现所有这些机制。

动态端口分配

由于可以在一台机器上运行多个应用程序实例,所以我们必须保证端口号不冲突。幸运的是, Spring Boot 为应用程序提供了这样的机制。我们只需要将 application.yml 中的 server.port属性设置为 0 。因为我们的应用程序会在 Eureka 中注册,并且发送唯一的标识 instanceId ,默认情况下这个唯一标识是将字段 spring.cloud.client.hostname , spring.application.name和 server.port 拼接而成的。

示例应用程序的当前配置如下所示。

可以看到,我通过将端口号替换为随机生成的数字来改变了生成 instanceId 字段值的模板。

spring:
application:
name: example-service
server:
port: ${PORT:0}
eureka:
instance:
instanceId: ${spring.cloud.client.hostname}:${spring.application.name}:${random.int[1,999999]}
启用Actuator的Metric

为了启用 Spring Boot Actuator ,我们需要将下面的依赖添加到 pom.xml 。

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
我们还必须通过HTTP API将属性 management.endpoints.web.exposure.include 设置为 ‘*‘ 来暴露 Actuator 的端点。现在,所有可用的指标名称列表都可以在 /actuator/metrics 端点中找到,每个指标的详细信息可以通过 /actuator/metrics/{metricName} 端点查看。

优雅地停止应用程序

除了查看 metric 端点外, Spring Boot Actuator 还提供了停止应用程序的端点。然而,与其他端点不同的是,缺省情况下,此端点是不可用的。我们必须把 management.endpoint.shutdown.enabled 设为 true 。在那之后,我们就可以通过发送一个 POST 请求到 /actuator/shutdown 端点来停止应用程序了。

这种停止应用程序的方法保证了服务在停止之前从 Eureka 服务器注销。

启用Eureka自动发现

Eureka 是最受欢迎的发现服务器,特别是使用 Spring Cloud 来构建微服务的架构。所以,如果你已经有了微服务,并且想要为他们提供自动伸缩机制,那么 Eureka 将是一个自然的选择。它包含每个应用程序注册实例的IP地址和端口号。为了启用 Eureka 客户端,您只需要将下面的依赖项添加到 pom.xml 中。

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
正如之前提到的,我们还必须保证通过客户端应用程序发送到 Eureka 服务器的 instanceId 的唯一性。在“动态端口分配”中已经描述了它。

下一步需要创建一个包含内嵌 Eureka 服务器的应用程序。为了实现这个功能,首先我们需要在 pom.xml 中添加下面这个依赖:

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
这个 main类 需要添加 @EnableEurekaServer 注解。

@SpringBootApplicationbr/>@EnableEurekaServer
public class DiscoveryApp {
public static void main(String[] args) {
new SpringApplicationBuilder(DiscoveryApp.class).run(args);
}
}
默认情况下,客户端应用程序尝试使用 8761 端口连接 Eureka 服务器。我们只需要单独的、独立的 Eureka 节点,因此我们将禁用注册,并尝试从另一个 Eureka 服务器实例中获取服务列表。

spring:
application:
name: discovery-service
server:
port: ${PORT:8761}
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://localhost:8761/eureka/
我们将使用 Docker 容器来测试上面的自动伸缩系统,因此需要使用 Eureka 服务器来准备和构建 image 。

Dockerfile 和 image 的定义如下所示。

我们可以使用命令 docker build -t piomin/discovery-server:2.0 来进行构建。

FROM openjdk:8-jre-alpine
ENV APP_FILE discovery-service-1.0-SNAPSHOT.jar
ENV APP_HOME /usr/apps
EXPOSE 8761
COPY target/$APP_FILE $APP_HOME/
WORKDIR $APP_HOME
ENTRYPOINT ["sh", "-c"]
CMD ["exec java -jar $APP_FILE"]
为弹性伸缩构建一个Jenkins流水线

第一步是准备 Jenkins 流水线,负责自动伸缩。我们将创建 Jenkins 声明式流水线,它每分钟运行一次。可以使用 triggers 指令配置执行周期,它定义了自动化触发流水线的方法。我们的流水线将与 Eureka 服务器和每个使用 Spring Boot Actuator 的微服务中公开的 metric 端点进行通信。

测试服务的名称是 EXAMPLE-SERVICE ,它和定义在 application.yml 文件 spring.application.name 的属性值(大写字母)相同。被监控的 metric 是运行在Tomcat容器中的HTTP listener线程数。这些线程负责处理客户端的HTTP请求。

pipeline {
agent any
triggers {
cron(‘ *‘)
}
environment {
SERVICE_NAME = "EXAMPLE-SERVICE"
METRICS_ENDPOINT = "/actuator/metrics/tomcat.threads.busy?tag=name:http-nio-auto-1"
SHUTDOWN_ENDPOINT = "/actuator/shutdown"
}
stages { ... }
}
使用Eureka整合Jenkins流水线

流水线的第一个阶段负责获取在 discovery 服务器上注册的服务列表。 Eureka 发现了几个HTTP API端点。其中一个是 GET /eureka/apps/{serviceName} ,它返回一个给定服务名称的所有活动实例列表。我们正在保存运行实例的数量和每个实例 metric 端点的URL。这些值将在流水线的下一个阶段中被访问。

下面的流水线片段可以用来获取活动应用程序实例列表。 stage 名称是 Calculate 。我们使用 HTTP请求插件 来发起HTTP连接。

stage(‘Calculate‘) {
steps {
script {
def response = httpRequest "
http://192.168.99.100:8761/eureka/apps/${env.SERVICE_NAME}"
def app = printXml(response.content)
def index = 0
env["INSTANCECOUNT"] = app.instance.size()
app.instance.each {
if (it.status == ‘UP‘) {
def address = "http://${it.ipAddr}:${it.port}"
env["INSTANCE
${index++}"] = addressbr/>}
}
}
}
}
@NonCPS
def printXml(String text) {
return new XmlSlurper(false, false).parseText(text)
}
下面是 Eureka API对我们的微服务的示例响应。响应 content-type 是 XML 。

图片描述(最多50字)

使用Spring Boot Actuator整合Jenkins流水线

Spring Boot Actuator 使用 metric 来公开端点,这使得我们可以通过名称和选择性地使用标签找到 metric 。在下面可见的流水线片段中,我试图找到 metric 低于或高于阈值的实例。如果有这样的实例,我们就停止循环,以便进入下一个阶段,它执行向下或向上的伸缩。应用程序的IP地址是从带有 INSTANCE_ 前缀的流水线环境变量获取的,这是在前一阶段中被保存了下来的。

stage(‘Metrics‘) {
steps {
script {
def count = env.INSTANCE_COUNT
for(def i=0;i 100)
return "UP"
else if (value.toInteger() < 20)
return "DOWN"
else
return "NONE"
}
关闭应用程序实例

在流水线的最后一个阶段,我们将关闭运行的实例,或者根据在前一阶段保存的结果启动新的实例。通过调用 Spring Boot Actuator 端点可以很容易执行停止操作。在接下来的流水线片段中,首先选择了 Eureka 实例。然后我们将发送 POST 请求到那个ip地址。

如果需要扩展应用程序,我们将调用另一个流水线,它负责构建 fat JAR 并让这个应用程序在机器上跑起来。

stage(‘Scaling‘) {
steps {
script {
if (env.SCALE_TYPE == ‘DOWN‘) {
def ip = env["INSTANCE_0"] + env.SHUTDOWN_ENDPOINT
httpRequest url: ip, contentType: ‘APPLICATION_JSON‘, httpMode: ‘POST‘
} else if (env.SCALE_TYPE == ‘UP‘) {
build job: ‘spring-boot-run-pipeline‘
}
currentBuild.description = env.SCALE_TYPE
}
}
}
下面是 spring-boot-run-pipeline 流水线的完整定义,它负责启动应用程序的新实例。它先从 git 仓库中拉取源代码,然后使用 Maven 命令编译并构建二进制的jar文件,最后通过在 java -jar 命令中添加 Eureka 服务器地址来运行应用程序。

pipeline {
agent any
tools {
maven ‘M3‘
}
stages {
stage(‘Checkout‘) {
steps {
git url: ‘https://github.com/piomin/sample-spring-boot-autoscaler.git‘, credentialsId: ‘github-piomin‘, branch: ‘master‘
}
}
stage(‘Build‘) {
steps {
dir(‘example-service‘) {
sh ‘mvn clean package‘
}
}
}
stage(‘Run‘) {
steps {
dir(‘example-service‘) {
sh ‘nohup java -jar -DEUREKA_URL=
http://192.168.99.100:8761/eureka target/example-service-1.0-SNAPSHOT.jar 1>/dev/null 2>logs/runlog &‘
}
}
}
}
}
扩展到多个机器

在前几节中讨论的算法只适用于在单个机器上启动的微服务。如果希望将它扩展到更多的机器上,我们将不得不修改我们的架构,如下所示。每台机器都有 Jenkins 代理运行并与 Jenkins master通信。如果想在选定的机器上启动一个微服务的新实例,我们就必须使用运行在该机器上的代理来运行流水线。此代理仅负责从源代码构建应用程序并将其启动到目标机器上。这个实例的关闭仍然是通过调用HTTP端点来完成。

图片描述(最多50字)

假设我们已经成功地在目标机器上启动了一些代理,我们需要对流水线进行参数化,以便能够动态地选择代理(以及目标机器)。

当扩容应用程序时,我们必须将代理标签传递给下游流水线。

build job:‘spring-boot-run-pipeline‘, parameters:[string(name: ‘agent‘, value:"slave-1")]
调用 流水线具体由那个标签下的代理运行,是由" ${params.agent} "决定的。

pipeline {
agent {
label "${params.agent}"
}
stages { ... }
}
如果有一个以上的代理连接到主节点,我们就可以将它们的地址映射到标签中。由于这一点,我们能够将从 Eureka 服务器获取的微服务实例的IP地址映射到与 Jenkins 代理的目标机器上。

pipeline {
agent any
triggers {
cron(‘ *‘)
}
environment {
SERVICE_NAME = "EXAMPLE-SERVICE"
METRICS_ENDPOINT = "/actuator/metrics/tomcat.threads.busy?tag=name:http-nio-auto-1"
SHUTDOWN_ENDPOINT = "/actuator/shutdown"
AGENT_192.168.99.102 = "slave-1"
AGENT_192.168.99.103 = "slave-2"
}
stages { ... }
}
总结

在本文中,我演示了如何使用 Spring Boot Actuato metric 来自动伸缩 Spring Boot 应用程序。使用 Spring Boot 提供的特性以及 Spring Cloud Netflix Eureka 和 Jenkins ,您就可以实现系统的自动伸缩,而无需借助于任何其他第三方工具。本文也假设远程服务器上也是使用 Jenkins 代理来启动新的实例,但是您也可以使用 Ansible 这样的工具来启动。如果您决定从 Jenkins 运行 Ansible 脚本,那么将不需要在远程机器上启动 Jenkins 代理。

原文地址:http://blog.51cto.com/13952953/2299734

时间: 2024-10-31 08:49:04

在微服务领域Spring Boot自动伸缩如何实现的相关文章

构建微服务:Spring boot

构建微服务:Spring boot 在上篇文章构建微服务:Spring boot 提高篇中简单介绍了一下spring data jpa的基础性使用,这篇文章将更加全面的介绍spring data jpa 常见用法以及注意事项 前几篇文章地址: 构建微服务:Spring boot 入门篇 构建微服务:Spring boot 提高篇 构建微服务:Spring boot中Redis的使用 构建微服务:thymeleaf使用详解 作者:纯洁的微笑出处:http://www.ityouknow.com/

构建微服务:Spring boot 入门篇

构建微服务:Spring boot 入门篇 什么是spring boot Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.用我的话来理解,就是spring boot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包,spring boot整合了所有的框架(不知道这样比喻是否合适). 使用spring boot有什

Java微服务实践—Spring Boot系列

Java微服务实践-Spring Boot系列网盘地址:https://pan.baidu.com/s/1aMqPO4pXLeXDHvRuze-JWw 密码: j62z备用地址(腾讯微云):https://share.weiyun.com/c74335d7e383158ee3c4aaf193d471ed 密码:r5gqsk 原文地址:http://blog.51cto.com/12218470/2088359

微服务,spring boot,spring cloud

什么是微服务 将复杂的业务系统根据业务拆分成多个子系统协同完成主体业务. 微服务的九大特性(根据Martin Fowler 在 Microservices 中的归纳) 服务组件化(灵活拆装,低耦合) 按业务组织团队(分工驱动团队的技术知识储备) 做产品的态度,团队对整个生命周期负责,业务进行拆分后,每个模块的的业务小而精,更容易做纵向扩展,把小功能做精 智能端点和哑管道,组件间从原先的方法调用的交互方式变为基于粗粒度的通信协议(Http的RESTful API,HSF,RabbitMQ) 去中心

微服务架构-Spring Boot(一)

最近在看微服务架构,包括Spring Boot.Spring Data.Spring Cloud. 先从Spring boot开始讲起:为什么会有Spring Boot? 原本实用Spring开发一个web应用步骤: 1.创建一个web项目并且导入相关jar包.SpringMVC Servlet 2.创建一个web.xml 3.编写一个控制类(Controller) 4.需要一个部署web应用的服务器:例Tomcat 而Spring Boot就是用来简化上述所示的新Spring应用的初始搭建以及

SpringCloud(8)微服务监控Spring Boot Admin

1.简介 Spring Boot Admin 是一个管理和监控Spring Boot 应用程序的开源软件.Spring Boot Admin 分为 Server 端和 Client 端,Spring Boot Admin UI部分使用AngularJs将数据展示在前端. 2.工程架构 Eureka Server:服务注册中心,端口为8761. Admin Server:用于对微服务系统进行统一的监控和管理. Admin Clinet:客户端集成Admin. 3.构建Admin Server 新建

小马哥-Java 微服务实践 - Spring Boot 系列-01Java 微服务实践 - Spring Boot 系列(一)初体验

课程github地址 https://github.com/mercyblitz/segmentfault-lessons 传统的web应用架构.微服务是一种架构.不限定什么语言 单体应用和微服务的对比 SOA 微服务的发展史 rpc更讲究面向接口 socket更面向于底层 分布式的,也叫作进程外的 业务处理的结果一般返回给服务组件. rest可以是json.xml.html.为什么很多会会选择json,json的格式比较简单清晰. 微服务面临的挑战 表达式驱动依赖反射驱动 目录概要 demo

深入学习微框架:Spring Boot

由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.通过这种方式,Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者. 多年以来,Spring IO平台饱受非议的一点就是大量的XML配置以及复杂的依赖管理.在去年的SpringOne 2GX会议上,Pivotal的CTO Adrian Colyer回应了这些批评,并且

深入学习微框架:Spring Boot(转)

转:http://www.infoq.com/cn/articles/microframeworks1-spring-boot/ 相关参考: https://spring.io/guides/gs/spring-boot/ http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/ https://github.com/spring-projects/spring-boot 深入学习微框架:Sprin