同步Alice和Bob之间的对话中的当前消息ID

时间:2015-06-17 11:47:07

标签: network-programming communication network-protocols

我面对这种情况:

Diagram

主机 A B 正在通过代理在对话中交换消息。

当主持人 B 收到消息时,会向主持人 A 发送一个递送令牌,以便向用户显示 B 已收到他的消息。 反过来也可能发生这种情况。

在任何时候 A B 可能处于离线状态,经纪人会保留这些消息,直到他们上线然后发送消息。

每个主机都存储它自己,另一个主机将数据存储在数据库表中:

ID | From | To | Msg | Type | Uid 

我认为使用天真表主键id识别消息是一个不好的选择(因为它依赖于插入顺序)所以我定义了一个自定义唯一id字段(uid)。

我的问题是:

如何确保主机A和B之间的当前消息ID 保持同步,以便只有一条消息具有该ID?这样我就可以使用传递令牌ID来识别收到的消息,如果我有多条消息具有相同的Id,则无法实现。

如果我每次发送/接收消息时都天真地增加它,那么看起来没问题:

Host A sends message with ID 1 and increases it's current ID to 2
Host B receives a message and increases it's current ID to 2
Host B sends message with ID 2 and increases it's current ID to 3
Host A receives message and increases it's current ID to 3
...

但它很容易破裂:

Host A sends message with ID 1 and increases it's current ID to 2
Host B sends a message (before receiving the previous one) with ID 1
clash.. two messages with ID 1 received by both hosts

我想过每次都会生成一个大的UUID(碰撞的可能性极低),但它会带来很大的开销,因为每条消息都需要携带和存储一个。

不幸的是,关于经纪人的任何解决方案都不可行,因为我无法触及经纪人的代码。

1 个答案:

答案 0 :(得分:1)

这是分布式系统的典型问题(课堂练习?)。我想您正在尝试保留相同的ID,以确定Alice和Bob之间交换的所有消息之间的绝对顺序。如果不是这种情况,john1020评论中提供的解决方案应该足够了。其他可能性是将ID存储在A和B都可以访问的一个节点中,并且分布式锁机制同步​​访问。这样,即使面对碰撞,您也始终定义订单。但这并非总是可行,有时效率也不高。

不幸的是,没有办法保持绝对顺序(除了具有分布式锁的唯一计数器)。如果您有一个可由A和B修改的ID,则会出现最终一致性和冲突风险的问题。碰撞基本上就是您描述的问题。

现在,想象Bob和Alice同时发送一条消息,两者都将ID设置为2.您将存储消息的顺序是什么?实际上并不重要,这就像两个人同时在电话里讲话的情况一样。发生了碰撞。

然而,有趣的是识别实际上具有序列或因果关系的消息:因此您可以在消息之间保持由其他消息引起的消息:Bob邀请Alice跳舞而Alice说是,两条消息订单。

为了保持这样的顺序,您可以应用一些技术,如矢量时钟(基于Leslie Lamport&#s;时间戳矢量算法):https://en.wikipedia.org/wiki/Vector_clock。您还可以阅读有关AWS' DynamoDB:http://the-paper-trail.org/blog/consistency-and-availability-in-amazons-dynamo/

此外,您可以使用Cassandra用于分布式计数器的相同机制。这是一个很好的描述:http://www.datastax.com/wp-content/uploads/2011/07/cassandra_sf_counters.pdf