Python在公司中如何发展。Yandex报告

13年前,开始在大型Yandex服务中使用Python的实验。实验证明是成功的(谁会对此表示怀疑!),Python开始为公司的服务取得胜利。Yandex.Afisha,Yandex。天气-一段时间后,有很多服务。与它们一起出现了解决问题的“最佳实践”和“行之有效的方法”。





在我的演讲中,我回顾了Python在公司中的发展:从打包在deb包中并在裸机上推出的第一批服务,到具有自己的构建系统和云的复杂的单一存储库。故事中还会涉及Django,Flask,Tornado,Docker,PyCharm,IPv6和我们多年来遇到的其他事物。



-让我告诉你我自己。我于2008年来到Yandex。起初,我从事内容服务,尤其是Yandex.Afisha。我在Python中写过代码,我们从Perl和其他有趣的技术重写了该服务。



然后我切换到内部服务。内部服务部门逐渐转变为组织的搜索界面和服务的管理。从一个我已经成长为一个简单的开发人员到我们部门的python开发负责人,已经过去了很多时间,大约有30个人。



重要的一点:公司规模很大,我不能代表Yandex的全部。当然,我与其他部门的同事沟通,我知道他们的生活。但是基本上我只能谈论我们的部门,我们的产品。我的报告将专注于此。有时我会告诉你,在Yandex中的其他地方,他们会这样做。但这并不常见。



在公司的许多地方都使用Python:任何技术,任何技术堆栈,任何语言。想到的一切都在公司的某个地方,无论是作为实验还是其他。在任何Yandex服务中,一个组件或另一个组件中肯定会有Python。



我只想说说我对事件的解释。我不假装绝对客观。这一切也都经过我的双手,它在情感上是彩色的。我所有的经验都是非常个人的。







报告的结构如何?为了让您更容易地感知信息,并让我说出来,我决定将从2007年到现在的整个发展细分为几个时代。该报告将严格按照这些时代来组织。这个时代意味着基础设施或发展方式的某种根本性改变。如果我们的铁基础设施发生了变化,同时又改变了我们开发服务的方式,使用的工具,那将是一个时代。很明显,我不得不稍作调整。显然,并不是所有事情都同步发生,而且这些更改之间还存在差距,但是我试图将所有事情都放在一个时间轴上,只是为了使其更加紧凑。







我们是哪个时代的?在这里,一切都是版权,所有名称都是我的。第一个时代被称为“硬件”,这是我刚进入公司时就开始的。因此,一切都发生了一些变化。那个时代变成了“铁+ venv”。此外,我将揭示这些名称背后隐藏的内容。首先,我想向您提供有关我将告诉您的内容的指南。



下一个时代是“容器”,这里的一切都差不多。我现在也将介绍这个我们迈入的时代是“二进制大会”。







每个时代将如何构成?这一点也很重要,因为我想做一个有节奏的叙述,以便每个部分都经过严格的组织和易于理解。时代由基础架构,我们使用的框架,我们与依赖项的工作方式,我们的开发环境以及这种方式的优缺点来描述。



(技术暂停。)我告诉您介绍,介绍了报告的结构,让我们继续讲故事本身。



年龄1:铁







加入公司后,我开始做的第一项服务称为“每个人都去哪里”。这是Afisha的卫星,这是第一个大型Django服务。



格里莎·巴库诺夫(Grisha Bakunov)波布克可以说出他为什么曾经决定将Django转移到Yandex的原因-总的来说,它发生了。我们开始在Django上提供服务。



我来了,他们告诉我:让我们做每个人都去的地方。然后已经有了某种基础。我联系上了,我们认为这是一种实验-是否可以进行。实验成功。每个人都同意可以在Python和Django中的Yandex中创建Web服务。精细!我们的基础设施为此做好了准备,人们已经做好了准备,世界也已经做好了准备。走吧,让我们进一步在整个公司范围内分发Python和Django。我们开始做。我们重写了Yandex.Afish,Weather。然后-电视节目。然后一切都变得迷雾重重,他们开始重写所有内容。



到那时,Yandex的基础架构看起来像整个后端都是主要由专业人士编写的。显然,向Python的迁移在许多地方大大加快了开发速度,这已受到公司和管理层的欢迎。现在让我们讨论一下基础架构-这些服务在哪里工作,它们在运行什么以及所有这些。







