- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章微服务领域Spring Boot自动伸缩的实现方法由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
前言 。
自动伸缩是每个人都想要的,尤其是在微服务领域。让我们看看如何在基于spring boot的应用程序中实现.
我们决定使用kubernetes、pivotal cloud foundry或hashicorp's nomad等工具的一个更重要的原因是为了让系统可以自动伸缩。当然,这些工具也提供了许多其他有用的功能,在这里,我们只是用它们来实现系统的自动伸缩。乍一看,这似乎很困难,但是,如果我们使用spring boot来构建应用程序,并使用jenkins来实现ci,那么就用不了太多工作.
今天,我将向您展示如何使用以下框架/工具实现这样的解决方案:
它是如何工作的 。
每一个包含spring boot actuator库的spring boot应用程序都可以在/actuator/metrics端点下公开metric。许多有价值的metric都可以提供应用程序运行状态的详细信息。在讨论自动伸缩时,其中一些metric可能特别重要:jvm、cpu metric、正在运行的线程数和http请求数。有专门的jenkins流水线通过按一定频率轮询/actuator/metrics 端点来获取应用程序的指标。如果监控的任何metric【指标】低于或高于目标范围,则它会启动新实例或使用另一个actuator端点/actuator/shutdown来关闭一些正在运行的实例。在此之前,我们需要知道当前有那些实践在提供服务,只有这样我们才能在需要的时候关闭空闲的实例或启动新的新例.
在讨论了系统架构之后,我们就可以继续开发了。这个应用程序需要满足以下要求:它必须有公开的可以优雅地关闭应用程序和用来获取应用程序运行状态metric【指标】的端点,它需要在启动完成的同时就完成在eureka的注册,在关闭时取消注册,最后,它还应该能够从空闲端口池中随机获取一个可用的端口。感谢spring boot,只需要约五分钟,我们可以轻松地实现所有这些机制.
动态端口分配 。
由于可以在一台机器上运行多个应用程序实例,所以我们必须保证端口号不冲突。幸运的是,spring boot为应用程序提供了这样的机制。我们只需要将application.yml中的server.port属性设置为0。因为我们的应用程序会在eureka中注册,并且发送唯一的标识instanceid,默认情况下这个唯一标识是将字段spring.cloud.client.hostname, spring.application.name和server.port拼接而成的.
示例应用程序的当前配置如下所示.
可以看到,我通过将端口号替换为随机生成的数字来改变了生成instanceid字段值的模板.
1
2
3
4
5
6
7
8
|
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.
1
2
3
4
|
<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中.
1
2
3
4
|
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-netflix-eureka-client</artifactid>
</dependency>
|
正如之前提到的,我们还必须保证通过客户端应用程序发送到eureka服务器的instanceid的唯一性。在“动态端口分配”中已经描述了它.
下一步需要创建一个包含内嵌eureka服务器的应用程序。为了实现这个功能,首先我们需要在pom.xml中添加下面这个依赖:
1
2
3
4
|
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-netflix-eureka-server</artifactid>
</dependency>
|
这个main类需要添加@enableeurekaserver注解.
1
2
3
4
5
6
7
|
@springbootapplication
@enableeurekaserver
public
class
discoveryapp {
public
static
void
main(string[] args) {
new
springapplicationbuilder(discoveryapp.
class
).run(args);
}
}
|
默认情况下,客户端应用程序尝试使用8761端口连接eureka服务器。我们只需要单独的、独立的eureka节点,因此我们将禁用注册,并尝试从另一个eureka服务器实例中获取服务列表.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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来进行构建.
1
2
3
4
5
6
7
8
|
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请求.
1
2
3
4
5
6
7
8
9
10
11
12
|
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连接.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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对我们的微服务的示例响应。响应content-type是xml.
使用spring boot actuator整合jenkins流水线 。
spring boot actuator使用metric来公开端点,这使得我们可以通过名称和选择性地使用标签找到metric。在下面可见的流水线片段中,我试图找到metric低于或高于阈值的实例。如果有这样的实例,我们就停止循环,以便进入下一个阶段,它执行向下或向上的伸缩。应用程序的ip地址是从带有instance_前缀的流水线环境变量获取的,这是在前一阶段中被保存了下来的.
1
2
3
4
5
6
7
8
9
10
11
|
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并让这个应用程序在机器上跑起来.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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服务器地址来运行应用程序.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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端点来完成.
假设我们已经成功地在目标机器上启动了一些代理,我们需要对流水线进行参数化,以便能够动态地选择代理(以及目标机器).
当扩容应用程序时,我们必须将代理标签传递给下游流水线.
1
|
build job:
'spring-boot-run-pipeline'
, parameters:[string(name:
'agent'
, value:
"slave-1"
)]
|
调用流水线具体由那个标签下的代理运行,是由"${params.agent}"决定的.
1
2
3
4
5
6
|
pipeline {
agent {
label
"${params.agent}"
}
stages { ... }
}
|
如果有一个以上的代理连接到主节点,我们就可以将它们的地址映射到标签中。由于这一点,我们能够将从eureka服务器获取的微服务实例的ip地址映射到与jenkins代理的目标机器上.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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/14010829/2299257 。
最后此篇关于微服务领域Spring Boot自动伸缩的实现方法的文章就讲到这里了,如果你想了解更多关于微服务领域Spring Boot自动伸缩的实现方法的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
背景: 我最近一直在使用 JPA,我为相当大的关系数据库项目生成持久层的轻松程度给我留下了深刻的印象。 我们公司使用大量非 SQL 数据库,特别是面向列的数据库。我对可能对这些数据库使用 JPA 有一
我已经在我的 maven pom 中添加了这些构建配置,因为我希望将 Apache Solr 依赖项与 Jar 捆绑在一起。否则我得到了 SolarServerException: ClassNotF
interface ITurtle { void Fight(); void EatPizza(); } interface ILeonardo : ITurtle {
我希望可用于 Java 的对象/关系映射 (ORM) 工具之一能够满足这些要求: 使用 JPA 或 native SQL 查询获取大量行并将其作为实体对象返回。 允许在行(实体)中进行迭代,并在对当前
好像没有,因为我有实现From for 的代码, 我可以转换 A到 B与 .into() , 但同样的事情不适用于 Vec .into()一个Vec . 要么我搞砸了阻止实现派生的事情,要么这不应该发
在 C# 中,如果 A 实现 IX 并且 B 继承自 A ,是否必然遵循 B 实现 IX?如果是,是因为 LSP 吗?之间有什么区别吗: 1. Interface IX; Class A : IX;
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在阅读标准haskell库的(^)的实现代码: (^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 a -> b ->a expo x0
我将把国际象棋游戏表示为 C++ 结构。我认为,最好的选择是树结构(因为在每个深度我们都有几个可能的移动)。 这是一个好的方法吗? struct TreeElement{ SomeMoveType
我正在为用户名数据库实现字符串匹配算法。我的方法采用现有的用户名数据库和用户想要的新用户名,然后检查用户名是否已被占用。如果采用该方法,则该方法应该返回带有数据库中未采用的数字的用户名。 例子: “贾
我正在尝试实现 Breadth-first search algorithm , 为了找到两个顶点之间的最短距离。我开发了一个 Queue 对象来保存和检索对象,并且我有一个二维数组来保存两个给定顶点
我目前正在 ika 中开发我的 Python 游戏,它使用 python 2.5 我决定为 AI 使用 A* 寻路。然而,我发现它对我的需要来说太慢了(3-4 个敌人可能会落后于游戏,但我想供应 4-
我正在寻找 Kademlia 的开源实现C/C++ 中的分布式哈希表。它必须是轻量级和跨平台的(win/linux/mac)。 它必须能够将信息发布到 DHT 并检索它。 最佳答案 OpenDHT是
我在一本书中读到这一行:-“当我们要求 C++ 实现运行程序时,它会通过调用此函数来实现。” 而且我想知道“C++ 实现”是什么意思或具体是什么。帮忙!? 最佳答案 “C++ 实现”是指编译器加上链接
我正在尝试使用分支定界的 C++ 实现这个背包问题。此网站上有一个 Java 版本:Implementing branch and bound for knapsack 我试图让我的 C++ 版本打印
在很多情况下,我需要在 C# 中访问合适的哈希算法,从重写 GetHashCode 到对数据执行快速比较/查找。 我发现 FNV 哈希是一种非常简单/好/快速的哈希算法。但是,我从未见过 C# 实现的
目录 LRU缓存替换策略 核心思想 不适用场景 算法基本实现 算法优化
1. 绪论 在前面文章中提到 空间直角坐标系相互转换 ,测绘坐标转换时,一般涉及到的情况是:两个直角坐标系的小角度转换。这个就是我们经常在测绘数据处理中,WGS-84坐标系、54北京坐标系
在软件开发过程中,有时候我们需要定时地检查数据库中的数据,并在发现新增数据时触发一个动作。为了实现这个需求,我们在 .Net 7 下进行一次简单的演示. PeriodicTimer .
二分查找 二分查找算法,说白了就是在有序的数组里面给予一个存在数组里面的值key,然后将其先和数组中间的比较,如果key大于中间值,进行下一次mid后面的比较,直到找到相等的,就可以得到它的位置。
我是一名优秀的程序员,十分优秀!