如果可以的话,请贴我:我们如何调试生产。 第一部分

UPD:本文的第二部分已准备就绪

哈Ha! 我叫亚历山大·伊兹麦洛夫(Alexander Izmailov)。 在Badoo,我领导一个发布工程师团队。 我知道,在许多公司中,您可以将代码更改发送给受过专门培训的人员,他会查看这些更改并将其添加到应有的位置(例如,Git代码正是这种情况)。 我想谈谈我们如何与我们一起自动执行此过程。

我的故事将包括两个部分。 在这一部分中,我将讨论我们希望从新系统中获得什么,它在第一个版本中的外观,以及为什么最后必须重做。 在第二部分中,我们将讨论重建系统的过程及其带来的意外收益。


图片: 来源

曾几何时,在我们公司中,每个人都可以直接向主分支机构进行更改,并亲自进行布置。 为此,我们编写了一个特殊的MSCP实用程序,该实用程序的工作原理很原始:它将更改从一台计算机复制到另一台计算机并设置必要的权限。

随着时间的流逝,公司不断发展壮大-我们不得不考虑流程的自动化,包括进行小改动的流程。 因此,我们有了创建补丁系统的想法。 首先,我们希望它允许任何开发人员将其更改发送到Git并将其放在服务器上。 就我们而言,我们要求另一位开发人员查看更改,并将其与我们的错误跟踪系统(我们使用Jira)中的任务联系在一起。

贴片收集器6000
我必须说,这些要求并不吸引所有开发人员。 在我们看来,花几分钟来创建任务并不是一件容易的事,但是对我们来说,这意味着更刻意地使用该系统。 但是开发人员开始反抗,认为布局更改所需的时间比创建新票证所需的时间少几倍。 结果,我们仍然有“通用”任务,其中要附加数百个补丁。

另外,该系统的设计目标是解决紧急问题,并且很难在凌晨三点找到补丁的审阅者。

我们需要什么?


是的,窗口上只有一盏灯……我们的问题可以有条件地分为两部分:我们需要某种方式来接受对存储库的更改,并需要一种方式来安排这些更改。

我们足够快地决定了第一个问题:我们制作了一个表格,必须将更改附加到表格上并指出详细信息(审阅者和任务)。


在第二页上,您可以查看更改,拒绝或接受更改。



确认后,更改归入主目录。

第二个问题:如何将这些更改快速交付给服务器? 如今,许多人使用持续集成,如果我们的“诚实”构建和布局不花太多时间,它就可以很好地完成工作。

公平集会


我们的组装一直很复杂。 一般原则是这样的:在一个单独的目录中,我们将文件布置为与目标服务器上的文件相同; 然后我们将该状态保存在快照(文件系统快照)中并进行布局。

我们将PHP代码放入目录,该目录直接从存储库中获取,并向其中添加了生成的文件(例如,模板和翻译)。 我们分别布置了静点。 这是一个相当复杂的过程,您可以专门撰写整篇文章,但是结果,我们有了一个版本映射,可以为与主代码一起保留的用户生成文件链接。

接下来,目录的状态需要保存在某处。 为此,我们使用了块设备 ,我们称之为循环。 将整个目录复制到一个空设备,然后将其归档并传送到单独的“主”服务器。 在布局过程中,我们从这些服务器中获取了档案。 每个档案的大小为200 MB,解压缩后的循环重1 GB。 在没有静态的情况下,我们花了大约五分钟的时间进行构建。

公平的布局


首先,我们需要将存档传递到目标服务器。 我们有成千上万的服务器,因此对我们来说交付问题一直是一个大问题:我们有多个平台(数据中心),并且在“最厚”的一千台带有代码的服务器上。 为了获得更好的性能(最少的时间和资源),我们尝试了不同的方法:从简单的SCP到种子。 最后,我们决定使用UFTP。 该方法快速(在天气好的情况下-一分钟),但是不幸的是,并非没有问题。 定期发生故障,我们不得不去找管理员和网络管理员。

存档(以某种方式)在服务器上发现之后,必须将其解压缩,这也不是免费的。 如果您记得该过程执行了数千次,尽管在不同的计算机上并行执行,则此过程似乎特别昂贵。

没有组装


因此,老实说,发布更改要花费很多时间,并且交付速度对于补丁程序系统非常重要,因为假定在某些情况不再起作用时他们会使用它。 因此,我们回到了使用MSCP的想法:快速且易于实现。 因此,在向导中显示更改之后,可以在单独的页面上依次分解更改的文件。



还活着


系统正在运行。 尽管对这些小事情有些不满意,但是开发人员可以完成他们的工作,因此,他们不需要访问主服务器或服务器。

但是,当然,通过这种布局方法,我们遇到了问题。 有些是可以预见的,有些甚至可以以某种方式决定。 其中大多数与并行文件编辑有关。

一个补丁可保存多个文件


