作者:vivo 互联网服务器团队- Wu Qinghua

本文从目前业界实现Jenkins的高可用的实现方案,分析各方案的优缺点,引入vivo目前使用的Jenkins高可用方案,以及目前Jenkins资源的调度方案的设计实践和目前的落地运行效果。

一、前言

现在的企业很多都在用Jenkins做持续集成,各个业务端都依靠Jenkins,vivo Devops也是使用Jenkins来进行持续构建,部署Jenkins服务时如何保障服务的高可用变得尤为重要。

下面是目前Jenkins存在的一些问题

  1. Jenkins本身是单体的,即只能有一个Jenkins Master。虽然你也可以在多台机器上部署多个Jenkins Master,但这些Master之间没有联系,都是各自把任务交给手下的slave去执行,没有任何交集。也许某个master下的slave很忙,而另一个master下的slave却很闲,资源得不到充分利用。

  2. 当其中一个slave宕机之后,该slave上的运行的job任务没有版本重新进行分配,需要用户重新执行。并且slave节点离线之后没有通知管理员。

  3. 当系统业务量比较大的时候业务请求集中在Jenkins Master上,会对Jenkins造成压力,甚至的造成Jenkins服务不可用。

  4. 当有job任务在jenkins Master上队列排队的时候,Jenkins Master宕机后,队列任务不可持久化。

  5. Jenkins Workspace没有自动清理功能,会导致磁盘空间不足,任务执行不了的情况。

基于以上情况,vivo Devops对Jenkins的部署架构进行优化搭建,并且配套了一套Jenkins资源调度系统用于管理Jenkins资源。

二、业界实现

目前业界也包含一些Jenkins 高可用的设计方式,但是并不能完全的满足解决上述问题,比如:

2.1 方案一  Gearman + Jenkins

这是OpenStack团队使用的方案。这个方案使用了gearman, gearman是个任务分发框架。

需要在每个Master上安装好gearman的插件,并配置好能连接到gearman server,同时在每个Master必须建立相同的job。

之后运行任务的流程如下:

  1. gearman worker运行在各个Jenkins Master中等待gearman server分发任务;

  2. gearman client向gearman server发出运行job的请求;

  3. gearman server通知各个gearman worker有任务拉,第一个闲着的worker会接受任务,如果所有的worker都忙,则放入gearman的任务队列,得worker空闲时再分配;

  4. gearman worker闲下来后会从任务队列里取job来执行,执行完之后,将结果发回给gearman server;

  5. gearman server将结果返回给 gearman client。

优点:

这样各个salver资源可以得到充分利用,某个master挂掉另外的master可以继续服务。

弊端:

每个master的slave必须配置一致,否则会造成job调度错误,同时会造成一些资源的浪费。当一个master出现问题,该master的任务不会进行自动重新分配。

2.2 方案二 改造Jenkins的文件存储方式

目前Jenkins的配置文件都是直接在硬盘上以文件形式存储的,你在JENKINS_HOME的个文件夹下能看到各种.xml文件。有些公司在Jenkins上进行二次开发,将Jenkins的数据存储方式改为数据库存储,这样前端可以起多个Jenkins服务,后端连相同的数据库即可。数据库也有比较成熟的高可用方案。

优点:   可以达到Jenkins的高可用也就是某个master挂掉另外的master可以继续服务。

弊端:需要对Jenkins进行二次开发,使用数据库会降低读取资源效率下降。

2.3 方案三 最简单的Jenkins一主一备模式

平时让Jenkins A机器提供服务,并使用SCM Sync configuration plugin保存数据,JenkinsA机器修改配置后触发Jenkins B更新配置,一旦Jenkins A出现问题挂掉后,切换到备机Jenkins B上。

优点:   可以达到Jenkins的高可用,当master宕机后会进行切换到备机上。

弊端:   会有一批Jenkins备机存在资源浪费,切换master时间过长,会导致有段时间Jenkins服务不可用。

