通过龙卷风进行进程间通信

时间:2013-12-27 12:54:24

标签: python ipc tornado

我一直致力于推荐系统,到目前为止,我们只是构建了一个简单的算法,即邻域方法,用于电子商务商店。

系统是用Python构建的,可以广泛使用它的数学库,它以一种非常简单的方式工作:它接收客户导航的产品列表,输出是前10个推荐项目的列表

为此,我们在python中实现了2个脚本:一个是我们使用Tornado接收URL的Web服务,第二个是邻居本身,我们在其中使用我们的相似性矩阵来计算推荐。它们通过Inter Process Communication(IPC)进行通信,我们使用内置的库多处理来实现这一目的。

我们创建了这样的网络服务:

import sys
sys.path.append("..")

import tornado.httpserver
import tornado.ioloop
import tornado.web
from tornado.escape import json_encode
from shared.bootstrap import *

import argparse

from clients import ClientFactory, ClientNotFoundException

class WService(tornado.web.RequestHandler):

    _clients = {}

    def get(self, algorithm = None):

        algorithm = 'neighborhood' if not algorithm else algorithm
        rec_list = []

        if algorithm == 'favicon.ico':
            algorithm = 'neighborhood'

        print "value of algorithm %s" %(algorithm)

        try:

            if not algorithm in self._clients:

                self._clients[algorithm] = ClientFactory.get_instance(algorithm)        

            arguments = self.get_arguments_by_client(self._clients[algorithm].get_expected_arguments())


            rec_list = self._clients[algorithm].call(arguments)

        except ClientNotFoundException as err:
            error("Erro " + str(err))

        except Exception as err:
            error("Erro: " + str(err))
            self._clients[algorithm] = ClientFactory.get_instance(algorithm)

        rec_dict = {"skus" : [str(sku) for sku in rec_list]}
        self.write(json_encode(rec_dict))

    def get_arguments_by_client(self, expected_arguments):
        arguments = {}
        for key in expected_arguments:
            arguments[key] = self.get_argument(key, expected_arguments[key])

        return arguments

application = tornado.web.Application([
                                       (r"/(.*)", WService),
                                       ])


def parse_command_line_params():

    parser = argparse.ArgumentParser()

    parser.add_argument('--port', help="Service running port number",  required=True)
    return parser.parse_args()

if __name__ == "__main__":

    http_server = tornado.httpserver.HTTPServer(application)
    cmd_args = parse_command_line_params()
    http_server.listen(cmd_args.port)
    tornado.ioloop.IOLoop.instance().start()

基本上当Tornado收到GET请求时,我们的ClientFactory会启动我们的邻居应用程序,如果它尚未启动并启动IPC(为此我们会执行this thread on SO,第二个回答)。

因此,当Tornado收到一个URL时,它基本上解析它,通过IPC将项目列表发送到我们的邻居应用程序,然后处理信息并通过相同的IPC将结果发送回Tornado,最终以JSON格式输出选择的产品。

这里的例子是发送到Tornado的URL:

http://localhost:8000/?skus_navigated=PR840ACG60NNV,BO185SHF79ZRG,BO185SHF99OBK&skus_carted=&skus_purchased=AN658APF41AIC&category=49

发送的最大项目是每个参数中的10个产品。如果它们最终都是null或无法识别的东西,则默认响应为空JSON。

我们的邻域算法有一个稀疏的Scipy矩阵,目前它的形状围绕(300k,300k)的值。如果我们发送参数:

skus_navigated = PR840ACG60NNV,BO185SHF79ZRG,BO185SHF99OBK

skus PR840ACG60NNV ,BO185SHF79ZRG ,BO185SHF99OBK在内部映射(如果在数据中观察到它们)并且它们会收到给定的分数(假设为1.0),所以如果它们的映射类似于:

PR840ACG60NNV = 7
BO185SHF79ZRG = 5000
BO185SHF99OBK = 300

然后我们创建一个向量v,例如:

v = zeros(300k)
v[[7, 300, 5000]] = 1.0

然后我们使用v乘以我们的scipy矩阵来获得最佳推荐。

之后我们尝试使用系统并且它工作了几分钟,但随后响应时间开始大幅增加到我们不得不关闭系统的程度。

即使系统平均只需要10毫秒来解析URL以输出JSON结果,但系统开始需要更长时间来响应和分解。

我们的基础架构似乎没有问题,我们正在使用一些可以处理我们请求数量的虚拟机。

所以我想问你是否有办法使用Tornado制作这个IPC并连接到我们的邻居,可能是以某种异步方式,以避免请求排队并最终崩溃。

在Tornado和邻居之间有没有更好的方法来建立这个系统?

我们认为在龙卷风中加载我们的邻域矩阵会使它有点不稳定,因为如果一个发生故障,那么另一个发生故障。但到目前为止我们创建的解决方案似乎已经使系统更不稳定,即使处理请求的速度相当快。

感谢您的帮助,如果您需要更多信息,请告诉我们。

提前致谢,

0 个答案:

没有答案