mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2026-05-11 04:04:34 +08:00
mod
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
<audio id="audio" title="12 | 持续交付知易行难,想做成这事你要理解这几个关键点" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/78/c0/782ed922d61b4c431a6410622024c4c0.mp3"></audio>
|
||||
|
||||
前面几篇文章,我们介绍了非常基础的运维建设环节。如果我们想要这些运维基础建设发挥出更大的作用和价值,就需要针对运维场景进行**场景化设计和自动化**,让效率和稳定性真正提升上来。也就是说,把基础的事情做好之后,我们就要进入效率提升的**运维场景自动化阶段**了。
|
||||
|
||||
在这一阶段,我个人的经验和建议是,**首先要把持续交付做好**。
|
||||
|
||||
为什么要先做持续交付?如果说我们完成了一些运维职责范围内的自动化工具,提升的是运维效率的话,那么,**做持续交付就是提升整个研发体系效率的关键**。
|
||||
|
||||
做持续交付的价值表现在哪里?
|
||||
|
||||
持续交付覆盖了应用的整个生命周期,涉及产品、开发、测试、运维以及项目管理等相关方面。**从生命周期出发,自然就会牵出整个自动化的全貌,就会有从全局着眼的规划设计**,这时无论是在开发还是运维过程中存在的问题,都会完完整整地暴露出来。那么,应该以什么样的主线开展?各方应该如何配合?应该以怎样的优先级明确任务?这些问题就都清楚了。同时,也避免了各个环节只把注意力放在各自职责范围内的事情上,而忽略了整体的配合。所以,**做好持续交付,对于整个研发体系意义重大**。
|
||||
|
||||
我们面临的实际场景是怎样的?
|
||||
|
||||
我们知道,随着业务复杂度的升高,不管是分层架构,还是微服务架构,都会带来一个最明显的变化,那就是应用数量增多,有时甚至多达几十个、上百个。不同的应用就有不同的代码、依赖和配置,为了协同多应用之间的在线发布,我们还要做到服务能够平滑地进行上下线切换。同时,为了最大限度地降低发布风险,我们还需要进行多环境下的验证,以及上线后的灰度策略等等。
|
||||
|
||||
应对这一切,如果只是手工维护,或者利用简单的工具脚本进行维护,都不能保证正常运作。这个时候,我们必须有一系列的流程、机制和工具链来支持和保障。
|
||||
|
||||
由杰斯·赫布尔(Jez Humble)、戴维·法利( David Farley)编著,乔梁老师翻译的《持续交付:发布可靠软件的系统方法》(Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation)这本书,针对持续交付的过程、方法和指导建议几个方面做了非常详细的描述。我向你强烈推荐这本书,不过,这本书的内容并不仅仅针对于微服务架构。
|
||||
|
||||
接下来我就分享如何把持续交付的理念和实践相结合,讲一讲在实践过程中,做好持续交付最关键的几步是什么,以及具体应该怎么做。
|
||||
|
||||
## 什么是持续交付?
|
||||
|
||||
我们现在经常会接触到这些名词,比如持续交付、持续集成、持续部署、持续发布、DevOps和敏捷开发等等。大多有关持续交付的分享或文章中,这些名词经常会同时出现。它们之间到底有什么区别?我自己之前也弄不清楚,直到看到乔梁老师的这张图。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/66/5b/66122883028db01898eb72a1c5c6b25b.jpeg" alt="" />
|
||||
|
||||
这里我重点解释一下持续交付这个概念,通俗地说,**持续交付代表着从业务需求开始到交付上线之后的端到端的过程**。后面我们会针对这个过程的关键环节进行分享。
|
||||
|
||||
受篇幅所限,其它名词就先不作过多解释了,你可以看图自己体会,都不难理解。后面针对某些概念我们还会提到。
|
||||
|
||||
## 持续交付的关键点
|
||||
|
||||
可以说,这一部分也是我们后面将要分享内容的提纲。
|
||||
|
||||
从前面那张图来看,做持续交付需要**端到端考虑**,同时还要有一些非常关键的准备工作。我把这些工作大致分为以下几个部分。
|
||||
|
||||
**1. 配置管理**
|
||||
|
||||
这一部分会利用到我们前面讲过的标准化和CMDB打下的基础,同时还会有更大的外延,比如环境配置、代码配置以及依赖管理等等。
|
||||
|
||||
配置管理是非常关键的基础工作。有一点值得注意,那就是**标准化是一个持续的过程**。我们不太可能在一开始就把所有运维对象、属性和关系全部都考虑清楚,面面俱到是不太现实的,所以,**一定要具备标准化的意识,在开展运维工作的过程中,持续不断地用这个思路去标准化新出现的对象。先标准,再固化,然后自动化**。
|
||||
|
||||
**2. 需求拆解**
|
||||
|
||||
需求拆解这个工作跟业务需求部门和业务开发有更直接的关系。在这里,运维需要做的是,明确需求拆解的粒度和我们最终发布上线的粒度相匹配。
|
||||
|
||||
**3. 提交管理**
|
||||
|
||||
需求拆解完成后,就进入到开发阶段,开发完成后向代码库中提交代码,这个过程中代码分支的合并策略选择就是提交管理。
|
||||
|
||||
**4. 构建打包**
|
||||
|
||||
这一部分是指将提交后的代码编译成可发布的软件包。
|
||||
|
||||
**5. 自动化测试**
|
||||
|
||||
自动化测试包括**功能测试和非功能性测试**。对于运维来说,会更注重非功能方面的特性,所以后面我会着重讲非功能性相关的测试环节。
|
||||
|
||||
**6. 部署发布**
|
||||
|
||||
这一部分是指发布到不同的环境,如开发环境、预发环境、线上Beta以及线上全量环境。针对不同的环境,发布策略和注意事项也会不同。
|
||||
|
||||
以上是一个完整的持续交付过程中最重要的几个环节,后面我们分篇进行详细介绍。
|
||||
|
||||
从我自己的实践经验来看,**配置管理、提交管理、构建和部署发布是持续交付的重中之重,是关键路径,是从开发代码开始,到发布上线的必经之路**。当时,因为这几个环节出现了问题,不能解决,运维同学经常做手工发布,这样效率就跟不上,还经常出现各种问题。
|
||||
|
||||
后来,我们就是先从这几个环节入手,把阻塞的问题解决掉,然后在这个主流程上不断增加外围能力,让整个流程的功能更加丰富和全面。整个系统也从原来的只具备持续部署发布功能的平台,逐步演进为具有持续交付能力的平台。由此可见,我们实现持续交付的过程,也不是一蹴而就的,而是在摸索中逐步演进完善的。
|
||||
|
||||
最后,给你留两个思考题。
|
||||
|
||||
<li>
|
||||
先放下持续交付的概念,你所理解或经历的从开发完代码到发布到线上这个过程中,会有哪些环节?和我列出来的这几部分是否有相同之处?
|
||||
</li>
|
||||
<li>
|
||||
持续交付是谁的持续交付,它的主体是谁?或者有哪些主体?
|
||||
</li>
|
||||
|
||||
欢迎你留言与我讨论。
|
||||
|
||||
如果今天的内容对你有用,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
87
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/13 | 持续交付的第一关键点:配置管理.md
Normal file
87
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/13 | 持续交付的第一关键点:配置管理.md
Normal file
@@ -0,0 +1,87 @@
|
||||
<audio id="audio" title="13 | 持续交付的第一关键点:配置管理" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/b2/b5/b216f751f93509c984d08bbfe61bacb5.mp3"></audio>
|
||||
|
||||
今天我们来看持续交付的第一个关键点:**配置管理**。按照持续交付的理念,这里所说的配置管理范围会更广,主要有以下几个部分。
|
||||
|
||||
- 版本控制
|
||||
- 依赖配置
|
||||
- 软件配置
|
||||
- 环境配置
|
||||
|
||||
讲持续交付,一上来就先讲配置管理,主要还是想强调:**配置管理是基础,是关键**。我们后面将要讲的每一个持续交付环节,都对配置管理有很强的依赖。这个基础工作做不好,也就谈不上的持续交付的成功。**勿在浮沙筑高台,我们做工具平台或系统,一定要重视基础的建设**。
|
||||
|
||||
同时,这里还有一个前提,就是**一定要做到代码和配置的分离**。不要让配置写死在代码里,需要依靠严格的规范和约束。同时,对于那些因历史原因遗留在代码中的配置,要多花些时间和精力把配置剥离出来,做这项工作没有什么好的方法或经验,只能多上心,多投入些精力。
|
||||
|
||||
配置管理中,对于版本控制和依赖配置目前都有比较成熟的工具体系支持,也有丰富的实践经验供我们参考学习,下面我会做一个简要的介绍。
|
||||
|
||||
对于软件配置和环境配置管理,这两项配置跟我们自身的业务软件特性强相关,是整个持续交付过程的关键,我会结合我们自身的实践经验进行重点介绍和分享。
|
||||
|
||||
## 版本控制
|
||||
|
||||
**版本控制的主要作用是保证团队在交付软件的过程中能够高效协作,版本控制提供了一种保障机制**。具体来说,就是团队在协作开发代码的情况下,记录下代码的每一次变更情况。
|
||||
|
||||
说到这里,你是不是想到了SVN和Git这样的版本管理工具?对,其实我们每天都在接触,每天都在不停地做这个事情,所以目前看来这是一件很平常的事情。
|
||||
|
||||
关于这一部分我在后面的文章里会介绍关于提交阶段的实践经验。这里我们只要知道,**版本控制及其工具是必不可少的,因为这是开发团队协作最基础的工具**。现在应该很少有团队不采用版本控制的管理机制吧?
|
||||
|
||||
## 依赖管理
|
||||
|
||||
这里以Java为例,我们使用Java进行开发,必然会依赖各种第三方的开源软件包。同时,内部还会有不同组件的二方包。这些三方包和二方包就是一个应用编译和运行时所依赖的部分。
|
||||
|
||||
有过开发经验的同学肯定都知道,即使运行一个非常简单的Web应用,都会有大量的jar包依赖。如果人工去管理这些依赖,基本上是不可能的,所以就需要有依赖管理的工具。
|
||||
|
||||
**对于Java来说,我们熟知的依赖管理工具有Ant、Maven和Gradle**。当然这些工具不仅仅提供依赖管理这样单一的能力,一般都具备以下几个能力:
|
||||
|
||||
- 二方包、三方包的仓库(Repository)管理;
|
||||
- 依赖管理;
|
||||
- 构建打包。
|
||||
|
||||
下面介绍下我自己的实践经验。因为我们的经验基础都在Maven上,再加上Maven周边有一些优秀插件和业界经验可以借鉴,比如后面将要介绍到的AutoConfig,所以我们选取了Maven作为主力构建工具。
|
||||
|
||||
大致用法是建立一个本地Maven源,构建时会优先从本地源中获取依赖包,本地源中没有对应的依赖时,会从公网上下载,同时缓存到本地。这也是业界绝大多数公司采用的一种通用方案。具体如何构建打包呢?这个内容会在构建阶段进行分享。
|
||||
|
||||
## 软件配置
|
||||
|
||||
这里我把软件配置细化为两类:**一类是代码配置,一类是应用配置**。
|
||||
|
||||
**1. 代码配置**
|
||||
|
||||
我们可以这样理解,**代码配置是跟代码运行时的业务逻辑相关的**。比如应用的服务接口、并发线程数、超时时间等这些运行时参数;还有类似于业务或技术上的开关,比如商品评论是否开放、优惠时间段设置等等。
|
||||
|
||||
**2. 应用配置**
|
||||
|
||||
还记得我们在标准化文章中提到的应用吗?**应用配置就是应用这个对象的属性和关系信息**。我们把应用配置放到持续交付这个场景中进行分析,对于这个配置可以细分为:
|
||||
|
||||
- **应用构建时配置**,比如它的编程语言、Git地址以及构建方式等;
|
||||
- **应用的部署配置**,源代码目录、应用日志目录、Web日志目录、临时目录、脚本目录等;
|
||||
- **应用的运行配置**,应用启停、服务上下线方式、健康监测方式等;
|
||||
- **应用运行时与基础组件的关联关系**,比如其依赖的DB、缓存、消息以及存储的IP地址、域名、端口、用户名或Token等。
|
||||
|
||||
从上面这种分类方式中,应该可以体会到,我们对于配置的分类,也是基于应用生命周期的不同阶段进行分解和分析的。所以,标准化的过程也是一个持续迭代的过程。不同的场景下,一个应用可能会具备不同的属性。这个时候,如果我们无法在一开始就把这些属性梳理得清清楚楚,具备标准化的意识和思路就显得更为重要。这样,当我们遇到新场景的时候,随时可以对它做标准化分析和建模。
|
||||
|
||||
**3. 代码配置和应用配置的区别**
|
||||
|
||||
从上面的分析中,你有没有找出两者的区别?这里建议你暂停一下,花一分钟时间自己先想想代码配置和应用配置有什么区别,再往下看。
|
||||
|
||||
**从区别上讲,我们可以认为代码配置是跟业务或代码逻辑相关的,动一下就会改变系统执行状态,是运行时的配置,但不依赖周边环境。而应用配置,是跟业务和代码逻辑无关的,不管你怎么动,业务逻辑是不会改变的,但是它跟环境相关**。
|
||||
|
||||
与环境相关,按阶段分又大致可以分为两个阶段、三种情况。
|
||||
|
||||
- **第一种**,软件在交付过程中,环境会不一样。比如我们正式发布软件前,会历经开发测试环境、预发环境和生产环境等等。那开发测试环境访问的DB,跟线上访问的DB就不能是同一套。同时这个环境中的应用,依赖的大多是本环境内的基础组件和应用,但不是必然,原因我们后面会讲到。还有日志级别也可能不同,比如测试环境可以开Debug级别,但是线上是绝对不允许开Debug的。
|
||||
- **第二种**,软件交付上线后,线上可能会存在多机房环境,特别是有海外业务的公司,一个站点可能会在中国、北美、欧洲以及东南亚等不同区域建立当地访问的分站点;或者大型网站做了单元化,在国内也会分多机房部署,这个时候每个机房的环境配置必然不同。
|
||||
- **第三种**,软件交付后,一套软件可能交付给不同的客户,分别独立运行,比如类似ERP、CRM这样的软件,或者私有部署的SaaS服务等。不同客户的基础环境是不一样的,有的可能是Linux,有的是Unix,还有的可能是Windows,这时应用配置中的各种目录、用户名等信息可能也是不一样的,软件的交付模式就取决于最终的客户环境。
|
||||
|
||||
对于平台类的产品,遇到第一、二种情况的可能性更大,这两种情况更多的是对周边依赖的配置不同,比如不同的服务注册中心、DB、缓存或消息等等。对于一些针对不同客户进行私有部署的产品,可能更多的是第三种情况,这种情况就是应用的基础配置比如目录、用户名以及基础软件版本等会有不同。
|
||||
|
||||
我们回到代码配置和应用配置之间的区别这个问题上来。
|
||||
|
||||
对于代码配置,我们一般会通过Config Server这样专门的配置管理服务进行动态管理,在软件运行过程中可以对其进行动态调整。之所以增加这些配置,主要是让开发能够以更灵活的方式处理业务逻辑。当然,也有一些为了稳定性保障而增加的配置,比如限流降级、预案开关等等。对于前者运维不必关注太多,而后者是运维关注的重点,这个内容我们后面讲到稳定性部分会重点分享。
|
||||
|
||||
对于应用配置,是我们在构建软件包时就需要面对的问题。这个配置取决于环境,所以就延伸出持续交付过程中非常重要的一个配置管理:**环境配置管理**。解释一下就是,**不同环境中的应用配置管理**。
|
||||
|
||||
环境配置是我们在持续交付过程中要关注的重中之重,也是最为复杂的一部分。我们自己的团队在做多环境发布和管理的时候,遇到最头疼的问题就是环境配置管理,我们下一期就着重来聊聊环境的配置管理。
|
||||
|
||||
今天我和你分享了做持续交付的第一步:配置管理,主要包括版本控制、依赖配置、软件配置和环境配置四个部分。关于今天分享的内容,你有怎样的思考或疑问,欢迎你留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友。我们下期见!
|
||||
|
||||
|
||||
112
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/14 | 如何做好持续交付中的多环境配置管理?.md
Normal file
112
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/14 | 如何做好持续交付中的多环境配置管理?.md
Normal file
@@ -0,0 +1,112 @@
|
||||
<audio id="audio" title="14 | 如何做好持续交付中的多环境配置管理?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/54/eb/54d525ad4796a9d66a0d5dcfd782e8eb.mp3"></audio>
|
||||
|
||||
上一篇内容中,我们讲到软件配置中的代码配置和应用配置,这两种配置之间最大的区别就是看跟环境是否相关。由此,就引出了持续交付过程中最为复杂的环境配置管理这个问题,准确地说,应该是不同环境下的应用配置管理。
|
||||
|
||||
今天我就结合自己的经验和你聊一聊环境管理的解决方案。
|
||||
|
||||
## 多环境问题
|
||||
|
||||
上篇内容我们介绍了应用配置的三种情况,今天我们稍微聚焦一下,以上篇文章中提到的前两种应用配置场景为主进行介绍,也就是平台类的业务。我们一起来看同一套软件在持续交付过程中和交付上线后,多环境情况下的配置管理问题。
|
||||
|
||||
我们先从生命周期的角度,对环境做个简单说明,主要包括:
|
||||
|
||||
- **开发环境**,主要是在应用或软件开发过程中或完成后,开发人员对自己实现的代码进行单元测试、联调和基本的业务功能验证;
|
||||
- **集成环境**,开发人员完成代码开发并自验证通过后,将应用软件发布部署到这个环境,测试人员再确保软件业务功能可用,整个业务流程是可以走通的;
|
||||
- **预发环境**,在真实的生产数据环境下进行验证,但是不会接入线上流量,这也是上线前比较重要的一个验证环节;
|
||||
- **Beta环境**,也就是灰度环境或者叫金丝雀发布模式。为了整个系统的稳定性,对于核心应用,通常会再经历一个Beta环境,引入线上万分之一,或千分之一的用户流量到这个环境中;
|
||||
- **线上环境**,经历了前面几个阶段的业务功能和流程验证,我们就可以放心地进行版本发布了,这个时候就会将应用软件包正式发布到线上 。
|
||||
|
||||
以上是一个持续交付体系中必须要有的几个环境。环境建设,又是一个比较大的话题,我们后面会专门来讲,今天就聚焦在环境配置管理上。
|
||||
|
||||
## 不同环境下的应用配置管理
|
||||
|
||||
我们前面提到,环境配置管理,解释得更准确一点,应该是**不同环境下的应用配置管理**,所以这里的核心是**应用配置管理**。因为有多个环境,所以增加了其管理的复杂性。持续交付过程中涉及到应用配置管理的属性和关系如下:
|
||||
|
||||
- **应用属性信息**,比如代码属性、部署属性、脚本信息等,你可以参考之前我们对这块的细分,这里就不细讲了;
|
||||
- **应用对基础组件的依赖关系**。这个也不难理解,应用对DB、缓存、消息以及存储有依赖,不同的环境会有不同的访问地址、端口、用户名和密码。另外,在分布式架构中,一个应用必然要依赖一个环境中的其它应用,这时对于应用的服务注册、服务发现也要求必须在本环境中完成。举一个最简单的例子,我们肯定不允许一个线上应用服务注册到线下环境中去,让线下业务测试的服务调用影响到线上服务运行,要不然就会导致线上的业务故障了。
|
||||
|
||||
讲到这里,你应该会发现,对于我们假设的平台类业务场景,应用的基础属性信息是不会随着环境的变化而发生变化的,但是应用依赖的基础设施和依赖这个关系是会随环境不同而不同的。所以,我们可以再进一步理解,**环境配置管理主要是针对应用对基础设施和基础服务依赖关系的配置管理**。
|
||||
|
||||
如果是针对不同的客户进行私有化部署的软件,那么应用的基础属性信息可能也会发生变化,但是这样的场景就更会更加复杂一些,但是配置管理上的解决思路上是一样的,所以这里我们还是简化场景。
|
||||
|
||||
## 环境配置管理解决方案
|
||||
|
||||
上面详细讲解了环境和应用配置之间的管理,下面就结合我自己团队和业界的一些方案,来看看这个问题应该怎样解决。
|
||||
|
||||
我们的示例尽量简化场景,重点是讲清楚思路。所以我们假设现在有三个环境:
|
||||
|
||||
- 开发环境
|
||||
- 预发环境
|
||||
- 线上环境
|
||||
|
||||
继续假设某应用有配置文件:config.properties,里面存储了跟环境相关的配置,简化配置如下:
|
||||
|
||||
- 缓存地址:cache.app.url
|
||||
- 消息地址:message.app.url
|
||||
- 数据库地址:db.app.url
|
||||
- 支付调用地址:pay.url
|
||||
- 支付调用Token:pay.app.token
|
||||
|
||||
很明显,不同的环境,配置是不完全相同的。我们看以下几个解决思路。
|
||||
|
||||
**方案一,多个配置文件,构建时替换**。
|
||||
|
||||
这是一个比较简单且直接有效的方式,就是不同环境会分别定义一个配置文件,比如:
|
||||
|
||||
- 开发环境dev_config.properties
|
||||
- 预发环境pre_config.properties
|
||||
- 线上环境online_config.properties
|
||||
|
||||
这几个配置文件中的配置项保持相同,但是配置的值根据环境不同是不一样的,不过都是固定的实际信息。比如开发环境配置文件中的缓存地址:
|
||||
|
||||
- cache.app.url=10.88.77.66
|
||||
|
||||
而线上环境配置文件中:
|
||||
|
||||
- cache.app.url=10.22.33.44
|
||||
|
||||
然后在构建时,我们会根据当前所选定的环境进行替换。比如,我们现在构建开发环境的软件包,这时就会选择dev_config.properties作为配置文件,并将其文件名替换为config.properties打包到整个软件包中。
|
||||
|
||||
我们看下这种方案的优缺点:
|
||||
|
||||
- **优点**,就是简单直接。在环境相对固定且配置项变化不大的情况下,是最为简便的一种环境配置管理方式。
|
||||
- **缺点**,也比较明显。首先是在实际的场景中,我们的环境可能会更多,且交付上线后可能还会有线上多环境。这时每多出一个环境,就要多一个配置文件,这时配置项的同步就会成为大问题,极有可能会出现配置项不同步,配置错误这些问题。特别是如果配置项也不断地增加和变化,管理上会变得非常繁琐。再就是,这里需要针对不同环境进行单独的构建过程,也就是要多次打包,这一点是跟持续发布的指导建议相悖的。
|
||||
|
||||
**方案二,占位符(PlaceHolder)模板模式**。
|
||||
|
||||
这种方案在Maven这样的构建工具中就可以很好地支持,直接示例如下:
|
||||
|
||||
- cache.app.url=${cache.app.url}
|
||||
|
||||
我们可以看到,这种模式下,配置项的值用变量来替代了,具体的值我们可以设置到另外一个文件中,比如antx.properits(这个文件后面在autoconfig方案中我们还会介绍),这里面保存的才是真正的实际值。
|
||||
|
||||
这时我们只需要保留一个config.properties文件即可,没必要把值写死到每个不同环境的配置文件中,而是在构建时直接进行值的替换,而不是文件替换。这个事情,Maven就可以帮我们做,而不再需要自己写脚本或逻辑进行处理。
|
||||
|
||||
不过,这个方案仍然不能很好地解决上面第一种方案提到的问题,配置文件是可以保留一个了,但是取值的antx.properties文件是不是要保留多个?同时,对于配置文件中配置项增加后,antx.propertis文件中是否同步增加了配置,或者配置项名称是否完全匹配,这一点Maven是不会帮我们去检查的,只能在软件运行时才能验证配置是否正确。
|
||||
|
||||
最后,这个方案还是没有解决只打包一次的问题,因为Maven一旦帮我们构建完成软件包之后,它并没有提供直接针对软件包变更的方式。所以,针对不同的环境,我们仍然要打包多次。
|
||||
|
||||
**方案三,AutoConfig方案**。
|
||||
|
||||
AutoConfig是阿里开源的Webx框架中的一个工具包,在阿里的整个持续交付体系中被广泛应用,它继承了Maven的配置管理方式,同时还可以作为插件直接与Maven配合工作,针对我们上面提到的部分问题,它也针对性地进行了加强和改进,比如:
|
||||
|
||||
- **配置校验问题**。AutoConfig仍然是以上述第二种方案的模板模式为基础,最终通过antx.properties文件中的配置值来替换,但是它会做严格校验;同时也可以自定义校验规则,来检查配置项是否与模板中的设定严格匹配,如果不匹配,就会在构建时报错,这样就可以让我们提前发现问题,而不是软件包交付到环境中运行时才发现。
|
||||
- **只打包一次的问题**。AutoConfig不需要重新构建就可以对软件包,比如war包或jar包的配置文件进行变更,所以它很好地解决了针对不同环境需要重复构建的问题。但是,比较遗憾的是,它的Maven插件模式并没有解决这个问题,还需要与AutoConfig工具模式配合才可以。
|
||||
|
||||
讲到这里,我们可以看到AutoConfig的方案已经相对完善了,也可以满足我们的大部分需求,但是它仍然没有解决多环境配置值管理的问题,我们是通过多个antx.properties文件来管理,还是有其它方式?
|
||||
|
||||
这里,我们**就需要基于AutoConfig做一下二次开发了**,也就是我们要把这些配置项做到一个管理平台中,针对不同环境进行不同值的管理,然后根据AutoConfig的规则,在变更后生成对应不同环境的配置文件,然后再结合AutoConfig针对配置管理文件的能力,这样就可以很方便地做多环境的软件包构建了。
|
||||
|
||||
这样的配置项管理平台,AutoConfig自己也没有做,所以需要我们自己开发。同时,对于比较敏感的配置信息,特别是涉及用户名、Token、核心DB地址等信息,还是不要放到配置文件中,最好是放到管理平台中,进行受控管理。同时,这里也要特别强调,密码信息一定不允许放在配置文件中出现,更不允许以明文的方式出现,这一点是需要开发、运维和安全共同来保障的。
|
||||
|
||||
## 总结
|
||||
|
||||
今天我们针对多环境的配置管理进行了分享,这里更多的还是思路和方案上的引导。如果你对Maven和AutoConfig不熟悉的话,建议自行查询资料进行学习了解,甚至是自己动手尝试一下。
|
||||
|
||||
另外,对于文章中的方案,我是尽量简化了场景来分享的,虽然思路上是相通的,但是实际情况下各种细节问题会更繁琐,要具体问题具体分析。
|
||||
|
||||
你在这个过程中遇到过什么问题?有什么好的解决方案?或者还有什么具体的疑问?欢迎你留言与我一起讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
113
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/15 | 开发和测试争抢环境?是时候进行多环境建设了.md
Normal file
113
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/15 | 开发和测试争抢环境?是时候进行多环境建设了.md
Normal file
@@ -0,0 +1,113 @@
|
||||
<audio id="audio" title="15 | 开发和测试争抢环境?是时候进行多环境建设了" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/7c/31/7c8b28699f72a10b2045883c72097e31.mp3"></audio>
|
||||
|
||||
在上一期文章里,我们介绍了多环境下的应用配置管理问题,从这期开始,我们会分两期文章详细聊聊多环境建设的问题:就是我们到底需要哪些环境?这些环境都有什么作用?环境建设的思路和方式是怎样的?
|
||||
|
||||
今天我就结合自己的经验和理解与你聊一聊持续交付中的线下多环境建设。
|
||||
|
||||
## 环境分类
|
||||
|
||||
通常,我们主要按照环境所起到的作用,将环境分为两大类:
|
||||
|
||||
- 线下环境:测试验收用。
|
||||
- 线上环境:为用户提供服务。
|
||||
|
||||
从建设角度来说,线下环境和线上环境,在网段上是要严格隔离的。这一点在做环境建设时就要确定网络规划,同时在网络设备或者虚拟网络的访问策略上要严格限定两个环境的互通,如果限制不严格,就极易引起线上故障,甚至是信息安全问题。
|
||||
|
||||
如果你维护过这样两套环境,我想你一定在这方面有过深刻的感受,甚至是痛苦的经历。
|
||||
|
||||
所以,从规划上,线上环境和线下环境是两套独立的区域,所有的应用、基础服务都是全套独立部署的。但是线下环境所需的资源往往是要少于线上环境,毕竟只有负责开发测试的少数人使用,不会有线上流量进来。如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/57/8d/5787cdca12eab7956c5b71fdac0be28d.jpg" alt="" />
|
||||
|
||||
但是,在实际情况中,这两个环境远远满足不了我们日常开发、测试和运维方面的需求。从保障软件质量和系统稳定的角度出发,我们在实际操作中还需要在这两个大的环境区域中,建立细分的小环境,来满足不同阶段和不同角色的工作需求。
|
||||
|
||||
## 线下环境分类建设
|
||||
|
||||
线下环境最初建设的时候,主要是提供给测试使用,帮助其建立一个模拟环境,在软件发布上线前进行需求功能验证,保障业务流程顺畅,以确保应用在上线前达到最低质量要求。
|
||||
|
||||
所以,我们**在线下环境区域内,建设的第一个环境就是集成测试环境**。甚至在一开始,线下环境=集成测试环境,这个环境下的应用和各类基础服务必须跟线上保持一致,但是集群规模不用这么大(如我们上图所示)。
|
||||
|
||||
所以,集成测试环境极其重要,这个环境中的应用有严格的发布标准,并且要求环境稳定,不能随意发生变更,否则将会大大影响测试的效率。
|
||||
|
||||
不过,随着集成测试环境建设起来,业务需求迭代越来越快,应用和开发人员数量也越来越多,软件发布和变更也会更加频繁,这个时候就会出现开发和测试人员争抢集成测试环境的问题。
|
||||
|
||||
比较典型的场景就是,测试人员正在验证一个功能,突然发现应用停止运行了,原来开发为了验证和尽快发布新功能,更新了代码,这样就阻塞了测试的正常工作,但是不更新代码,开发的工作又会停滞下来。
|
||||
|
||||
后来这个矛盾越来越严重。这时,我们就需要考虑多建设一套给开发用的环境来解决这个问题。
|
||||
|
||||
于是,我们就开始建设**线下的第二套环境:开发测试环境。**这个环境主要是让开发同学能够尽快发布自己开发完的代码,并在一个具备完整业务应用和基础服务的环境下,验证自己的代码功能。
|
||||
|
||||
但是,是否需要跟集成测试环境一样,再建设一套独立完整的线下环境出来呢?答案是否定的。因为这时的应用变化范围相对独立,变化也较小,周边依赖需要同时变化的应用也不会太多,就像上面说的,只要能把它们放到一个完整的环境中进行验证即可。
|
||||
|
||||
所以,这个环境只要按照最小化原则建设即可,如果有依赖,可以直接访问到集成测试环境。在这里,我们以简单的模型展示开发测试环境跟集成测试环境的关系:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/db/a0/dbf8baa543f0643ae25dd66379ac44a0.jpg" alt="" />
|
||||
|
||||
再往后,开发测试环境上,又会出现开发和测试的冲突和争抢,因为从场景上,业务开发团队可能要同时承担多个并行项目的研发,而且可能会有多个业务开发团队一起参与进来。
|
||||
|
||||
比如对于电商来说,到了年底,就集中会有“双11”、“双12”、“双旦节”以及“年货节”等等这样的大型营销项目,因为时间非常紧凑,所以就必须多项目并行。
|
||||
|
||||
这个时候,分解下来,对于我们的应用软件来说,有可能是存在多个开发分支的。到了项目联调和验证环节,就必然会存在同一个应用有多个版本需要同时发布和测试的情况,但是开发测试环境却只有一个,这就必然导致双方激烈的争抢。
|
||||
|
||||
所以这个时候,就必须建立解决冲突的方案,开始建设线下的第**三套环境:项目环境**。
|
||||
|
||||
项目环境可能有多套,一个项目对应一套环境,但是无论从资源成本还是维护成本方面考虑,项目环境仍然不会像集成测试环境那样形成一套完整的开发测试体系。
|
||||
|
||||
所以项目环境同开发测试环境一样,仍然是以最小化为原则来建设,也就是说,在这个环境里面,只部署同一项目中涉及变更的应用,而对于基础服务和不涉及项目需求变更的应用不做重复建设。如果对项目环境中不存在的应用有依赖,那么访问集成测试环境中对应的应用就可以了。
|
||||
|
||||
在这里,我们同样以简单的模型展示多个项目测试环境、开发测试环境与集成测试环境的关系:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/88/ca/88a5bf0c9a42adfa4102224f0ff40bca.jpg" alt="" />
|
||||
|
||||
不过,如果说随项目的增加就需要分别建设对应的项目环境,那么这对于开发、测试和运维来说都会有非常大的维护负担。所以通常情况下,我们会严格限制建设项目环境的起步线。
|
||||
|
||||
比如只有公司级大促、公司战略级的项目,或者超过一定人日的跨团队项目,才允许建立独立的项目环境。一般情况下,还是引导优先使用开发测试环境。
|
||||
|
||||
## 环境建设上的关键技术点
|
||||
|
||||
线下环境细分出集成测试环境、开发测试环境以及多个项目环境之后,带来的最大的成本其实不在资源上,而是在管理和维护上,而且单单就线下维护的工作量来说,甚至要超过线上维护的工作。
|
||||
|
||||
复杂度和涉及到的技术点有以下四个方面。
|
||||
|
||||
第一是**网段规划**。每个环境都要有独立的网段,比如整个线下环境要独立占用一个B段,项目环境和开发测试环境相对较小,可以独立占用一个C段。虽然不需要做网络策略上的隔离,但是为了便于管理,如分配回收资源以及部署应用,还是要在逻辑上区分出来。同时,网段规划也是为下面的单元化调用做准备。
|
||||
|
||||
第二是**服务化框架的单元化调用**。这一点需要服务化框架支持,比如上面我们提到的项目环境,到了联调阶段就需要一组应用单独联调,而不能跨项目环境调用。同时,对于项目中依赖的未变化的应用,就需要调用集成测试环境中稳定版本的应用。这个服务调用的基本规则就是基于上述网段的规划来建立的,规则要放到服务化的注册中心,也就是ConfigServer这个部件中保存,同时需要服务化框架支持规则调用,优先支持本单元调用,本单元不存在可以调用集成测试环境单元。
|
||||
|
||||
第三是**环境的域名访问策略**。这么多的环境 ,内外部DNS域名是保持一套还是多套,比如访问蘑菇街主页(www.mogujie.com),首页域名就一个,但是怎么能确保访问到我们所期望的环境上呢。这里有几种方式:
|
||||
|
||||
- 第一种,DNS服务保持一套,域名,特别是外部域名多套,每个环境分别配置一个不同的域名,比如开发测试环境,dev.mogujie.com。但是如果这样,下层的二级域名和二级目录等等都要跟着变动,而且对于项目环境来说,数量不固定,每次都换一个也不方便记忆和管理,所以这个方案基本不可行。
|
||||
- 第二种,DNS服务保持一套,域名保持一套,但是做域名的hosts绑定,也就是自己来设置要访问域名所对应的环境。这样一来,如果相对固定的开发测试环境和集成测试环境所对应的hosts相对固定,那么只需要绑定一次就可以通用。但是项目环境始终在不断的变化中,绑定规则可能随时在变化,所以这种方案的复杂度在于对hosts配置的管理上。
|
||||
- 第三种,DNS服务多套,也就是不同的环境中配置独立的DNS服务,这样可以减少繁琐的hosts绑定,但是也会提高多套DNS服务管理上的复杂度,而且对于项目环境有可能依赖集成测试环境中的服务,这时仍然会涉及本地DNS服务的hosts绑定。
|
||||
- 第四种,对于公网域名,可以直接通过无线路由劫持的方式访问,可以在无线路由器上配置多个接入点,这样一来,连接不同的接入点,就会自动对应到不同环境的域名IP地址上去。
|
||||
|
||||
通常,对于公网域名来说,如果具备稳定的环境,如集成测试环境,直接通过第四种劫持方式指定到对应环境中去,这样最方便,这种方案在后续线上多环境建设中还会使用。
|
||||
|
||||
对于内部域名,则有多种方案,没有优劣,主要看场景和管理成本。我们选择的是第二 种,即绑定hosts的方式。每个环境会对应一套hosts配置,当选择不同环境进行联调或访问时,就将hosts配置下发到对应部署应用的主机上。
|
||||
|
||||
在这里,我们仍然以模型展示第二、四种方案和多种线下环境之间的运行逻辑:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/97/87/9792cf71700cc4e875fbe54534d71b87.jpg" alt="" />
|
||||
|
||||
但是,无论采取哪种方式,我们可以看到,这个管理过程仍然是比较复杂繁琐的,必须要非常仔细地规划和部署,同时还需要配套的自动化工具支持,否则靠人管理是不现实的,所以最后一点就是自动化的配套。
|
||||
|
||||
第四是**自动化管理**。按照我们之前分享的管理模式,这里虽然有这么多的线下环境,但我还是会把它们以应用为核心给管理起来,即应用的开发测试环境,应用的集成测试环境,应用的项目环境。这样一来,上面提到的不同环境的网段信息、配置信息、资源分配回收以及软件部署发布,都能够以应用为出发点去做,这一点我们在后面的文章会详细分享。
|
||||
|
||||
## 总结
|
||||
|
||||
最后,不知道你有没有感受到,单单一个线下环境就要如此复杂和繁琐,整个持续交付体系建设是多么的有挑战性,就可想而知了。
|
||||
|
||||
我们对线下环境稍微做个总结:
|
||||
|
||||
- 集成测试环境,主要供测试使用,这个环境会最大程度与线上版本保持同步。作为对应用的功能、需求、业务流程等在正式发布上线进行验证的主要环境,集成测试环境的稳定性和可测试需要加强保障,进行全套建设。同时,作为整个线下环境的中心节点,也要为开发测试环境和项目环境提供部分依赖服务。
|
||||
- 开发测试环境,主要供开发人员使用,针对偏日常的需求开发、联调和功能验证,以最小化原则进行建设,但是一般情况下不对资源进行回收。
|
||||
- 项目环境,供开发和测试共同使用,针对多团队多人员协作的项目型场景,可以同时存在多个项目环境,在这个环境中针对项目需求进行独立开发、联调和验证。测试也需要提前介入这个环境进行基本功能的验收,并遵循最小化的建设原则,但是要有生命周期,即项目启动时分配资源,项目结束回收资源,不能无限期占用。
|
||||
|
||||
最后,在实际操作中,仍然会很多细节问题,这些问题会跟业务场景有关,针对这些场景又有可能有不同的建设要求,比如消息的消费问题会涉及全业务流程验证等等。
|
||||
|
||||
所以,留几个问题给你思考:在线下环境的建设过程中,你通常会遇到哪些问题?会有哪些独立环境?或者你有什么更好的经验和建议分享?
|
||||
|
||||
欢迎你留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
125
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/16 | 线上环境建设,要扛得住真刀真枪的考验.md
Normal file
125
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/16 | 线上环境建设,要扛得住真刀真枪的考验.md
Normal file
@@ -0,0 +1,125 @@
|
||||
<audio id="audio" title="16 | 线上环境建设,要扛得住真刀真枪的考验" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/e8/28/e81b916ad4c39454221a38b4cc1c5a28.mp3"></audio>
|
||||
|
||||
前面几期我们分享了一些线下环境建设方面的内容,我们可以感受到,整个线下环境的建设是比较复杂的,那经过线下环境的验证,是不是就可以直接发布到线上生产环境了呢?答案同样是否定的,由线下正式交付到线上之前,我们仍然会做很多的验证和稳定性保障工作。
|
||||
|
||||
今天我们就一起来看一下线上环境是如何建设的。
|
||||
|
||||
下面,我们就生产环境、Beta环境、预发环境、办公网生产环境这四种线上环境分别展开讨论。
|
||||
|
||||
## 生产环境
|
||||
|
||||
我们还是进入到现实场景中。最初我们的软件代码开发完成后,就可以发布到生产环境,也就是可以正式接入用户流量,承载真实的业务场景。
|
||||
|
||||
在最早期,我们业务复杂度不高,用户量不大,集群规模小,软件架构也相对简单。在这种情况下,其实这一个环境就足够了,真有问题,也可以快速回退掉。退一步讲,即使有问题也回退不了的话,影响范围也有限。
|
||||
|
||||
所以,这个时候,线上环境=生产环境。
|
||||
|
||||
我们知道,随着业务量增大和业务复杂度升高,我们的软件架构、部署模式、集群规模等等也相应变得复杂和庞大起来。同时,业务产品在用户和业界的影响力也在变得越来越大。
|
||||
|
||||
这个时候,任何一个小的变更或一个不起眼的小问题,都有可能导致非常严重的故障,从而造成公司资损甚至是恶劣的产品口碑影响。
|
||||
|
||||
比如,我们假想一下,如果国内某个大型电商平台不可用,或者某即时通讯软件不可用,会造成何等严重的后果,就不难想象了。
|
||||
|
||||
所以,这时就需要我们非常严肃而谨慎地应对生产环境的变更。
|
||||
|
||||
我想你可能跟我一样,会想到一个问题:就是我们不是已经在线下环境经过了很多轮不同形式的验证测试环节,为什么到了生产环境还会有验证不到的严重问题?
|
||||
|
||||
这里涉及一个用户和业务场景的概念,就是线下和线上的用户场景是完全不同的:线下是我们模拟出来的,线上却是真实的用户场景,这两者之间会存在巨大的差异,有差异,系统的表现状况就会不一样。
|
||||
|
||||
所以线下我们只能尽可能地确保业务功能和业务流程是正常的,但是没法百分之百模拟线上场景,特别是一些异常特殊场景方面。这一点后面的文章我们还会再分享,这篇文章我们只要知道存在差异即可。
|
||||
|
||||
这个时候,我们的第一个思路就是:即使有影响,也要把它控制在小范围内,或者是在萌芽状态时就发现。这样就可以提前处理,而不是全量发布到生产环境后才发现问题,影响全局。
|
||||
|
||||
所以,**线上的第二个环境,Beta环境**就产生了。这个环境也可以叫作灰度环境,包括我们常提到的金丝雀发布,也是基于这个环境的发布模式。
|
||||
|
||||
## Beta环境
|
||||
|
||||
这个环境的建设,我们简单理解,就是从生产环境的集群中,再建立一个独立集群。看过我们之前介绍CMDB应用和服务分组的文章的读者应该不难理解,针对应用,就是再建立一个分组,独立出一个集群出来,但是这个集群中服务器数量1-2台即可,主要还是针对小规模真实业务流量。如何做到小规模呢?这就要在负载均衡策略上做工作了,主要两种方式:
|
||||
|
||||
- 调用RPC,在服务化框架的复杂均衡策略中,将其权重或者流量配比降低;
|
||||
- 调用HTTP,在四层VIP或者七层权重上,将权重降低。
|
||||
|
||||
这个环境同样不会全量建设,通常只针对核心应用,比如交易链路上的各个应用。同时,除了承担的流量比重不同外,其他与生产环境的应用没有任何差别。
|
||||
|
||||
后面的部署发布环节,我们会看到,针对核心应用,必须要经过Beta发布环节,才允许正式发布到生产环境。
|
||||
|
||||
有了Beta环境之后,上面说到的影响范围的问题从一定程度上就可控了。但是在Beta环境上我们仍然会有两个问题无法很好的解决:
|
||||
|
||||
<li>
|
||||
影响范围再可控,其实也已经影响到了部分真实用户,特别是当访问量特别大的时候,即使是千分之一、万分之一,也是不小的数量。
|
||||
</li>
|
||||
<li>
|
||||
之前经历的线下环境毕竟是一个模拟环境,一方面,在数据规模、分布特点、多样性以及真实性方面,跟生产环境的数据场景还是会有很大的区别,所以有很多跟业务逻辑相关性不大,但是跟数据相关性特别强的场景功能,在线下环境就很难验证出来;另一方面,对于一些第三方的系统,特别是商家、支付和物流这样的体系,在线下环境极有可能是Mock出来的,所以验证的时候并不能代表真实场景,但是等到了线上再去发现问题,就可能就会造成真实的业务影响。业务访问失败可以重试,但是造成商家真实的销售数据错误,或者用户真实的支付资金错误,这样就会非常麻烦了。所以,从线下直接进入Beta环境,还是会给生产环境,特别是数据层面造成影响。
|
||||
</li>
|
||||
|
||||
当业务复杂度和系统规模发展到一定程度后,上面两个问题就会非常突出,所以单纯的Beta环境是无法满足要求的。
|
||||
|
||||
这时,**线上第三套环境,预发环境**,就产生了。
|
||||
|
||||
## 预发环境
|
||||
|
||||
预发环境在建设上,有以下几个规则要求:
|
||||
|
||||
- 状态基础服务共用,如DB、KV、文件存储以及搜索类的数据服务。这里基本就是真实的生产环境的基础了,我们上述的问题在这个基础上就可以很好地解决了。除有状态服务外,其他都需要在预发环境上进行全套建设,但是资源使用上,一般是一个应用部署一个实例即可,所以规模比生产环境要小很多。
|
||||
- 网络隔离上,预发环境做独立网段的划分,不承担线上真实流量,独占一个B段,同时在网络上进行逻辑隔离。业务调用必须本环境内闭环,预发不允许跨环境进行应用服务调用,如预发应用调用生产环境应用,反之亦然。
|
||||
- 要保证一定的稳定性。预发环节就是基于线上真实环境进行功能和业务流程的最终验证,所以对于版本质量要求是要高于线下环境,所以不允许反复频繁地变更部署,出现异常或警告也必须要以较高优先级处理。
|
||||
|
||||
上述环境的搭建,使用的技术方案,跟我们上篇文章讲到的方案是通用的,如服务单元化调用、绑定hosts以及网络策略隔离等等。预发环境与生产环境的关系如下图:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/f5/b8/f54620e2dff7509c359a1465fcde34b8.jpeg" alt="" />
|
||||
|
||||
预发环境正式使用后的另一用途,就是在生产环境出现问题,但是线下复现不了时,就可以在预发环境上复现,这样对于问题定位会带来很大帮助。如果是在生产环境上做调试和问题定位,有时候会影响到正常用户访问,但是预发环境的影响就可控一些。
|
||||
|
||||
不过,定位问题可以,但是绝对不可以通过预发环境去做下面两件事:
|
||||
|
||||
- 与数据订正和变更相关的事情。因为这是由业务流程触发,而不应该由调测触发。而且要时刻牢记,在这个环境做的任何事情都是会对生产环境产生直接影响的,所以这里必要要靠强调意识、事先培训等方式进行避免。
|
||||
- 阻塞他人工作。在定位问题的过程中,如果发现有其他应用依赖,这时要停下来,优先保证环境稳定性,而不是阻塞依赖方发布前的准备工作。
|
||||
|
||||
形象一点描述,预发环境就像是球类运动员,他们平时可以在训练场进行训练,但是正式比赛前,一定是要到正式比赛场地提前适应场地或者热身。一方面是为了了解现场的实际情况,做针对性的准备和调整;另一方面也是为了调动赛前兴奋度和氛围。
|
||||
|
||||
预发环境搭投入使用之后,有很多问题在这个阶段被发现,而且是开发和测试同学目前强依赖的一个环境,所以确实进一步保障了业务的稳定性。
|
||||
|
||||
然而,在这个环境中仍然存在一个问题。下面我还是以电商为例。
|
||||
|
||||
电商每年大促,一般都是提前几个月准备,有可能开发团队在大促活动正式开始前3-4周左右,业务功能都已经开发完成,但是这个时候是不能上线的,或者上线了也要有入口开关控制,绝对不能让用户流量提前进来。
|
||||
|
||||
与此同时,运营侧的招商、报名以及商品上架这些工作也会提前完成,所以这时线上实际已经具备了真实的大促环境,只是因为时间点不到,暂时只能等着。
|
||||
|
||||
但是,如果有一个只让员工访问,让员工们体验和反馈问题的环境,那么,在这个阶段我们是可以提前暴露很多问题,并进行很多优化改进的。这样做就更进一步保障了大促的系统问题和用户体验。
|
||||
|
||||
不过,上述Beta环境和生产环境是无法满足要求的。预发环境能满足一部分要求,但是因为这个环境主要还是供开发和测试验证功能使用,在访问的便捷性和功能体验方面,不能完全保证达到真实用户访问的要求和体验。
|
||||
|
||||
为了满足上述需求,我们会再单独建设一个环境出来,于是,**线上环境的第四套环境,办公网生产环境**,就应运而生了。
|
||||
|
||||
## 办公网生产环境
|
||||
|
||||
办公网生产环境建设的技术方案与预发环境一致,但是在要求上又有所不同:
|
||||
|
||||
- 访问用户是办公网内的员工用户,所以必须连接指定的办公网wifi接入点。于是,员工会通过wifi被劫持到这个环境上,这时用户就可以在这个环境中提前体验新版本软件的功能,比如我们之前说的大促活动等。
|
||||
- 稳定性要求上,办公网生产环境相当于生产环境,虽然不是外部用户访问,但是一个公司内的员工也算是真实用户了,他们发现的问题等同于线上问题,但是级别上会降低一级处理。
|
||||
- 建设规模上,公司有上千、上万名员工,他们的频繁访问行为,也产生一定的业务量,所以综合上述稳定性要求,办公网生产环境在规模上会根据应用容量进行相应的资源分配,这里至少每个应用应该以两个实例做冗余。
|
||||
|
||||
所以这个环境,从建设规模和稳定性要求上,就相当于一个小号的生产环境,所以我们内部又把它简称为**“小蘑菇”环境**。
|
||||
|
||||
## 总结
|
||||
|
||||
我们简单构建一张模型图来对线上环境作个展示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/cb/f7/cbe19d3f94cf077a70a495615d3a97f7.jpeg" alt="" />
|
||||
|
||||
我在这两期文章中介绍了这么多环境,我们可以看到,环境建设是一项异常繁琐复杂的工作,这些工作不是一蹴而就,而是根据实际的场景和问题催生出来的,所以是个逐步渐进的过程。
|
||||
|
||||
而且,因为不同的业务类型和场景,以及业务发展的不同阶段,场景和问题可能都是不一样的,而且其建设需求也不一样,所以在实际操作中,一定要切合具体情况进行建设。
|
||||
|
||||
再就是,环境管理是复杂的,多一个环境就多一份管理成本。所以环境并不是越多越好,反而是越精简越好。这个时候也需要各位读者能够有一定的ROI评估,毕竟能带来最大价值的投入才是有意义的,而不是盲目地建设和投入。
|
||||
|
||||
最后,给你留几个问题思考:
|
||||
|
||||
- 我们分别介绍了线下环境和线上环境的建设,这两个环境在持续交付体系中,分别对应哪些理念和指导思想?
|
||||
- 我们建设了这么多的环境,都是为了解决不同场景下的问题,那么还有哪些问题是上述这些环境仍然解决不了的?
|
||||
|
||||
欢迎你留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
<audio id="audio" title="17 | 人多力量大vs.两个披萨原则,聊聊持续交付中的流水线模式" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/62/37/62d86c44d56041a7af64a61f14b92e37.mp3"></audio>
|
||||
|
||||
在前面5期文章中,我们分别详细介绍了持续交付体系基础层面的建设,主要是多环境和配置管理,这些是持续交付自动化体系的基础,是跟我们实际的业务场景和特点强相关的,所以希望你一定要重视基础的建设。
|
||||
|
||||
本期文章是我们持续交付系列的第6篇文章,从本期开始,我们进入到交付流水线体系相关的内容介绍中。
|
||||
|
||||
## 持续交付流水线简要说明
|
||||
|
||||
从一个应用的代码提交开始,到发布线上的主要环节,整个流程串起来就是一个简化的流水线模式。如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/4d/d0/4dd0d31b8b6df7a3f0d58c7554a8e7d0.jpg" alt="" />
|
||||
|
||||
我们前面介绍了持续交付的多环境以及配置管理,而流水线模式的整个过程正是在这个基础上执行,所以它的某些环节和要素与我们的多环境是有一些交叉的。比如,功能测试会在线下相关的几个环境上完成,比如我们前面介绍到的开发联调环境、项目环境和集成测试环境。
|
||||
|
||||
但是,它们要达成的测试目的是不同的:对于非功能验收,我们会在线上的预发环境完成,因为预发环境更接近真实场景,所以像容量、性能、安全这些跟线上稳定性相关的能力验收,越接近真实环境,效果越好。
|
||||
|
||||
后面几期文章,我会结合我们的实践,分环节来介绍。本期文章我们先看项目需求分解和开发模式选择。
|
||||
|
||||
## 项目需求分解
|
||||
|
||||
持续交付我认为更多的是针对应用层面,所以项目需求分解这一部分,这里我们就不展开讲了。这里我们的工作重点,就是将项目管理中的需求与持续发布中的应用这二者很好地关联起来。
|
||||
|
||||
比较通用的做法,就是要求业务架构师在做需求分析和功能设计时,**要针对一个需求进行拆分,最终拆分成一个个的功能点,这些功能点最终落实到一个个对应的应用中,对应的逻辑体现就是应用代码的一个feature分支**。
|
||||
|
||||
如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/49/69/499a10123bf4b2b30aa90d6c04d78269.jpg" alt="" />
|
||||
|
||||
举个简单的例子,比如我们要做大促的优惠活动,同一店铺商品购满500元,可以使用10元店铺内优惠券,同时还可以使用10元全站优惠券。
|
||||
|
||||
这样一个需求最终拆解下来,可能需要店铺应用支持多优惠活动的叠加,同时下单应用和购物车应用在计算价格时也要设定相关的优惠逻辑,这一个需求可能就拆出三四个功能点。
|
||||
|
||||
这样做的好处就是,**从一开始的需求管理维度,就确定了最终多个应用联调、测试以及最终发布的计划和协作方式**,从而就会让我们明确同一个项目环境中到底需要部署哪些应用,这些应用的发布顺序怎样安排。
|
||||
|
||||
比如,如果A应用依赖B应用,那么B应用就必须优先发布。所以,上述这个过程对于项目进度管理、团队协作以及最终的发布计划都是有帮助的。
|
||||
|
||||
讲到这里,你是不是又进一步感受到了运维的重要性呢?
|
||||
|
||||
当然,每个公司都有不同的项目管理方式,这里我们只要明确做好需求拆分与应用功能的对应即可。
|
||||
|
||||
## 提交阶段之开发模式选择
|
||||
|
||||
在代码提交阶段,我们遇到的第一个问题,就是分支管理问题。这反映出研发团队协作模式的问题。
|
||||
|
||||
我们所熟知的开发协作模式有以下三种:
|
||||
|
||||
- **主干开发模式**。这也是极限编程里提倡的一种模式,每一次代码提交都是合并到master主干分支,确保master随时是可发布状态。但是它对代码开发质量以及持续集成自动化和完善程度要求非常高,通常一般的团队很难做到。
|
||||
- **gitflow开发模式**。因为git的流行,gitflow是专门基于git代码管理的工作流工具,它的特点是在master分支之外,会有一条常驻develop开发分支,所有功能开发和缺陷修复都在这个分支上再建立分支。发布时合入一个从master分支中签出的release分支,最终发布的是release分支代码,然后release分支再合并回master和develop分支。如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/fd/66/fd8f8147903857b8b3297022b106ec66.jpg" alt="" />
|
||||
|
||||
- **分支开发模式**。相对于gitflow模式,分支开发模式会简单清晰很多。它的特点是,功能开发或缺陷修复从master签出独立的一个feature或bug分支,发布前从master分支签出一个release分支,并将要发布的feature或bug分支合入。发布完成后,release分支合入master分支。如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/74/73/74118c699251e8e4371983adf6fd9973.jpg" alt="" />
|
||||
|
||||
## 开发模式的选型原则
|
||||
|
||||
上面我分别介绍了三种开发模式的特点,那么,在实际操作中,我们选择哪一种比较好呢?
|
||||
|
||||
这里的选型原则就是:一看这几种模式的适用场景;二看我们实际的使用场景是怎么样的。
|
||||
|
||||
下面,我们分别看看主干开发和gitflow开发这两种模式。
|
||||
|
||||
**主干开发模式**。它的特点是,所有的代码变更直接提交到master分支,这种情况比较适合规模较大的应用,这类应用自身集中了所有的需求功能点,且需求串行开发,需要多人协作共同完成同一个需求,发布时间点明确、统一。
|
||||
|
||||
这种模式最简单,且便于管理,不需要再建立各种分支。我们之所以在极限编程中提倡这种模式,也是因为这种模式最简单,最便捷,也最高效。因为我们的软件架构在早期还是单体结构且分层架构的,代码相对集中,所以,主干开发模式也是适用的。
|
||||
|
||||
但是,在现实场景下,需求总是层出不穷的,所以就需要需求并行开发。这就会产生这样一种情况:同一应用会有多个团队在同时提交不同需求的代码,且每个需求发布的时间点是不同的。
|
||||
|
||||
所以如果采用主干开发模式,就可能会将还没有经过测试验证的代码发布到线上。这时,我们就需要在代码里预设很多功能开关配置,这样一来,在应用正式上线前,代码可以发布,但是功能不开放,而这样也必然会增加代码的复杂度。
|
||||
|
||||
所以,就有了**gitflow开发模式**。
|
||||
|
||||
gitflow开发模式能够适应并行开发,解决上述我们所说的问题,而且gitflow工具能够从技术层面帮我们解决各种分支合并问题。
|
||||
|
||||
通过上面gitflow的图示,我们可以看出,gitflow开发模式带来的分支的管理代价还是比较高的,且随着分支增加,开发人员之间的沟通协作成本也会随之提高。
|
||||
|
||||
同时,gitflow开发模式还是在代码相对集中的应用场景中更加适用,因此,基于这个应用完成较多的并行需求,就需要通过多个分支来管理。
|
||||
|
||||
在现实场景中,尽管我们日常需求非常多,但是这些需求拆解下来的功能都是集中在某个或某几个应用上的吗?
|
||||
|
||||
其实不然。我们从原来的单体或分层架构演进到微服务架构后,带来的一个好处就是每个应用的职责更加明确和独立,与此同时,针对应用的开发,团队也更加自制,规模更小,符合“两个披萨原则”。
|
||||
|
||||
所以,一个需求拆解出功能,对应到每个应用上,这样可以很好地控制并行的功能点数量,大大降低开发协作的沟通复杂度,即使有合并冲突问题,往往内部沟通一下就可以很快解决。
|
||||
|
||||
而实际上,我们设想的这种复杂的gitflow场景,在微服务架构下的组织架构中极少存在。
|
||||
|
||||
在此,经过对主干开发模式和gitflow开发模式这二者的综合对比,结合前面我对分支开发模式的介绍,我们可以看出,分支开发模式简单清晰,在实际操作中更适合我们使用。
|
||||
|
||||
最后,留个问题给你:你对于开发协作模式是如何选择的?存在哪些问题?有什么更好的建议?
|
||||
|
||||
欢迎你留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
98
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/18 | 持续交付流水线软件构建难吗?有哪些关键问题?.md
Normal file
98
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/18 | 持续交付流水线软件构建难吗?有哪些关键问题?.md
Normal file
@@ -0,0 +1,98 @@
|
||||
<audio id="audio" title="18 | 持续交付流水线软件构建难吗?有哪些关键问题?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/a8/83/a8c746d51bb2ca8c954ccae145999983.mp3"></audio>
|
||||
|
||||
上期文章我们介绍了需求分解与应用对应的管理方式,以及提交环节的开发协作模式,今天我们详细介绍一下提交阶段的构建环节,也就是我们经常提到的代码的编译打包。
|
||||
|
||||
## 构建环节
|
||||
|
||||
由于静态语言从过程上要比动态语言复杂一些,代码提交后,对于Java和C++这样的静态语言,我们要进行代码编译和打包。而对于PHP和Python这样的动态语言,就不需要编译,直接打包即可。
|
||||
|
||||
同时,编译过程就开始要依赖多环境以及多环境下的配置管理,并根据不同的环境获取不同的配置,然后打包到最终的软件发布包中。
|
||||
|
||||
下面我就结合自己的实践经验,以Java为例,对构建环节做下介绍。
|
||||
|
||||
构建过程中我们要用到以下**4种工具**:
|
||||
|
||||
- **Gitlab**,代码管理工具,也是版本管理工具;
|
||||
- **Maven**,依赖管理和自动化构建工具,业界同类型的工具还有Gradle等;
|
||||
- **Docker**,用来提供一个干净独立的编译环境;
|
||||
- **自动化脚本和平台**,自动化构建的任务我们使用Python脚本来实现代码获取、编译执行、软件包生成等。
|
||||
|
||||
具体整个构建过程图示如下:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/2e/87/2ecde6e88787e007f41fb01a85718687.png" alt="" />
|
||||
|
||||
我们以Java为例描述如下。
|
||||
|
||||
1.首先准备好JDK的编译镜像,这个镜像环境与线上运行环境保持一致,比如OS版本、内核参数以及JDK版本等基础环境。当需要启动一个构建任务时,就创建一个对应的Docker实例,作为独立的编译环境。
|
||||
|
||||
2.构建任务会根据应用配置管理中的Git地址,将代码克隆下来放到指定的编译目录。Docker实例启动后,将编译目录挂载到Docker实例中。
|
||||
|
||||
3.执行mvn package命令进行编译打包,最终会生成一个可发布war的软件包。同样的,对于C++、Go、Node.js,也会准备好类似的编译镜像。不同的是,打包时,对于C++中的cmake和make,Go中的go install等等,最终也会生成一个可发布的软件包。
|
||||
|
||||
4.构建完成后,生成软件包放到指定构件库目录,或者直接发布到maven的构件库中管理,然后将Docker实例销毁。
|
||||
|
||||
上述就是一个完整的构建过程。在这里,你一定会有一些疑问,那么,我先回答几个比较常见的问题,欢迎你留言和我继续讨论。
|
||||
|
||||
## 几个关键问题
|
||||
|
||||
**1.配置文件如何打包?**
|
||||
|
||||
这个问题,我们在前面持续交付的多环境配置管理文章中,已经详细介绍过。这里我们结合构建过程,再介绍一下。
|
||||
|
||||
在上述第3个步骤中,我们要进行代码编译。按照持续交付理念,软件只需打包一次就可以各处运行,这对于代码编译是没有问题的,但是对于一些跟环境相关的配置就无法满足。
|
||||
|
||||
比如,我们前面讲到,不同的环境会涉及到不同的配置,如DB、缓存。而且,其他公共基础服务在不同环境中也会有不同的地址、域名或其他参数配置。
|
||||
|
||||
所以,我们就需要建立环境与配置之间的对应关系,并保存在配置管理平台中,至于如何来做,大家可以参考前面多环境配置管理的文章。
|
||||
|
||||
这里我们回到打包过程上来。
|
||||
|
||||
在做构建时,我们是可以确认这个软件包是要发布到哪个环境的。比如,按照流程,当前处于线下集成测试环境这个流程环节上,这时只要根据集成测试环境对应的配置项,生成配置文件,然后构建进软件包即可。如果是处于预发环境,那就生成预发环境对应的配置文件。
|
||||
|
||||
在我们的实际场景中,多个环境需要多次打包,这与我们持续交付中只构建一次的理念相悖。这并不是有意违背,而是对于Java构建出的交付件,最终无论生成的是war包,还是jar包,上述提到的跟环境相关的配置文件,是要在构建时就打入软件包中的。
|
||||
|
||||
而且在后续启动和运行阶段,我们是无法修改已经构建进软件包里的文件及其内容的。这样一来,配置文件无法独立发布,那么就必须跟软件包一起发布。所以,在实际场景下,我们要针对不同环境多次打包。
|
||||
|
||||
那么,我们如何确保多次打包的效果能够和“只构建一次”理念的效果相一致呢?
|
||||
|
||||
这就还是要依赖我们前面介绍的各个环节的建设过程,主要有以下3个方面:
|
||||
|
||||
- 代码提交。通过分支提交管理模式,每次构建都以master为基线,确保合入的代码是以线上运行代码为基础的。且前面的发布分支代码未上线之前,后续分支不允许进入线上发布环节,确保发布分支在多环境下是同一套代码。
|
||||
- 编译环境统一。上述过程已经介绍,编译环境通过全新的Docker容器环境来保证。
|
||||
- 配置管理。前面介绍到的多环境配置管理手段, 通过模板和auto-config的配置管理能力,确保多环境配置项和配置值统一管理。
|
||||
|
||||
至此,一个完整的软件构建过程就完成了。可以看到,如果充分完善前期的准备工作,在做后期的方案时就会顺畅很多。
|
||||
|
||||
**2.为什么用Docker做编译环境的工具?**
|
||||
|
||||
Docker容器很大的一个优势在于其创建和销毁的效率非常高,而且每次新拉起的实例都是全新的,消除了环境共用带来的交叉影响。而且对于并发打包的情况,Docker可以快速创建出多个并行的实例来提供编译环境,所以无论在效率上还是环境隔离上,都有非常好的支持。
|
||||
|
||||
你可以尝试一下我的这个建议,确实会非常方便。
|
||||
|
||||
**3.为什么不直接生成Docker镜像做发布?**
|
||||
|
||||
在使用Docker容器做编译的过程中,我们最终取得的交付件模式是一个war包,或者是一个jar包,这个也是我们后续发布的对象。
|
||||
|
||||
可能有读者会问:为什么不直接生成Docker镜像,后续直接发布镜像?
|
||||
|
||||
这确实是一个好问题。如果单纯从发布的维度来看,直接发布镜像会更方便,更高效。不过,在现实场景下,我们应该更全面地看问题。
|
||||
|
||||
早期我们曾有一段时间使用OpenStack+Docker的模式进行物理机的虚拟化,以提升资源利用率。这实际上是将容器虚拟机化。
|
||||
|
||||
也就是说,虽然Docker是一个容器,但是我们的使用方式仍然是虚拟机模式,要给它配置IP地址,要增加很多常用命令比如top、sar等等,定位问题需要ssh到容器内。
|
||||
|
||||
这里一方面是因为基于Docker的运维工具和手段没有跟上,当时也缺少Kubernetes这样优秀的编排工具;另一方面,我们之前所有的运维体系都是基于IP模式建设的,比如监控、发布、稳定性以及服务发现等等,完全容器化的模式是没有办法一步到位的。
|
||||
|
||||
所以,这里我们走了个小弯路:容器虚拟机化。那为什么我们不直接使用虚拟机,还能帮我们省去很多为了完善容器功能而做的开发工作?所以一段时间之后,我们还是回归到了KVM虚拟机使用方式上来。
|
||||
|
||||
这样也就有了上述我们基于虚拟机,或者更准确地说,是基于IP管理模式下的持续交付体系。
|
||||
|
||||
经过这样一个完整的持续交付体系过程后,我们总结出一个规律:
|
||||
|
||||
容器也好,虚拟机也罢,这些都是工具,只不过最终交付模式不一样。但是前面我们所讲的不管是标准化、多环境、配置管理等等这些基础工作,无论用不用容器都要去做。而且,容器的高效使用,一定是建立在更加完善和高度标准化的体系之上,否则工具只会是越用越乱。
|
||||
|
||||
关于持续交付流水线软件构建方面的内容,我们今天先分享到这里,欢迎你留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
<audio id="audio" title="19 | 持续交付中流水线构建完成后就大功告成了吗?别忘了质量保障" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/cc/2a/cc333de633f9dfcc578996011c0a052a.mp3"></audio>
|
||||
|
||||
上期文章我结合自己的实践经验,介绍了持续交付中流水线模式的软件构建,以及在构建过程中的3个关键问题。我们可以看出,流水线的软件构建过程相对精简、独立,只做编译和打包两个动作。
|
||||
|
||||
但需要明确的是,在持续交付过程中,我们还要做很多与质量保障相关的工作,比如我们前面提到的各类功能测试和非功能测试。
|
||||
|
||||
所以,今天我们聊一聊在流水线构建过程中或构建完成之后,在质量保障和稳定性保障方面,我们还需要做哪些事情。
|
||||
|
||||
首先,我们回顾一下之前总结的这张流程图:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ea/da/ea926382484f49fb6a9250a07fc4a5da.jpeg" alt="" />
|
||||
|
||||
可以看出,在流水线构建过程中,我们尤其要重视以下3个方面的工作内容。
|
||||
|
||||
## 依赖规则限制
|
||||
|
||||
主要是对代码依赖的二方包和三方包做一些规则限制。比如,严格限定不允许依赖Snapshot版本;不允许引入有严重漏洞的版本,如Struts2的部分版本;检测JAR包冲突,如我们常用的Netty、Spring相关的包;限定某些软件包的最低版本发布,如内部提供的二方包,以确保版本收敛,降低维护成本。
|
||||
|
||||
过滤规则上,通过Maven构建软件包过程中生成的dependency:list文件,将GroupID和ArtifactID作为关键字,与我们设定的版本限制规则进行匹配。
|
||||
|
||||
两个示例如下(真实版本信息做了修改):
|
||||
|
||||
检测JAR包冲突:
|
||||
|
||||
>
|
||||
<p>[WARNING] 检测到jar包冲突: io.netty:netty-all, 版本: 4.0.88.Final, 当前使用:<br />
|
||||
4.0.22.Final</p>
|
||||
|
||||
|
||||
限定最低版本:
|
||||
|
||||
>
|
||||
<p>[WARNING] 检测到 mysql:mysql-connector-java, 版本 5.0.22, 版本不符合要求, 需要大于等于<br />
|
||||
5.0.88。旧版存在已知兼容性bug,导致连不上数据库, 请在2018-01-15 00:00:00前升级完成, 否则将被禁止发布,如有疑问,请联系@发布助手</p>
|
||||
|
||||
|
||||
JAR包依赖以及维护升级,通常是一件令我们比较头疼的事情,特别是在运行时出现的冲突异常,更是灾难性的。为了从技术角度更好地进行管理,我们需要做好隔离,这一点可以利用JVM类加载机制来实现。
|
||||
|
||||
如果你有兴趣,可以在网上参考阿里的潘多拉(Pandora)容器设计资料,这里我们就不作详细介绍了。
|
||||
|
||||
## 功能测试
|
||||
|
||||
包括单元测试、接口测试、联调测试和集成测试。这里的每个测试环节起到的作用不同,联调测试和集成测试依赖的主要手段还是手工验证,所以这里我们分享下可以通过自动化手段完成的单元测试和接口测试。
|
||||
|
||||
这里主要用到的几个工具:
|
||||
|
||||
- JUnit 和TestNG,分别做单元测试和接口测试;
|
||||
- Maven插件,maven-surefire-plugin,用来执行JUnit或TestNG用例;
|
||||
- JaCoCo,分析单元测试和接口测试后的代码覆盖率;
|
||||
- Jenkins,自动化测试任务执行,报表生成和输出,与Maven、JUnit、GitLab这些工具结合非常好。
|
||||
|
||||
关于上述这几种工具,我在此就不展开详细介绍了,你可以自行上网查询和学习。
|
||||
|
||||
下面,我们分析一下功能测试中的两个重要环节:单元测试和接口测试。
|
||||
|
||||
- **单元测试**,由开发完成测试用例的开发,对于需要连接DB的用例,可以用DBUnit这样的框架。用例的自动执行,每次代码开发完成,开发执行mvn test在本地进行自测通过,然后提交到GitLab。可以在GitLab中设置hook钩子,和回调地址,提交的时候在commitMsg增加钩子标识,如unitTest,这样提交后就触发回调自动化单元测试用例执行接口,确保提交后的代码是单元测试通过的,最终可以通过JaCoCo工具输出成功率和代码覆盖率情况。
|
||||
- **接口测试**,用例编写上使用TestNG,这个测试框架相比JUnit功能更全面,也更灵活一些。但是过程上与单元测试类似,当然也可以不通过hook方式出发,可以通过手工触发进行测试。
|
||||
|
||||
上述自动化测试环节结束,软件包就可以发布到我们之前说的项目测试环境或集成测试环境进行功能联调和测试了,这时就需要部分人工的介入。
|
||||
|
||||
## 非功能测试
|
||||
|
||||
在功能验证的同时,还需要并行进行一些非功能性验证,包括安全审计、性能测试和容量评估 。分别介绍如下:
|
||||
|
||||
- **安全审计**,由安全团队提供的源代码扫描工具,在构建的同时,对源代码进行安全扫描,支持Java和PHP语言。可以对源代码中的跨站脚本、伪造请求、SQL注入、用户名密码等敏感信息泄露、木马以及各类远程执行等常见漏洞进行识别,对于高危漏洞,一旦发现,是不允许构建出的软件包发布的。而且实际情况是,不审不知道,一审吓一跳,我们前面几次做代码扫描时,各种漏洞触目惊心,但是随着工具的支持和逐步改进,基本已经将这些常见漏洞消灭在萌芽状态。
|
||||
|
||||
下面是扫描结果的简单示例(目前扫描工具已经开源,请见文末链接):
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/f2/ba/f23e8221f44961933cea0cf17404c8ba.png" alt="" />
|
||||
|
||||
- **性能和容量压测**,主要针对核心应用,进行发布前后的性能和容量比对,如果出现性能或容量差异较大,就会终止发布。关于这一点,我在后面稳定性保障的文章中会详细介绍到。这个验证工作,会在预发或Beta环境下进行验证,因为这两个环境是最接近线上真实环境的。
|
||||
|
||||
下图是一张发布前后的效果比对示意图,正常情况下,性能曲线应该是基本重叠才对,不应该出现较大的偏差。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/f0/a9/f0f7fb90f2b67b9136aeebebfe987ba9.jpeg" alt="" />
|
||||
|
||||
## 最后
|
||||
|
||||
到这里,我们稍作一个总结。
|
||||
|
||||
关于持续交付中的流水线模式,我们在前面两期文章以及本期的分享中,相对完整地介绍了从需求分解开始,到代码提交、软件构建,再到功能和非功能测试验证的整个过程。这个过程就是我们常说的持续集成。
|
||||
|
||||
之所以我没有在一开始引入这个概念,是因为,如果我们将注意力集中到这一过程中具体的动作和问题上,会更有利于我们理解,而不是一开始就被概念性的术语和框架束缚住。
|
||||
|
||||
流水线模式功能测试和非功能测试的整个过程可以总结如下:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/0b/83/0b305f4deb787c3f272c5267c22c6683.jpeg" alt="" />
|
||||
|
||||
同时,我们在上面持续集成的过程中,要基于前面介绍的各类环境和基础配置管理,比如功能验证就需要在线下环境中的开发环境、项目环境以及集成测试环境上进行验收。
|
||||
|
||||
而非功能验证的性能和容量评估,就需要在线上环境里的预发或Beta环境中完成。这里就已经涉及到了软件的部署发布。
|
||||
|
||||
下一期文章,我将分享线上发布的整个过程,并对整个持续交付体系内容做一个收尾。欢迎你留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
附:源代码安全审计工具<br />
|
||||
[https://github.com/wufeifei/cobra](https://github.com/wufeifei/cobra%5Breference_end%5D)
|
||||
@@ -0,0 +1,102 @@
|
||||
<audio id="audio" title="20 | 做持续交付概念重要还是场景重要?看“笨办法”如何找到最佳方案" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/4e/c4/4e00d399014a5495a126d27fdf1f36c4.mp3"></audio>
|
||||
|
||||
上期文章中我们讲到,在经过严格的依赖规则校验和安全审计之后,构建出的软件包才可以部署发布。
|
||||
|
||||
在开发环境、项目环境、集成测试环境以及预发环境下,我们还要进行各类的功能和非功能性测试,最后才能发布到正式的生产环境之上。
|
||||
|
||||
通常状况下,做一次软件版本发布,必须经过以下几个环境(如下图所示)。需要明确的是,项目环境和“小蘑菇”(内部叫法)环境,只有特殊版本才会配备,这里我们不做强制。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/36/6e/36066f4cc87bf4337a4f84e42cfd256e.jpg" alt="" />
|
||||
|
||||
上述这些环境我们在之前都介绍过。而历经如此多的环境,高效的自动化持续部署和发布就变得尤为重要。
|
||||
|
||||
特别是最后的线上发布环节,还需要确保业务连续稳定、无间断,所以,在复杂的微服务架构环境下,我们对软件的发布策略选择、自动化程度和稳定性要求就更高了。
|
||||
|
||||
今天,我们一起看看整个流水线软件部署和发布的细节。
|
||||
|
||||
## 软件的持续部署发布
|
||||
|
||||
这里,我们直接以生产环境的发布过程来讲解。软件的部署发布,简单来说就是:
|
||||
|
||||
**将构建完成和验证通过的应用软件包,发布到该应用对应环境下的IP主机上的指定目录下,并通过应用优雅上下线,来实现软件最新版本对外提供服务的过程。**
|
||||
|
||||
这个过程会包含的环节,我以图示整理如下:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/71/b0/71bf16155f4071bda146db69a3ac67b0.jpg" alt="" />
|
||||
|
||||
我们可以看到,软件部署发布,听上去就是把软件部署一下,然后启动起来。这样的操作方式对于单体架构软件没有问题,但是在微服务架构下就满足不了要求了。
|
||||
|
||||
单体架构软件启动起来就可以提供服务,但是对于微服务应用,无论停止还是启动,都需要考虑到对周边其它依赖和被依赖应用的影响才可以,考虑的点也就相对较多。
|
||||
|
||||
我们针对单机发布,分环节来看一下:
|
||||
|
||||
1.从CMDB中,拿到线上生产环境下的应用主机IP列表去对应关系,目的是要将软件包发布到应用对应的IP主机上。
|
||||
|
||||
2.检查每台机器上的服务是否正常运行,如果是正常服务的,说明可以发布,但是服务本身异常,就要记录或跳过。
|
||||
|
||||
3.下载war包到指定目录。这里要依赖前期我们介绍的应用配置管理,在这一步要获取到该应用的源代码目录。
|
||||
|
||||
4.关闭该应用在这台主机上的监控,以免服务下线和应用终止产生线上错误告警。
|
||||
|
||||
5.优雅下线。RPC服务从软负载下线,如果该应用还提供了http的Web调用,就需要从Nginx这样的七层负载下线,下线动作均通过API接口调用方式实现。
|
||||
|
||||
6.下线后经过短暂静默,重启应用。对于Java应用来说,重启时可以自动解压,启停命令等还是之前从应用配置管理中获取响应路径和命令脚本名称。
|
||||
|
||||
7.优雅上线,进行健康监测,检查进程和应用状态是否正常,如果全部监测通过,则开始上线服务,开启监控。
|
||||
|
||||
上述是一个应用的单机发布过程,过程比较长,但是可以看出,每个环节并不复杂。这里我们需要注意两个关键点:
|
||||
|
||||
- **针对场景,进行细分,这样就可以化整为零,把一个乍看上去很复杂的过程,分解成一个个可执行的步骤。**
|
||||
- 与服务化的软负载和注册中心进行交互,确保应用是可以优雅上下线的,而不是简单粗暴地启动和停止。
|
||||
|
||||
## 发布策略
|
||||
|
||||
上述过程是针对单机的操作步骤。但是,如果我们有上百台主机,甚至一些大的集群有上千台主机,这时应该怎么发布呢?这里就涉及到发布策略问题。
|
||||
|
||||
业界常见的几种模式,如蓝绿发布、灰度发布(金丝雀发布)、滚动发布等等,这几种模式网上资料丰富,在这里我们就不逐一展开详细介绍了。
|
||||
|
||||
这里,我们主要以**灰度发布和滚动发布的组合方式**为例,详细分析一下这种发布模式。
|
||||
|
||||
前面介绍的线上Beta环境,选择的就是金丝雀发布模式,我们内部称之为灰度发布或Beta发布。后来国外Netflix持续交付经验传播比较广,所以我们经常可以听到金丝雀发布这种方式,而其本质上还是灰度发布模式。
|
||||
|
||||
Beta环境下,我们会保留1-2台应用主机,引入较少的线上真实用户流量。发布到这个环境上时,对于核心应用和大规模的集群,我们会静默较长时间,以观察应用的新版本运行状态。
|
||||
|
||||
如果没有严重的报错或崩溃,静默期过后,我们认为软件质量和稳定性是没有问题的,接下来就会发布到正式的生产环境上。
|
||||
|
||||
因为生产环境上大的集群可能会有上百台甚至上千台主机,如果每台主机逐一单独发布,这样会导致发布效率过低;但是一次性发布数量太多,又会对线上应用容量大幅度缩减,极有可能会导致服务雪崩或业务中断。
|
||||
|
||||
所以我们选择的方式就是滚动发布,或者可以理解为分批次发布:即每批次发布10台或20台,升级完成后,再启动下一批次发布。这样每次发布的机器数量可以自行设定,但是必须低于50%。
|
||||
|
||||
至此,一个应用的滚动发布流程就结束了。根据我们实践的具体情况,这种灰度加滚动的发布模式,相对平稳和可控。相比于蓝绿发布,不需要额外再独立一个环境出来,且不需要每次发布都要做一次整体的流量切换,避免产生较大的操作风险。
|
||||
|
||||
对于回滚,我们会根据上个版本的war包名称记录,在发布过程中或发布后出现严重情况时,直接快速回滚。因为这个操作是在紧急和极端的情况下才执行,所以提供一键操作,过程跟上述的发布过程相似,在此也不再赘述。
|
||||
|
||||
## 持续交付体系的收益
|
||||
|
||||
持续交付体系运作起来后,整个流水线过程完全自助发布,运维无需介入,达到了DevOps,或者说是NoOps的效果。如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e5/2f/e5970628742eda8e67e2b9509fcde02f.jpg" alt="" />
|
||||
|
||||
## 总结
|
||||
|
||||
至此,我们整个持续交付体系的内容就全部介绍完了。对于整个过程的总结,你可以参考本专栏“持续交付”主题的第一篇文章[《持续交付知易行难,想做成这事你要理解这几个关键点》](https://time.geekbang.org/column/article/2631),我在文中对整个持续交付体系进行了比较完整的梳理。
|
||||
|
||||
细心的你应该可以发现,到本期文章为止,我并没有提到太多DevOps相关的内容,而这个恰恰是当前业界非常火热的概念。在写作过程中,我也没有特别强调持续交付是什么,持续集成是什么,而这些又是当前DevOps里面特别强调的部分。
|
||||
|
||||
我之所以这样做是因为,概念都是一个个名词或者Buzzword(时髦名词),它们所表达的意思也都非常泛,每个人,每个团队或每个组织对它们的理解以及解读都是不一样的。
|
||||
|
||||
就拿DevOps举例,有谁能说清楚它到底是什么,到底代表什么意思?估计一千个人会有一千种理解,不同的团队对它的实践模式也不一样。
|
||||
|
||||
所以,如果直接从概念出发,反而容易让我们迷失方向,忘记想要解决的问题,让我们脱离所处的实际场景,把精力都放在了各种所谓的工具和技术上。这一点也恰恰与我所一直强调的,要从实际问题和业务场景出发来考虑解决方案相违背。
|
||||
|
||||
在我们“持续交付”主题的分享中,你可以看到,有很多的解决方案并没有标准化的模式,也没有哪一个工具或技术能够直接解决这些问题。
|
||||
|
||||
我们所采取的手段,其实都是些笨办法:即找到问题,分析问题,调研解决方案,讨论碰撞,然后慢慢摸索和实践,找出最合适我们的方式。
|
||||
|
||||
希望我的分享能够给你带来启发,就像我们开篇词提到的:思路上的转变远比技术上的提升更为重要。
|
||||
|
||||
欢迎你留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
83
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/21 | 极端业务场景下,我们应该如何做好稳定性保障?.md
Normal file
83
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/21 | 极端业务场景下,我们应该如何做好稳定性保障?.md
Normal file
@@ -0,0 +1,83 @@
|
||||
<audio id="audio" title="21 | 极端业务场景下,我们应该如何做好稳定性保障?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/3d/64/3d7ed5a0f68a60d1361710a6a2c5e764.mp3"></audio>
|
||||
|
||||
从今天开始,和你分享我对微服务和分布式架构下的稳定性保障的理解。
|
||||
|
||||
稳定性保障需要一定的架构设计能力,又是微服务架构比较核心的部分。在陈皓老师的“左耳听风”专栏,以及杨波老师的“微服务架构核心20讲”专栏都有非常详细的介绍。所以在我的专栏里,我会结合特定的场景,并着重从运维和技术运营的角度来分享。
|
||||
|
||||
## 我们所面对的极端业务场景
|
||||
|
||||
首先,看一下我们当前所面对的极端业务场景,我把它大致分为两类。
|
||||
|
||||
1.**可预测性场景**
|
||||
|
||||
什么是可预测性?简单来说,就像电商每年的大促,如618、双11、双12等等。这类业务场景是可预测的,业务峰值和系统压力峰值会出现在某几个固定的时间点,我们所做的所有准备工作和稳定性应对措施,都是针对这些固定时间点的,比如零点时刻。
|
||||
|
||||
峰值压力可预测,就意味着可以提前评估用户访问模型,并根据模型进行压测调优。发现系统中的瓶颈就调优或者扩容,调整完成之后,继续压测,继续调整,直至系统容量达到原来设定的目标。由此可见,在可预测的场景下,与后面的不可预测场景相对比,从准备过程上来说会更加从容。
|
||||
|
||||
但是,我们的优化或扩容是有限度的,也就是不会无限度地投入成本,来满足零点这个峰值时刻,让所有用户都能够正常访问。从成本和收益角度来说,这样做是不现实的。
|
||||
|
||||
所以,在峰值那个时间点上,当用户流量远远大于系统容量时,我们所采取的措施绝不是再去扩容或优化,因为无论是从时效性、系统稳定性还是成本收益上看,这样做都已经无法满足要求了。
|
||||
|
||||
那我们该采取什么策略呢?这里我们采取的策略是在系统承诺容量内,保证系统的核心功能能够正常运行。以电商为例,就是要确保整个交易链路是正常的,用户可以正常登陆,访问商品,下单并最终支付。对于非核心功能,就会通过预案执行功能降级。对于超出系统承诺容量的部分进行流量限流,并确保在某些异常状况下能够熔断或旁路,比如缓存故障,就要马上限流并将请求降级到数据库上。
|
||||
|
||||
所以,我们在618,双11和双12的零点峰值时刻去访问各大电商网站,很大概率上都会提示系统正忙,请稍后再试,短则2~3分钟,长则5~10分钟,再去访问,网站功能就一切正常了。这并不代表各大电商网站宕机了,而是其在瞬时超大流量访问压力下采取的一种保护措施,这一点反而说明这些电商网站的大促预案非常完善。
|
||||
|
||||
2.**不可预测性场景**
|
||||
|
||||
我刚刚提到的电商大促场景,其实已经非常复杂了,没有一定的整体技术能力,想做好从容应对也并非易事。我们这两年做大促模拟压测,动辄上百号人通宵投入,说到底还是在这方面的经验以及各类工具平台的积累不够,体系的完善需要一定的周期和过程。
|
||||
|
||||
那不可预测的场景就更为复杂。社交类业务就具有这种明显的特征,比如微博、朋友圈、空间等等。以微博为例,我们知道之前鹿晗公布恋情,王宝强以及乔任梁等的突发事件等等,这些事情什么时候发生,对于平台来说事先可能完全不知道,而且极有可能是大V的即兴发挥。当然,现在因为商业合作上的原因,某些大V的部分营销活动也会与各类社交业务平台提前沟通,确保活动正常执行,但是即使是提前沟通,周期也会非常短。
|
||||
|
||||
对于不可预测性的场景,因为不知道什么时候会出现突发热点事件,所以就无法像电商大促一样提前做好准备。社交类业务没法提前准备,就只能随时准备着,我认为这个挑战还是非常大的。
|
||||
|
||||
## 我们要迎接的技术挑战
|
||||
|
||||
说完了场景,我们来看看这给技术带来了哪些挑战。
|
||||
|
||||
1.**运维自动化**
|
||||
|
||||
这个不难理解,应对极端场景下的系统压力,一定要有资源支持,但是如何才能将这些资源快速扩容上去,以提供业务服务,这一点是需要深入思考的。结合前面我们讲过的内容,**标准化覆盖面是否足够广泛,应用体系是否完善,持续交付流水线是否高效,云上资源获得是否足够迅速,这些都是运维自动化的基础**。特别是对于不可预测的场景,考验的就是自动化的程度。
|
||||
|
||||
2.**容量评估和压测**
|
||||
|
||||
我们要时刻对系统容量水位做到心中有数,特别是核心链路,比如电商的交易支付链路。我们只有对系统容量十分清楚,才能针对特定场景判断出哪些应用和部件需要扩容,扩容多少,扩容顺序如何。同时,系统容量的获取,需要有比较完善的自动化压测系统,针对单接口、单应用、单链路以及全链路进行日常和极端场景下的模拟压测。
|
||||
|
||||
3.**限流降级**
|
||||
|
||||
我们前面提到了电商大促的例子,业务在峰值时刻,系统是无论如何也抵御不住全部流量的。这个时候,我们要做的就是保证在承诺容量范围内,系统可用;对于超出容量的请求进行限流,请用户耐心等待一下。如何判断是否需要限流呢?这时我们要看系统的各项指标,常见的指标有CPU、Load、QPS、连接数等等。
|
||||
|
||||
同时,对于非核心的功能,在峰值时刻进行降级,以降低系统压力。这里有两种方式,分别是**主动降级**和**被动降级**。主动降级就是在峰值时刻,主动把功能关掉,如商品评论和推荐功能等等;我们前面介绍到的静态化,也是一种降级策略。对于被动降级,也就是我们常听到的**熔断**。某个应用或部件故障,我们要有手段将故障隔离,同时又能够保证业务可用,所以会涉及故障判断和各类流量调度策略。
|
||||
|
||||
4.**开关预案**
|
||||
|
||||
上面介绍到的限流降级,也是一类开关,属于**业务功能开关**;还有一类是**系统功能开关**,比如当缓存故障时,我们就需要将请求转发到数据库上,目的也只有一个,让系统可用。但是问题来了,数据库的访问效率没有缓存高,所以缓存可以支撑的流量,数据库肯定是支撑不了的,怎么办呢?这时,就要与限流策略结合起来,先限流,限到数据库能够支撑的容量,再做降级。这样几个策略组合在一起,就是应急预案的执行了。当然,预案里面还会有业务预案。
|
||||
|
||||
5.**故障模拟**
|
||||
|
||||
上述预案,需要在日常,甚至是从经历过的故障中提炼出场景,制定好策略,然后不断进行模拟演练。只有这样,等到真正出现问题时,我们的预案才可以高效执行。我们知道Netflix的Chaos Engineering,其中的Chaos Monkey,就是专门搞线上破坏,模拟各种故障场景,以此来看各种预案执行是否到位,是否还有可以改进的地方。
|
||||
|
||||
所以,类似Chaos Engineering的**故障模拟系统**,也需要建设起来。我们需要模拟出一些场景,比如最常见的CPU异常,RT响应异常,QPS异常等等,看我们的预案是否能够快速执行,能够保持系统或将系统快速恢复到正常状态。
|
||||
|
||||
6.**监控体系**
|
||||
|
||||
最后,我再提一下监控。通过我们前面介绍的内容,监控的重要性就不言而喻了,因为所有的指标采集和统计,异常判断,都需要监控体系的支持。监控体系和前面介绍的运维自动化一样,都是最为基础的支撑平台。
|
||||
|
||||
## 极端业务场景下的不确定因素
|
||||
|
||||
上面我们讨论了极端业务场景给技术层面带来的挑战。但是**对于稳定性保障而言,我认为最困难的部分,不在技术层面,而是在业务层面,也就是用户的业务访问模型**。从技术层面来说,我们还有一些确定的套路可以去遵循,但是访问模型就是个极不确定的因素了。
|
||||
|
||||
我们这里还是以电商来举例说明,比如大促时用户下单这个逻辑。一个用户在购物车勾选商品去结算这个场景,用户的访问模型或业务场景就可能会有很多变化,比如是下1个商品的订单,还是同时5个商品的订单?每个商品的购买数量是1个、2个还是3个?商品的购买数量有没有限制?这些商品涉及1个卖家,还是多个卖家?不同卖家又会有不同的优惠折扣,是买二送一,还是满100送20?满一定额度之后是否包邮?全站促销是否有全站优惠,是否有时间段限制?优惠之间是否有优先级和互斥逻辑?支付方式是优先使用支付宝,还是微信,亦或是银行卡等等。
|
||||
|
||||
上面这些还只是简单描述,并且是针对单个用户的。当用户数量达到几十万,上百万之后,用户行为可能还有访问首页、详情页以及搜索的情况等等,场景更复杂,整个业务模型中的变量因素就会非常多,且不确定。
|
||||
|
||||
往往某个因素的变化,就可能带来容量模型的改变。假设1个商品,1个卖家,1个优惠策略,对DB产生的QPS是20,TPS是10,但是这其中的因素稍微一变化,产生的QPS和TPS就是翻倍的。如果这一点评估不到位,大促时实际的用户场景跟预估的偏差过大,系统可能就会挂掉。
|
||||
|
||||
所以,**对于稳定性而言,用户访问模型才是关键,这个摸不准,只有技术是没用的,这就更需要我们能够深入业务,理解业务**。
|
||||
|
||||
我们经常听到的“脱离业务谈架构,谈技术,都是不负责任的”,原因就在于此。希望今天的内容能够让你在学习到知识和技能的同时,也有所启发,切忌脱离业务,空谈技术。
|
||||
|
||||
今天我们分享了极端业务场景下,如何做好稳定性保障。关于稳定性保障,你还有哪些问题?有过怎样的经验?欢迎你留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
57
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/22 | 稳定性实践:容量规划之业务场景分析.md
Normal file
57
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/22 | 稳定性实践:容量规划之业务场景分析.md
Normal file
@@ -0,0 +1,57 @@
|
||||
<audio id="audio" title="22 | 稳定性实践:容量规划之业务场景分析" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/18/f5/184f68243dbba41a7ca5d9ca52d3a6f5.mp3"></audio>
|
||||
|
||||
上期文章我们从整体上介绍了极端业务场景下,如何做好稳定性保障工作。今天,我们结合电商大促这个场景,来看一下容量规划这项工作。
|
||||
|
||||
稳定性保障的一个难点是我们要面对一个非常复杂的因素,那就是业务模型,或者叫用户访问模型。因为它的不确定性,会衍生出很多不同的业务场景,而不同的场景,就会导致我们的应对策略有所不同。
|
||||
|
||||
所以,**容量规划,就是对复杂业务场景的分析,通过一定的技术手段(如压力测试),来达到对资源合理扩容、有效规划的过程。**
|
||||
|
||||
## 容量规划的场景分析
|
||||
|
||||
我们一直在讲,不能脱离业务场景空谈技术,所以我们还是先从电商大促这个业务场景入手来分析。
|
||||
|
||||
对于电商来说,核心链路就是交易链路。简单来说,就是用户要能登录,然后能通过浏览商品详情页下单订购,或者加购物车,通过购物车进行订购结算,这个过程中还要进行各种优惠的批价处理,库存的判断等等,形成订购之后,最终还要能够支付成功,一个完整的交易支付流程才算走完。
|
||||
|
||||
在大促的峰值时刻,场景可能又有不同,因为绝大部分用户选购什么商品,早已加入到了购物车中,且各种优惠券也已经申领成功,就等着最后这个时间点直接下单完成订购。所以,在大促这个场景下,交易下单这个环节是核心中的核心。
|
||||
|
||||
因为这个时间点的交易流量实在是太高了,所以近两年电商也改变了一些玩法,其目的就是希望减少峰值流量,让流量在整个大促阶段更加均匀。具体的运营和玩法细节这里就不详细介绍了。
|
||||
|
||||
那么,我们要应对的场景就相对清晰了,就是在大促零点峰值时刻,评估好交易流量,再进一步转化一下,就是每秒的交易订单峰值。
|
||||
|
||||
下图就是我们进行评估的路径分析示例,用户首先从首页、大促会场或者微信里的分享页面转化过来,然后通过搜索、店铺、详情页以及购物车进行最后的转化,形成订购下单和最终的支付。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/90/b5/90685bdcdcd7bf196d42ce764250eab5.jpg" alt="" />
|
||||
|
||||
具体数值的评估上,我们会跟产品运营团队共同讨论,整体的业务目标由运营团队给出,比如GMV目标收入,UV、PV、转化率、客单价以及商品单价,这些都是业务目标。通过这些业务数据,我们根据上图的路径逐步分解,就会逐步得出每一层的流量数据。
|
||||
|
||||
假设大促会场会有500万UV,根据GMV和客单价,如果要完成目标,推导出到详情页的转化率需要达到60%(产品运营需要努力达成这个业务目标),那详情页的UV就是300万;根据用户访问行为分析,对详情页的各个应用产生的QPS再做一个评估,这样单个应用的容量值就有了,然后再进一步向下转化,能够形成订购,形成加购物车的又有多少,再进行评估,最后就可以得出一个交易下单的峰值以及支付的峰值。
|
||||
|
||||
计算出峰值后,还要与历年评估的峰值数据,以及实际的峰值数据进行对比,根据对比情况进行调整。评估出来的这个峰值,就是系统要承诺支撑的容量,因为只有达到这个容量值,才能支撑业务完成对应的业务目标。
|
||||
|
||||
总结来说,**这就是一个根据业务GMV、UV等目标,对技术上的交易下单峰值这个核心指标进行推导的过程**。
|
||||
|
||||
那么,接下来就根据评估的各个应用和基础服务需要承担的流量,先扩容一轮,同时开始构造数据模型和压测模型来模拟真实流量,以此验证我们的系统是否能够达标,过程中再进行局部的扩容和优化。
|
||||
|
||||
一般来说,先进行单链路压测,比如购物车订购,详情页订购等场景的压测,达标后再进行多链路压测,最后再进行全链路压测,直至达成目标。为了能够保有一定的容量缓冲,最后几轮压测,我们会将压测流量调整到目标值的120%或150%,来保证系统能够应对足够极端的场景,这样才能够游刃有余地实现100%的目标。
|
||||
|
||||
## 构造压测的数据模型
|
||||
|
||||
如何构造压测的数据模型呢?这是一个比较复杂的问题,因为我们靠拍脑袋或者靠猜,是无法准确评估的。通常情况下,我们从以下两方面入手。
|
||||
|
||||
**一方面,数据模型要接近真实场景**。这就需要我们不断地积累经验,记录早期大促的详细数据和真实场景(比如不同用户购物车里的商品数量、优惠策略、不同渠道比例等,以及各种运营活动的玩法),这样可以最大程度地模拟真实的用户访问模型。这个过程,蘑菇街更多的还是手工推导,像阿里做得比较极致,可以通过BI系统,将往年模型和当年模型进行分析比对,直接生成对应的数据模型,甚至是多套模型。
|
||||
|
||||
**另一方面,数据量要接近真实场景**。数据量有很多维度,比如用户数量、商品数量、店铺数量、优惠券数量等等。这里一般会通过数据工厂这样的工具平台,结合运营团队给出的数据量评估,快速制造出对应量级的数据。另一种方式就是从线上将真实数据,进行敏感信息脱敏处理后,导出到另一张影子表中,专门提供给压测使用,这样做的好处是不会污染线上运行数据。
|
||||
|
||||
## 总结
|
||||
|
||||
通过上面的分享,我们应该不难发现,容量规划工作,单纯靠技术能力是无法解决的,需要经验和数据的积累,到了阿里这个体量就必须借助人工智能和各类分析算法这样更高级的手段才能解决。
|
||||
|
||||
同时,容量问题,也不是简简单单通过资源扩容这种成本投入就可以解决的,扩容是最后的执行手段,但是怎么合理的、科学的扩容,就需要有合理的规划。当业务体量和复杂度到达一定程度时,就要依靠技术人员对业务的深入理解。能够合理规划业务、技术和数据模型,是需要一些经验积累,以及在各类极端场景下的经历。
|
||||
|
||||
最后,如此复杂的技术体系,也只有在同样复杂的场景下才会被催生出来,才会有存在意义。所以,我们在学习借鉴时,还是要从各自的实际场景出发,慢慢积累,大可不必强求短期速成。
|
||||
|
||||
你自己是否有过容量规划的经历?遇到过哪些问题?欢迎你留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
87
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/23 | 稳定性实践:容量规划之压测系统建设.md
Normal file
87
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/23 | 稳定性实践:容量规划之压测系统建设.md
Normal file
@@ -0,0 +1,87 @@
|
||||
<audio id="audio" title="23 | 稳定性实践:容量规划之压测系统建设" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/4f/b4/4ff5e3192cd50a27611c806c93b2bbb4.mp3"></audio>
|
||||
|
||||
容量规划离不开对业务场景的分析,分析出场景后,就要对这些场景进行模拟,也就是容量的压力测试,用来真实地验证系统容量和性能是否可以满足极端业务场景下的要求。同时,在这个过程中还要对容量不断进行扩缩容调整,以及系统的性能优化。
|
||||
|
||||
今天,我们就来看压力测试的技术实现方式:**压力测试系统的建设**。我们详细讲讲压力测试的几个维度。
|
||||
|
||||
## 第一个维度,压测粒度
|
||||
|
||||
压测粒度上,我们一般会遵照从小到大的规律来做。
|
||||
|
||||
1.**单机单应用压力测试**
|
||||
|
||||
优先摸清单个应用的访问模型是怎样的,再根据模型进行单机单应用压力测试。这时我们就可以拿到单个应用和单个应用集群的容量水位,这个值就是后续我们根据业务模型分析之后扩容的基础。
|
||||
|
||||
2.**单链路压力测试**
|
||||
|
||||
获取到单个应用集群的容量水位之后,就要开始对某些核心链路进行单独的压力测试,比如商品详情浏览链路、加购物车链路、订购下单链路等等。如下图的交易下单链路压测模型示例,连线上的数字是不同应用或接口调用的流量占比。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/54/c0/54c5addd42cbc53f96dae60a5c1fb7c0.jpg" alt="" />
|
||||
|
||||
3.**多链路/全链路压力测试**
|
||||
|
||||
当单链路的压测都达标之后,我们就会组织多链路,或者全链路压测。多链路本质上就是多个单链路的组合,全链路就是多链路的组合。如下图就是多个交易场景的多链路组合。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/d5/da/d5aafb73831112af3913aee25a1e7eda.jpg" alt="" />
|
||||
|
||||
## 第二个维度,压测接口及流量构造方式
|
||||
|
||||
接口一般分为HTTP接口和RPC接口,这一点应该不难理解,就不做过多讲解了。
|
||||
|
||||
流量构造方式上,根据压测粒度的不同,会采用不同的方式,我们常见的有以下几种方案。
|
||||
|
||||
1.**线上流量回放**
|
||||
|
||||
这种方式直接利用了线上流量模型,比较接近真实业务场景,常见的技术手段如TCPCopy,或者Tcpdump抓包保存线上请求流量。但是这种方式也存在一些代价,比如需要镜像请求流量,当线上流量非常大的时候就很难全部镜像下来,而且还需要大量额外的机器来保存流量镜像。到了回放阶段,还需要一些自动化的工具来支持,还要解决各种session问题,真正实施的时候,还是会有不少的工作量。
|
||||
|
||||
2.**线上流量引流**
|
||||
|
||||
既然线上回放比较麻烦,那为什么不直接使用线上流量进行压测呢?这个思路确实是可行的,我们前面讲过,压测的主要是HTTP和RPC两种类型的接口,为了保证单个应用的流量压力足够大,这里可以采取两种模式。
|
||||
|
||||
一个是将应用集群中的流量逐步引流到一台主机上,直到达到其容量阈值;另一个方案是,可以通过修改负载均衡中某台主机的权重,将更多的流量直接打到某台主机上,直到达到其容量阈值。
|
||||
|
||||
这个过程中,我们可以设定单台主机的CPU、Load或者QPS、RT等阈值指标,当指标超出正常阈值后就自动终止压测,这样就可以获取到初步的容量值。
|
||||
|
||||
这种方式的好处是,不需要额外的流量模拟,直接使用最真实的线上流量,操作方便,且更加真实。下图是两种引流的方案示例。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/51/f9/51385cd8c40d401c0f2a55742f99adf9.jpg" alt="" />
|
||||
|
||||
3.**流量模拟**
|
||||
|
||||
上述两种流量模拟方式,更适合日常单机单应用的容量压测和规划,但是对于大促这种极端业务场景,真实流量就很难模拟了,因为这种场景只有特定时刻才会有,我们在日常是无法通过线上流量构造出来的。
|
||||
|
||||
所以这里就需要利用数据工厂,最终通过流量平台来形成压测流量。这里的工具用到了Gatling,是一款开源的压测工具,用Scala开发的,后来我们针对自己的需求,比如自动生成压测脚本等,做了一些二次开发。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/19/71/19a2690fca9316a17cfe2b5ccd659971.jpg" alt="" />
|
||||
|
||||
如果会有多种流量模型的话,就要生成多个流量模型,具体可见下图:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/a0/d3/a0d0fc33ecc3e56b3569d22a47b070d3.jpg" alt="" />
|
||||
|
||||
## 第三个维度,施压方式
|
||||
|
||||
上面介绍了容量压测的构造过程,那接下来我们要做的就是对真实的线上系统施加压力流量了。很自然的,这里就需要有施加压力的机器,在上面“全链路压测系统”那张图中,你可以看到,我们的施压方式是通过上百台的机器根据压测脚本和压测数据对系统施压的,我来简单介绍一下大致过程。
|
||||
|
||||
1. 通过实现在Web控制台配置好的压测场景,自动生成压测脚本。
|
||||
1. 利用数据工厂构造出压测数据,这个就是业务场景的模拟,像阿里做得比较完善,就可以借助AI和BI的技术手段生成很多压测模型,且基本都接近于现实情况下的业务场景。
|
||||
1. 通过Web控制台,根据压测脚本和压测数据,生成压测任务,推送到压测集群的Master节点,再通过Master节点推动到上百台的Slave节点,然后就开始向线上系统施加模拟的流量压力了。
|
||||
|
||||
关于施压机的分布,大部分仍然是跟线上系统在同机房内,少量会在公有云节点上。但是对于阿里,因为其自身的CDN节点遍布全球,所以他就可以将全球(主要是国内)的CDN节点作为施压机,更加真实地模拟真实用户从全球节点进入的真实访问流量。这种方式对于蘑菇街就显得成本过高,技术条件和细节也还达不到这个程度。
|
||||
|
||||
当前阿里已经将这种压测能力输出到了阿里云之上,可以说是对其云生态能力的有力补充,同时也为中小企业在容量规划和性能压测方面提供了很好的支持。
|
||||
|
||||
## 第四个维度,数据读写
|
||||
|
||||
压测过程中,对于读的流量更好构造,因为读请求本身不会对线上数据造成任何变更,但是对于写流量就完全不一样了,如果处理不好,会对线上数据造成污染,对商家和用户造成资损。
|
||||
|
||||
所以,对于写流量就要特殊处理,这块也有比较通用的解决方案,就是**对压测的写请求做专门的标记**。当请求要写数据库时,由分布式数据库的中间件框架中的逻辑来判断这个请求是否是压测请求,如果是压测写请求则路由到对应的影子库中,而不是直接写到线上正式的库中。
|
||||
|
||||
在这之前,要提前创建好对应的影子库。假设建立影子库的原则是原schema + mirro,如果正式库是order,则影子库为order_mirror,这时两个库中的数据量必须是一致的。对于非敏感信息,数据内容也可以保持一致,这样可以在最大程度上保证数据模型一致。
|
||||
|
||||
这里再呼应一下我们最开始提到的基础服务标准化工作,如果这个工作在前面做得扎实,它的优势在这里就体现出来了。我们刚刚提到的影子库的路由策略是基于中间件框架来实现的,如果使用的框架不一样,不是标准的,这个功能可能就很难应用起来。这一点在后面全链路以及开关等稳定性方案中,还会涉及到。
|
||||
|
||||
今天我们介绍了容量压测的技术方案,比较复杂,而且需要对相应场景进行针对性的建设。关于细节部分,你还有什么问题,欢迎留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
109
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/24 | 稳定性实践:限流降级.md
Normal file
109
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/24 | 稳定性实践:限流降级.md
Normal file
@@ -0,0 +1,109 @@
|
||||
<audio id="audio" title="24 | 稳定性实践:限流降级" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/3b/62/3b54c9135d31324ecfcc96ada8e38762.mp3"></audio>
|
||||
|
||||
本周我们继续来讨论稳定性实践的内容。在现实情况下,当面对极端的业务场景时,瞬时的业务流量会带来大大超出系统真实容量的压力。
|
||||
|
||||
为了应对,前面我们介绍了容量规划方面的实践经验。不过,我们不会无限度地通过扩容资源来提升容量,因为无论从技术角度,还是从成本投入角度,这样做都是不划算的,也是不现实的。
|
||||
|
||||
所以,我们通常采取的策略就是**限流降级**,以保障承诺容量下的系统稳定;同时还有业务层面的**开关预案**执行,峰值时刻只保障核心业务功能,非核心业务功能就关闭。
|
||||
|
||||
今天我们就先来介绍一下**限流降级的解决方案**。
|
||||
|
||||
## 什么是限流和降级
|
||||
|
||||
首先,我们先梳理清楚限流和降级的概念,明白它们会发挥怎样的作用,这样才便于我们理解后续的解决方案。
|
||||
|
||||
<li>
|
||||
**限流**,它的作用是根据某个应用或基础部件的某些核心指标,如QPS或并发线程数,来决定是否将后续的请求进行拦截。比如我们设定1秒QPS阈值为200,如果某一秒的QPS为210,那超出的10个请求就会被拦截掉,直接返回约定的错误码或提示页面。
|
||||
</li>
|
||||
<li>
|
||||
**降级**,它的作用是通过判断某个应用或组件的服务状态是否正常,来决定是否继续提供服务。以RT举例,我们根据经验,一个应用的RT在50ms以内,可以正常提供服务,一旦超过50ms,可能就会导致周边依赖的报错或超时。所以,这时我们就要设定一个策略,如果应用的RT在某段时间内超过50ms的调用次数多于N次,那该应用或该应用的某个实例就必须降级,不再对外提供服务,可以在静默一定时间后(比如5s或10s)重新开启服务。
|
||||
</li>
|
||||
|
||||
这里再特别说一下降级,今天我们讲的内容可以理解为服务降级,后面我会介绍业务开关,可以理解为业务降级。这里只是叫法不同,不同的人有不同的理解,所以我们在讨论概念时,还是尽量回到我们要解决的问题和场景上来,上下文保持一致了,在观点和思路上也更容易达成一致。
|
||||
|
||||
讲到这里,再提个问题,我们讲的降级,和熔断这个概念是什么关系?你不妨停下来,按照我们刚刚讲过的思路思考一下。
|
||||
|
||||
## 常见的限流解决方案
|
||||
|
||||
我们先看几种常见的限流类型。
|
||||
|
||||
**第一类,接入层限流。**
|
||||
|
||||
作为业务流量的入口,我们限流的第一道关卡往往会设置在这里,而且接入层限流往往也是最有效的。这里又有两类解决方案,根据接入层所使用的技术方案而定。
|
||||
|
||||
1.**Nginx限流**
|
||||
|
||||
Nginx或其开源产品是最常用的Web服务器,我们使用的是TEngine。对于一个Web类应用,如Web页面或H5页面,我们通常会将限流策略增加到这一层,会设置QPS、并发数以及CPU的Idle作为限流指标。Nginx有对应的函数接口,可以获取到以上指标信息,然后通过Lua脚本实现限流的逻辑,并作为TEngine的插件安装即可。
|
||||
|
||||
2.**API路由网关模式**
|
||||
|
||||
对于客户端模式的接入,我们使用了API路由网关模式,一方面可以更方面地管理客户端与服务端的链接,另一方面也可以通过配置的方式管理服务接口,这里的服务管理会复用到微服务架构的配置中心,并实现相应的路由策略。对于QPS和并发限流,直接在配置中心中进行配置即可。
|
||||
|
||||
**第二类,应用限流。**
|
||||
|
||||
这一类的限流策略跟上面API路由网关模式的限流相似,同样是依赖配置中心管理,限流逻辑会配套服务化的框架完成。
|
||||
|
||||
**第三类,基础服务限流。**
|
||||
|
||||
主要针对数据库、缓存以及消息等基础服务组件的限流而设定。同样,限流逻辑会配套分布式数据库中间件,缓存或消息的框架来实现。
|
||||
|
||||
讲到这里,我来解释几个关键的技术点。
|
||||
|
||||
<li>
|
||||
**资源和策略**。资源是我们要进行限流的对象,可能是一个应用,或者一个方法,也可能是一个接口或者URL,体现了不同的限流粒度和类型。策略就是限流的规则,比如下面我们要提到的QPS和并发数限流。
|
||||
</li>
|
||||
<li>
|
||||
**时间精度**。主要指对于QPS、并发数或CPU的阈值判断。比如对于QPS,我们就会设定一个QPS时间精度(假设3s),如果低于阈值则不启用策略,如果超过阈值就启动限流策略。
|
||||
</li>
|
||||
<li>
|
||||
**指标计数**。对于并发限制请求,会统计当前的并发数,1次请求进入到限流模块加1,等请求结束退出时减1,当前正在处理的请求数就是并发数。对于QPS限流,统计QPS不能按照秒统计,因为第1s,系统可能就被打挂了,所以QPS得按照毫秒级别去统计,统计的级别越小,性能损耗越大。所以定在10ms~100ms的级别去统计会更平滑一些,比如将1s切成10份,每一份100ms,一个请求进来肯定会落在某一份上,这一份的计数值加1。计算当前的QPS,只需要将当前时间所在份的计数和前面9份的计数相加,内存里面需要维护当前秒和前面2秒的数据。
|
||||
</li>
|
||||
<li>
|
||||
**限流方式**。对于Nginx就针对总的请求进行限流即可,但是粒度会比较粗。对于应用层,因为配置中心的灵活性,其限流就可以做得更细化。比如可以针对不同来源限流,也可以针对去向限流,粒度上可以针对类级别限流,也可以针对不同的方法限流,同时还可以针对总的请求情况限流,这些灵活策略都可以在微服务的配置中心实现。
|
||||
</li>
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ce/76/ceaba63c6820d82e6e12ff47122d4d76.jpg" alt="" />
|
||||
|
||||
<li>
|
||||
**Spring AOP**。对于Java应用,绝大多数公司都会用到Spring框架,包括我们上面讲到的分布式数据库等组件,也一样会依赖Spring框架,比如我们用到的MyBatis开源组件。而Spirng框架中的关键技术点,就是IoC和AOP,我们在限流方案的实现上,也会利用到相关技术。简单来说就是,我们通过配置需要限流的方法作为AOP的切入点,设定Advice拦截器,在请求调用某个方法,或请求结束退出某个方法时,进行上述的各种计数处理,同时决定是否要进行限流,如果限流就返回约定好的返回码,如果不限流就正常执行业务逻辑。基于AOP这样一个统一的技术原理,我们就可以开发出与业务逻辑无关的限流组件,通常会在对外的服务调用、数据库调用、缓存调用、消息调用这些接口方法上设置默认的切面,并在业务代码运行时注入,这样就可以做到对业务透明,无侵入性。
|
||||
</li>
|
||||
<li>
|
||||
**Web类型的限流**。对于Web类型URL接口限流,我们就利用Servlet的Filter机制进行控制即可。
|
||||
</li>
|
||||
<li>
|
||||
**控制台**。上面我们讲了各种配置和策略,如果都是通过人工来操作是不现实的,这时就需要开发对应的限流降级的控制台,将上述的各种配置和策略通过界面的方式进行管理,同时在配置完成之后,能够同步到对应的服务实例上。比如对于Nginx,当一个策略配置完成后,就要同步到指定的服务器上生成新的配置文件并Reload。对于配置中心模式的策略,也就是Spring AOP模式的限流,在控制台上配置完成后,就要将配置值同步更新到配置中心里,同时再通过运行时的依赖注入,在线上运行的业务代码中生效。
|
||||
</li>
|
||||
|
||||
整体简化的示意图如下:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e2/ce/e2295ae12fc4b83e7efc51c456f421ce.jpg" alt="" />
|
||||
|
||||
## 限流降级的难点
|
||||
|
||||
上面整体介绍了限流降级的解决方案,我们可以看到涉及到很多新概念,各种不同的限流类型,同时还有比较复杂的技术细节,所以要清晰地理解这些概念。
|
||||
|
||||
对于降级,主要是针对RT来进行判断,它的整个技术方案没有限流这么复杂,且思路上跟限流是相似的,所以我们就不再单独介绍降级的技术方案了。
|
||||
|
||||
从整个建设过程来看,我的体会是,**限流降级的难点和关键还是在于整体技术栈的统一,以及后期对每个应用限流降级资源策略的准确把握和配置。**
|
||||
|
||||
**我们先来看整体技术栈的统一,这其实也就是我们在专栏最开始就讲到的标准化建设**。这里我们会基于一个统一的技术栈进行限流降级方案的设计,要求有统一的Web服务器类型。对服务化框架、各类分布式框架以及代码开发框架(如Spring),这些都要有很明确的要求。如果这里面有某些应用使用的框架不同,那么这套统一的方案就无法推广落地。
|
||||
|
||||
我们在实际推广过程中就遇到很多类似的问题,导致大量的时间耗费在技术栈统一上,甚至会要求业务代码做出改变和调整,代码上线运行后再进行统一,这个代价是非常大的。
|
||||
|
||||
这也是为什么我们在一开始就非常强调标准化的重要性。这里我们再强调一下标准化,再来复习一下以应用为核心的运维体系的思维导图。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/30/12/30e69662ae3e40cef3002587cbca3212.jpg" alt="" />
|
||||
|
||||
**再来看对应用的限流降级资源策略的把握,这个就需要对应用和业务有深入的了解**。比如开发人员要非常清楚哪些接口是核心接口,它的来源和去向有哪些;哪些来源是核心的,哪些是非核心的;如果要限流,需要对哪些接口限流,同时要重点保障哪些接口等等。
|
||||
|
||||
对于限流和降级的具体策略,就是QPS和并发数的配置,也要来源于线上实际运行维护的经验,才能知道配置多少是合适的,配置太大没有限流效果,太小又会频繁触发限流,影响正常业务运行。
|
||||
|
||||
所以,限流和降级也是一个**动态调测和完善的过程**,对于有些动态变化的资源是做不到一劳永逸的。
|
||||
|
||||
怎么办呢?一方面我们要**依赖人的经验**;另一方面,从最终的解决方案看,当调用次数和日志达到一定体量时,我们希望能够**借助机器学习算法的手段**,来帮助我们分析什么样的设置是最合理的。
|
||||
|
||||
今天我们讨论了限流和降级的概念、解决方案以及难点,欢迎留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
74
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/25 | 稳定性实践:开关和预案.md
Normal file
74
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/25 | 稳定性实践:开关和预案.md
Normal file
@@ -0,0 +1,74 @@
|
||||
<audio id="audio" title="25 | 稳定性实践:开关和预案" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/35/f9/35d1a3ea3fa8b41b3a4ad430f40ed1f9.mp3"></audio>
|
||||
|
||||
在稳定性保障中,限流降级的技术方案,是针对服务接口层面的,也就是服务限流和服务降级。这里还有另外一个维度,就是业务维度,所以今天我们就从业务降级的维度来分享,也就是**开关和预案**。
|
||||
|
||||
## 如何理解开关和预案
|
||||
|
||||
**开关,这个概念更多是业务和功能层面的,主要是针对单个功能的启用和停止进行控制,或者将功能状态在不同版本之间进行切换。**
|
||||
|
||||
在业务层面,就像我们前面经常提到的大促场景案例,我们会关闭掉很多非核心功能,只保留交易链路的核心功能。比如我们认为商品评论是非核心功能,这时就会通过开关推送这种方案将这个功能关闭。当用户访问商品详情页时,这个接口就不再被调用,从用户角度来说,就是在大促峰值时刻看不到所浏览商品的评论列表。
|
||||
|
||||
在功能层面,我们技术架构中会使用缓存技术,但是要考虑到缓存有可能也会出现故障,比如不可访问,或者数据错乱异常等状况,这时我们就会考虑旁路掉缓存,直接将请求转到数据库这一层。
|
||||
|
||||
这里有两种做法:一种做法是通过我们上一篇介绍到的降级手段,也就是我们常说的熔断,自动化地旁路;另一种做法,比如在数据异常情况下,请求是正常的,但是数据是有问题的,这时就无法做到自动化旁路,就要通过主动推送开关的方式来实现。
|
||||
|
||||
**预案,可以理解为让应用或业务进入到某种特定状态的复杂方案执行,这个方案最终会通过开关、限流和降级策略这些细粒度的技术来实现,是这些具体技术方案的场景化表现。**
|
||||
|
||||
我们还是接着上面的这个案例来讨论。因为每个业务或应用都会有自己的开关配置,而且数量会有很多,如果在大促前一个个推送,效率就会跟不上,所以我们就会针对某个应用的具体场景,提供批量操作的手段,通过预案场景将同一应用,甚至多个应用的开关串联起来。
|
||||
|
||||
比如上面提到的商品详情页,我们不仅可以关闭商品评论,还可以关闭商品收藏提示、买家秀、店铺商品推荐、同类型商品推荐以及搭配推荐等等。有了场景化的预案,管理和维护起来就会更容易。
|
||||
|
||||
除了业务层面的预案,我们还可以将预案应用到应急场景下,比如上面提到的缓存故障异常。在真实场景下,要考虑得更全面,比如缓存能够支撑的业务访问量是要远远大于数据库的,这时我们就要做功能降级,这就要考虑数据库是否能够支撑住这么大的请求量(通常情况下肯定是支撑不住的)。所以,遇到这种场景,我们首要考虑的是限流,先将业务流量限掉三分之一甚至是一半,然后再将功能降级到数据库上。
|
||||
|
||||
这样就又涉及到多种策略的串行执行。如果没有预案都是单个执行的话,效率肯定会低,而且还可能涉及到多个应用都会执行相同的业务降级策略,这时就必须要有预案来统一管理,提前梳理好哪些应用需要在这种场景下执行对应的开关、限流和降级策略。
|
||||
|
||||
## 技术解决方案
|
||||
|
||||
技术方案上并不复杂,开关的字段主要以Key-Value方式管理,并从应用维度,通过应用名管理起来,这个对应关系就可以放到统一的控制台中管理。
|
||||
|
||||
下图是整个开关和预案管理,以及推送的示意图,我们一起分步骤看一下。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/b6/f6/b6f09f054d05cf429f5e3b40e73c1df6.jpg" alt="" />
|
||||
|
||||
1.**开关管理**
|
||||
|
||||
通过上述我们所说的Key-Value方式保存,与代码中的具体Field字段对应起来。这里就又会涉及到我们上篇内容中讲到的Spring的AOP和注解技术。
|
||||
|
||||
如下面代码所示,我们通过注解方式定义了一个开关testKey,它与控制台中配置的Key相对应,并获取对应的Value取值,在业务运行阶段,我们就可以根据这个值,来决定业务执行逻辑,下面是简化的示例。
|
||||
|
||||
```
|
||||
@AppSwitcher(key="key1",valueDes = "Boolean类型")
|
||||
|
||||
private Boolean key1;
|
||||
|
||||
代码中直接调用AppName对应的开关配置,进行不同业务逻辑的实现:
|
||||
|
||||
Boolean key1 = MoguStableSwitch.isStableSwitchOn("key1");
|
||||
|
||||
if (key1)
|
||||
{
|
||||
//开关打开时业务逻辑实现
|
||||
}else
|
||||
{
|
||||
//开关关闭时业务逻辑实现
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
2.**开关推送**
|
||||
|
||||
当在控制台上修改开关值后,会推送到微服务的配置中心做持久化,这样当应用下次重启时依然可以获取到变更后的值。还有另外一种方式,就是通过HTTP的方式推送,这种情况的应用场景是,当第一种情况失败时,为了让开关快速生效预留的第二个接口。
|
||||
|
||||
3.**配置变更**
|
||||
|
||||
应用中引入的开关SDK客户端会监听对应配置的变更,如果发生变化,就会马上重新获取,并在业务运行时生效。
|
||||
|
||||
4.**预案执行**
|
||||
|
||||
就是多个开关策略的串行执行,会重复上面这几个关键步骤。
|
||||
|
||||
关于开关和预案的内容,我们今天就介绍到这里。留一个问题,我们在上篇文章中介绍到限流降级方案的难点,请你思考一下,我们今天讲的开关预案这个内容,可能会遇到哪些难点呢?欢迎留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
101
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/26 | 稳定性实践:全链路跟踪系统,技术运营能力的体现.md
Normal file
101
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/26 | 稳定性实践:全链路跟踪系统,技术运营能力的体现.md
Normal file
@@ -0,0 +1,101 @@
|
||||
<audio id="audio" title="26 | 稳定性实践:全链路跟踪系统,技术运营能力的体现" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/32/a1/32dd3c428f8bfb3aeab6c4d1c8b3caa1.mp3"></audio>
|
||||
|
||||
今天我们来分享全链路跟踪系统建设方面的内容。我们知道,随着微服务和分布式架构的引入,各类应用和基础组件形成了网状的分布式调用关系,这种复杂的调用关系就大大增加了问题定位、瓶颈分析、容量评估以及限流降级等稳定性保障工作的难度,如我们常见的调用网状关系。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/4c/f6/4c034ffe82db8509f252218f632ec2f6.png" alt="" />
|
||||
|
||||
图片出自:[https://www.linkedin.com/pulse/100-million-members-125-hours-watched-per-day-hundreds-probst/](https://www.linkedin.com/pulse/100-million-members-125-hours-watched-per-day-hundreds-probst/%5Breference_end%5D)
|
||||
|
||||
正是这样的背景,催生了**分布式链路跟踪**,也叫**全链路跟踪**的解决方案。
|
||||
|
||||
关于这一块的技术解决方案,在Google的Dapper论文发表之后,近些年业界已经有非常多且非常成熟的实践经验和开源产品。
|
||||
|
||||
比如阿里的鹰眼系统,就是全链路跟踪系统在国内的最佳实践;再比如美团点评的CAT分布式监控系统,也是从产品实践中逐步开源出来,在业界已经得到了非常广泛的应用;还有一些独立的开源产品,比如国内分布式监控技术专家吴晟创建的Skywalking项目,也是非常优秀的产品,而且也有比较广泛的应用。
|
||||
|
||||
除此之外,还有大量优秀的商业产品,这类产品通常叫APM,应用性能管理系统,比如国内的听云、博瑞、OneAPM等等,他们在产品化方面做的会更完善,在很多场景下可以非常方便地落地应用。
|
||||
|
||||
介绍上述这些产品,主要还是想说明,当前在分布式或全链路跟踪监控这个领域,无论是在技术还是产品层面都已经相对成熟,我们完全可以通过对这些产品的调研来选择适合自己的解决方案。
|
||||
|
||||
蘑菇街在这块也是自研了一套体系,但是技术方案和思路上跟上述这些开源或商业产品都很相似,所以技术层面我就不再做详细赘述。
|
||||
|
||||
如果想深入了解相关内容,一方面可以在网上找到非常多的资料,甚至是去阅读源码;另一方面还是推荐极客时间上陈皓老师的《左耳听风》专栏和杨波老师的《微服务架构核心20讲》,两位都是骨灰级的微服务和分布式架构专家,他们在技术层面的分享会更有深度和针对性。
|
||||
|
||||
## 全链路跟踪系统在技术运营层面的应用
|
||||
|
||||
接下来,主要分享我们利用全链路跟踪系统在技术运营层面做的一些事情,这里提到的运营,就是应用在线上运行时,我们根据应用运行数据所做的运行维护工作,这里我们会更加强调数据的作用。
|
||||
|
||||
同时,这里的一个核心技术点就是 **TraceID**,当请求从接入层进来时,这个TraceID就要被创建出来;或者是通过Nginx插件方式创建放到http的header里面;或者是通过RPC服务化框架生成。然后在后续的请求中,这个字段会通过框架自动传递到下一个调用方,而不需要业务考虑如何处理这个核心字段。
|
||||
|
||||
有了这个TraceID,我们就可以将一个完整的请求链路给串联起来了,这也是后面场景化应用的基础。下面我们就一起来看会有哪些具体的技术运营场景。
|
||||
|
||||
## **第一个场景,问题定位和排查**
|
||||
|
||||
我们做全链路跟踪系统,要解决的首要问题就是在纷繁复杂的服务调用关系中快速准确地定位问题,所以这个场景是绕不开的。
|
||||
|
||||
**我们常见的问题场景,主要有两类:瓶颈分析和异常错误定位**。
|
||||
|
||||
首先看瓶颈分析。常见的问题就是某某页面变慢了,或者某个服务突然出现大量超时告警,因为无论是页面也好,还是服务也好,在分布式环境中都会依赖后端大量的其它服务或基础部件,所以定位类似的问题,我们期望能有一个详细的调用关系呈现出来,这样我们就可以非常方便快速地判断瓶颈出现在什么地方。
|
||||
|
||||
比如下图的情况,就是某个页面变慢。我们根据URL查看某次调用的情况,就发现瓶颈是在RateReadService的query接口出现了严重阻塞。接下来,我们就可以根据详细的IP地址信息,到这台机器上或者监控系统上,进一步判断这个应用或者这台主机的异常状况是什么,可能是机器故障,也可能是应用运行故障等等。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/9f/37/9f4ebfd7abe8f1ee76c978492c37ca37.jpeg" alt="" />
|
||||
|
||||
再来看一个案例。下图中我们可以看到,一次完整的请求耗时比较长,但是通过调用链分析会发现,其中任何一个单次请求的时延又非常低,并没有像上个案例那样有明显的请求瓶颈。我们再进一步分析,就会发现整个请求的列表非常长,且请求列表里面都是在访问缓存内容。很显然,这样的调用方式不合理,需要我们优化调用逻辑,要么通过批量接口方式,要么通过异步的方式,再或者要去分析业务场景是否合理。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/af/23/affe0cc8c37b7c84b94f85000deecf23.jpeg" alt="" />
|
||||
|
||||
通过上面的案例,我们可以看到,**在应用了全链路跟踪的解决方案后,复杂调用关系下的问题定位就相对简单多了**。
|
||||
|
||||
对于出现异常报错,也是一样的判断逻辑,限于篇幅我就不再赘述了。
|
||||
|
||||
## **第二个场景,服务运行状态分析**
|
||||
|
||||
上面的问题定位,主要还是针对单次请求或相对独立的场景进行的。更进一步,我们在采集了海量请求和调用关系数据后,还可以分析出更有价值的服务运行信息。比如以下几类信息。
|
||||
|
||||
**1.服务运行质量**
|
||||
|
||||
一个应用对外可能提供HTTP服务,也可能提供RPC接口。针对这两类不同的接口,我们可以通过一段时间的数据收集形成服务接口运行状态的分析,也就是应用层的运行监控,常见的监控指标有QPS、RT和错误码,同时还可以跟之前的趋势进行对比。这样就可以对一个应用,以及对提供的服务运行情况有一个完整的视图。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/7f/2e/7f0897395183ca37b613ab76071ccc2e.png" alt="" />
|
||||
|
||||
**2.应用和服务依赖**
|
||||
|
||||
除了上述单个应用的运行状态,我们还可以根据调用链的分析,统计出应用与应用之间,服务与服务之间的依赖关系及依赖比例,如下图所示。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/a7/97/a74dc9de0192d01e732f8e3d6b2db797.png" alt="" />
|
||||
|
||||
这个依赖管理的作用,就是给我们前面介绍的容量压测和限流降级这两个工作做好准备。我们可以根据来源依赖和比例评估单链路的扩容准备;同时根据去向依赖进行流量拆分,为下游应用的扩容提供依据,因为这个依赖比例完全来源于线上真实调用,所以能够反映出真实的业务访问模型。
|
||||
|
||||
同时,根据这个依赖关系,特别是服务依赖关系,我们还可以进一步分析依赖间的强弱关系,也就是强弱依赖。这一点又对我们做限流降级提供了对应的依据,也就是我们前面所说的,我们限流也好,降级也好,都是优先对非核心业务的限流和降级,这样的业务形成的依赖,我们就认为是弱依赖,是不关键的;但是对于核心业务我们就要优先保障,它们形成的依赖关系,是强依赖。无论是扩容也好,还是优化性能也罢,都要最大限度地确保强依赖关系的调用成功。
|
||||
|
||||
所以,强弱依赖的分析,还是要从业务场景入手。比如对于电商来说,核心就是交易链路,我们就要判断如果一条链路上的某个应用或服务失败了,是不是会影响订购下单,或者影响支付收钱,如果影响,就要标注为强依赖,这个应用就要标注为核心应用;如果这个应用失败了,可以通过限流或降级的方式绕过,只是影响用户体验,但是不影响用户订购支付,那这个依赖关系就可以标注为弱依赖,该应用就可以标注为非核心应用。
|
||||
|
||||
同时,因为我们的业务场景和需求在不断变化,应用和服务间的调用关系和依赖关系也是在不断变化中的,这就需要我们不断地分析和调整强弱依赖关系,同时也要关注各种调用间的合理性,这个过程中就会有大量的可优化的工作。
|
||||
|
||||
通常情况下,这些事情对于业务架构师和运维人员来说,都会比较关注。因为业务架构师要对业务访问模型十分了解,他要经常关注这些信息;而运维会关注线上稳定性,需要在关键时刻执行限流降级或开关预案策略,所以也必须对这些信息非常熟悉。
|
||||
|
||||
**3.依赖关系的服务质量**
|
||||
|
||||
上面介绍了应用和服务间的依赖管理,同样的我们也会关注被依赖的应用或服务的实时运行状态和质量,这样就可以看到应用间实时的调用状态。是不是有的应用调用QPS突然增加了,或者RT突然暴涨,通过这个依赖关系就可以快速确认。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/89/f3/89c3973e1b582c052c1df6387184def3.png" alt="" />
|
||||
|
||||
## **第三类场景,业务全息**
|
||||
|
||||
顾名思义,业务全息就是全链路跟踪系统与业务信息的关联。从上述的介绍中,我们可以看到,全链路跟踪系统的应用更多的还是在技术层面,比如定位“应用或服务”的问题,应用或服务间的依赖关系等等。
|
||||
|
||||
但是现实中,我们也会遇到大量的业务链路分析的场景,比如可能会有针对某个订单在不同阶段的状态等。假设一个情况是用户投诉,他的订单没有享受到满100元包邮的优惠,这时我们就要去查找用户从商品浏览、加购物车到下单整个环节的信息,来判断问题出在哪儿。其实,这个场景和一个请求的全链路跟踪非常相似。
|
||||
|
||||
所以,为了能够在业务上也采用类似的思路,我们就将前面介绍到的请求链路上的唯一TraceID与业务上的订单ID、用户ID、商品ID等信息进行关联,当出现业务问题需要排查时,就会根据对应的ID将一串业务链整个提取出来,然后进行问题确认。这就会极大地提升解决业务问题的效率。
|
||||
|
||||
## 总结
|
||||
|
||||
今天我们从技术运营层面的应用这个角度重新认识了全链路跟踪系统。同时,从这个案例中,我们也应该看到,技术、产品和运营相辅相成,共同促进彼此的完善和成熟。
|
||||
|
||||
全链路跟踪系统在技术方案的广泛应用,给我们提供了大量可分析处理的线上运行数据,从这些数据中,我们又能提炼出对线上稳定运行更有价值的信息。所以,技术之外,我们也应该更多地考虑技术在价值方面的呈现。
|
||||
|
||||
今天的内容就介绍到这里,你在这方面遇到过哪些问题,有怎样的经验,欢迎留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
80
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/27 | 故障管理:谈谈我对故障的理解.md
Normal file
80
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/27 | 故障管理:谈谈我对故障的理解.md
Normal file
@@ -0,0 +1,80 @@
|
||||
<audio id="audio" title="27 | 故障管理:谈谈我对故障的理解" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/c5/e8/c554ce88269402033fcbe965bcf1dde8.mp3"></audio>
|
||||
|
||||
对于任何一个技术团队来说,最令人痛苦、最不愿面对的事情是什么?我想答案只有一个,那就是:故障。
|
||||
|
||||
无论是故障发生时的极度焦虑无助,还是故障处理过程中的煎熬痛苦,以及故障复盘之后的失落消沉,都是我们不愿提及的痛苦感受。在海外,故障复盘的英文单词是Postmortem,它有另外一个意思就是验尸,想想就觉得痛苦不堪,同时还带有一丝恐怖的意味。
|
||||
|
||||
写故障相关的文章,也着实比较痛苦。一方面回顾各种故障场景,确实不是一件令人愉悦的体验;另一方面,故障管理这个事情,跟技术、管理、团队、人员息息相关,也是一套复杂的体系。
|
||||
|
||||
我们看Google SRE这本书(《SRE:Google运维解密》),绝大部分章节就是在介绍故障相关的内容。其实看看这本书就能明白稳定性和故障管理这项系统工程的复杂度了,而且从本质上讲,SRE的岗位职责在很大程度上就是应对故障。
|
||||
|
||||
所以,接下来的几期文章,我会谈谈我对故障管理的理解,以及一些实际经历的感受,也希望我们每一个人和团队都能够在故障管理中得到涅槃重生。
|
||||
|
||||
今天,先谈谈我们应该如何来看待故障这个事情。
|
||||
|
||||
## 系统正常,只是该系统无数异常情况下的一种特例
|
||||
|
||||
上面这句话,来自Google SRE这本书,我认为这是一个观点,但是更重要的,它更是一个事实。所以,正确理解故障,首先要接受这个现实。
|
||||
|
||||
故障,是一种常态,任何一个软件系统都避免不了,国内最牛的BAT避免不了,国外最牛的Google、Amazon、Facebook、Twitter等也避免不了。业务体量越大,系统越复杂,问题和故障就越多,出现故障是必然的。
|
||||
|
||||
可能你会有疑问,既然他们也存在各种故障,但是在我们的印象中,好像也没经常遇到这些大型网站整天出问题或不可访问的情况,这恰恰说明了这些公司的稳定性保障做得非常到位。
|
||||
|
||||
这里有一个非常重要的体现,就是**Design for Failure**的理念。**我们的目标和注意力不应该放在消除故障,或者不允许故障发生上,因为我们无法杜绝故障。所以,我们更应该考虑的是,怎么让系统更健壮,在一般的问题面前,仍然可以岿然不动,甚至是出现了故障,也能够让业务更快恢复起来**。
|
||||
|
||||
其实对这个理念的实践,我们在前面都已经介绍过了,比如限流降级、容量评估以及开关预案等技术方案的稳定性保障体系,这些技术方案本质上并不是为了杜绝故障发生,而是为了能够更好地应对故障。
|
||||
|
||||
同样的,我们刚提到的那些国内外超大型网站,之所以能够保持很高的稳定性和业务连续性,恰恰是说明他们在**故障隔离、快速恢复、容灾切换**这些方面做得非常优秀,一般的问题或故障,根本不会影响到业务访问。
|
||||
|
||||
所以,转变一下思路,重新理解系统运行的这种特点,会给我们后续在如何面对故障、管理故障的工作中带来不一样的思考方式。
|
||||
|
||||
## 故障永远只是表面现象,其背后技术和管理上的问题才是根因
|
||||
|
||||
简单表述一下,就是永远不要将注意力放在故障本身上,一定要将注意力放到故障背后的技术和管理问题上去。
|
||||
|
||||
这里的逻辑是这样的,技术和管理上的问题,积累到一定量通过故障的形式爆发出来,所以故障是现象,是在给我们严重提醒。
|
||||
|
||||
有时我们过分关注故障本身,就容易揪着跟故障相关的责任人不放,这样会给责任人造成很大的负面压力,进而导致一些负面效应的产生,这一块在后面我还会专门分享。
|
||||
|
||||
与之对应的改进措施,往往就容易变成如何杜绝故障。前面我们讲到,从现实情况看这是完全不可能的,所以就容易输出一些无法落地、无法量化的改进措施。
|
||||
|
||||
你可以思考一下,面对故障的时候,是不是经常出现上述这两种情况。
|
||||
|
||||
所以,想要更好地应对和管理故障,当故障发生后,我们需要考虑的问题应该是其背后存在的技术和管理问题。这里和你分享我自己在故障后的复盘中,经常会反思和提出的几个问题。
|
||||
|
||||
<li>
|
||||
为什么会频繁出故障?是不是人员技术不过硬?人为操作太多,自动化平台不完善,操作没有闭环?代码发布后的快速回滚措施不到位?
|
||||
</li>
|
||||
<li>
|
||||
为什么一个小问题或者某个部件失效,会导致全站宕机?进一步考虑,是不是业务高速发展,技术架构上耦合太紧,任何一个小动作都可能是最后一根稻草?是不是容量评估靠拍脑袋,系统扛不住才知道容量出问题了?是不是限流降级等保障手段缺失,或者有技术方案,但是落地效果不好?
|
||||
</li>
|
||||
<li>
|
||||
为什么发生了故障没法快速知道并且快速恢复?进一步考虑,是不是监控不完善?告警太多人员麻木?定位问题效率低,迟迟找不到原因?故障隔离还不够完善?故障预案纸上谈兵?
|
||||
</li>
|
||||
<li>
|
||||
管理上,团队成员线上敬畏意识不够?还是我们宣传强调不到位?Oncall机制是否还需要完善?故障应对时的组织协作是不是还有待提升?
|
||||
</li>
|
||||
|
||||
总结下来,任何一个故障的原因都可以归结到具体的技术和管理问题上,在故障复盘过程中,通常会聚焦在某个故障个例上,归纳出来的是一个个非常具体的改进措施。
|
||||
|
||||
用一句话总结:“**理解一个系统应该如何工作并不能使人成为专家,只能靠调查系统为何不能正常工作才行**。”(From SRE ,by Brian Redman)
|
||||
|
||||
最后,作为管理者,我会问自己一个终极问题:**下次出现类似问题,怎么才能更快地发现问题,更快地恢复业务?即使这一次的故障应对已经做得非常好了,下次是否可以有更进一步的改进?**
|
||||
|
||||
这个问题,会促使我个人更加全面地思考,且能够关注到更全局的关键点上。比如,是不是应该考虑有更加完善的发布系统,减少人为操作;是不是应该有整体的稳定性平台建设,包括限流降级、开关预案、强弱依赖、容量评估、全链路跟踪等子系统,以及建设完成后,应该如何一步步的落地;还有,故障预案和演练应该如何有效的组织起来,毕竟这些是从全局考虑,自上而下的一个过程。
|
||||
|
||||
## 最后
|
||||
|
||||
再表达两个观点。
|
||||
|
||||
**第一,出问题,管理者要先自我反省**。不能一味地揪着员工的错误不放,员工更多的是整个体系中的执行者,做得不到位,一定是体系上还存在不完善的地方或漏洞。在这一点上,管理者应该重点反思才对。
|
||||
|
||||
**第二,强调技术解决问题,而不是单纯地靠增加管理流程和检查环节来解决问题,技术手段暂时无法满足的,可以靠管理手段来辅助**。比如我上面提到的就基本都是技术手段,但是要建设一个完善的体系肯定要有一个过程,特别是对于创业公司。这时可以辅以一些管理措施,比如靠宣传学习,提升人员的线上安全稳定意识,必要的Double Check,复杂操作的Checklist等,但是这些只能作为辅助手段,一定不能是常态,必须尽快将这些人为动作转化到技术平台中去。
|
||||
|
||||
这样做的原因也很明显,单纯的管理手段还是靠人,跟之前没有本质区别,只不过是更加谨小慎微了一些而已。同时,随着系统复杂度越来越高,迟早有一天会超出单纯人力的认知范围和掌控能力,各种人力的管理成本也会随之上升。
|
||||
|
||||
今天和你分享了我对故障这件事情的理解,期望这样一个不同角度的理解能够带给你一些启发,欢迎你留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
87
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/28 | 故障管理:故障定级和定责.md
Normal file
87
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/28 | 故障管理:故障定级和定责.md
Normal file
@@ -0,0 +1,87 @@
|
||||
<audio id="audio" title="28 | 故障管理:故障定级和定责" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/32/a3/32b7377f9d7eb09fc7ffac6e223559a3.mp3"></audio>
|
||||
|
||||
故障管理的第一步是对故障的理解,只有正确地面对故障,我们才能够找到更合理的处理方式。今天就来和你分享关于**故障定级和定责**方面的经验。
|
||||
|
||||
## 故障的定级标准
|
||||
|
||||
上期文章中介绍到,如果我们的注意力仅仅盯着故障本身,就非常容易揪着责任人不放,进而形成一些负面效应,所以我们要将更多的注意力放到故障背后的技术和管理问题上。
|
||||
|
||||
但是,这并不是说对故障本身就可以不重视,相反,故障发生后,一定要严肃对待。这里就需要制定相应的标准和规范来指导我们的处理过程。这个过程并不是一定找出谁来承担责任,或者一定要进行处罚,而是期望通过这样的过程,让我们能够从故障中深刻地认识到我们存在的不足,并制定出后续的改进措施。
|
||||
|
||||
这里有一个**关键角色,我们称之为技术支持,也有的团队叫 NOC**(Network Operation Center)。这个角色主要有两个职责:一是跟踪线上故障处理和组织故障复盘,二是制定故障定级定责标准,同时有权对故障做出定级和定责,有点像法院法官的角色,而上面的两个标准就像是法律条款,法官依法办事,做到公平公正。
|
||||
|
||||
**所以,这里的一个关键就是我们要有明确的故障定级标准**。这个标准主要为了判定故障影响程度,且各相关利益方能够基于统一的标准判断和评估。
|
||||
|
||||
现实情况中,因为各方受到故障的影响不同,对故障影响的理解也不同,所以复盘过程中,经常会出现下面这两种争执场景。
|
||||
|
||||
<li>
|
||||
技术支持判定故障很严重,但是责任方认为没什么大不了的,不应该把故障等级判定到如此之高;
|
||||
</li>
|
||||
<li>
|
||||
技术支持认为故障影响较小,但是受影响方却认为十分严重,不应该将故障等级判定得这么低。
|
||||
</li>
|
||||
|
||||
遇到这种情况,技术支持作为故障判定的法官,就必须拿出严格的判定标准,并说明为什么这么判定。
|
||||
|
||||
我们将故障等级设置为P0~P4这么5个级别,P0为最高,P4为最低。对于电商,主要以交易下跌、支付下跌、广告收入资损这些跟钱相关的指标为衡量标准。对于其他业务如用户IM等,主要区分业务类型,制定符合业务特点的定级标准。两个示例如下。
|
||||
|
||||
交易链路故障定级标准示例:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/8d/ba/8de093d70e1383bfd52fc06e079f64ba.png" alt="" />
|
||||
|
||||
用户IM故障定级标准示例:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ce/e0/ce7d27043d1ba7abcc6fda831e2af3e0.png" alt="" />
|
||||
|
||||
故障定级的标准,会由技术支持与各个业务研发团队进行点对点的细节沟通讨论,从业务影响角度把影响面、影响时长这些因素串联起来。这样即使在后续出现争执,也会有对应的标准参考。这个标准可能覆盖不到有些故障影响或特例,但是技术支持可以根据自己的经验进行“自由裁量”。同时,每个季度或半年对标准进行一次修订和完善。这样,我们前面提到的争执就会越来越少,再加上我们内部树立了“技术支持角色拥有绝对话语权和决策权”的制度,执行过程中就会顺畅很多。
|
||||
|
||||
对于P0故障,通常是由两个级以上的P1故障叠加造成的,这说明已经发生了非常严重的全站故障。
|
||||
|
||||
不同的故障定级,在故障应对时采取的策略也就不同。一般来说,P2及以上故障就需要所有相关责任人马上上线处理,并及时恢复业务。对于P3或P4的问题,要求会适当放宽。整个过程,技术支持会给出一个基本判断,然后会组织召集临时故障应急小组处理。
|
||||
|
||||
关于全年全站,或者分业务的可用性和可靠性,这个可以借鉴业界通用的MTBF(Mean Time Between Failures,平均故障间隔时间)、MTTR(Mean Time To Recovery,平均修复时间)、MTTF(Mean Time To Failure,平均失效前时间)这几个指标来衡量,这里我们就不详细介绍了。
|
||||
|
||||
## 故障的定责标准
|
||||
|
||||
上述的故障定级标准,主要是用来判定故障等级,使得故障相关方不至于过分纠结在等级标准上。**而故障定责的主要目的是判定责任方**。这就需要有明确的故障定责标准,我认为有两个主要目的。
|
||||
|
||||
<li>
|
||||
**避免扯皮推诿**。比如我认为是你的责任,你认为是我的责任,大家争执不清,甚至出现诋毁攻击的情况。
|
||||
</li>
|
||||
<li>
|
||||
**正视问题,严肃对待**。不是为了处罚,但是作为责任方或责任团队一定要正视问题,找出自身不足,作为改进的主要责任者,来落地或推进改进措施。
|
||||
</li>
|
||||
|
||||
关于第一点,避免扯皮推诿,大概是很多团队都会遇到的非常头疼的问题,也是最令人生厌的问题,所以避免这样的问题,就必须得有相对清晰的定责标准。
|
||||
|
||||
比如我们经常会提到的运维背锅的说法,这种情况出现的场景经常是,某个核心功能出现了故障,有大量超时或失败,对应的开发定位一下,说我的代码没有问题,场景也没复现,这个应该是运维负责的主机、网络或者其他基础服务有问题吧,这个责任很轻易地就甩给了运维。类似的上游把责任推脱到下游的情况是经常出现的。
|
||||
|
||||
我们自己的实践,是严禁这种情况出现的。也就是作为受影响方,开发负责人有责任端到端地把问题定位清楚,只有当定位出来的问题确实是发生在运维的某个部件时,才允许将责任传递 ,否则不允许出现将自己的问题简单排除,就推断或者感觉应该是其他责任方的问题,然后终止后续排查或者指定下游责任方的情况出现。
|
||||
|
||||
当然,在这个过程中,如果需要配合,是可以要求各方投入支持的,因为共同的目标还是要清晰定位问题,找到解决方案。
|
||||
|
||||
这时候,就更加需要开放和宽松的氛围,如果大家始终朝着如何摆脱责任或甩锅的目标行事,就会出现非常负面的效应,这一点后面我们会详细分享。
|
||||
|
||||
关于定责,我们划分了几个维度,我简单示例如下。
|
||||
|
||||
1.**变更执行**
|
||||
|
||||
比如变更方没有及时通知到受影响方,或者事先没有进行充分的评估,出现问题,责任在变更方;如果通知到位,受影响方没有做好准备措施导致出现问题,责任在受影响方;变更操作的实际影响程度大大超出预期,导致受影响方准备不足出现故障,责任在变更方。
|
||||
|
||||
2.**服务依赖**
|
||||
|
||||
比如私自调用接口,或者调用方式不符合约定规则,责任在调用方;如果是服务方没有明确示例或说明,导致调用方出现问题,责任在服务方等等。
|
||||
|
||||
3.**第三方责任**
|
||||
|
||||
比如机房IDC电力故障、服务器故障、运营商网络故障等等,如果确实是不可抗力导致,责任在第三方;但是因自身的冗余或故障预案问题导致故障,责任在应用Owner。
|
||||
|
||||
有了这样的原则,在故障复盘时,就可以有效减少不和谐氛围的出现。因为每个公司的业务形态和特点不一样,里面的具体内容可能也不一样,上述的定责标准可能不完全适用,所以仅供示例参考。如果你在日常深受故障定责的困扰,建议尽快把规则明确起来,并能够与各方达成一致,这样就会最大程度地减少扯皮推诿的情况出现。
|
||||
|
||||
## 总结
|
||||
|
||||
今天我们讨论了故障管理中的定级和定责标准。蘑菇街在这方面的具体管理执行中,还是取得了不错的效果,所以分享出来,欢迎你留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
93
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/29 | 故障管理:鼓励做事,而不是处罚错误.md
Normal file
93
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/29 | 故障管理:鼓励做事,而不是处罚错误.md
Normal file
@@ -0,0 +1,93 @@
|
||||
<audio id="audio" title="29 | 故障管理:鼓励做事,而不是处罚错误" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/94/6d/94f5aa15769f72c1276158881b09556d.mp3"></audio>
|
||||
|
||||
故障发生后,我们一定要严肃对待,要对关键责任人或责任方定责,但是定责的目的不是处罚,因为故障复盘一旦以处罚为导向,就会导致非常严重的负面效应。
|
||||
|
||||
我们应该如何对待定责和处罚呢?今天就来分享一下我的理解,以及我个人的一些处理方式。
|
||||
|
||||
## 关于定责和处罚
|
||||
|
||||
定责的过程,是找出根因,针对不足找出改进措施,落实责任人。定责的目的,是责任到人,并且责任人能够真真切切地认识到自己的不足之处,能够主导改进措施的落地。同时,也让整个团队认识到,我们对于故障的态度一定是严肃严格的。
|
||||
|
||||
但是,在具体的执行过程中,我们一定要区分定责和处罚。**定责是对事不对人的**,但是**处罚就变成对人不对事了**,因为处罚一定会跟薪资、奖金、绩效、晋升等这些跟个人利益相关的事情直接挂钩。
|
||||
|
||||
**我的观点是,处罚不能一刀切,更不能上纲上线,一定要慎重。**
|
||||
|
||||
关于是否处罚,我个人认为可以遵循这样的原则:对于有明确底线,坚决不允许触碰的规则,如果因不遵守规则,故意触犯,导致了严重故障的出现,这种情况是要处罚的。
|
||||
|
||||
这样的规则建议通过设定高压线的方式让团队成员牢记心中,就像“**酒后不开车**”一样,简单明确。我大致列举几条我们的“高压线规则”。
|
||||
|
||||
- 未经发布系统,私自变更线上代码和配置;
|
||||
- 未经授权,私自在业务高峰期进行硬件和网络设备变更;
|
||||
- 未经严格的方案准备和评审,直接进行线上高危设备操作,如交换机、路由器防火墙等;
|
||||
- 未经授权,私自在生产环境进行调测性质的操作;
|
||||
- 未经授权,私自变更生产环境数据信息。
|
||||
|
||||
通过高压线去加强安全稳定意识,目的是要让每一个人对线上都心存敬畏。从我们的经验来看,**绝大多数的严重故障都是因为无意识或意识薄弱导致的,并不是因为单纯的技术能力不足等技术因素**。特别是那种自我感觉没问题,就把命令噼里啪啦敲到线上的操作,是最致命的。
|
||||
|
||||
2016年是公司业务高速发展的阶段,设备扩容比较频繁,网络割接操作也很多。因为没有明确严格的规则,导致团队成员为了赶工期,在白天进行网络设备变更,结果就是严重的P0和P1故障频发。复盘过程中,很多人的反馈就是:**我以为是没问题的,我以为是没影响的**。其实恰恰就是因为这种“想当然”,导致了严重故障。
|
||||
|
||||
后来我们总结,在这些关键的操作上,如果大家意识到位,能够谨小慎微,绝大多数低级失误都是可以避免的,所以针对这些场景,我们就专门制定了高压线。
|
||||
|
||||
制定高压线的效果也是很明显的。在近两年的时间里,我们没有出现过任何一例因为意识缺失或低级失误导致的P0和P1故障。反倒是跟我们有产品技术合作的第三方厂商,有时会出问题,我们了解下来,基本都是白天变更导致的,要么是没有放到凌晨实施,要么就是白天临时变更,没有准备充分。
|
||||
|
||||
所以,制定明确的高压线规则,提升意识,**碰一次就要疼一次**。这个时候的惩罚是为了提升责任人的敬畏意识和主观意识,人为失误才会减少,处罚也才会有效。
|
||||
|
||||
当然,更好的结果是,类似的故障越来少,处罚的执行也基本没有了。
|
||||
|
||||
## 鼓励做事,而不是处罚错误
|
||||
|
||||
前面我们分享过这句话:
|
||||
|
||||
>
|
||||
**理解一个系统应该如何工作并不能使人成为专家,只能靠调查系统为何不能正常工作才行。**(From SRE ,by Brian Redman)
|
||||
|
||||
|
||||
我想很多朋友跟我一样,都会产生共鸣。仔细考虑一下,我们每个人的技术能力提升,甚至是质的提升,基本都是伴随着大大小小故障的发生、处理、复盘和改进,这样一个过程提升起来的。
|
||||
|
||||
虽然我们不希望有故障发生,但是真的没有了故障,我们也就没有了真刀真枪实战成长的机会。我们对待故障一定要客观和辩证地理解,特别是对于管理者来说,**对于故障,一定要有容忍度,一定要有耐心**。
|
||||
|
||||
发生故障一方面暴露出我们整体技术架构的不足之处,另一方面,也给我们提供了未来改进的方向。同时,也是最重要的,我们的团队和人员,在这样一次次痛苦的经历后,各方面的能力都得到了锻炼,团队和个人素养也一定会有大幅度提升。所以,对故障有容忍度,有耐心,我们的团队就会变得越来越强,对于故障的应对也会变得更加游刃有余。
|
||||
|
||||
反观另一种管理方式,一出故障就劈头盖脸地把团队和责任人骂一通,并且还要严厉处罚的方式,最后的效果就是严重打击士气,适得其反。
|
||||
|
||||
所以,作为管理者,当一个故障发生之后,除故障本身外,还要关注更全面的内容,比如关注人、事情背景和前因后果。
|
||||
|
||||
列举一下我之前经常遇到的两种情况。
|
||||
|
||||
1.员工积极主动地承担了一些极具挑战性的工作,需要尝试某个新技术或解决方案,而团队、业界和社区可能都没有可供直接借鉴的经验,结果在落地的过程中踩到了一些坑,导致出现了问题。
|
||||
|
||||
这种情况在成熟的技术和产品中也极容易出现,比如开源产品,有时候不翻源码都不知道某个地方埋着深坑。即使是商业产品,像Oracle在他的官方bug库里列着一堆已知bug,就是明确告知用户使用时要非常小心,真的碰到bug了,官方一般也是建议升级版本。根据我的经验,对于这样一个庞大的bug库,不出问题一般没人会去把整个bug list都看一遍的。
|
||||
|
||||
2.业务高速发展时期,业务量成指数级增长时,团队人员技能和经验水平整体上还没法很好地应对,这个时候可能任何一个小变动都是最后一根稻草。这种时候就需要群策群力,而不是简单处罚了事。
|
||||
|
||||
这两种情况都需要全面了解信息之后,再做判断。甚至要优先传递信任,而不是不管三七二十一就直接批评和处罚。何况,如果不出问题,可能很多主管压根都没有关注过员工在做的事情,过程中是否有困难,是否需要支持等等,这本身就是管理者的失责。
|
||||
|
||||
在当前这种新业务和新形态不断涌现,又要求快速迭代的背景下,软件开发这种技术工作很大程度上还是要依赖员工的创新和创造。所以在很多情况下,管理者一定要对故障有一定的容忍度,因为员工努力做事的积极性一旦被打击,变得畏首畏尾起来,也就谈不上什么技术进步和突破了,而且想要再恢复起来也会非常困难,最终很大概率上会导致优秀人才流失,为别人做了嫁衣。
|
||||
|
||||
所以,团队内部一定要营造出鼓励做事向前冲的氛围,而不是制造担心犯错误被处罚的恐慌氛围。
|
||||
|
||||
## 处罚的“负”作用远超我们的想象
|
||||
|
||||
前面讲到,定责不是处罚,是就事论事。员工哪些地方做得不到位,是能力不足还是经验欠缺,这些东西主管可以基于事实,很正式、严肃地表达出来。通常情况下,员工也大多是可以接受的。同时帮助员工进一步分析应该怎么提升,或者聆听员工有什么求助或困难。这种情况下,员工的感受是,主管尊重我,在帮助我。
|
||||
|
||||
但是,话题和目的一旦转到处罚相关的事情,员工一般会有两种类型的反应:一种是消沉低落(反正都是我的错,你说咋样就咋样);另外一种是极力地反抗和质疑(凭什么罚我不罚别人,又不是我一个人的问题等等)。
|
||||
|
||||
这时,员工的注意力也会从怎么改进,转变到为什么要处罚我的角度上来。在这种消极和抵抗情绪中再去沟通什么改进措施,就没有任何效果了。作为管理者,也就非常容易陷入到与被沟通者的反复解释中,他质疑一句,你就解释一句,但是他压根就没听进去。
|
||||
|
||||
从我们的经验来看,**如果定责跟绩效强挂钩,团队就陷入这种恐慌、质疑、挑战以致最终相互不信任的局面**。员工害怕、甚至拒绝承担责任,宁可少做不做,也不愿多做多错,团队沟通成本上升,运作效率自然下降。特别是一个故障如果是涉及多方的,扯皮推诿就开始了,都想着把责任撇干净,甚至当众相互指责,这个负面效应杀伤力极大。
|
||||
|
||||
后来我们就取消挂钩,对于出现的故障有专门的系统记录,然后把这件事情放到员工一个季度,半年,甚至一年表现中进行整体判断。如果员工整体的表现都是不错的,甚至是突出的,说明员工已经改正或者那件事情确实是偶尔的失误导致,这种情况下员工仍然会有好的绩效。但如果是频繁出问题,这种情况就基于事实反馈,也会更加容易沟通。
|
||||
|
||||
我的团队中,就出现过类似的情况。有员工导致了线上严重故障,当个季度绩效较差,但是因为全年表现突出,年终仍然是优秀;也有员工,因为连着两个季度触碰高压线,全年又无明显突出的表现,年终绩效也就不理想。
|
||||
|
||||
## 总结
|
||||
|
||||
我们做个小总结,对于故障的态度,我们还是得要辩证地看。对于是否处罚,也要具体问题具体分析。完全不处罚,或者一刀切,一律处罚都是不可取的。作为管理者,还是要将规则和标准定义清楚,在执行时才能够做到公平公正。
|
||||
|
||||
另外,管理者除了关注故障本身之外,还要考虑得更加全面一些,要关注到人的感受,关注事情的前因后果,只有这样,在管理执行过程中才会让员工感受到尊重和信任。
|
||||
|
||||
最后,你在故障定责和处罚方面有什么经历和想法,欢迎留言与我讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
116
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/30 | 故障管理:故障应急和故障复盘.md
Normal file
116
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/30 | 故障管理:故障应急和故障复盘.md
Normal file
@@ -0,0 +1,116 @@
|
||||
<audio id="audio" title="30 | 故障管理:故障应急和故障复盘" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/53/5b/5303b035b8b5cc45a24df4ff6258cd5b.mp3"></audio>
|
||||
|
||||
上周我们分享了故障管理中,应该如何对待故障,怎样做好故障定级和定责方面的管理工作。今天我就和你分享当故障真正发生后,我们在故障通报和故障复盘方面的实践经验。
|
||||
|
||||
## 故障应急
|
||||
|
||||
当故障真实发生后,带来的影响不仅仅是技术层面的,更多的是业务层面的,比如用户和商家的批量投诉,交易量下跌,广告资损等等。而这些影响又会产生巨大的外部压力,并传递到技术团队,这时如果没有很好的故障应对机制,技术团队就很容易陷入慌乱,不知所措。
|
||||
|
||||
我们能否有效应对这种突发且高压的状况,我觉得有两个方面十分关键。
|
||||
|
||||
**第一方面,业务恢复预案。**
|
||||
|
||||
这也是我们在故障应急状态下一定要坚守的**第一原则:优先恢复业务,而不是定位问题**。这就需要我们事先有充足的预案准备以及故障模拟演练,这就跟我们前面介绍的各种稳定性保障措施相关,通过稳定性平台的建设,与我们能够预见到的,以及我们经历过的故障场景相结合,当发生故障时能够第一时间执行对应的恢复预案。
|
||||
|
||||
同时,预案的执行不能仅仅在故障发生时才执行,而是应该把故障模拟和恢复演练放在平时。我在团队中经常传递的一个理念就是:**凡是没有演练过的预案,都是耍流氓**。也就是如果我们在日常系统稳定的状态下都不敢执行预案,或者执行了没效果,那真到了故障发生后,在更为复杂的状况下,预案100%也是不敢做的,因为这种异常状态下,我们还要考虑执行了预案是否会导致次生故障。
|
||||
|
||||
关于故障模拟,可以分为不同层面来梳理,比如:
|
||||
|
||||
<li>
|
||||
**IDC层面**,如电力切换、UPS切换、核心网络设备切换,单设备故障等,这些故障是可以通过人为破坏进行模拟的,模拟手段相对简单,但是破坏力和影响面会很大,所以做之前一定要准备充分。我们会定期1~2个月做一次类似的模拟演练,涉及机房配合的,也会提前跟运营商约定好时间;
|
||||
</li>
|
||||
<li>
|
||||
**系统层面**,如CPU、磁盘IO、网络IO、网络时延、丢包等异常场景,这些都有开源或Linux系统自带的工具支持,比如Stress工具模拟CPU升高,dd模拟磁盘IO,tc模拟网络问题;
|
||||
</li>
|
||||
<li>
|
||||
**应用层面**,最典型的就是RT升高,抛出异常,返回错误码等等,这里还是会用Spring的注解功能,在运行时模拟异常状况,然后有针对性地看各种限流降级和开关预案策略能否生效。
|
||||
</li>
|
||||
|
||||
关于故障模拟,我再次向你推荐Netflix的Chaos Engineering,介绍得非常全面。
|
||||
|
||||
**第二方面,有效的组织协调。**
|
||||
|
||||
故障发生后的排障和恢复操作,往往需要多个技术团队协作完成,这时就需要有一定的应急机制,来确保相关人员能够快速响应和高效协作。同时,因为对业务造成的影响导致业务团队会承受很多外部压力,这时也需要有统一的口径对外反馈,比如大致原因(对外不用详细),影响面以及预估恢复时长等等,从而确保信息的透明,避免各种不着边际的猜测对公司信誉造成的影响。
|
||||
|
||||
这时,我们前面介绍到的技术支持这个角色就起到了非常关键的作用。对内,要有效组织技术团队的集中和协作;对外,负责对接业务部门同步信息,同时屏蔽各方对技术团队和故障处理人员的干扰。
|
||||
|
||||
出现一个严重故障后,技术支持通常要做如下几个关键事项。
|
||||
|
||||
<li>
|
||||
**确定故障影响面及等级**。故障会通过监控、告警、业务反馈或用户商家投诉几个渠道反馈过来,这时技术支持会根据故障定级标准,快速做出初步判断,确认影响面,以及故障等级。
|
||||
</li>
|
||||
<li>
|
||||
**组织应急小组**。对于无法马上恢复或仍需要定位排查的故障,会直接将相关技术团队的主管和骨干开发人员召集到一起,通常是专用的会议室,并确认故障处理主要指挥者,通常是受影响业务的技术负责人,比如商品出现故障就由商品的技术团队主管指挥排障,交易出现故障就由交易技术团队主管指挥,如果是全站性的故障通常会由技术总监直接介入负责指挥。
|
||||
</li>
|
||||
<li>
|
||||
**信息通报**。完成上述第一步后,通常会给相关技术和业务团队通报故障初步信息,包括登记、影响面、故障简述以及主要处理团队和责任人。完成第二步,组织起应急小组之后,每隔一定时间,如15~30分钟要对进展做一次信息同步。同时,如果等级和故障信息有变,也要同步出来,直至故障排除,业务恢复。为了保证沟通的顺畅,技术支持并不与处理故障的人员直接沟通,而是通过指挥者沟通,这样确保高效沟通,同时也确保处理故障的人员能够相对地专注在故障处理上,而不是响应来自各方的询问,甚至是质问。
|
||||
</li>
|
||||
|
||||
所以,整体总结下来,故障应急过程就是:**功夫要下在平时,注意建设各种工具和平台,同时要尽可能地考虑和模拟各种故障场景**。这就像一支军队在平时一定要做各种军事演习一样,然后就是临场发挥。当故障真正出现时,要有完善的应急机制,马上能够有效运转起来,而不是慌乱无措。
|
||||
|
||||
## 故障复盘
|
||||
|
||||
上面介绍了故障应急,那接下来我们再看故障管理的下一个阶段,也就是故障发生之后的复盘。
|
||||
|
||||
首先,我们一定要先搞清楚复盘的目的。**复盘的目的是为了从故障中学习,找到我们技术和管理上的不足,然后不断改进**。虽然我们不愿意故障发生,但是从故障中学习,反而是提升团队和员工能力的最佳手段,所以我们一定要辩证地看待故障这件事情。
|
||||
|
||||
同时,**切忌将复盘过程和目的搞成追究责任或实施惩罚,这对于团队氛围和员工积极性的打击是非常大的**。这一点在前面的内容中已经详细介绍过,这里就不再重复了。
|
||||
|
||||
在复盘过程中,技术支持仍然要起到关键作用。
|
||||
|
||||
<li>
|
||||
**召集复盘会议**。会提前将故障信息发给故障处理的参与方,准备复盘过程中需要讨论的问题,视情况决定是否邀请业务方人员参会;
|
||||
</li>
|
||||
<li>
|
||||
**组织会议流程**。协调和控制会议中的讨论,也就是俗称的控场;
|
||||
</li>
|
||||
<li>
|
||||
**对故障定级定责**。起到类似“法官”的判决作用,根据前面讲到的标准执行;
|
||||
</li>
|
||||
<li>
|
||||
**明确后续改进行动及责任人,录入系统并定期跟踪**。
|
||||
</li>
|
||||
|
||||
复盘会议中,通常会有哪些关键环节呢?
|
||||
|
||||
**第一,故障简单回顾**。主要针对故障发生时间点,故障影响面,恢复时长,主要处理人或团队做简要说明。
|
||||
|
||||
**第二,故障处理时间线回顾**。技术支持在故障处理过程中会简要记录处理过程,比如每个操作的时间点,责任人,操作结果,甚至是中间的沟通和协作过程,比如几点几分给谁打了电话,多长时间上线的等等,这个过程要求客观真实即可。业务恢复后,会发给处理人进行核对和补充。这个时间线的作用非常关键,它可以相对真实地再现整个故障处理过程。
|
||||
|
||||
**第三,针对时间线进行讨论**。回顾完上述时间线之后,我们会提出过程中存在的疑问,这一点会对主要处理人产生一定的压力,所以一定要保持对事不对人。通常我们会针对处理时长过长、不合理的环节提出质疑,比如为什么告警没有发现问题,而是用户投诉反馈的?为什么从发生故障,到有人上线响应拖了很长时间?为什么对应的场景没有限流、降级和开关等预案?为什么预案执行了没有生效?为什么没有做灰度发布和验证等等?通过这些问题和细节的讨论,我们会找出明显的不足,记录下过程中的改进点。
|
||||
|
||||
**第四,确定故障根因**。通过讨论细节,我们对故障根因进行判断,并再次对故障根因的改进措施进行讨论。在这个环节和上个环节中,通常会有很多讨论甚至是争论,技术支持要发挥的作用就是控制好场面,就事论事,一定不要让讨论失控,演变成相互指责和批斗会,一旦有这种苗头,技术支持一定要及时干预并给出警告。
|
||||
|
||||
**第五,故障定级定责**。根因确定后,结合前面已经确认的故障影响面,就可以对故障定级定责了,这里还要依赖前面我们介绍到的故障标准。不过,定责时,我们会让责任方团队和相关处理人员在场,小范围告知,这样做主要是考虑责任人的个人感受。如果无异议,就形成故障完结报告;如果有异议,则可以向上级主管反馈,直至技术团队负责人(CTO或技术VP)为止。
|
||||
|
||||
**第六,发出故障完结报告**。故障完结报告的主要内容包括故障详细信息,如时间点、影响面、时间线、根因、责任团队(这里不暴露责任人)、后续改进措施,以及通过本次故障总结出来的共性问题和建议。这样做的主要目的是保证信息透明,同时引以为戒,期望其它团队也能够查漏补缺,不要犯同样的错误。
|
||||
|
||||
## 定期总结故障案例
|
||||
|
||||
除了例行的故障应急和故障复盘,我们还会定期对一个时期内的故障案例进行总结。比如按照一个季度、半年和全年的周期,这样可以更容易地发现一些共性问题,以便于研发团队在稳定性建设方面的规划。
|
||||
|
||||
举个例子,2017年年底,我们整体总结了全年的故障案例,对P0~P2严重级别的故障进行分类汇总,就发现全年第三方原因的故障,以及数据类的故障占了很大比例。
|
||||
|
||||
我们再往细节分析,发现第三方原因的故障,多数是机房IDC的电力、网络切换,单台服务器硬件故障导致的。这些在单次故障复盘时,很容易归因于第三方,但是从全年来看,我们认为根因上,还是我们的系统健壮性不够,在限流降级以及日常的故障模拟演练上,还有很大的提升空间。所以,我们就拉上研发团队的主管和骨干员工,重新看这些故障,重新制定出稳定性提升的改进措施。
|
||||
|
||||
同时,在故障定级定责方面,由第三方原因导致的故障,后续不再作为故障根因,而只作为触发因素。所以,在故障复盘时一定要制定出我们自身需要改进的措施。
|
||||
|
||||
针对数据类故障,我们总结后发现大多集中在“有状态业务”发布过程中。代码和配置发布可以走发布系统,有完善的流程支持,但数据的变更却更多地依赖人工操作,且流程和周边部件的配合上也不成熟。所以,我们就明确下来,要加大对有状态业务的发布和数据变更工具的支持,将经验固化下来,而不是靠人。
|
||||
|
||||
## 总结
|
||||
|
||||
上述这些经验,同时又可以推广到整个研发团队,在不断总结的过程中,整个系统的稳定性不断提升,技术架构也不断完善。
|
||||
|
||||
到这里,我们整个故障管理的内容就介绍完了。
|
||||
|
||||
总结一下,我们首先要对故障有一个正确和理性的认识,既不能放任不管,也不要谈之色变;同时我们也需要科学的管理方式,跟业务结合,制定出对应的故障等级和定级定责制度。
|
||||
|
||||
其次,结合我们前面介绍的稳定性保障体系,在日常要做好各类预案和模拟演练,当故障真实发生时,能够做到冷静处理和高效地组织协调。
|
||||
|
||||
最后,在故障复盘中总结出我们的不足,然后不断地改进。
|
||||
|
||||
关于故障管理的内容,你还有哪些问题想和我交流,欢迎你留言讨论。
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
|
||||
|
||||
65
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/31 | 唇亡齿寒,运维与安全.md
Normal file
65
极客时间专栏/赵成的运维体系管理课/效率和稳定性最佳实践/31 | 唇亡齿寒,运维与安全.md
Normal file
@@ -0,0 +1,65 @@
|
||||
<audio id="audio" title="31 | 唇亡齿寒,运维与安全" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/51/0f/51c187afb5867fd9c4646a6c94eda40f.mp3"></audio>
|
||||
|
||||
故障管理模块告一段落了,今天我们来分享运维安全的内容。在日常工作中,我们运维团队和安全团队的配合确实是非常紧密的,有非常多的交集,我觉得可以做个整体的分享,算是抛砖引玉,以激发更多的讨论和思考。
|
||||
|
||||
## 运维和安全的关系
|
||||
|
||||
运维和安全,双方有一个共同的特点,就是时常要面对非常棘手,甚至是影响公司口碑声誉的问题。对于安全来说,这一点尤甚,想一想用户信息泄露会造成什么样的后果就不难理解了。
|
||||
|
||||
所以,运维和安全的合作,最初都是在这种场景下触发的,也就让两个团队显得更像是难兄难弟。
|
||||
|
||||
另外一层关系,就像我们今天分享的题目,运维和安全的关系,就是唇亡齿寒的关系。因为安全是整个业务和技术体系的一道防线,当这道防线被突破,最直接的影响和损失就体现在主机、系统和数据上,而这些又正好是运维的范畴。说得直白一点,就是一旦发生了安全事故,造成的影响,以及后续的修复,这些工作都将由运维来承担。
|
||||
|
||||
所以,**在双方工作的协作上,我一直认为运维不能只是被动响应,而应该主动与安全合作,共建安全体系,与运维体系融合,把防线建设好,从源头控制**。
|
||||
|
||||
同时,安全问题和需求一般都会放置在较高优先级上来响应,并通过固定的问题响应机制实行联动,从而实现最高效的配合响应。
|
||||
|
||||
## 蘑菇街安全体系简介
|
||||
|
||||
这里首先介绍一下我们的安全体系,限于篇幅,我只对部分关键系统和平台做一个简要概述,同时会介绍一下每个系统与运维系统之间的关系。
|
||||
|
||||
**1.入网管控**
|
||||
|
||||
这是VPN接入的管控,并与员工的统一登录鉴权结合,做到一键登录。因为VPN接入后,就等于进入了线上的网络环境中,可以访问到很多敏感系统和数据,这里的**入网管控就相当于整个环境的第一道防线**。
|
||||
|
||||
**2.堡垒机**
|
||||
|
||||
当接入VPN之后,对于技术同学就会有进一步的需求,比如访问线下和线上环境,登录主机和网络设备做维护工作,这时我们就需要有另外一道关卡,就是硬件或虚拟设备的登录管控,这个就由堡垒机来实现。这里堡垒机维护的主机列表、主机用户名、权限配置等信息,就需要与运维系统中的CMDB以及运维标准化的内容保持统一。
|
||||
|
||||
因为堡垒机基本属于每个公司安全建设的第一个产品,所以属于强需求,业界也随之出现了很多优秀的开源及商业产品,你可以自行了解一下。同时,关于这块内容,我们的安全工程师齐剑涛在2017年CUNTCon全球运维技术大会上做过分享,如果有兴趣可以进一步了解。
|
||||
|
||||
[固守服务器的第一道防线——美联集团堡垒机的前世今生](https://www.bilibili.com/video/BV1ct4y117H7/)
|
||||
|
||||
**3.主机安全管控**
|
||||
|
||||
在每台主机上运行一个安全Agent,实时地对可疑进程、可疑端口、可疑账号、可疑日志以及各类操作进行监控,一旦发现异常就会及时告警,确保能够第一时间发现异常,这种就可以一定程度上对黑客入侵导致的破坏进行控制。
|
||||
|
||||
**4.黑盒扫描**
|
||||
|
||||
这个系统主要针对主机上对外开放的端口和使用的服务进行扫描。比如我们之前遇到的Redis高危端口漏洞,OpenSSL心脏滴血漏洞等,同时从接入层会过滤出高频的url,通过注入或修改消息来模拟恶意攻击,量虽不会大,但是如果存在异常或高危漏洞就可以及时发现,同时这个扫描是不间断的。
|
||||
|
||||
**5.白盒扫描(代码审计)**
|
||||
|
||||
这个系统我们在前面的持续交付流水线中介绍过,会针对代码中明显的漏洞进行审计,比如XSS漏洞,SQL注入等问题,如果在代码中存在类似问题是不允许发布上线的。
|
||||
|
||||
这个项目已经开源,地址:[https://github.com/WhaleShark-Team/cobra](https://github.com/WhaleShark-Team/cobra)
|
||||
|
||||
这样,黑盒和白盒扫描搭配起来,就可以对内外部的服务和系统进程进行全方位的保障了。
|
||||
|
||||
**6.WAF,Web Application Firewall**
|
||||
|
||||
WAF用来对外部的Web服务进行保护。我们知道,对于业务系统来说,通常会有很多不正规的渠道来网站爬取各种信息,更有甚者会通过模拟用户行为来注册大量虚假账号,以此来领取各种优惠,或者提交大量虚假订单、评论等等,同时还会对服务器负载造成很大压力。对于这种恶意行为,就需要由WAF来保护,通过一定的业务规则配置和识别来阻止恶意访问。
|
||||
|
||||
**7.应急响应中心SRC**
|
||||
|
||||
在安全界,有这样一个不成文的说法,叫作**三分靠技术,七分靠人脉**,也就是安全的信息情报有时比单纯的技术攻防要重要得多。对于企业来说,除了要能够招聘到一些安全圈内的专业人士,另一方面,也要有对外公开的应急响应中心SRC,以此来聚集一些比较友好和善意的白帽子,通过他们主动发现一些网站和系统的漏洞,并能够通过SRC提交给公司安全部门。同时,作为企业也会有一些不同形式的奖励,比如奖金和纪念品这样的物质奖励,或者漏洞提交排名这样名誉上的认可,以此来形成更长久和深入的合作。
|
||||
|
||||
同时,SRC也能弥补一些我们主动做的,但是防护措施不到位的情况,最大程度地借助社区和圈子的力量,共同保障企业网站、信息和数据的安全。
|
||||
|
||||
上述我们提到的很多检测和限制规则,都会通过规则平台沉淀下来,这个就类似于我们的之前讲到的配置管理。
|
||||
|
||||
最后,以一张图作为总结,来整体呈现我们的安全体系。也欢迎你给我留言继续讨论。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/0c/48/0c67710666e9b52292fc22aef9fdc448.jpg" alt="" />
|
||||
|
||||
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
|
||||
Reference in New Issue
Block a user