三、vivo Jenkins Scheduler系统目标

由于目前业界的一些实现还不能完全的满足我们目前的需求,所以我们进行了vivo jenkins scheduler系统的设计与实现。该系统需要达到如下的目的:

  1. 提升整个构建服务可靠性时长。

    保证jenkins集群的高可用,解决目前master-slave的单点问题,保证整个构建服务的可靠性时长。

  2. 降低灾难时服务恢复时长。

    ①提供精准流控方式,在jenkins构建出现请求量过高的时候可以进行流控和持久化操作,减少对目前系统的冲击。

    ②当系统压力减少后,放开流控可以快速的对堆积的请求进行分配执行。

  3. 有效分配任务至各个子节点,保证资源的有效利用。

  4. 能保证灾难时的及时切换任务至可用节点上,同时能快速的通知管理员进行处理。

  5. 能进行数据的可视化分析,能提供一系列帮助改善开发效率的视图,比如构建时长报表、构建量报表等。

四、 vivo Jenkins Scheduler设计

该系统我们从两大部分进行了设计,首先,我们不采用原生的Jenkins部署方案,而是采用全master的方式。第二,设计并开发了一套用于管理Jenkins集群的调度系统。

五、底层 Jenkins 工具部署方案

不采用目前单master的搭建方案,采用多master的搭建方案,master下不进行挂载slave机器,任务直接有master进行处理,master之间的关系、任务分配、离线、插件安装等由调度系统进行管理。这样由于vivo Jenkins Scheduler系统为高可用的,解决了目前Jenkins的单点问题。

六、系统架构图

七、系统说明

7.1 API-Gateway

主要提供系统的外部请求,网关系统,功能包含:

  • 权限校验:校验用户发送集群管理系统的请求的权限。

  • 智能路由:接收外部一切请求,并转发到后端的外服上去。

  • 限流:与监控线程配合(当构建请求达到某个阈值时),进行限流操作。

  • API日志统一收集:类似于一个aspect切面,记录接口的进入和出去时的相关日志。

  • 数据处理:对请求的参数进行数据的转换处理。

7.2 事件中心

是整个系统通信调用的主要模块,采用的是Spring的Event机制实现,主要核心事件如下:

  1. Jenkins注册事件

    (EVENT_REGIST_JENKINS)

    Jenkins启动后,通过自定的插件会向系统发送注册请求时,系统接收到后会触发Jenkins管理模块将Jenkins的信息注册至调度系统中。

  2. Jenkins宕机事件 

    (EVENT_DOWN_JENKINS)    :

    监控管理轮询检查Jenkins状态,当发现有Jenkins宕机的情况会触发该事件,Jenkins管理模块处理将Jenkins的信息状态设置为不可用状态,从而是任务不能分配至该台jenkins。

  3. 任务从分配事件  (EVENT_JOB_REDO) :

    当Jenkins宕机后,如果该台jenkins上存在未执行完的任务时候,由job监控模块触发,job管理莫管处理,会对该Jenkins上未执行的job进行重新分配。

  4. 任务接受事件  (EVENT_JOB_RECIVE) :

    当job管理模块接受到创建请求,会触发该事件,由job管理模块放入Redis执行队列。

  5. 任务执行事件  (EVENT_JOB_EXECUTE) :

    job管理模块中的执行线程(10s执行一次,会从Redis队列中弹出任务),弹出任务后触发该事件,由调度中心选取合适的jenkins进行执行。

7.3 调度中心

是整个系统的核心模块,主要的功能是进行执行job时候能选取合适的jenkins进行处理任务,包含两个核心算法:

7.3.1 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用来执行任务:

7.3.2 Jenkins选取算法

当Jenkins分组好了后,我们接受到执行的job的信息就可以使用Jenkins选取算法进行快速的选取合适的Jenkins进行处理job,如下图所示。