这些是铁制机器,因此是这个时代的名字。什么是铁车?它们只是数据中心中的服务器。有许多服务器,它们全部组合成一个由15台计算机组成的群集。然后是30,然后是50,然后是100。所有这些都在Debian或Ubuntu上进行。到那时,我们已经从Debian迁移到Ubuntu。我们通过标准的初始化过程启动了所有应用程序。一切都是标准的,就像当时所做的那样。为了使我们的应用程序在Web服务器上进行通信,我们使用了FastCGI协议和flup库。如果您使用Python很久了,您可能已经听说过它。但是现在,我确定您不会使用它,因为它已经过时并且是一件很奇怪的事情,它运行非常缓慢。



显然,那时我们并没有使用Python 2.3编写第三个Python。然后他们迁移到2.4。狂野时代。我什至不想考虑它们,因为语言,社区和生态系统看上去完全不同,尽管它也很酷,但那时很多人对此很感兴趣。就个人而言,它使我沉浸在Python的世界中-即使存在奇异之处,也很清楚Python是一种很有前途的技术,您可以在其中投入时间。



要点很重要:那时我们还没有使用nginx,不再使用Apache,而是使用了一个名为Lighttpd的Web服务器。如果您长期从事Web服务,那么您可能也听说过。有一次他很受欢迎。







在这些框架中,我们实际上使用了Django。我们开始在Django上提供出色的服务。在公司的某个地方是CherryPy,在某个地方-Web.py。您可能也听说过这些框架。现在,它们还不处于首要位置,它们早已被年轻,大胆的框架所取代。然后他们有了自己的利基市场,但最终他们迟早要灭绝了,我们停止对它们做任何事情。他们开始在Django中做所有事情。



至此,Python在公司中变得如此普遍,以至于突然冒出了我们的部门:Python和Django中的Web服务开始在公司中的任何地方都可以使用。







让我们继续处理依赖项。然后,如果您来到一家大公司工作,很可能还会遇到这样的事情:该公司已经拥有完善的基础架构,您需要进行调整。 Yandex具有deb基础设施,deb包装的内部存储库。人们认为Yandex开发人员能够组装此deb包。我们被迫整合到此流程中,以成熟的deb软件包的形式组装我们的项目,然后作为deb软件包将所有这些内容放到我所说的服务器上,然后它们也以deb软件包的形式放置在群集上。



结果,所有依赖项和库(相同的Django)也必须打包在deb包中。为此,我们建立了自己的基础架构,建立了一个内部存储库,并学习了如何做。这不是一个非常原始的课程:如果您尝试构建RPM或deb软件包,那么您就知道了。 RPM稍微更简单,deb则更复杂。但都一样-您将不能只从街上走来,只要点击一下就可以开始。您需要挖掘一点。



此后,我们一直在构建Deb软件包。在我看来,并不是每个为工作需要这样做的人都了解幕后发生的事情。他们只是互相拿走,复制了空白,模板,但并没有深入挖掘。但是那些挖出内部问题的人变得非常有用,并且非常要求同事:如果突然之间没有什么事情要做,每个人都会向他们寻求建议,并要求细微之处和帮助进行调试。那是一段有趣的时光,因为我对弄清楚里面有什么感兴趣。因此,他在同事中不受欢迎。







除了依赖关系的生态系统之外,还可以使用通用代码。从一开始,项目的数量就已经有了爆炸性的增长,并且需要使用通用代码,创建通用库等。我们开始进行这种内部开源。我们提供了授权的一般功能,可以处理日志以及其他常见问题,内部API,内部存储。我们以库的形式完成了所有这些工作,并将其放入内部存储库中。最初,这些是SVN存储库,然后是内部GitHub。



最后,他们打包了所有这些依赖项,所有这些库也都放在deb中,并加载到单个存储库中。由此,形成了这样的包装环境。如果开始一个新项目,则可以在其中放置几个​​库,获得功能基础,然后立即在Yandex基础结构中启动该项目。很舒服









我们的典型服务器是什么样的?经典地。有系统依赖性,有python依赖性和应用程序。由此得出几件事。首先,在同一服务器上并因此在同一群集上运行的所有应用程序必须具有相同的依赖关系。因为如果安装一个软件包系统,它始终是一个版本,所以不能有多个版本,则必须进行同步。



