欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

微服務(wù)領(lǐng)域Spring Boot自動(dòng)伸縮的實(shí)現(xiàn)方法

 更新時(shí)間:2018年10月13日 10:50:15   作者:隨風(fēng)的海草  
這篇文章主要給大家介紹了關(guān)于微服務(wù)領(lǐng)域Spring Boot自動(dòng)伸縮的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用spring boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

自動(dòng)伸縮是每個(gè)人都想要的,尤其是在微服務(wù)領(lǐng)域。讓我們看看如何在基于Spring Boot的應(yīng)用程序中實(shí)現(xiàn)。

我們決定使用Kubernetes、Pivotal Cloud Foundry或HashiCorp's Nomad等工具的一個(gè)更重要的原因是為了讓系統(tǒng)可以自動(dòng)伸縮。當(dāng)然,這些工具也提供了許多其他有用的功能,在這里,我們只是用它們來實(shí)現(xiàn)系統(tǒng)的自動(dòng)伸縮。乍一看,這似乎很困難,但是,如果我們使用Spring Boot來構(gòu)建應(yīng)用程序,并使用Jenkins來實(shí)現(xiàn)CI,那么就用不了太多工作。

今天,我將向您展示如何使用以下框架/工具實(shí)現(xiàn)這樣的解決方案:

  • Spring Boot
  • Spring Boot Actuator
  • Spring Cloud Netflix Eureka
  • Jenkins CI

它是如何工作的

每一個(gè)包含Spring Boot Actuator庫的Spring Boot應(yīng)用程序都可以在/actuator/metrics端點(diǎn)下公開metric。許多有價(jià)值的metric都可以提供應(yīng)用程序運(yùn)行狀態(tài)的詳細(xì)信息。在討論自動(dòng)伸縮時(shí),其中一些metric可能特別重要:JVM、CPU metric、正在運(yùn)行的線程數(shù)和HTTP請(qǐng)求數(shù)。有專門的Jenkins流水線通過按一定頻率輪詢/actuator/metrics 端點(diǎn)來獲取應(yīng)用程序的指標(biāo)。如果監(jiān)控的任何metric【指標(biāo)】低于或高于目標(biāo)范圍,則它會(huì)啟動(dòng)新實(shí)例或使用另一個(gè)Actuator端點(diǎn)/actuator/shutdown來關(guān)閉一些正在運(yùn)行的實(shí)例。在此之前,我們需要知道當(dāng)前有那些實(shí)踐在提供服務(wù),只有這樣我們才能在需要的時(shí)候關(guān)閉空閑的實(shí)例或啟動(dòng)新的新例。


在討論了系統(tǒng)架構(gòu)之后,我們就可以繼續(xù)開發(fā)了。這個(gè)應(yīng)用程序需要滿足以下要求:它必須有公開的可以優(yōu)雅地關(guān)閉應(yīng)用程序和用來獲取應(yīng)用程序運(yùn)行狀態(tài)metric【指標(biāo)】的端點(diǎn),它需要在啟動(dòng)完成的同時(shí)就完成在Eureka的注冊(cè),在關(guān)閉時(shí)取消注冊(cè),最后,它還應(yīng)該能夠從空閑端口池中隨機(jī)獲取一個(gè)可用的端口。感謝Spring Boot,只需要約五分鐘,我們可以輕松地實(shí)現(xiàn)所有這些機(jī)制。

動(dòng)態(tài)端口分配

由于可以在一臺(tái)機(jī)器上運(yùn)行多個(gè)應(yīng)用程序?qū)嵗?,所以我們必須保證端口號(hào)不沖突。幸運(yùn)的是,Spring Boot為應(yīng)用程序提供了這樣的機(jī)制。我們只需要將application.yml中的server.port屬性設(shè)置為0。因?yàn)槲覀兊膽?yīng)用程序會(huì)在Eureka中注冊(cè),并且發(fā)送唯一的標(biāo)識(shí)instanceId,默認(rèn)情況下這個(gè)唯一標(biāo)識(shí)是將字段spring.cloud.client.hostname, spring.application.name和server.port拼接而成的。

示例應(yīng)用程序的當(dāng)前配置如下所示。

可以看到,我通過將端口號(hào)替換為隨機(jī)生成的數(shù)字來改變了生成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設(shè)置為'*'來暴露Actuator的端點(diǎn)?,F(xiàn)在,所有可用的指標(biāo)名稱列表都可以在/actuator/metrics端點(diǎn)中找到,每個(gè)指標(biāo)的詳細(xì)信息可以通過/actuator/metrics/{metricName}端點(diǎn)查看。