其中label子线程、语言子线程……就是我们上面的Jenkins分组的维度,有多少维度,那么这里就会有多少子线程处理。

构建任务进入主线程,然后主线程会按照分组维度分组操作并进行过滤,然后获取到每个分组中合适的Jenkins,再进行取交集(这个时候就获取到可以执行该构建任务的Jenkins了),在判断是否需要经过可选策略,最终得到Jenkins。

7.4 流控管理&队列管理

调度系统中的的任务接受采用的是队列的方式实现,当系统请求量达到阀后,系统将不会进入Redis队列,会将请求持久化至MySQL。后续如果有请求过来,job管理模块会检查数据库MySQL中是否有请求,如果有请求,会将请求放入Redis队列,如果没有请求就会将当前请求放入Redis队列,具体流程如下:

其中基于Redis实现的消息队列的时序图如下:

7.5 回调中心

该模块主要是监控任务的状态,当任务开始执行、中断执行、执行成功、执行失败的时候进行通知业务并存储数据,用于保存构建记录,方便后续数据的统计,用来完成数据的可视化。

八、实施效果

目前该系统已经投入生产环境运行,Jenkins任务已采用调度系统进行调度执行,运行稳定,运行效果。

九、后续展望

随着vivo Jenkins 调度系统的功能慢慢完善,Jenkins的机器也越来越多,目前还大多数运行在虚拟机上,从资源利用率和业务发布效率来看,未来的业务发布形态将会是以容器为主。目前公司也在大力发展k8s的容器生态建设,

所以我们希望将Jenkins工具后期进行容器化、池化,在提高资源利用率和发布效率的同时也可以为用户提供可靠的、简洁的、稳定调度执行。

vivo 自研Jenkins资源调度系统设计与实践的更多相关文章

  1. vivo 商品中台的可视化微前端实践

    一.背景 在电商领域内,商品是一个重要组成部分,与其对应的商品管理系统,则负责商品的新建.编辑.复制等功能.随着商品管理系统的成熟稳定和业务上的扩展需求,催化出了商品中台的诞生.它可以将现有商品功能最 ...

  2. vivo大数据日志采集Agent设计实践

    作者:vivo 互联网存储技术团队- Qiu Sidi 在企业大数据体系建设过程中,数据采集是其中的首要环节.然而,当前行业内的相关开源数据采集组件,并无法满足企业大规模数据采集的需求与有效的数据采集 ...

  3. Java生鲜电商平台-SpringCloud分布式请求跟踪系统设计与实践

    Java生鲜电商平台-SpringCloud分布式请求跟踪系统设计与实践 Java生鲜电商平台微服务现状 某个服务挂了,导致上游大量报警,如何快速定位哪个服务出问题? 某个核心挂了,导致大量报错,如何 ...

  4. vivo 云原生容器探索和落地实践

    作者:vivo 互联网容器团队- Pan Liangbiao 本文根据潘良彪老师在"2022 vivo开发者大会"现场演讲内容整理而成.公众号回复[2022 VDC]获取互联网技术 ...

  5. 持续集成高级篇之Jenkins资源调度

    系列目录 之前的示例我们主要关注点在于功能的实现,都是在一个节点的完成了.有了多个节点后,必须涉及到资源的调度问题.本节我们讲解在创建任务时与资源调度的有关选项以及一些平时没有注意到的但在生产环境需要 ...

  6. 一文看懂 K8s 日志系统设计和实践

    上一篇中我们介绍了为什么需要一个日志系统.为什么云原生下的日志系统如此重要以及云原生下日志系统的建设难点,相信DevOps.SRE.运维等同学看了是深有体会的.本篇文章单刀直入,会直接跟大家分享一下如 ...

  7. vivo 服务端监控架构设计与实践

    一.业务背景 当今时代处在信息大爆发的时代,信息借助互联网的潮流在全球自由的流动,产生了各式各样的平台系统和软件系统,越来越多的业务也会导致系统的复杂性. 当核心业务出现了问题影响用户体验,开发人员没 ...

  8. vivo互联网机器学习平台的建设与实践

    vivo 互联网产品团队 - Wang xiao 随着广告和内容等推荐场景的扩展,算法模型也在不断演进迭代中.业务的不断增长,模型的训练.产出迫切需要进行平台化管理.vivo互联网机器学习平台主要业务 ...

  9. 基于GitLab+Jenkins的DevOps赋能实践

    随着微服务.中台架构的兴起,DevOps也变得非常关键,毕竟是一些基础设施层面的建设,如果搞好了对后面的研发工作会有很大的效率提升.关于DevOps本身的概念,网上已经非常多了,在园子里随便搜索一些都 ...

  10. 从自动化到智能化,网易杭研的AIOps探索与实践

    在大数据时代下,我们借助机器学习.数据仓库.大数据平台等大数据技术手段,将运维产生的数据进行分析.处理,得出最佳运维策略,以期实现对故障的事先干预,将风险降低到最低,从而降低运维成本,提升运维效率,最 ...

