- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
作者:vivo 互联网服务器团队- Wu Qinghua 。
本文从目前业界实现Jenkins的高可用的实现方案,分析各方案的优缺点,引入vivo目前使用的Jenkins高可用方案,以及目前Jenkins资源的调度方案的设计实践和目前的落地运行效果.
现在的企业很多都在用Jenkins做持续集成,各个业务端都依靠Jenkins,vivo Devops也是使用Jenkins来进行持续构建,部署Jenkins服务时如何保障服务的高可用变得尤为重要.
下面是目前Jenkins存在的 一些问题 .
Jenkins本身是单体的,即只能有一个Jenkins Master。虽然你也可以在多台机器上部署多个Jenkins Master,但这些Master之间没有联系,都是各自把任务交给手下的slave去执行,没有任何交集。也许某个master下的slave很忙,而另一个master下的slave却很闲,资源得不到充分利用.
当其中一个slave宕机之后,该slave上的运行的job任务没有版本重新进行分配,需要用户重新执行。并且slave节点离线之后没有通知管理员.
当系统业务量比较大的时候业务请求集中在Jenkins Master上,会对Jenkins造成压力,甚至的造成Jenkins服务不可用.
当有job任务在jenkins Master上队列排队的时候,Jenkins Master宕机后,队列任务不可持久化.
Jenkins Workspace没有自动清理功能,会导致磁盘空间不足,任务执行不了的情况.
基于以上情况,vivo Devops对Jenkins的部署架构进行优化搭建,并且配套了一套Jenkins资源调度系统用于管理Jenkins资源.
目前业界也包含一些Jenkins 高可用的设计方式,但是并不能完全的满足解决上述问题,比如:
这是OpenStack团队使用的方案。这个方案使用了gearman, gearman是个任务分发框架.
需要在每个Master上安装好gearman的插件,并配置好能连接到gearman server,同时在每个Master必须建立相同的job.
之后运行任务的流程如下:
gearman worker运行在各个Jenkins Master中等待gearman server分发任务; 。
gearman client向gearman server发出运行job的请求; 。
gearman server通知各个gearman worker有任务拉,第一个闲着的worker会接受任务,如果所有的worker都忙,则放入gearman的任务队列,得worker空闲时再分配; 。
gearman worker闲下来后会从任务队列里取job来执行,执行完之后,将结果发回给gearman server,
gearman server将结果返回给 gearman client.
优点:
这样各个salver资源可以得到充分利用,某个master挂掉另外的master可以继续服务.
弊端:
每个master的slave必须配置一致,否则会造成job调度错误,同时会造成一些资源的浪费。当一个master出现问题,该master的任务不会进行自动重新分配.
目前Jenkins的配置文件都是直接在硬盘上以文件形式存储的,你在JENKINS_HOME的个文件夹下能看到各种.xml文件。有些公司在Jenkins上进行二次开发,将Jenkins的数据存储方式改为数据库存储,这样前端可以起多个Jenkins服务,后端连相同的数据库即可。数据库也有比较成熟的高可用方案.
优点: 可以达到Jenkins的高可用也就是某个master挂掉另外的master可以继续服务.
弊端: 需要对Jenkins进行二次开发,使用数据库会降低读取资源效率下降.
平时让Jenkins A机器提供服务,并使用SCM Sync configuration plugin保存数据,JenkinsA机器修改配置后触发Jenkins B更新配置,一旦Jenkins A出现问题挂掉后,切换到备机Jenkins B上.
优点: 可以达到Jenkins的高可用,当master宕机后会进行切换到备机上.
弊端: 会有一批Jenkins备机存在资源浪费,切换master时间过长,会导致有段时间Jenkins服务不可用.
由于目前业界的一些实现还不能完全的满足我们目前的需求,所以我们进行了vivo jenkins scheduler系统的设计与实现。该系统需要达到如下的目的:
提升整个构建服务可靠性时长.
保证jenkins集群的高可用,解决目前master-slave的单点问题,保证整个构建服务的可靠性时长.
降低灾难时服务恢复时长.
①提供精准流控方式,在jenkins构建出现请求量过高的时候可以进行流控和持久化操作,减少对目前系统的冲击.
②当系统压力减少后,放开流控可以快速的对堆积的请求进行分配执行.
有效分配任务至各个子节点, 保证资源的有效利用.
能保证灾难时的及时切换任务至可用节点上 ,同时能快速的通知管理员进行处理.
能进行数据的可视化分析 ,能提供一系列帮助改善开发效率的视图,比如构建时长报表、构建量报表等.
该系统我们从两大部分进行了设计,首先,我们不采用原生的Jenkins部署方案,而是采用全master的方式。第二,设计并开发了一套用于管理Jenkins集群的调度系统.
不采用目前单master的搭建方案,采用多master的搭建方案,master下不进行挂载slave机器,任务直接有master进行处理,master之间的关系、任务分配、离线、插件安装等由调度系统进行管理。这样由于vivo Jenkins Scheduler系统为高可用的,解决了目前Jenkins的单点问题.
主要提供系统的外部请求,网关系统,功能包含:
权限校验: 校验用户发送集群管理系统的请求的权限.
智能路由: 接收外部一切请求,并转发到后端的外服上去.
限流: 与监控线程配合(当构建请求达到某个阈值时),进行限流操作.
API日志统一收集: 类似于一个aspect切面,记录接口的进入和出去时的相关日志.
数据处理: 对请求的参数进行数据的转换处理.
是整个系统通信调用的主要模块,采用的是Spring的Event机制实现,主要核心事件如下:
Jenkins注册事件 。
(EVENT_REGIST_JENKINS) :
Jenkins启动后,通过自定的插件会向系统发送注册请求时,系统接收到后会触发Jenkins管理模块将Jenkins的信息注册至调度系统中.
Jenkins宕机事件 。
(EVENT_DOWN_JENKINS) : 。
监控管理轮询检查Jenkins状态,当发现有Jenkins宕机的情况会触发该事件,Jenkins管理模块处理将Jenkins的信息状态设置为不可用状态,从而是任务不能分配至该台jenkins.
任务从分配事件 (EVENT_JOB_REDO) : 。
当Jenkins宕机后,如果该台jenkins上存在未执行完的任务时候,由job监控模块触发,job管理莫管处理,会对该Jenkins上未执行的job进行重新分配.
任务接受事件 (EVENT_JOB_RECIVE)
当job管理模块接受到创建请求,会触发该事件,由job管理模块放入Redis执行队列.
任务执行事件 (EVENT_JOB_EXECUTE) : 。
job管理模块中的执行线程(10s执行一次,会从Redis队列中弹出任务),弹出任务后触发该事件,由调度中心选取合适的jenkins进行执行.
是整个系统的核心模块,主要的功能是进行执行job时候能选取合适的jenkins进行处理任务,包含两个核心算法:
每台Jenkins都可以使用标签的方式,打上多个标签,比如Jenkins可以构建Java程序,使用的构建工具可以是maven和gradle,这个时候我们就可以给其打上Java、maven、gradle三个标签.
标签的维度主要有以下几个:
标签配置: 判断构建配置是否配置了标签,根据标签选择对应标签的Jenkins,比如配置了(docker等).
构建语言: 根据构建配置的语言,比如Java、C++、Python、Go等.
构建工具和版本: 比如Maven、gradle、Ant,Cmark、Blade等.
JDK版本: 比如JDK7、JDK8等.
Go语言版本: 比如1.15.x.、1.16.x等.
GCC版本: 如6.x、4.x等.
Python版本: 2.x、3.x等.
是否存活: 判断Jenkins是否存活,如果宕机直接过滤.
(可选策略)选择执行过该job的Jenkins,减少下载代码的过程: (第一次构建还是会比较慢,可以采用预执行的方式,在配置构建配置的时候,就预先执行一次,这样在用户执行的时候就使用该job执行过得workspace,减少代码下载的时间).
(可选策略)根据job的构建的平均构建时长 ,如果构建时长达到某个配置阈值时,优先选择构建器空闲多的Jenkins进行执行,并指出Jenkins的锁定功能。其他的job不允许分配上来.
。
如果我们给Jenkins打上标签,那么我们就可以使用标签为维度将Jenkins进行分组,并且存入至Redis中缓存,方便后续选取Jenkins用来执行任务:
当Jenkins分组好了后,我们接受到执行的job的信息就可以使用Jenkins选取算法进行快速的选取合适的Jenkins进行处理job,如下图所示.
。
其中label子线程、语言子线程……就是我们上面的Jenkins分组的维度,有多少维度,那么这里就会有多少子线程处理.
。
构建任务进入主线程,然后主线程会按照分组维度分组操作并进行过滤,然后获取到每个分组中合适的Jenkins,再进行取交集(这个时候就获取到可以执行该构建任务的Jenkins了),在判断是否需要经过可选策略,最终得到Jenkins.
。
调度系统中的的任务接受采用的是队列的方式实现,当系统请求量达到阀后,系统将不会进入Redis队列,会将请求持久化至MySQL。后续如果有请求过来,job管理模块会检查数据库MySQL中是否有请求,如果有请求,会将请求放入Redis队列,如果没有请求就会将当前请求放入Redis队列,具体流程如下
其中基于Redis实现的消息队列的时序图如下
该模块主要是监控任务的状态,当任务开始执行、中断执行、执行成功、执行失败的时候进行通知业务并存储数据,用于保存构建记录,方便后续数据的统计,用来完成数据的可视化.
目前该系统已经投入生产环境运行,Jenkins任务已采用调度系统进行调度执行,运行稳定,运行效果.
。
。
随着vivo Jenkins 调度系统的功能慢慢完善,Jenkins的机器也越来越多,目前还大多数运行在虚拟机上,从资源利用率和业务发布效率来看,未来的业务发布形态将会是以容器为主。目前公司也在大力发展k8s的容器生态建设, 。
所以我们希望将Jenkins工具后期进行容器化、池化,在提高资源利用率和发布效率的同时也可以为用户提供可靠的、简洁的、稳定调度执行.
最后此篇关于vivo自研Jenkins资源调度系统设计与实践的文章就讲到这里了,如果你想了解更多关于vivo自研Jenkins资源调度系统设计与实践的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
本文分享自华为云社区《大模型LLM之分布式训练》,作者: 码上开花_Lancer。 随着语言模型参数量和所需训练数据量的急速增长,单个机器上有限的资源已无法满足大语言模型训练的要求。需要设计分布式训
本文分享自华为云社区《五大基础算法--动态规划法》,作者: 大金(内蒙的)。 一、基本概念 动态规划法,和分治法极其相似。区别就是,在求解子问题时,会保存该子问题的解,后面的子问题求解时,可以直接拿来
pip install scp pip install pexpect 测试代码: import os import stat import paramiko # 用于调用scp命令 def s
我目前正在实现“ token ”REST 服务。 token 只是一个字符串,由一些参数构建而成,然后经过哈希处理并在一定时间后过期。 我想在我的 REST 服务中有一个可以验证 token 的端点,
打开软删除后,我在客户端上添加一条记录,推送,删除添加的记录推送,然后尝试使用与初始记录相同的主键添加新记录(然后推送),我得到一个异常(exception)。 EntityDomainManager
打开软删除后,我在客户端上添加一条记录,推送,删除添加的记录推送,然后尝试使用与初始记录相同的主键添加新记录(然后推送),我得到一个异常(exception)。 EntityDomainManager
我有一个应用程序,每 x 秒接收一次天气信息。我想将此数据保存到 XML 文件中。 我应该为每个天气通知创建一个新的 XML 文件,还是将每个通知附加到同一个 XML 文件中?我不确定 XML 标准的
我猜我们大多数人都必须在某个时候处理这个问题,所以我想我会问这个问题。 当您的 BLL 中有很多集合并且您发现自己一遍又一遍地编写相同的旧内联(匿名)谓词时,显然有必要进行封装,但实现封装的最佳方
我有一些 c# 代码已经运行了一段时间了..我不得不说,虽然我了解 OO 原则的基础知识,但显然有不止一种方法可以给猫剥皮(尽管我讨厌那个短语!)。 因此,我有一个基本抽象类作为基本数据服务类,如下所
我设计了一个 SQL 数据库系统(使用 Postgre),我有一个问题,即创建一个关系/引用的常见做法是什么,这种关系/引用即使在引用的对象被删除时也能持续存在。 比如有一个UserORM,还有Act
我们的目标是搜索用户输入的字符串并计算在其中找到多少元音。不幸的是我被困在这里,有什么帮助吗? def numVowels(s): vowels= "AEIOUaeiou" if s
我有一个适用于我的“items”int 数组的旋转函数。下面的代码完成了它,除了我不必要地传输值。我正在努力实现“就地”轮换。我的意思是 ptrs 会递增或递减,而不是从数组中获取值。我需要通过这种方
我有一个 json 存储在我的应用程序文档文件夹中,我需要在我的所有 View 中使用它。我正在加载 json 并将其添加到每个 View 中的 NSMutableArray。但现在我了解到,我可以将
我用 C++ 开始了一个项目。这种语言的内存管理对我来说是新的。 我过去常常使用 new () 创建对象,然后传递指针,虽然它可以工作,但调试起来很痛苦,人们看到代码时会用有趣的眼神看着我。我为它没有
已结束。 这个问题是 off-topic .它目前不接受答案。 想要改进这个问题? Update the question所以它是on-topic堆栈溢出。 关闭 10 年前。 Improve thi
保持类松散耦合是编写易于理解、修改和调试的代码的一个重要方面——我明白这一点。然而,作为一个新手,几乎任何时候我都会超越我所苦苦挣扎的最简单的例子。 我或多或少地了解如何将字符串、整数和简单数据类型封
我发现我需要编写大量重复代码,因为我无法从其他 Controller 调用函数。例如,这里新闻提要内容在我的代码中重复,我对一个 Controller 做一些特定的事情,然后需要像这样加载我的新闻提要
假设需要一种数字数据类型,其允许值在指定范围内。更具体地说,假设要定义一个整数类型,其最小值为0,最大值为5000。这种情况在很多情况下都会出现,例如在对数据库数据类型,XSD数据类型进行建模时。 在
假设我想循环整个数组来访问每个元素。使用 for 循环、for...in 循环或 for...of 循环是 JavaScript 开发人员的标准做法吗? 例如: var myArray = ["app
我有一个旧的 SL4/ria 应用程序,我希望用 Breeze 取代它。我有一个关于内存使用和缓存的问题。我的应用程序加载工作列表(一个典型的用户可以访问大约 1,000 个这些工作)。此外,还有很多
我是一名优秀的程序员,十分优秀!