優(yōu)雅地停止應(yīng)用程序

除了查看metric端點(diǎn)外,Spring Boot Actuator還提供了停止應(yīng)用程序的端點(diǎn)。然而,與其他端點(diǎn)不同的是,缺省情況下,此端點(diǎn)是不可用的。我們必須把management.endpoint.shutdown.enabled設(shè)為true。在那之后,我們就可以通過發(fā)送一個(gè)POST請(qǐng)求到/actuator/shutdown端點(diǎn)來停止應(yīng)用程序了。

這種停止應(yīng)用程序的方法保證了服務(wù)在停止之前從Eureka服務(wù)器注銷。

啟用Eureka自動(dòng)發(fā)現(xiàn)

Eureka是最受歡迎的發(fā)現(xiàn)服務(wù)器,特別是使用Spring Cloud來構(gòu)建微服務(wù)的架構(gòu)。所以,如果你已經(jīng)有了微服務(wù),并且想要為他們提供自動(dòng)伸縮機(jī)制,那么Eureka將是一個(gè)自然的選擇。它包含每個(gè)應(yīng)用程序注冊(cè)實(shí)例的IP地址和端口號(hào)。為了啟用Eureka客戶端,您只需要將下面的依賴項(xiàng)添加到pom.xml中。

<dependency>
 <groupId>org.springframework.cloud</groupId>
 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

正如之前提到的,我們還必須保證通過客戶端應(yīng)用程序發(fā)送到Eureka服務(wù)器的instanceId的唯一性。在“動(dòng)態(tài)端口分配”中已經(jīng)描述了它。

下一步需要?jiǎng)?chuàng)建一個(gè)包含內(nèi)嵌Eureka服務(wù)器的應(yīng)用程序。為了實(shí)現(xiàn)這個(gè)功能,首先我們需要在pom.xml中添加下面這個(gè)依賴:

<dependency>
 <groupId>org.springframework.cloud</groupId>
 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

這個(gè)main類需要添加@EnableEurekaServer注解。

@SpringBootApplication
@EnableEurekaServer
public class DiscoveryApp {
 public static void main(String[] args) {
  new SpringApplicationBuilder(DiscoveryApp.class).run(args);
 }
}

默認(rèn)情況下,客戶端應(yīng)用程序嘗試使用8761端口連接Eureka服務(wù)器。我們只需要單獨(dú)的、獨(dú)立的Eureka節(jié)點(diǎn),因此我們將禁用注冊(cè),并嘗試從另一個(gè)Eureka服務(wù)器實(shí)例中獲取服務(wù)列表。

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容器來測(cè)試上面的自動(dòng)伸縮系統(tǒng),因此需要使用Eureka服務(wù)器來準(zhǔn)備和構(gòu)建image。

Dockerfile和image的定義如下所示。

我們可以使用命令docker build -t piomin/discovery-server:2.0來進(jìn)行構(gòu)建。

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"]

為彈性伸縮構(gòu)建一個(gè)Jenkins流水線

第一步是準(zhǔn)備Jenkins流水線,負(fù)責(zé)自動(dòng)伸縮。我們將創(chuàng)建Jenkins聲明式流水線,它每分鐘運(yùn)行一次。可以使用triggers指令配置執(zhí)行周期,它定義了自動(dòng)化觸發(fā)流水線的方法。我們的流水線將與Eureka服務(wù)器和每個(gè)使用Spring Boot Actuator的微服務(wù)中公開的metric端點(diǎn)進(jìn)行通信。

測(cè)試服務(wù)的名稱是EXAMPLE-SERVICE,它和定義在application.yml文件spring.application.name的屬性值(大寫字母)相同。被監(jiān)控的metric是運(yùn)行在Tomcat容器中的HTTP listener線程數(shù)。這些線程負(fù)責(zé)處理客戶端的HTTP請(qǐng)求。

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流水線

流水線的第一個(gè)階段負(fù)責(zé)獲取在discovery服務(wù)器上注冊(cè)的服務(wù)列表。Eureka發(fā)現(xiàn)了幾個(gè)HTTP API端點(diǎn)。其中一個(gè)是GET /eureka/apps/{serviceName},它返回一個(gè)給定服務(wù)名稱的所有活動(dòng)實(shí)例列表。我們正在保存運(yùn)行實(shí)例的數(shù)量和每個(gè)實(shí)例metric端點(diǎn)的URL。這些值將在流水線的下一個(gè)階段中被訪問。

