Python Django、芹菜、Redis、RabbitMQ:用于写操作时扇出的链接任务
我一直在看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的用户将在以下键处拥有一个列表: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这样拥
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批次:明白了。这可能是一个很好的指示,我应该使用显式返回语句。