关于在分布式环境中RVN和使用场景的介绍2

简介

在《关于在分布式环境中RVN和使用场景的介绍1》中我们介绍了RVN的基本概念和基本使用的场景以及目标。在本文中,我们将介绍使用RVN来解决其它的一些有关问题。

问题

假设我们有如下的一个使用场景:

关于在分布式环境中RVN和使用场景的介绍2_第1张图片

一个ECS service从一个message queue里读取并处理数据。该数据是包含RVN的并且有不同primary key的。我们要求在处理相同primary key的数据时要同步处理,也就是说我们要保证在同一时间对于拥有相同primary key的数据只能处理一条,而不能同时处理。这个要求对于很多实际用例都是合理的,因为相同primary key的数据本质上是相互关联的,如果并行处理会带来处理结果的不准确的问题。但是,这个要求同时也意味着拥有相同primary key的数据是被串行处理的。那么如果有非常多的数据拥有相同的primary key,我们就会遇到性能瓶颈。这种情况下,数据只能串行处理,即便我们scale up再多的资源也无法解决该问题。这种情况在下图中被描述:

关于在分布式环境中RVN和使用场景的介绍2_第2张图片

在这里我们看到KEY 1的消息最多,而且KEY 1的消息都要串行处理,所以KEY 1的消息频率是整个系统的性能瓶颈。而KEY 2和KEY 3的消息较少,但是即便有ECS task处理完了KEY 2和KEY 3的消息还是无法令KEY 1的消息处理的更快。

解决方式讨论

在这里我们考虑到RVN的消息处理应该是满足幂等的,同时还应该可以正确的处理消息乱序,丢失,和重复等情况,我们可以想办法减少对于消息的处理。具体来说,我们可以对同一个primary key的消息处理频率设置一个阈值(threshold),在处理频率快于该阈值时我们暂时放弃对该消息的处理,而是等待一定时间后再次尝试处理该消息。此时我们需要记录下我们已经处理过的最新的RVN。当一个消息被receive后,我们要比较该消息的RVN是否比已经处理过的RVN更旧。如果更旧,我们就可以直接丢掉该消息,否则,依照处理的频率决定是否要处理该消息。依照这种方法,会有大量的消息因为变得陈旧而无需处理,所以它可以解决我们这里所遇到的问题。比如,在我们上面的例子中,我们假设KEY 1的消息2和消息3因为处理频率的要求被延迟到消息5之后处理,我们就会发现消息2和消息3因为此时已经陈旧所以可以直接丢弃。

对于AWS的SQS来说,这种机制很容易实现。SQS拥有visibility timeout的feature,也就是在一个消息是receive后,该消息将在一定的时间内不可见。假如该消息没有被删除,在一定时间之后,在消息又可以被receive。所以,我们处理的流程图应该如下所示:

关于在分布式环境中RVN和使用场景的介绍2_第3张图片

该流程图简单描述如下:

  1. 从message queue里receive消息;
  2. 比较消息的RVN和保存的最新RVN确认该消息是否已经stale。如果已经stale,我们就可以直接将该消息从message queue里删除,然后结束消息处理;如果没有,到step 3;
  3. 查看该primary key的上一次处理时间,确认该primary key是否处理的过快。如果是,则直接结束本次消息处理,等待该消息再次变成visible。如果不是,则到step 4;
  4. 保存最新处理的RVN和处理时间;
  5. 处理该消息;
  6. 处理完成后,从message queue里删除该消息,然后结束本次消息处理。

补充和下一步

这种处理机制还可以被用到其它用途,比如对处理频率的控制。假如我们的service在向外发送notification,但是我们不希望同一个primary key的notification发送的过快,那么我们可以考虑使用上面的机制来控制同一primary key的消息的处理频率。

但是如果我们审视上面的流程图,我们会发现缺少一些东西。假如我们几乎同时收到了同一个primary key的多个消息,那就会有多个该流程同时进行。显然我们需要一些同步机制,否则该流程的结果就可能不正确。比如,我们刚刚检查完自己的RVN是最新的,但是在保存RVN和处理该消息之前,另一个更新的RVN刚刚被处理完。此时我们如果继续保存该消息的RVN和处理该消息,我们就会用旧的数据和处理结果覆盖掉新的数据和处理结果。我们会在后面的文章中讨论一下其中的同步机制和技巧。

你可能感兴趣的:(AWS,分布式系统设计,云计算,分布式,云计算,aws,系统架构)