下面的流水線片段可以用來獲取活動(dòng)應(yīng)用程序?qū)嵗斜怼tage名稱是Calculate。我們使用HTTP請(qǐng)求插件 來發(fā)起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["INSTANCE_COUNT"] = app.instance.size()
 app.instance.each {
 if (it.status == 'UP') {
  def address = "http://${it.ipAddr}:${it.port}"
  env["INSTANCE_${index++}"] = address
 }
 }
 }
 }
}
@NonCPS
def printXml(String text) {
 return new XmlSlurper(false, false).parseText(text)
}

下面是Eureka API對(duì)我們的微服務(wù)的示例響應(yīng)。響應(yīng)content-type是XML。

使用Spring Boot Actuator整合Jenkins流水線

Spring Boot Actuator使用metric來公開端點(diǎn),這使得我們可以通過名稱和選擇性地使用標(biāo)簽找到metric。在下面可見的流水線片段中,我試圖找到metric低于或高于閾值的實(shí)例。如果有這樣的實(shí)例,我們就停止循環(huán),以便進(jìn)入下一個(gè)階段,它執(zhí)行向下或向上的伸縮。應(yīng)用程序的IP地址是從帶有INSTANCE_前綴的流水線環(huán)境變量獲取的,這是在前一階段中被保存了下來的。

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"
}

關(guān)閉應(yīng)用程序?qū)嵗?/strong>

在流水線的最后一個(gè)階段,我們將關(guān)閉運(yùn)行的實(shí)例,或者根據(jù)在前一階段保存的結(jié)果啟動(dòng)新的實(shí)例。通過調(diào)用Spring Boot Actuator端點(diǎn)可以很容易執(zhí)行停止操作。在接下來的流水線片段中,首先選擇了Eureka實(shí)例。然后我們將發(fā)送POST請(qǐng)求到那個(gè)ip地址。

如果需要擴(kuò)展應(yīng)用程序,我們將調(diào)用另一個(gè)流水線,它負(fù)責(zé)構(gòu)建fat JAR并讓這個(gè)應(yīng)用程序在機(jī)器上跑起來。

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流水線的完整定義,它負(fù)責(zé)啟動(dòng)應(yīng)用程序的新實(shí)例。它先從git倉庫中拉取源代碼,然后使用Maven命令編譯并構(gòu)建二進(jìn)制的jar文件,最后通過在java -jar命令中添加Eureka服務(wù)器地址來運(yùn)行應(yīng)用程序。

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 &'
    }
   }
  }
 }
}

擴(kuò)展到多個(gè)機(jī)器

在前幾節(jié)中討論的算法只適用于在單個(gè)機(jī)器上啟動(dòng)的微服務(wù)。如果希望將它擴(kuò)展到更多的機(jī)器上,我們將不得不修改我們的架構(gòu),如下所示。每臺(tái)機(jī)器都有Jenkins代理運(yùn)行并與Jenkins master通信。如果想在選定的機(jī)器上啟動(dòng)一個(gè)微服務(wù)的新實(shí)例,我們就必須使用運(yùn)行在該機(jī)器上的代理來運(yùn)行流水線。此代理僅負(fù)責(zé)從源代碼構(gòu)建應(yīng)用程序并將其啟動(dòng)到目標(biāo)機(jī)器上。這個(gè)實(shí)例的關(guān)閉仍然是通過調(diào)用HTTP端點(diǎn)來完成。

假設(shè)我們已經(jīng)成功地在目標(biāo)機(jī)器上啟動(dòng)了一些代理,我們需要對(duì)流水線進(jìn)行參數(shù)化,以便能夠動(dòng)態(tài)地選擇代理(以及目標(biāo)機(jī)器)。

當(dāng)擴(kuò)容應(yīng)用程序時(shí),我們必須將代理標(biāo)簽傳遞給下游流水線。

build job:'spring-boot-run-pipeline', parameters:[string(name: 'agent', value:"slave-1")]

調(diào)用流水線具體由那個(gè)標(biāo)簽下的代理運(yùn)行,是由"${params.agent}"決定的。

pipeline {
 agent {
  label "${params.agent}"
 }
 stages { ... }
}

