Facebook生态系统是由成千上万的分布式系统和微服务驱动构成的,其中许多服务都得益于异步作业,特别是在在线流量的高峰时期。异步化提供了诸多好处:更有效地利用资源、提高系统可靠性、允许计划执行,以及微服务彼此间可靠通信。实现这些优势都需要一个队列——一个存储作业的地方,允许其异步发生,或者从一个服务传递到另一个服务。facebook有序队列服务FOQS应运而生。
FOQS在Facebook上支持数百个服务,包括:
构建分布式优先队列
FOQS的主要能力是存储位于namespace中的topic中的item。它公开了一个Thrift API,包含以下操作:
-
Enqueue -
Dequeue -
Ack -
Nack -
GetActiveTopics
FOQS通过内部服务Shard Manager来管理对主机的分片分配。每个分片分配给一台主机。为了更容易地与其他后端服务通信,FOQS实现了Thrift接口。下面来分别介绍各部分的原理和设计:
Item
item是FOQS中优先队列的消息,其中包含用户指定的数据。一般来说,它由以下字段组成:
-
Namespace FOQS的多租户单元 -
Topic 即一个优先队列; 一个 namespace可以包含许多(数千个) topics. -
Priority (用户指定的32位整数), 数值越小优先级越高。 -
Payload 不可变二进制大对象,大小可以到10kb。开发人员可以自由地在这里放置他们想要的任何东西。 -
Metadata 可变二进制对象。开发人员可以自由地在这里放置他们想要的任何东西。通常,元数据应该只有几百字节。 -
Dequeue delay — Item应该从队列中退出的时间戳。这也称为deliver_after. -
Lease duration 一个Item需要被消费者ACK或者NACK而出队列的持续时间,如果消费者什么都没有做,则FOQS可以根据客户指定的重试策略(至少一次、最多一次和最大重试计数)重新投递Item。 -
FOQS-assigned unique ID 用于通过API标识一个Item. -
TTL 限制Item在队列中的驻留时间。一旦一个Item的生存时间(TTL)被命中,它将被删除。
「FOQS中的每个Item对应于MySQL表中的一行。在进入队列时,会给一个Item分配一个ID。」
topic
一个topic就是一个逻辑优先队列,一般是一个字符串,由用户指定。它包含item,并按它们的优先级和deliver_after值对它们进行排序。主题是廉价且而且是动态变动的,只需将item排队并指定topic标识就可以创建topic。
由于topic是动态的,FOQS为开发人员提供了一个API,通过查询活动topic(至少包含一个item)来发现topic。当一个topic没有更多的item时,它就不再存在。
namespace
一个namespace和一个队列用例相匹配。它是FOQS的多租户单位。每个namespace都有一定的容量保证,以每分钟的队列数量衡量。命名空间可以共享同一列(一列是FOQS主机和MySQL分片的集合,为一组命名空间提供服务),且不相互影响。命名空间只映射到一个列。
Enqueue
Enqueues是item进入FOQS的入口。如果成功进入队列,则会执行持久化,最终出队列。