当项目很少时,您仍然可以以某种方式进行。当有很多东西时,一切都会变得非常复杂。它们是由不同的团队制作的,很难达成共识。每个团队都希望尽早升级到某些库或要升级框架。其他所有人都应遵循此规则。随着时间的流逝,这会带来很多问题。这促使我们放弃这种方案,进入下一个时代。但是我稍后再谈。



让我们谈谈开发环境。但是对开发环境有了如此广泛的了解。这就是您的工作方式,代码编写方式,调试方式,代码使用方式,检查位置,运行方式,测试运行方式等等。







当我加入公司时,我们都是在远程开发服务器上工作。也就是说,您拥有某种桌面,可以在Windows或Linux上使用,这没关系。您使用正确的Debian和正确的软件包存储库进入远程服务器。然后您运行,运行vim,Emacs,编写代码,调试。



这不是很方便,但是后来我们真的不了解另一种生活。那些幸运地拥有Linux台式机或笔记本电脑的人可能会尝试在本地执行此操作。但是也没有特别说明,什么也没有。这么疯狂的时间。当时生活在Windows和Mac上并希望在本地开发的特殊人群提出了一个虚拟机,其中包含Linux。他们在此虚拟机中编写了代码并启动了它。更准确地说,他们在主机系统上编写了代码,在虚拟机内部运行了代码,并以某种方式转发了文件系统,从而使所有内容同步。一切工作都非常糟糕,但还是得以幸存。



这种发展方式在这个时代有什么利弊?实际上-明显的缺点:



  • 正如我所说,总体集群局促。
  • 集群上的所有项目都必须具有相同的依赖关系。
  • . , , Django . , . 15-20 . . , , — . X, . , . - , - , . . , , . .
  • Yandex依赖Debian基础架构。我们支持它,构建软件包,维护内部存储库。当然,这也不是很好,不是很方便,也不是很灵活。您依赖于公司未完成的奇怪事情。尽管如此,Debian作为开源解决方案和Linux发行版还是用于其他任务。


让我们再谈谈Django。我们为什么开始使用它?我只是想在报告之前坐在椅子上之前,原来是11年前,我在基辅的一次会议上发表了一个主题为“我为什么要使用Django?”的演讲。然后我自己喜欢它。我是一个受人敬佩的开发人员,他阅读了文档,做了我的第一个项目,在他看来,所有东西现在都通用了,您甚至可以钉在钉子上,我不知道。



但是花了很长时间。我仍然喜欢Django,它仍然在我们部门和公司中广泛使用。例如,即使在2018年秋天之前,爱丽丝也将Django纳入其后端。现在她不再在那里了,但是为了快速起步,她的同事们选择了她。由于部分优点仍然有效-大型生态系统,因此仍然有很多专家。有您需要的所有电池。



并且有足够的灵活性。当您刚开始使用Django时,在您看来,它非常局限您,牵扯您,需要一定的工作流程。但是,如果您进行更深入的研究,则可以禁用,更改和配置许多功能。而且,如果您熟练地使用此功能,则可以获得与最受欢迎的Python框架相关的所有优点。您可以绕过所有缺点。它们也很多,但是它们以某种方式停止了。



年龄2:铁+虚拟



我们已经结束了关于这个时代的讨论。2011年已经结束,我们进入了下一个时代,“铁+ venv”。您已经了解硬件,现在您需要告诉发生了什么事,venv的名称来自何处。抒情离题:venv没出现是因为出现了虚拟机。为什么用引号引起来?因为我们开始尝试各种类似于容器的事情,例如OpenVZ或LXC。那时它们发展得很差,不像现在。他们并没有真正和我们一起飞行。我们仍然生活在通用集群上,我们仍然必须与其他项目并存在同一台机器上。我们正在寻找解决方案。







例如,我们从init切换到upd systemd,不久之后,我们在启动应用程序时有了灵活性。我们放弃了FastCGI,开始使用WSGI接口与Web服务器或HTTP进行通信。至此,我们已经在使用或多或少的现代Python,该生态系统已经非常完善。我们改用nginx作为Web服务器,总的来说一切都很好。







