Selenium 4 的新技巧

Selenium Grid:一种允许您将测试分发到多台机器上的机制。

在他的系列文章的第四篇也是最后一篇中,Simon Stewart 继续讨论 Selenium 4 的新功能,并回顾 Selenium Grid 中的新功能。

在过去的几篇博客文章中,我们已经讨论了很多内容,包括如何为该项目做出贡献,以及作为 Selenium 用户您可以期望的一些细节。但 Selenium 的内容不仅仅是您用来编写测试的 API,我们尚未介绍的一大功能是更新后的 Selenium Grid:一种允许您将测试分发到多台机器上的机制。

在进一步深入之前,总是很高兴承认我们来自哪里,这不仅因为这很有趣,而且还有助于解释刷新设计的“原因”。

很久以前(2008 年),Jennifer Bevin 和 Jason Huggins 在 Google 开发了一个名为 Selenium Farm 的系统。这是一个位于某个橱柜中的机器群,允许您运行原始的 Selenium 协议。当然,这是在 Google 的规模上,所以不止一个橱柜 :)

这使得 Google 的人们可以分发他们的测试并扩展到他们各自的机器之外。这个想法太棒了,以至于当 Jennifer 在 Selenium 聚会上谈论 Farm 时,Philippe Haringou(当时在 ThoughtWorks)决定编写一个相同的开源实现,他将其称为“Selenium Grid”。

Selenium Grid 是一项很棒的技术,但它有一个缺点:它只支持原始的 Selenium RC 协议。这很好,但是 WebDriver 使用的是不同的线路协议,称为 JSON 线路协议,人们希望能够同时使用 Selenium RC 和 WebDriver。

这就是 Francois Reynaud 出现的地方。他当时在 eBay 工作,向 Michael Palotas 汇报,他编写了一些类似于原始 Selenium Grid 的东西,但也可以与 JSON 线路协议一起使用。他们非常慷慨地将该工作贡献给了 Selenium 项目,它构成了 Selenium Grid 2 的基础。当时我们决定,Selenium 独立服务器实际上是一个“网格之一”:它将拥有设置 Selenium Grid 所需的一切,以及作为单个独立服务器工作。合并代码并使其稳定花了一段时间,但由于 Francois、Kristian Rosenvold 和其他许多人的努力,我们在 2011 年将 Grid 2 合并到主 Selenium 项目并发布了 Selenium 2。

即使 2011 年感觉并不久远,现代世界也发生了相当大的变化。2011 年,我们没有 Docker。我们没有 Kubernetes,我们实际上也没有 AWS。因此,Selenium Grid 并不知道这些东西即将到来,并且没有编写来利用它们。幸运的是,当时我们有虚拟机,Grid 2 被设计为能够支持它们。

这是名为 Zalenium 的优秀项目的切入点。Zalenium 由 Diego Molina 开发,在 Grid 2 的基础上增加了非常好的 UI,并支持 Docker 和 Kubernetes。这使得 Selenium Grid 至今仍然相关且有用,这是一项了不起的成就。

但是,就像我说的那样,我们花了时间来稳定 Grid 2:大约六个月的辛勤工作,主要是由 Kristian 领导。这是因为虽然 Grid 2 很复杂,但代码难以阅读和维护,而且很少有人能做到这一点。更糟糕的是,Grid 2 和原始 Selenium 服务器的合并非常粗糙;实际上,有两个独立的服务器在同一个二进制文件中发布。这导致在网格中出现问题,但在以独立模式运行时不会出现,反之亦然。

对于 Selenium 4,我们决定咬紧牙关,解决这三个问题。首先,我们想要一些更容易开发和维护的东西。其次,我们希望将服务器合并为一个单元。第三,我们希望一些东西能够利用我们现在可用的现代基础设施世界,不仅以 Docker 和 Kubernetes 的形式,而且还可以使用诸如分布式跟踪等新兴技术。

为此,我们研究了 Grid 提供的功能,并将每个部分建模为一个组件,我们既可以“在内存中”运行(允许我们拥有单个独立服务器),也可以以更分布式的方式运行,允许我们从原始 Selenium Grid 熟悉的“中心和节点”架构,发展到完全分布式的设计。

第一个组件是“路由器”。它充当 Grid 的入口点。您可以将其暴露给互联网,它会将请求定向到 Grid。它被设计为无状态的,因此您可以根据需要向 Grid 添加更多内容。

当路由器看到新的会话请求时,它会将其放入“会话队列”。会话队列由一个名为“分发器”的组件读取,该组件维护一个网格中所有可以运行会话的位置的模型:我们称之为“槽位”。槽位由称为“节点”的组件托管,每个节点可以有一个或多个槽位。当分发器从队列中提取新的会话请求时,它会识别最适合使用的槽位,并将请求转发给拥有该槽位的节点。一旦节点启动会话,分发器会将会话 ID 和运行测试的节点的 URL 放入“会话映射”中——你可以将会话映射看作是一个简单的会话 ID 到 URL 的映射——新的会话响应将被发送回等待的测试。

运行会话的请求(即大多数 webdriver 调用!)的处理方式略有不同。路由器将使用会话映射来查找将请求转发到哪个节点,从而避免完全涉及分发器。这意味着您可以不断向网格添加节点,并且架构中的瓶颈更少,从而减慢您的请求速度。

从概念上讲,网格内有这五个移动部件。但实际上还有第六个,即消息总线。五个网格组件通过消息总线在内部进行通信,但当您考虑网格时,您需要考虑的实际组件是路由器、会话队列、分发器和节点。

当您以“独立”模式运行 Selenium Grid 4 时,您实际上会获得一个“单节点网格”。我们将所有这些组件连接在一个进程中,但它们仍然存在。

您也可以使用 Selenium Grid 2 中看到的传统的 Hub 和 Node 方法运行它,您启动一个 Hub 和一个 Node 并进行注册。如果您最近使用过 Selenium Grid,那么这可能是您熟悉的架构。在这种情况下,大多数组件(路由器、会话队列和分发器)都在 Hub 中运行,而 Node 则运行会话本身。

Grid 4 的新功能是,您可以根据需要进入完全分布式模式。通常,您需要使用 Kubernetes 之类的东西来实现此目的,并且某些关键组件被设计为使用数据库或 Redis 来存储数据,以提高可靠性和可扩展性。

需要注意的是,当运行分布式网格时,弄清楚发生了什么变得非常困难,尤其是在出现问题时。为了缓解这个问题,我们采用了 Open Telemetry 来为网格带来可观察性。我们所说的可观察性是什么意思?这仅仅意味着我们希望能够看到发生的一切。

最后,我们希望以有意义且有用的方式公开有关正在运行的网格的信息。原始网格同时支持 JMX(Java 管理 API)和基于 HTML 的控制台。虽然不错,但这并没有使查询您可能感兴趣的网格的特定区域变得容易,这些区域没有在 UI 中显示(例如,有多少个可用槽位,或者查找特定会话在哪个节点上运行)。为了提供更大的灵活性,我们选择为网格提供 GraphQL 端点。为了确保 GraphQL 端点足够灵活,我们正在使用它构建新的网格控制台。这应该也允许您从网格中提取有用的指标和信息,以满足您的监控需求。

这些是新 Selenium Grid 的一些亮点。您对什么最兴奋?

这最初发布在 https://saucelabs.com/blog/whats-coming-in-selenium-4-the-new-selenium-grid

最后修改于 2021 年 8 月 7 日: 重命名目录 (e9895f27c26)