无服务器架构能否支持高内存需求?
Can a serverless architecture support high memory needs?
挑战是 运行 一组消耗比预期更多内存的数据处理和数据科学脚本。
这是我的要求:
- 运行 10-15 Python 3.5 脚本通过 Cron Scheduler
- 这些不同的 10-15 个脚本每个都需要 10 秒到 20 分钟才能完成
- 他们 运行 在一天中的不同时间,有些 运行 每 10 分钟一次,有些 运行 一天一次
- 每个脚本都会记录它所做的事情,这样我以后可以在出现问题时查看它
- 一些脚本会向我和我的队友发送电子邮件
- None 个脚本有 HTTP/web 个服务器组件;他们都 运行 在 Cron 计划上而不是面向用户
- 所有脚本的代码都来自我的 Github 存储库;当脚本唤醒时,它们首先执行 git pull origin master 然后开始执行。这意味着,推送到 master 会导致所有脚本都处于最新版本。
这是我目前拥有的:
- 目前我正在为这些脚本使用 3 个 Digital Ocean 服务器(droplets)
- 有些脚本需要大量内存(我在内存不足 4GB 的液滴中出现分段错误)
- 我愿意介绍一个可能需要更大内存的新脚本(新脚本目前在 4GB droplet 中出错)
- droplet 的设置相对容易(感谢 Python venv),但还没有达到执行单个命令来分离新 droplet 并进行设置的程度
为我的新脚本配备一个完全专用的 8GB / 16B droplet 听起来有点低效且昂贵。
处理此问题的更有效方法是什么?
What would be a more efficient way to handle this?
我分三部分回答:
- 减少内存消耗的选项
- 无服务器计算的简约架构
- 如何到达那里
(一)减少内存消耗
Some handle large loads of data
如果您发现脚本使用的内存比您预期的多,减少内存需求的唯一方法是
- 了解脚本的哪些部分会消耗内存
- 重构脚本以使用更少的内存
导致内存消耗的典型问题是:
使用了错误的数据结构 - 例如如果您有数值数据,通常最好将数据加载到 numpy 数组而不是 Python 数组。如果你创建了很多自定义对象类,使用__slots__
会有所帮助
一次将太多数据加载到内存中 - 例如如果可以将处理拆分成几个相互独立的部分,那么只加载一个部分需要的数据,然后使用循环处理所有部分可能会更高效。
保留不再需要的对象引用 - 例如在处理过程中,您创建对象来表示或处理数据的某些部分。如果脚本保留对此类对象的引用,则在程序结束之前不会释放它。解决此问题的一种方法是使用 weak references, another is to use del
to dereference objects explicitely. Sometimes it also helps to call the garbage collector.
在有在线版本(用于机器学习)时使用离线算法 - 例如一些 scikit 的算法为 incremental learning 提供了一个版本,例如 LinearRegression
=> SGDRegressior
或 LogisticRegression
=> SGDClassifier
some do minor data science tasks
有些算法确实需要大量内存。如果不能选择使用在线算法进行增量学习,那么下一个最佳策略是使用仅对实际计算 time/memory 使用收费的服务。这就是通常所说的 无服务器计算 - 您不需要自己管理服务器(droplet)。
好消息是,原则上您使用的提供商 Digital Ocean 提供了一种仅对实际使用的资源收费的模型。然而,这并不是真正的无服务器:创建、启动、停止和删除 droplet 以实际受益仍然是您的任务。除非这个过程是完全自动化的,否则乐趣系数有点低;-)
(II) 无服务器计算的极简架构
a full dedicated 8GB / 16B droplet for my new script sounds a bit inefficient and expensive
由于您的脚本 运行 只是偶尔/按计划,您的 droplet 不需要 运行 甚至一直存在。所以你可以通过以下方式设置它:
创建一个调度 droplet。这可以是小尺寸。它的唯一目的是 运行 一个调度程序并在脚本到期时创建一个新的 droplet,然后提交任务以在这个新的 worker droplet 上执行。 worker droplet 可以具有特定大小以容纳脚本,即每个脚本都可以有一个它需要的任何大小的 droplet。
创建一个通用工作器。这是 运行 在调度程序创建新 Droplet 时执行的程序。它接收 URL 到 git 存储库的输入,其中存储了要 运行 的实际脚本,以及存储结果的位置。然后它从存储库中检出代码,运行s 脚本并存储结果。
脚本完成后,调度程序将删除 worker droplet。
通过这种方法,每个脚本仍然有完全专用的 droplet,但它们只在脚本 运行 时花钱。
(三)如何到达
一种选择是构建如上所述的架构,这本质上是 serverless computing. There are several Python libraries to interact with the Digital Ocean API. You could also use libcloud
作为通用多提供商云 API 的简约架构的实现,以使其更容易(更) 稍后切换供应商。
也许在构建自己之前更好的选择是评估现有 open source serverless options. An extensive curated list is provided by the good fellows at awesome-serverless 之一。请注意,在撰写本文时,许多开源项目仍处于早期阶段,更成熟的选项是商业化的。
与工程决策一样,需要在构建或托管自己 v.s 所需的 time/cost 之间进行权衡。使用现成的商业服务的成本。最终,这是只有您才能做出的决定。
挑战是 运行 一组消耗比预期更多内存的数据处理和数据科学脚本。
这是我的要求:
- 运行 10-15 Python 3.5 脚本通过 Cron Scheduler
- 这些不同的 10-15 个脚本每个都需要 10 秒到 20 分钟才能完成
- 他们 运行 在一天中的不同时间,有些 运行 每 10 分钟一次,有些 运行 一天一次
- 每个脚本都会记录它所做的事情,这样我以后可以在出现问题时查看它
- 一些脚本会向我和我的队友发送电子邮件
- None 个脚本有 HTTP/web 个服务器组件;他们都 运行 在 Cron 计划上而不是面向用户
- 所有脚本的代码都来自我的 Github 存储库;当脚本唤醒时,它们首先执行 git pull origin master 然后开始执行。这意味着,推送到 master 会导致所有脚本都处于最新版本。
这是我目前拥有的:
- 目前我正在为这些脚本使用 3 个 Digital Ocean 服务器(droplets)
- 有些脚本需要大量内存(我在内存不足 4GB 的液滴中出现分段错误)
- 我愿意介绍一个可能需要更大内存的新脚本(新脚本目前在 4GB droplet 中出错)
- droplet 的设置相对容易(感谢 Python venv),但还没有达到执行单个命令来分离新 droplet 并进行设置的程度
为我的新脚本配备一个完全专用的 8GB / 16B droplet 听起来有点低效且昂贵。
处理此问题的更有效方法是什么?
What would be a more efficient way to handle this?
我分三部分回答:
- 减少内存消耗的选项
- 无服务器计算的简约架构
- 如何到达那里
(一)减少内存消耗
Some handle large loads of data
如果您发现脚本使用的内存比您预期的多,减少内存需求的唯一方法是
- 了解脚本的哪些部分会消耗内存
- 重构脚本以使用更少的内存
导致内存消耗的典型问题是:
使用了错误的数据结构 - 例如如果您有数值数据,通常最好将数据加载到 numpy 数组而不是 Python 数组。如果你创建了很多自定义对象类,使用
__slots__
会有所帮助
一次将太多数据加载到内存中 - 例如如果可以将处理拆分成几个相互独立的部分,那么只加载一个部分需要的数据,然后使用循环处理所有部分可能会更高效。
保留不再需要的对象引用 - 例如在处理过程中,您创建对象来表示或处理数据的某些部分。如果脚本保留对此类对象的引用,则在程序结束之前不会释放它。解决此问题的一种方法是使用 weak references, another is to use
del
to dereference objects explicitely. Sometimes it also helps to call the garbage collector.在有在线版本(用于机器学习)时使用离线算法 - 例如一些 scikit 的算法为 incremental learning 提供了一个版本,例如
LinearRegression
=>SGDRegressior
或LogisticRegression
=>SGDClassifier
some do minor data science tasks
有些算法确实需要大量内存。如果不能选择使用在线算法进行增量学习,那么下一个最佳策略是使用仅对实际计算 time/memory 使用收费的服务。这就是通常所说的 无服务器计算 - 您不需要自己管理服务器(droplet)。
好消息是,原则上您使用的提供商 Digital Ocean 提供了一种仅对实际使用的资源收费的模型。然而,这并不是真正的无服务器:创建、启动、停止和删除 droplet 以实际受益仍然是您的任务。除非这个过程是完全自动化的,否则乐趣系数有点低;-)
(II) 无服务器计算的极简架构
a full dedicated 8GB / 16B droplet for my new script sounds a bit inefficient and expensive
由于您的脚本 运行 只是偶尔/按计划,您的 droplet 不需要 运行 甚至一直存在。所以你可以通过以下方式设置它:
创建一个调度 droplet。这可以是小尺寸。它的唯一目的是 运行 一个调度程序并在脚本到期时创建一个新的 droplet,然后提交任务以在这个新的 worker droplet 上执行。 worker droplet 可以具有特定大小以容纳脚本,即每个脚本都可以有一个它需要的任何大小的 droplet。
创建一个通用工作器。这是 运行 在调度程序创建新 Droplet 时执行的程序。它接收 URL 到 git 存储库的输入,其中存储了要 运行 的实际脚本,以及存储结果的位置。然后它从存储库中检出代码,运行s 脚本并存储结果。
脚本完成后,调度程序将删除 worker droplet。
通过这种方法,每个脚本仍然有完全专用的 droplet,但它们只在脚本 运行 时花钱。
(三)如何到达
一种选择是构建如上所述的架构,这本质上是 serverless computing. There are several Python libraries to interact with the Digital Ocean API. You could also use libcloud
作为通用多提供商云 API 的简约架构的实现,以使其更容易(更) 稍后切换供应商。
也许在构建自己之前更好的选择是评估现有 open source serverless options. An extensive curated list is provided by the good fellows at awesome-serverless 之一。请注意,在撰写本文时,许多开源项目仍处于早期阶段,更成熟的选项是商业化的。
与工程决策一样,需要在构建或托管自己 v.s 所需的 time/cost 之间进行权衡。使用现成的商业服务的成本。最终,这是只有您才能做出的决定。