随机推荐

  1. perl reverse函数

    转载至  Perl - 列表 - reverse 操作 reverse(逆转)操作将输入的一串列表(可能是数组)按相反的顺序返回. my @arr=("Head_PMA1",&qu ...

  2. ES6高级编程(一)

    一.JavaScript概要 1.1.JavaScript组成 JavaScript主要由三部分构成,分别是ECMAScript.DOM与BOM ECMAScript定义了该语言的语法.类型.语句.关 ...

  3. 大数据下一代变革之必研究数据湖技术Hudi原理实战双管齐下-上

    @ 目录 概述 定义 发展历史 特性 使用场景 编译安装 编译环境 编译Hudi 关键概念 TimeLine(时间轴) File Layouts(文件布局) 索引 表类型 查询类型 概述 定义 Apa ...

  4. 《不一般的 DFT》阅读随笔

    感觉上前置知识是毛啸 16 年的论文? 我手头也有,到时候发现有 at 到的地方就插一嘴说一句 srds 先这篇是因为有纸质版的这篇 感觉上大篇幅在讲复杂度模数大小相关的做法. 1 引言 我这写个啥? ...

  5. 【Java SE】Day02 数据类型转换、运算符、方法入门

    一.数据类型转换 1.自动转换 取值范围小在运算时会提升为取值范围大的类型 byte+int=int int+double=double 转换规则:byte.short.char-->int-- ...

  6. 【面试题总结】JVM01-组成及垃圾回收

    一.概念 1.JVM组成及作用 (1)组成:类加载器.运行时数据区(Java内存模型).执行引擎.本地库接口 (2)作用: 类加载器(ClassLoader)把class文件转换成字节码: 运行时数据 ...

  7. DOM(原生js事件绑定)

    一:原生js事件绑定 1.开关灯案例 <!DOCTYPE html> <html lang="en"> <head> <meta char ...

  8. 高性能 Jsonpath 框架,Snack3 3.2.50 发布

    Snack3,一个高性能的 JsonPath 框架 借鉴了 Javascript 所有变量由 var 申明,及 Xml dom 一切都是 Node 的设计.其下一切数据都以ONode表示,ONode也 ...

  9. TortoiseGit (小乌龟安装配置及使用)

    TortoiseGit 使用教程 (图文详解) 第一步 下载Git:下载地址:https://gitforwindows.org 第二步 下载TortoiseGit 以及 汉化包 (安装教程这里就不详 ...

  10. 深入理解 Linux 物理内存分配全链路实现

    前文回顾 在上篇文章 <深入理解 Linux 物理内存管理>中,笔者详细的为大家介绍了 Linux 内核如何对物理内存进行管理以及相关的一些内核数据结构. 在介绍物理内存管理之前,笔者先从 ...