我们也开始为自己适应新的框架。例如,他们开始使用龙卷风。当然,那时候Flask已经出现了,2012年之后Flask已经非常流行,流行并且Django威胁要放弃Python中流行框架的基础。而且,当然,他们开始使用Celery。因为随着项目的增长,它们的数量会增加,它们变得越来越重,解决了更多的问题,处理了更多的数据,然后您需要一个框架来在大型计算集群上离线执行任务。当然,我们开始为此使用Celery。但是稍后会更多。







发生了巨大变化的是使用依赖项。我们开始收集虚拟环境。大约在那个时候,python社区意识到不可能将python库放到系统中,而是创建一个虚拟环境,然后将您需要的所有python依赖项放到那里,这样的环境将是完全独立的。一台机器上可以有尽可能多的虚拟环境。这是孤立的,非常方便的成瘾。您仍然使用它。我们也对所有内容进行了调整。最后,我们做了什么?我们创建了一个虚拟环境,并在其中放置了所有python依赖项,将其打包到一个deb包中,并将其滚动到服务器上。



结果,所有项目都不再相互干扰,这取决于系统中常见的python依赖关系,他们可以轻松选择要使用哪个版本的框架或库。非常方便。通用代码也有所变化。由于我们部分放弃了Debian基础设施,尤其是停止使用deb软件包安装python依赖项,因此我们需要一些可以卸载所有通用代码和通用库以及放置它们的地方。





到幻灯片的链接



到那时,已经有几种PyPI实现,即python软件包的存储库,尤其是用Django编写的实现。我们选择了其中之一。叫做Localshop,这是参考。该存储库仍然有效,其中已经包含约一千个内部软件包。也就是说,从2011年至2012年左右,一家Yandex规模的公司生成了大约一千种用Python编写的不同的库,实用程序,据信这些库可在其他项目中重用。您可以估计比例。



所有库都发布在此内部资源库上。然后从那里将它们安装在Python中,或者使用一种特殊的自动基础结构将它们转变为Debian。它或多或少地实现了自动化和便捷。我们不再花费太多资源来维护Debian基础架构。它或多或少地独立运作。



这是定性的一步。这是我所谈论的图表。









也就是说,对宠物的依赖性最终不再对每个人都一样。系统的仍然存在,但数量不多。例如,数据库驱动程序,XML解析器需要系统二进制文件。通常,那时我们无法摆脱这些依赖关系。







开发环境也发生了变化。自从venv出现以来,虚拟环境就可以访问并且可以在任何地方使用,因此,我们通常可以在任何本地平台上组装项目。这大大简化了生活。不再需要去烦Debian,也不需要虚拟机。您可以只使用任何操作系统,例如说虚拟venv,然后pip安装一些东西。而且有效。



此方案的优点是什么?由于我们已经使用了很长的时间-也许超过三年-使用这种参数配置,住在群集旅馆变得更加容易。这真的很方便。也就是说,我们停止了依赖整个公司中某些Django的这些全局更新。我们可以更精确地选择适合我们的版本,并在关键漏洞解决漏洞或其他问题时更频繁地更新。这是一种非常正确的方法,我们喜欢它并为我们节省了很多东西。



但是也有缺点。系统依赖性仍然很常见。有时它会开火,有时会造成阻碍。再一次,我将超出我们部门的范围,讨论公司。由于公司规模很大,所以并不是每个人都与我们一起追赶这些时代。当时,该公司仍继续使用deb软件包来处理python依赖项。让我更详细地告诉您为什么我们开始使用这些框架。特别是龙卷风。







我们需要一个异步框架,我们现在有任务。第三个Python及其异步功能尚不存在,或者它们处于初始状态,使用它们还不是很可靠。因此,我们尝试选择要使用的异步框架。有几个选项:Gevent和Twisted。最有可能的是,还有更多,但我们从中选择。公司已经使用了Twisted,例如Yandex.Taxi后端是用Twisted编写的。但是我们看了看它们,就决定Twisted看起来不是pythonic,即使PEP-8也不符合要求。还有Gevent-内部存在一些带有宠物堆栈的骇客。让我们使用龙卷风。



我们没有后悔。我们仍在某些服务中使用Tornado-在那些尚未重写为第三个Python的服务中。多年来,该框架已被证明是紧凑,可靠且可以信赖的。



