10

我正在开发一个 Web 后端/API 提供程序,它从 3rd 方 Web API 获取实时数据,将其放入 MySQL 数据库并通过 HTTP/JSON API 使其可用。

我正在为 API 提供烧瓶并使用 SQLAlchemy Core 处理数据库。

对于实时数据抓取部分,我有通过发送请求、将返回的 xml 解析为 Python dict 并返回它来包装 3rd 方 API 的函数。我们将调用这些 API 包装器。

然后我在其他方法中调用这些函数,这些方法获取相应的数据,根据需要进行任何处理(如时区转换等)并将其放入数据库中。我们将调用这些处理器。

我一直在阅读有关异步 I/O 和 eventlet 的具体内容,印象非常深刻。

我将把它合并到我的数据抓取代码中,但我首先有一些问题:

  1. 猴子修补所有东西对我来说安全吗?考虑到我有烧瓶、SQLAlchemy 和一堆其他库,猴子修补有什么缺点(假设没有后期绑定)?

  2. 我应该将任务划分为什么粒度?我正在考虑创建一个定期生成处理器的池。然后,一旦处理器到达它调用 API 包装器的部分,API 包装器将启动一个 GreenPile 以使用 eventlet.green.urllib2 获取实际的 HTTP 数据。这是一个好方法吗?

  3. 超时 - 我想确保没有绿线挂起。将每个 greenthread 的 eventlet.Timeout 设置为 10-15 秒是一个好方法吗?

仅供参考,我有大约 10 组不同的实时数据,并且每 5-10 秒产生一个处理器。

谢谢!

4

2 回答 2

3

我认为将 Flask/SQLAlchemy 与异步风格(或事件驱动)编程模型混合使用并不明智。

但是,既然您声明您使用 RDBMS (MySQL) 作为中间存储,为什么不创建异步工作器,将第三方 Web 服务的结果存储在 RDMBS 中,并保持前端 (Flask/SQLAlchemy) 同步?

在这种情况下,您不需要猴子补丁 Flask 或 SQLAlchemy。

关于粒度,您可能希望使用mapreduce范例来执行 Web API 调用和处理。这种模式可以让您了解如何在逻辑上分离连续的步骤,以及如何控制所涉及的过程。

就个人而言,我不会使用异步框架来执行此操作。使用多处理、Celery或真正的 mapreduce 类型的系统(如Hadoop )可能会更好。

只是一个提示:从小处着手,保持简单和模块化,如果您需要更好的性能,稍后再进行优化。这也可能在很大程度上受到您希望信息的实时性的影响。

于 2012-05-30T13:46:14.993 回答
-1

修补由纯 python 编写并使用标准库的模块是安全的。

  • 很少有纯 mysql 适配器:
  • PyMysql 有一个 sqlalchemy 测试套件,您可以为您的案例运行测试。
  • 有一个名为 pymysql_sa 的模块为 sqlalchemy 提供方言
  • Flask 由纯 python 编写,100% 符合 WSGI 1.0。使用eventlet.wsgi来提供服务。

尽可能使用绿色模块通过单次获取来划分任务。将jobs放入一个队列,同样由eventlet提供,每个taskworker从队列中取出一个job,取出完成后将结果存入db,或者发送到event.Event对象触发等待的job任务完成。或者,这两个进程。

更新:

eventlet官方文档强烈推荐使用主模块第一行的patch,多次调用monkey_patch是安全的。阅读更多页面http://eventlet.net/doc/patching.html

有一些绿色模块可以与 eventlet 一起工作,它们都在 eventlet.green 中。bitbucket上的列表。确保在您的代码中使用绿色模块,或者在导入使用标准库的第三个模块之前对其进行修补。

但是monkey_patch 只接受少数模块,需要手动导入绿色模块。

def monkey_patch(**on):
    """全局修补某些系统模块,使其对绿色线程友好。

    关键字参数提供了对修补哪些模块的一些控制。
    如果没有提供关键字参数,则修补所有可能的模块。
    如果关键字设置为 True,则仅修补指定的模块。例如,
    ``monkey_patch(socket=True, select=True)`` 只修补选择和
    插座模块。大多数参数修补同名的单个模块
    (操作系统,时间,选择)。例外是套接字,它也修补了 ssl
    模块(如果存在);和线程,它修补线程、线程和队列。

    多次调用 monkey_patch 是安全的。
    """    
    Accepted_args = set(('os', 'select', 'socket',
                         '线程','时间','psycopg','MySQLdb'))
    default_on = on.pop("全部",无)
于 2012-05-31T10:05:26.677 回答