Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django、芹菜、Redis、RabbitMQ:用于写操作时扇出的链接任务_Python_Django_Redis_Rabbitmq_Celery - Fatal编程技术网

Python Django、芹菜、Redis、RabbitMQ:用于写操作时扇出的链接任务

Python Django、芹菜、Redis、RabbitMQ:用于写操作时扇出的链接任务,python,django,redis,rabbitmq,celery,Python,Django,Redis,Rabbitmq,Celery,我一直在看Rick Branson的PyCon视频:。为了回答这个问题,您可能需要观看视频。里克·布兰森用芹菜、Redis和兔子。为了让您了解最新情况,每个用户的homefeed都有一个redis列表。每个列表都包含他们关注的人发布的照片的媒体ID 比如贾斯汀·比伯就有150万粉丝。当他发布一张照片时,需要将该照片的ID插入每个追随者的每个redis列表中。这称为写时扇出方法。然而,这种方法存在一些可靠性问题。这是可行的,但对于贾斯汀·比伯(Justin Bieber)或Lady Gaga这样拥

我一直在看Rick Branson的PyCon视频:。为了回答这个问题,您可能需要观看视频。里克·布兰森用芹菜、Redis和兔子。为了让您了解最新情况,每个用户的homefeed都有一个redis列表。每个列表都包含他们关注的人发布的照片的媒体ID

比如贾斯汀·比伯就有150万粉丝。当他发布一张照片时,需要将该照片的ID插入每个追随者的每个redis列表中。这称为写时扇出方法。然而,这种方法存在一些可靠性问题。这是可行的,但对于贾斯汀·比伯(Justin Bieber)或Lady Gaga这样拥有数百万粉丝的人来说,在web请求中执行此操作(您有0-500毫秒的时间来完成请求)可能是个问题。到那时,请求将超时

因此Rick Branson决定使用芹菜,这是一种基于分布式消息传递的异步任务队列/作业队列。任何繁重的工作,如将媒体ID插入追随者列表,都可以在web请求之外异步完成。请求将完成,芹菜将继续将ID插入所有列表

这种方法非常有效。但同样,你也不想把贾斯汀的所有追随者都一块一块地交给芹菜,因为这会束缚芹菜工人。为什么不让多个工人同时工作,以便更快地完成?好主意!您可能希望将此块分解为更小的块,并让不同的工人处理每个批次。里克·布兰森(Rick Branson)有一批10000名追随者,他使用一种称为光标的东西不断为贾斯汀·比伯(Justin Bieber)的所有追随者插入媒体ID,直到完成为止。在视频中,他在3:56谈到了这一点

我想知道是否有人能对此进行更多的解释,并举例说明如何做到这一点。我目前正在尝试相同的设置。我使用Andy McCurdy的redis py python客户端库与我的redis服务器通信。对于我服务中的每个用户,我都会创建一个redis追随者列表

因此,ID为343的用户将在以下键处拥有一个列表:

followers:343
我还为每个用户创建一个homefeed列表。每个用户都有自己的列表。 因此,ID为1990的用户将在以下键处拥有一个列表:

homefeed:1990
在“followers:343”redis列表中,它包含跟随用户343的人的所有ID。用户343有20007个追随者。下面,我正在检索列表中从索引0一直到-1结尾的所有ID,只是为了向您展示它的外观

>>> r_server.lrange("followers:343", 0, -1)
['8', '7', '5', '3', '65', '342', '42', etc...] ---> for the sake of example, assume this list has another 20,000 IDs.
您看到的是跟踪用户343的所有用户ID的列表

这是我的proj/mydjangoapp/tasks.py,其中包含我的insert_into_homefeed函数:

from __future__ import absolute_import
from celery import shared_task
import redis
pool = redis.ConnectionPool(host='XX.XXX.XXX.X', port=6379, db=0, password='XXXXX')

@shared_task
def insert_into_homefeed(photo_id, user_id):
    # Grab the list of all follower IDs from Redis for user_id.
    r_server = redis.Redis(connection_pool=pool)

    followers_list = r_server.lrange("followers:%s" % (user_id), 0, -1)

    # Now for each follower_id in followers_list, find their homefeed key 
    # in Redis and insert the photo_id into that homefeed list.

    for follower_id in followers_list:
        homefeed_list = r_server.lpush("homefeed:%s" % (follower_id), photo_id)
    return "Fan Out Completed for %s" % (user_id)
在这个任务中,当从Django视图调用时,它将获取跟随用户343的人的所有ID,然后将照片ID插入他们的所有homefeed列表中

这是我的项目/mydjangoapp/views.py中的上传视图。我基本上调用芹菜的延迟方法并传递必要的变量,以便请求快速结束:

# Import the Celery Task Here
from mydjangoapp.tasks import insert_into_homefeed


@csrf_exempt
def Upload(request):
    if request.method == 'POST':
        data  = json.loads(request.body)
        newPhoto = Photo.objects.create(user_id = data['user_id'], description= data['description'], photo_url = data['photo_url'])
        newPhoto_ID = newPhoto.pk
        insert_into_homefeed.delay(newPhoto_ID, data['user_id'])
        return HttpResponse("Request Completed")

我如何才能做到这一点,以10000为单位进行批处理?

视频中描述的方法是任务“链接”

要使任务方法以链的形式启动并运行,您需要在跟随者列表中添加一个表示索引的额外参数。该任务不处理跟随者的完整列表,而只在固定的批处理大小上工作,从它所传递的索引参数开始。完成时,任务应创建一个新任务并通过新索引

INSERT_INTO_HOMEFEED_BATCH = 10000

@shared_task
def insert_into_homefeed(photo_id, user_id, index=0):
    # Grab the list of all follower IDs from Redis for user_id.
    r_server = redis.Redis(connection_pool=pool)

    range_limit = index + INSERT_INTO_HOMEFEED_BATCH - 1 # adjust for zero-index

    followers_list_batch = r_server.lrange("followers:%s" % (user_id), index, range_limit)

    if not followers_list_batch:
        return # zero followers or no more batches

    # Now for each follower_id in followers_list_batch, find their homefeed key 
    # in Redis and insert the photo_id into that homefeed list.
    for follower_id in followers_list:
        homefeed_list = r_server.lpush("homefeed:%s" % (follower_id), photo_id)

    insert_into_homefeed.delay(photo_id, user_id, range_limit + 1)

这很好,因为Redis和lrange命令。

感谢您的快速回复!:)好办法!但这不是一个无限循环吗?即使在我浏览了整个列表之后,任务也会被一遍又一遍地调用吗?啊!我刚刚看到了if followers\u list\u批次:明白了。这可能是一个很好的指示,我应该使用显式返回语句。