当然是芹菜。我已经部分地讲述了这一点。我们需要一个用于分布式执行延迟任务的框架。我们得到了它。







Celery为不同的经纪人提供支持非常方便。我们积极地将此b用于各种任务,以试图找到一个或另一个正确的经纪人。是Mongo,SQS和Redis。但是我们尝试根据需要进行选择,并且成功了。



尽管事实上存在许多关于Celery,如何在内部编写,如何调试,如何进行日志记录的抱怨,但它确实有效。Celery仍然在我们部门的几乎每个项目中都活跃使​​用,据我所知,在我们项目之外。芹菜是必不可少的。如果您需要推迟执行任务,那么每个人都可以参加Celery。或一开始他们不接受,尝试尝试其他事情,但后来他们仍然来到芹菜。



我们进入下一个时代。我们已经接近当今,更加现代化。在这里,时代的名字不言而喻。



年龄3:容器







我们公司内部有一个兼容docker的云。内部,而不是docker runtime,而是内部开发。但同时,您可以在其中部署docker映像。这对我们有很大帮助,因为我们能够使用整个docker生态系统进行开发和测试。我们可以使用各种各样的好东西,然后,仅在收到测试图像后,将其上传到此云中即可。它从那里开始,并按需工作。



到那时,我们已经独立于容器内的操作系统。您可以选择任何一个。当然,我们没有使用普通的恶魔,而是例如主管。随后,每个人都转而使用uWSGI-事实证明,uWSGI不仅知道如何运行您的Web应用程序并为其中的Web服务器提供接口。对于启动流程来说,这也是一件好事。



但是,那里有一些奇怪的配置,但是总的来说很方便。我们摆脱了不必要的本质,开始通过uWSGI进行所有操作。我们还使用它与Web服务器进行通信。云的特殊性使得我们无法使用uWSGI协议与作为全局组件的平衡器进行通信,该平衡器在云中全局表示。但这没关系。在uWSGI内部,HTTP服务器实现得很好,可以快速,可靠地工作。







框架呢? Falcon框架出现了,我们在Falcon上用Django重写了同一个Alice,因为存在一定数量的apis-它们必须快速工作,但同时它们也不是很复杂。



Django在某些时候变得有点多余,为了提高速度并摆脱如此大的依赖关系(一个大的库),我们决定将其重写为Falcon。



当然还有异步。我们开始在第三个Python中编写新服务,并在第三个Python中重写旧服务。仅在我们部门,现在大约有30种用Python编写的服务。这些是30种成熟的产品,具有后端,前端和自己的基础结构。处理数据的内容可为内部和外部使用者提供服务。



但是,正如您所知,该公司拥有数千个Python服务,而且它们是不同的。它们位于不同的框架,不同的Python(旧版本和更新版本)上。现在,该公司几乎使用了您所知道的所有现代框架。 Django,Flask,Falcon,其他异步工具-Tornado,Twisted和asyncio。一切都被利用和有益。



让我们回到时代的结构-我们如何开始使用依赖项。







这里的一切都很简单。现在,我们不能使用虚拟环境。我们不需要deb软件包。在构建映像时,我们只需使用pip安装所需的所有内容。它是完全隔离的。我们不会打扰任何人。而且很方便。任何系统依赖项,您都可以选择Debian,Ubuntu等任何基础映像。我们喜欢。充分的自由。



但是实际上,众所周知,完全自由还有另一面。当您拥有一家大公司时,甚至当您想要推广统一的开发方法和方法,测试方法以及文档编制方法时,甚至更多—在这一刻,您将面临一个事实,那就是该动物园一方面会在某个方面提供帮助。相反,它使情况复杂化。例如,他不容易将某些库注入所有服务中,因为服务是不同的。他们有不同版本的Python,Django或其他框架。这使事情变得复杂。但是最后,典型的服务器开始看起来像这样。









是的,这是一台服务器。我们有完全独立的容器。它们每个都有自己的系统环境,并且我们的应用程序旋转。非常舒适。但是,正如我所说,存在弊端。



让我们回到码头一段时间。我们开始使用docker进行开发,这对我们有很大帮助。







Docker适用于所有平台。您可以测试,使用docker-compose,创建docker swarm,并尝试在小型集群上模拟您的生产环境以进行测试。也许进行负载测试。我们开始积极使用它。



