为消息队列处理选择消费者服务类型:部署或作业或无服务器?
我设计并部分管理在云上 Kubernetes (Azure) 上运行的模块化单体应用程序(约 25 个服务)。我最近收到了对具有以下特征的工作负载的需求: 1.工作负载必须异步运行(完成后会立即通知用户) 每个工作负载都需要相当数量的 CPU——比如 4 个内核。 这些工作负载的并发性并不高,比如说最多需要并行运行 10-20 个实例。 每个工作量应在 3 分钟内完成。越快越好。 该工作负载将在一
我设计并部分管理在云上 Kubernetes (Azure) 上运行的模块化单体应用程序(约 25 个服务)。我最近收到了对具有以下特征的工作负载的需求:
1.工作负载必须异步运行(完成后会立即通知用户)
-
每个工作负载都需要相当数量的 CPU——比如 4 个内核。
-
这些工作负载的并发性并不高,比如说最多需要并行运行 10-20 个实例。
-
每个工作量应在 3 分钟内完成。越快越好。
-
该工作负载将在一天中零星运行,主要集中在工作日开始时,但这可能跨越时区。
如您所见,这是一个非常具体的要求,需要一个非常具体的解决方案。
我们可以采取哪些可能的方法来解决这个问题?
选项 1:使用 kubernetes 部署。
最简单的选择是只使用 Kubernetes 部署。它很简单,原生,大多数其他服务已经是部署。 在这个非常具体的要求中,缺点是保持部署运行的成本很高,因为每个 pod 至少需要 4 个核心的 CPU 请求。我们必须运行至少 10 个副本来支持并发性和性能。
如果我们知道这些工作负载的大致时间窗口,我们就可以安排虚拟机的横向扩展,让它们提前做好准备。由于我们没有非常狭窄的窗口,我们需要依赖自动缩放器。水平 pod 自动缩放器不能很好地工作,因为 pod 的平均 CPU 利用率需要一些时间才能达到横向扩展的水平。由于 pod 大部分时间都是空闲的,如果同时有多个工作负载进来,它们可能会被分配到同一个 pod,从而降低它们的性能。即使可以通过某种方式解决这个问题,如果 VM 上没有足够的资源,节点自动缩放器就会开始启动一个新的 VM,然后在该 VM 上创建新的副本,然后工作负载必须在那里运行。显着延迟(约 2-3 分钟,但在我们的上下文中很重要)。
还有一点需要注意,如果我们选择这条路线,那就是关于 CPU 节流。因为这些是 CPU 密集型工作负载,我们需要注意这个问题。即使您没有完全消除限制,您也需要将限制设置为至少比所需的高 2 个核心。
因此,最好为一个请求“保留”所有 4 个内核。这让我们...
选项 2:使用 Kubernetes 作业。
使用一项作业来处理一个请求。作业启动速度快(在 2-3 分钟工作负载的情况下),只做一件事,完成后释放资源。
但是您如何动态地创建工作呢?我们从 k8s 获得的作业的唯一控制器是 cronjob,这不是我们想要的。根据请求或消息触发作业会很棒。你怎么做到这一点?您可以使用 KEDA 来触发 Kubernetes 作业!让运行工作负载的请求进入队列,使用 KEDA 对监控队列并在每条消息上创建作业。
虽然作为作业运行解决了不使用时资源耗尽的问题,但它仍然无法处理 VM 耗尽资源时横向扩展的情况。例如,如果 16 核 VM 已经运行了 3 个作业(每个都说请求 5 个内核),那么当第 4 个作业被触发时会发生什么?节点自动缩放器必须启动一个新的虚拟机,这会导致延迟。不仅仅是延迟,它还会导致工作负载性能的不可预测性。对此的一种解决方案是减少 CPU 请求,以将一些额外的 pod 放入现有的 VM 中,假设您的节点尚未达到峰值。 (如果在 Azure 中有一个基于 cpu / 内存使用百分比而不是挂起的 Pod 工作的节点自动缩放器,我会很棒的。)
让我们也尝试一种非 k8s 的方法,看看是否有替代方案......
选项 3:使用容器即服务 - Azure 容器实例
使用virtual kubelet将 pod 调度到“虚拟”节点类型上,并在ACI中创建调度在该节点上的 pod。
理想情况下,这应该是可行的,但是,ACI 还面临着如果没有基础基础设施就必须提供的问题。我认为 ACI 位于 AKS 和 Azure Functions 之间。 (Leaky Abstractions还不够吗?)
因此,ACI 也存在冷启动问题,并且无法保证启动时间(对我来说需要 0.5-5 分钟)。它最多可以为您提供 4 核 CPU,因此,如果工作负载可以容忍长达 5 分钟的启动延迟或不可预测性,那就没问题了。
选项 4:无服务器
Azure Functions 会起作用吗?消耗计划有 1 个 CPU 限制,因此没有用。等等,AWS Lambda 现在在其现收现付计划中有 6 个核心的限制!它确实有效。但是连接 Azure 和 AWS(考虑到我在 Azure 上拥有的所有其他东西),设置 VPC,只开放对 lambda 的数据库访问,确保在 Terraform 脚本中考虑 lambda ......这是一场噩梦,不值得好处。
但是高级计划中的 Azure Functions 呢?这行得通,最多允许 4 个内核。您可以使用 Always Ready 实例,以及一些可突发的实例(需要按消耗付费。我相信即使您使用 Always Ready 实例,您仍然会遇到一些冷启动问题,我还没有真正实现过这个。但是,当我在 Azure 定价计算器中尝试数学计算时,发现它比简单地运行 VM(保留 3 年)要贵得多。
最后的话:
那么我选择了什么?
-
用于运行工作负载的基于 KEDA 的作业。
-
适当调整 CPU 请求和限制
-
在 Azure 中进行为期 3 年的 VM 预订 - 您将获得大量折扣。 FaaS 没有预订折扣。
4.对于很少使用的服务,以及需要大量资源的服务,尽量避免部署。首选 Kubernetes 作业或 Azure Functions(您甚至可以在 AKS 中运行函数运行时而不会产生任何成本)。
我很确定这种情况可能还有更多可能的解决方案。即使是要求的微小变化也会使一种解决方案的适用性超过另一种解决方案。
图片来自Pichara BannonUnsplash[由我修改;) ]
更多推荐
所有评论(0)