如果有一個(gè)以上的代理連接到主節(jié)點(diǎn),我們就可以將它們的地址映射到標(biāo)簽中。由于這一點(diǎn),我們能夠?qū)腅ureka服務(wù)器獲取的微服務(wù)實(shí)例的IP地址映射到與Jenkins代理的目標(biāo)機(jī)器上。

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 { ... }
}

總結(jié)

在本文中,我演示了如何使用Spring Boot Actuato metric來自動(dòng)伸縮Spring Boot應(yīng)用程序。使用Spring Boot提供的特性以及Spring Cloud Netflix Eureka和Jenkins,您就可以實(shí)現(xiàn)系統(tǒng)的自動(dòng)伸縮,而無需借助于任何其他第三方工具。本文也假設(shè)遠(yuǎn)程服務(wù)器上也是使用Jenkins代理來啟動(dòng)新的實(shí)例,但是您也可以使用Ansible這樣的工具來啟動(dòng)。如果您決定從Jenkins運(yùn)行Ansible腳本,那么將不需要在遠(yuǎn)程機(jī)器上啟動(dòng)Jenkins代理。

好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Java中HashMap里面key為null存放到哪

    Java中HashMap里面key為null存放到哪

    這篇文章主要介紹了Java中HashMap里面key為null存放到哪,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • Spring?BeanFactory工廠使用教程

    Spring?BeanFactory工廠使用教程

    Spring的本質(zhì)是一個(gè)bean工廠(beanFactory)或者說bean容器,它按照我們的要求,生產(chǎn)我們需要的各種各樣的bean,提供給我們使用。只是在生產(chǎn)bean的過程中,需要解決bean之間的依賴問題,才引入了依賴注入(DI)這種技術(shù)
    2023-02-02
  • JProfiler11使用教程之JVM調(diào)優(yōu)問題小結(jié)

    JProfiler11使用教程之JVM調(diào)優(yōu)問題小結(jié)

    這篇文章主要介紹了JProfiler11使用教程之JVM調(diào)優(yōu),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • Java中的線程生命周期核心概念

    Java中的線程生命周期核心概念

    這篇文章主要介紹了Java中的線程生命周期核心概念,通過使用一個(gè)快速的圖解展開文章內(nèi)容,需要的小伙伴可以參考一下
    2022-06-06
  • SpringMVC使用@Valid注解進(jìn)行數(shù)據(jù)驗(yàn)證的方法

    SpringMVC使用@Valid注解進(jìn)行數(shù)據(jù)驗(yàn)證的方法

    本篇文章主要介紹了SpringMVC使用@Valid注解進(jìn)行數(shù)據(jù)驗(yàn)證的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-02-02
  • Spring Boot與前端配合與Idea配置部署操作過程

    Spring Boot與前端配合與Idea配置部署操作過程

    這篇文章主要介紹了Spring Boot與前端配合與Idea配置部署的操作過程,本文圖文并茂給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2018-02-02
  • Java中常用的數(shù)據(jù)庫連接池_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java中常用的數(shù)據(jù)庫連接池_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    數(shù)據(jù)庫連接池負(fù)責(zé)分配、管理和釋放數(shù)據(jù)庫連接,它允許應(yīng)用程序重復(fù)使用一個(gè)現(xiàn)有的數(shù)據(jù)庫連接,而不是再重新建立一個(gè);釋放空閑時(shí)間超過最大空閑時(shí)間的數(shù)據(jù)庫連接來避免因?yàn)闆]有釋放數(shù)據(jù)庫連接而引起的數(shù)據(jù)庫連接遺漏
    2017-08-08
  • SpringBoot2使用Jetty容器操作(替換默認(rèn)Tomcat)

    SpringBoot2使用Jetty容器操作(替換默認(rèn)Tomcat)

    這篇文章主要介紹了SpringBoot2使用Jetty容器操作(替換默認(rèn)Tomcat),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • 如何使用Spring AOP的通知類型及創(chuàng)建通知

    如何使用Spring AOP的通知類型及創(chuàng)建通知

    這篇文章主要給大家介紹了關(guān)于如何使用Spring AOP的通知類型及創(chuàng)建通知的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring AOP具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • 關(guān)于application.yml數(shù)據(jù)庫配置方式

    關(guān)于application.yml數(shù)據(jù)庫配置方式

    這篇文章主要介紹了關(guān)于application.yml數(shù)據(jù)庫配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08

最新評(píng)論