Docker还与各种开发环境很好地集成在一起。例如,我正在PyCharm中进行开发,我的大多数同事也在开发中。内置了对Docker的支持以及它的优缺点,但是总的来说,一切都可以正常工作。



它已经变得非常方便,我们已经迈出了质的一步,而现在正是这一阶段。使用docker进行开发很方便,即使我们将在其上部署应用程序的目标云不是成熟的Docker Runtime,也有一些局限性。但这仍然不能阻止我们在本地及相关任务中使用Docker Engine。



让我们回顾一下这个时代。优点-完全隔离,方便的开发工具链以及我所说的IDE支持。



也有缺点。 Docker无处不在,但如果不是Linux,它的工作原理会有些奇怪。拥有MacBook的Yandex开发人员会为Mac安装docker。还有一些功能,例如,IPv6工作异常,或者您需要以某种方式对其进行调整。在我们公司中,IPv6非常普及。我们长期以来一直缺乏IPv4地址,因此整个内部基础结构很大程度上都与IPv6相关。当IPv6无法在笔记本电脑上或笔记本电脑上的docker内部运行时,您会遭受痛苦并且无法真正执行任何操作,那么我们必须绕过它。







尽管如此,我们还是非常喜欢docker。它高效且具有良好的生态系统。人们说,人们从街上来到我们这里-您可以泊船吗?他们-是的,我可以。一切都很好。一个人来了并立即立即开始变得有用,因为他不需要深入研究如何开始和如何构建项目,如何运行测试,如何查看编写,任何调试输出。人已经知道了一切。这是外界的事实上的标准,它提高了我们的效率,我们可以快速为用户提供功能,而无需在基础架构上花费金钱。



年龄4:二进制版本



但是我们已经接近了我们刚刚进入的最后一个时代。当我说到这里时,我将回到报告的开头:您来到一家拥有自己的基础架构方法的大公司。 Yandex也是如此。如果以前是Debian基础设施,那么现在则有所不同。很长一段时间以来,该公司只有一个整体存储库,所有代码都在此逐步收集。围绕它构建了构建机制,分布式测试机制,一系列工具以及我们尚未使用但已经开始使用的所有工具。也就是说,我们的python项目也访问此存储库。我们尝试使用相同的工具进行收集。但是,由于这些工具是单个存储库中的工具(主要是在C ++,Java和Go中进行了改进),因此这里有其独特之处。









特殊性是这个。如果现在我们的项目组装的结果是Docker引擎,其中带有所有依赖项的源代码就简单地位于其中,那么我们得出的结论是,我们的项目组装的结果将只是一个二进制。这只是一个Binar,其中有一个python解释器,代码以及我们的python和所有其他必要的依赖项,它们是静态链接的。



可以相信,您可以将这个二进制文件扔到任何具有兼容体系结构的Linux服务上,它将起作用。这是真的。



似乎有点不自然。 python社区中的大多数人都不会这样做,而且我敢肯定您不会这样做。这有其优点和缺点。优点:



  • . , , , , , . , . , , . .
  • , , , . , , . , . , checkout , , . .
  • , .


当然,还有一个缺点:封闭的生态系统。局外人需要沉浸于一切的运作方式中,以告诉其运作方式。他必须尽力而为,直到那才生效。我们才刚刚开始。也许,如果我在一两年内参加这次会议,我可以告诉您我们是如何进行这一转变的。但是现在我们对未来很乐观,并且遵守一些内部公司规则,我们宁愿不喜欢它,因为我们会得到很多内部好处。



结论



他们更具哲学性。该报告本身并不是技术性的,而是哲学性的。



  • 进化是不可避免的。如果您提供一项服务并且使用寿命很长,那么您将对其进行发展,发展其基础架构以及开发方式。
  • . , , , .
  • . , Django, . , . , , , Django - , . , .
  • Python-. , , -. , , . , , , , , : , . , .


这个话题很大。我非常简单地向您介绍了我们的工作方式以及Python在我国的发展情况。您可以使用每个时代,将每个项目放在幻灯片上,然后更深入地分解。这也足够40分钟-您可以在很长一段时间内谈论依赖关系,内部开源和基础架构。我给了一张概览图片。如果有任何主题很受欢迎,我可以在下一次聚会或会议上进行介绍。谢谢。



All Articles