2011-09-18 116 views
12

我需要在django(使用AJAX long-polling)开发一个实时最近的活动feed,我想知道服务器端最好的策略是什么。轻量级通知技术

伪代码:

def recent_activity_post_save(): 
    notify_view() 

[in the view] 
while not new_activity(): 
    sleep(1) 
return HttpResponse(new_activity()) 

自带的一点是查询数据库每秒的第一件事。不可行。其他选项:

  1. 使用缓存为使用专门的工具通知服务
  2. ,如芹菜(我宁可不这样做,因为这似乎有点小题大做)

什么是最好的去这里的路?

回答

5

我会建议保持简单...

创建一个数据库表来存储您的活动,插入到该表在适当的时候,那么就实现一个简单的Ajax轮询技术打服务器的每X秒在客户端。

我有使用推送通知的方式或使用NoSQL数据存储库考虑其他解决方案的关注。与使用内置于Django框架的工具的传统pull-notification系统相比,它要复杂得多,除了非常罕见的例外情况外,这些工具都是过分的。除非您特别需要严格的实时解决方案,否则请保持简单并使用框架中已有的工具,对于基于数据库或网络性能的异议人士,我只能说,过早优化是所有的邪恶。

构建一个模型,其中包含特定于您的应用程序的最新活动数据,然后,只要您的应用程序执行了某些应该记录新活动的内容,您可以将其插入此表中。

您的看法与其他任何视图一样,从此RecentActivity表格(可选地基于查询参数以及其他)中拔出顶部的x行。

然后,在客户端,您只需要一个简单的ajax轮询器,每x秒就会触发您的视图。没有复杂的插件和技术,你可以使用的不足,但是,自己写也没那么复杂或者:

function simplePoll() { 
    $.get("your-url", {query-parameters}, function(data){ 
    //do stuff with the data, replacing a div or updating json or whatever 
    setTimeout(simplePoll, delay); 
    }); 
} 

我的观点是性能问题不是真正的问题,直到您的网站是成功足以让他们成为一个问题。一个传统的关系数据库可以很好地扩大规模,直到你开始达到像Twitter,Google等成功的水平。我们大多数人都不在这个水平:)

0

您可以使用触发器(每当发布新帖子时触发)。例如,这个触发器可以在轮询目录中写入一个新文件,其中包含必要的数据(比如主键)。然后你的python就可以直接观察该文件夹中的新文件创建,而无需触摸数据库直到出现一个新文件。

1

您可以使用彗星解决方案,如Ape project。这种类型的项目旨在将实时数据发送到浏览器,并且可以利用现代浏览器的网络套接字功能。

0

如果你是在彗星解决方案,然后you could use orbited。让我警告你,虽然这是因为它是一个相当利基的解决方案,很难找到有关如何在生产环境中部署和使用orbited的良好文档。

0

这里有一个类似的讨论,从服务器端的角度回答:Making moves w/ websockets and python/django (/ twisted?) ,最重要的答案是this one

还有this answer,指向从Django尝试此操作的非常稳定的替代方案。

如果你确实想从现有的Django应用程序获得这个服务,请不要执行此服务器端。将HTTP套接字劫持为单个浏览器的连接是破坏应用程序的快速方法。两个合理的选择是:探索各种网络套接字选项(如上面使用Pyramid托管服务的选项),或者查看让浏览器定期向服务器发送轮询请求以查找更新。

+1

这通常是很好的建议,但问题确实说明了“在Django(使用AJAX long-polling)”。 – dkamins

2

你有没有考虑过使用信号?您可以在recent_activity_post_save()中发送信号,并且可能有一个侦听器将信息存储在缓存中。

视图只会引用缓存来查看是否有新的通知。当然,你不需要信号,但恕我直言,它会更清洁一些,因为你可以添加更多的“通知处理程序”。

这似乎是最佳的,因为您不需要轮询数据库(人工加载),通知几乎是立即“可见”(仅在处理信号并与缓存进行交互所需的时间之后)。

所以伪代码是这样的:

# model 
def recent_activity_post_save(): 
    post_save_signal.send() 

# listener 
def my_handler(...): 
    cache.set('notification', ....) 

post_save_signal.connect(my_handler) 

# view 
def my_view(request): 
    new_notification = None 
    while not new_notification: 
     sleep(1) 
     new_notification = cache.get('notification') 
    return HttpResponse(...) 
+0

这正是我现在使用的;这对我来说似乎也是最佳的,但我正在寻找关于这个问题的其他意见。 +1 –

+0

我一直喜欢这个解决方案,直到我看到'while not not_notification'这行...理论上无法无限期地挂起请求 - 大概是某种ajax轮询请求 - 而它等待一个新通知进来了吗?如果缓存是空的,从视图返回一个空数据集不是更好吗? –

+0

@DMactheDestroyer是某种伪代码,当然如果没有新的活动,它会在30秒左右后返回空结果。 –

0

你应该决定,如果你宁愿用“拉”或“推”的架构去传递你的信息,请参阅本post on quora!如果您喜欢将解决方案“推”到接收者的通知,那么基于缓存/ nosql的系统是可取的,因为它们不会为大量写操作产生如此高的负载。

的Redis例如其有序集合/列表数据结构为您提供了大量的实例。见例如。 this post(尽管它不是python)来获得一个想法。例如,您也可以查看“真实”消息队列,例如RabbitMQ

对于这里的其他职位应该已经给了你关于如何使用扭曲和类似的框架一些想法的客户端连接。

芹菜可以永远是一个很好的工具,你可以例如。将所有信息写入用户的异步作业中的活动流!

+0

感谢您的洞察力;尽管我正在寻找_lightweight_解决方案,因为在网站中为单个页面安装NoSQL数据库没有意义,对吧? –

0

我不认为有必要限制自己使用长轮询的,如果这是不是真的有必要。有些库可以利用最佳选项(如果没有以前的选项可用,可能是短轮询,长轮询,websocket甚至是微型flash插件)。 Node.js拥有用于这样一个工作的最好的库之一,名为Socket.IO,但幸运的是,还有两个Python实现可用,gevent-socketiotornadio,但后来建立在龙卷风框架之上,所以可能不在题。

如果适合你,你可以用一些NoSQL的(文件)数据库,该数据库证明更快,轻便不是关系数据库的组合它们。有许多选项,包括CouchDB,MongoDB,Redis,...... Socket.IO和基于文档的数据库的组合已被证明是快速,轻量且可靠的。

虽然我已经看到你已经在评论认为NoSQL的,我个人的看法是,如果你需要一个快速和简单的解决方案,以上套装的选择你,这是你可以采取的最好机会。