Multi-Destination-Cast(MDC)是一种功能,允许 Aeron 从单个 Publication 同时向多个目的地传送数据。Multiple-Destination-Cast是 Aeron 的一项高级功能,本指南将介绍如何开发一个简单示例的基本知识。
一、MDC Publications
注:
MDC Publications 能够在不支持 UDP 组播的环境中提供与 UDP 组播大致相同的行为。请注意,这不是真正的组播—数据是单独发送到每个订阅(subscription)的,但支持流量控制功能。
MDC Publications可以动态或手动模式运行。对于动态 MDC Publications,Subscription 会在运行时动态添加到Publications中。对于手动 MDC Publications,Subscription 必须显式添加到Publications中。
动态 MDC Publications的工作方式与标准 Aeron Publications非常相似,但配置是颠倒的。
Type | Publication | Subscription |
---|---|---|
Standard | channel指向Subscription(Channel points to Subscription) | Channel/port on localhost |
Dynamic Multi-Destination-Cast Publication | Channel/port on localhost | channel指向Subscription(Channel points to Publication) |
Sample Dynamic MDC Publication(示例)
完整的multi-host示例可在 GitHub 上找到。该示例创建了一个具有动态 MDC Publication的单个publisher,以及两个订阅 MDC Publication的客户端。每个进程都位于一个专用的 Docker 容器中。
Media Driver Configuration
Media Driver不需要任何特定配置,但是,如果您要求 Publications 能够在未连接任何 Subscriptions 的情况下发布数据,则可以选择启用 spiesSimulateConnection
。示例代码如下:
final var mediaDriverContext = new MediaDriver.Context()
.spiesSimulateConnection(true)
.errorHandler(this::errorHandler)
.threadingMode(ThreadingMode.SHARED)
.sharedIdleStrategy(new SleepingMillisIdleStrategy())
.dirDeleteOnStart(true);
Publication
MDC 动态Publication使用特定的通道配置,其中至少包括:
aeron:udp?control-mode=dynamic|control=MDC_HOST:MDC_CONTROL_PORT
control-mode=dynamic
告知 Aeron 这是一个Dynamic MDC Publication。上述示例中的 MDC_HOST
必须是运行该Publication的主机(host)。在幕后,Subscriptions会使用控制端口连接到该主机,以构建运行时流程,因此控制端口必须是客户端已知的端口。
示例代码(sample code)构建Publication channel的过程如下:
final var publicationChannel = "aeron:udp?control-mode=dynamic|control=" + host
+ ":" + controlChannelPort;
final var publication = aeron.addExclusivePublication(publicationChannel, 100);
除基本配置外,还可通过通道配置流量控制策略。其中包括基于组限制的流量控制策略,即必须连接最少数量的节点,Publication才会进入连接状态。
Subscription
将MDC Subscription连接到dynamic Publication非常简单—通道配置必须包括 MDC Publication host和远程主机(host)将发布到的本地端点。最小配置如下:
aeron:udp?endpoint=LOCALHOST:0|control=MDC_HOST:MDC_CONTROL_PORT|control-mode=dynamic
与Publication一样,control-mode=dynamic
(动态控制模式)告诉 Aeron 这是一个dynamic MDC connection,endpoint=LOCALHOST:0
指的是 MDC Dynamic Publication将向其发布数据的本地主机上的一个短暂端口,也可以是一个预定义端口。最后,control=MDC_HOST:MDC_CONTROL_PORT
告诉 Aeron 如何连接远程动态 MDC Publication。
示例代码( sample code )构建订阅通道的过程如下:
final mdcSubscription = aeron.addSubscription("aeron:udp?endpoint=" + host
+ ":0|control=" + mdcHost + ":" + mdcControlPort + "|control-mode=dynamic", 100);
该示例运行两个客户端实例,每个实例位于一个专用的 Docker 主机中。
Sample output
以下是通过 docker-compose up
运行的示例输出,经过简单编辑:
mdc-subscriber-2_1 | 16:47:00.945 [main] INFO MultiDestinationSubscriberAgent - launching media driver
mdc-publisher_1 | 16:47:00.946 [main] INFO MultiDestinationPublisherAgent - launching media driver
mdc-subscriber-1_1 | 16:47:01.066 [main] INFO MultiDestinationSubscriberAgent - launching media driver
mdc-subscriber-2_1 | 16:47:01.082 [main] INFO MultiDestinationSubscriberAgent - connecting aeron; media driver directory /dev/shm/aeron-root
mdc-publisher_1 | 16:47:01.083 [main] INFO MultiDestinationPublisherAgent - launching aeron
mdc-subscriber-2_1 | 16:47:01.093 [main] INFO MultiDestinationSubscriberAgent - adding the subscription
mdc-subscriber-2_1 | 16:47:01.093 [main] INFO MultiDestinationSubscriberAgent - detected ip4 address as 10.1.0.3
mdc-publisher_1 | 16:47:01.093 [main] INFO MultiDestinationPublisherAgent - Media Driver directory is /dev/shm/aeron-root
mdc-publisher_1 | 16:47:01.095 [main] INFO MultiDestinationPublisherAgent - detected ip4 address as 10.1.0.2
mdc-publisher_1 | 16:47:01.107 [main] INFO MultiDestinationPublisherAgent - creating publication
mdc-subscriber-2_1 | 16:47:01.128 [mdc-subscriber] INFO MultiDestinationSubscriberAgent - starting
mdc-subscriber-1_1 | 16:47:01.162 [main] INFO MultiDestinationSubscriberAgent - connecting aeron; media driver directory /dev/shm/aeron-root
mdc-publisher_1 | 16:47:01.165 [mdc-publisher] INFO MultiDestinationPublisherAgent - Starting up
mdc-publisher_1 | 16:47:01.166 [mdc-publisher] INFO MultiDestinationPublisherAgent - appended 1
mdc-subscriber-1_1 | 16:47:01.170 [main] INFO MultiDestinationSubscriberAgent - adding the subscription
mdc-subscriber-1_1 | 16:47:01.170 [main] INFO MultiDestinationSubscriberAgent - detected ip4 address as 10.1.0.4
mdc-subscriber-1_1 | 16:47:01.201 [mdc-subscriber] INFO MultiDestinationSubscriberAgent - starting
mdc-publisher_1 | 16:47:03.167 [mdc-publisher] INFO MultiDestinationPublisherAgent - appended 2
mdc-subscriber-2_1 | 16:47:03.170 [mdc-subscriber] INFO MultiDestinationSubscriberFragmentHandler - received 2
mdc-subscriber-1_1 | 16:47:03.171 [mdc-subscriber] INFO MultiDestinationSubscriberFragmentHandler - received 2
mdc-publisher_1 | 16:47:05.167 [mdc-publisher] INFO MultiDestinationPublisherAgent - appended 3
mdc-subscriber-1_1 | 16:47:05.171 [mdc-subscriber] INFO MultiDestinationSubscriberFragmentHandler - received 3
mdc-subscriber-2_1 | 16:47:05.170 [mdc-subscriber] INFO MultiDestinationSubscriberFragmentHandler - received 3
...
注:
示例使用了宽松的
IdleStrategy
配置,这就解释了为什么在append
andreceive
之间会有 3 到 4 毫秒的间隔。
mdc-publisher_1
的日志条目中appended 1
,但两个客户端却没有显示相应的received 1
的日志。这是因为mdc-publisher_1
Media Driver将spiesSimulateConnection
设置为 true,而mdc-subscriber-*
进程尚未连接。它们确实收到了 2。
Flow Control
上面的例子提出了一个问题:如果
mdc-subscriber-1
开始落后于mdc-subscriber-2
,mdc-publisher
应该怎么办?在 Aeron 中可以通过流量控制配置这种行为。可以在Media Driver中将流量控制配置为默认值,然后按通道进行自定义。
Flow Control Types
Type | Description |
---|---|
max | Publication将受到最快订阅(Subscription)的限制。速度慢的消费者可能会丢失数据包。这是 Aeron 的默认设置。(Publication will be limited by the fastest Subscription. Slow consumers may lose data packets. This is the default in Aeron.) |
min | Publication将受到最慢订阅(Subscription)的限制。(Publication will be limited by the slowest Subscription.) |
tagged | Publication将受到组内最慢标记订阅(Subscription)的限制(Publication will be limited by the slowest tagged Subscription within a group) |
如果Publication产生数据的速度超过了流量控制策略规定的水平,Publication就会受到back pressure(背压:实际上就是常规说的堵上游)。
MAX FLOW CONTROL
例如,通过在通道配置中设置 fc=max
来配置最大流量控制:
aeron:udp?control-mode=dynamic|control=MDC_HOST:MDC_CONTROL_PORT|fc=max
或者使用Media Driver Context设置默认值(注意,UDP 组播和多目的地组播(Multi-Destination-Cast)都使用 multicastFlowControlSupplier
):
final var mediaDriverContext = new MediaDriver.Context()
...
.multicastFlowControlSupplier(new MaxMulticastFlowControlSupplier())
...
MIN FLOW CONTROL
例如,通过在通道配置中设置 fc=min
来配置最小流量控制:
aeron:udp?control-mode=dynamic|control=MDC_HOST:MDC_CONTROL_PORT|fc=min
可设置的其他选项包括组大小。下面的示例用 g:/5 设置了 5 个组。组大小控制着Publication的连接状态—例如,如果组大小为 5,则只有当 5 个Subscriptions连接时,Publication才会被视为已连接。这样,系统就可以在至少有 5 个已连接Subscriptions的情况下运行,其中最慢的Subscriptions将为所有已连接Subscriptions设定速度。
aeron:udp?control-mode=dynamic|control=MDC_HOST:MDC_CONTROL_PORT|fc=min,g:/5
这也可以在Media Driver Context中进行默认设置(此处将组大小设置为 5):
final var mediaDriverContext = new MediaDriver.Context()
...
.multicastFlowControlSupplier(new MinMulticastFlowControlSupplier())
.flowControlGroupMinSize(5)
...
TAGGED FLOW CONTROL
有时,您需要在Multi-Destination-Cast中进行更精细的控制,例如,您可能有一组用户不应该丢失数据包,但您也可能连接了不受数据丢失影响的其他用户,您不希望这些接受数据丢失的用户用最小流量(min
)控制策略拖住所有Subscriptions用户。标记流量控制策略可以实现这一点。
以下配置将 Publication 信道的流量控制设置为标记(tagged
),组设置为 101
。
aeron:udp?control-mode=dynamic|control=MDC_HOST:MDC_CONTROL_PORT|fc=tagged,g:101
要让Subscription加入带有 101
标签的流量控制(从而受到流量控制,就像最小策略一样),需要对 gtag
进行如下设置:
aeron:udp?endpoint=LOCALHOST:0|control=MDC_HOST:MDC_CONTROL_PORT|control-mode=dynamic|gtag=101
如果Subscription需要加入同一个 MDC Publication,但不担心数据丢失(即不受流量控制),则可以删除 gtag
:
aeron:udp?endpoint=LOCALHOST:0|control=MDC_HOST:MDC_CONTROL_PORT|control-mode=dynamic
以下是设置Media Driver默认值的等效方法:
final var mediaDriverContext = new MediaDriver.Context()
...
.multicastFlowControlSupplier(new TaggedMulticastFlowControlSupplier())
.flowControlGroupTag(101)
...
与最小(min
)流量控制策略一样,标记(tagged
)流量控制也可设置最小分组规模。在本例中,标签设置为 101
,组大小设置为 5:
aeron:udp?control-mode=dynamic|control=MDC_HOST:MDC_CONTROL_PORT|fc=tagged,g:101/5
See Also
- Multiple Destinations in the Aeron Wiki
- Flow and Congestion Control in the Aeron Wiki
- Flow Control in Aeron by Michael Barker