可预测问题的示例。 依次布置新文件。 如果您需要更改多个文件并且更改与它们相关,该怎么办? 例如,我想在一个文件中添加新方法,然后立即在其他文件中使用它。 只要没有使用方法的环回(请参阅相互递归 ),就足以记住正确的文件布局顺序。

诚实的决定
为了解决这个问题,我们需要原子替换几个文件。 对于单个文件,解决方案是已知的:您需要使用文件操作重命名。 假设我们有一个文件F,我们需要替换它的内容。 为此,创建一个TMP文件,向其中写入必要的信息,然后重命名TMPF。

让任务复杂化。 假设我们有一个目录D,我们需要替换它的内容。 重命名操作将无济于事,因为它无法替换非空目录。 但是,有一种解决方法:可以使用所谓的符号链接(symlink)预先替换D目录。 然后,内容本身将位于其他位置,例如在目录D_1中,并且D将是到D_1的链接。 在需要替换的时刻,新内容将写入D_2目录,并在该目录上创建新的TMP链接。 现在,重命名TMP D将起作用,因为此操作可以应用于链接。

此解决方案看起来很合适:您可以使用代码更改整个目录,复制旧文件并在其上写入新文件。 问题是复制所有代码很长而且很昂贵。 您只能替换文件更改的子目录,但是所有带代码的子目录都应该是链接,因为在布局过程中我们无法用任何东西替换填充目录。 该解决方案不仅看起来非常复杂-您还必须记住添加一些限制,以使两个进程无法同时更改同一目录或目录及其子目录。

结果,我们找不到技术解决方案,但是我们想出了一些简化生活的方法:我们通过界面中的一个动作对多个文件进行了布局。 开发人员指定了文件的布局,然后系统交付了它们。

每个文件多个补丁


如果只有一个文件,并且有多个开发人员想要更改该文件,则更加困难。 我们应用了第一个补丁,但没有分解它。 此时,第二个补丁到达并被要求分解。 怎么办 更为有趣的是,如果应用了第二个补丁,则此时要求我们分解第一个补丁。

可能需要澄清的是,我们总是只布局向导中的最新版本。 否则,可能会出现其他问题。 例如,将旧版本布置在新版本之上。

我们没有为这个问题提出一个非常好的解决方案。 我们向开发人员展示了他们在给定时间的布局与机器上的布局之间的区别,但这并不总是可行。 例如,可能会有很多更改,并且开发人员可能会着急或懒惰(可能发生任何事情)。

很多补丁,每个人都更改相同的文件


这是您甚至不愿再谈的最糟糕的选择。 如果多个开发人员的更改影响了几个相同的文件,那么我们的补丁程序系统将无济于事-它仍然依赖于开发人员的专心以及他们彼此之间进行通信的能力。 但从理论上讲,当以任何布局顺序在服务器中的某个位置上部分破坏代码时,很有可能会遇到“鱼”。


图片: 来源

铁问题


当由于某种原因其中一台服务器不可用时,又出现了另一个问题。 我们有一种机制可以将此类服务器从布局中排除,效果很好。 他们复职后出现困难。 事实是,我们已经检查了工作服务器上的配置和代码版本(有一个完整的监控部门!),并且当服务器恢复运行时,我们确保所有版本都是最新的。 但是我们没有补丁的版本控制-我们只是将新文件复制到当前代码中。

我们没有提出准确的方法来对已分解的补丁进行版本控制,但我们尝试通过变通办法解决该问题。 例如,在布局过程结束时,从相邻计算机发出rsync。 但是以某种方式我们无法检查。

我们针对此问题提供了几种解决方案,例如,我们也希望在“主”服务器上应用补丁(记住要部署的是打包版本,即需要应用补丁并将版本打包回来,这一点很重要),但是实现起来非常困难。

一勺蜂蜜


但是,除了问题之外,还有积极的方面。

首先,开发人员很快就发现,除了解决问题外,借助修补程序系统,有时您还可以上传新功能,例如在紧急需要时。 像任何公司一样,我们不可抗力。 但是,如果以前我们必须创建一个非凡的构建,使测试人员和发布工程师无法集中精力,那么现在开发人员可以自行分解一些更改。

其次,不再需要某些有权利的特殊人来解决问题。 任何开发人员本人都可以发布他的编辑。 但这还不是全部:总体而言,构建变得更容易了,现在将问题分为关键问题和可以使用补丁修复的问题。 这样就可以减少回滚的频率,并更快地决定我们是否成功。

简而言之,我们喜欢该系统并获得了普及。 我们继续尝试对其进行改进,但是由于存在上述问题,我们不得不再活几年。 以及我们如何决定它们,系统现在如何工作以及在更新过程中我们几乎是如何度过了新年假期的,我将在文章的第二部分中讲述。

Source: https://habr.com/ru/post/zh-CN413503/


All Articles