返回介绍

7.3 有关消息投递的一些说明

发布于 2024-08-21 22:20:21 字数 1874 浏览 0 评论 0 收藏 0

整个Akka应用是由消息驱动的。消息是除了Actor之外最重要的核心组件。作为在并发程序中的核心组件,在Actor之间传递的消息应该满足不可变性,也就是不变模式。因为可变的消息无法高效的在并发环境中使用。理论上Akka中的消息可以使用任何对象实例,但实际使用中,强烈推荐使用不可变的对象。一个典型的不可变对象的实现如下:

01 public final class ImmutableMessage {
02   private final int sequenceNumber;
03
04   private final List<String> values;
05
06   public ImmutableMessage(int sequenceNumber, List<String> values) {
07     this.sequenceNumber = sequenceNumber;
08     this.values = Collections.unmodifiableList(new ArrayList<String>(values));
09   }
10
11   public int getSequenceNumber() {
12     return sequenceNumber;
13   }
14
15   public List<String> getValues() {
16     return values;
17   }
18 }

上述代码实现了一个不可变的消息。注意代码中对final的使用,它申明了当前消息中的几个字段都是常量,在消息构造完成后,就不能再发生改变了。更加需要注意的是,对于values字段,final关键字只能保证values引用的不可变性,并无法保证values对象的不可变性。为了实现彻底的不可变性,代码第8行构造了一个不可变的List对象。

对于消息投递,大家可能还有另外一个疑问,那就是消息投递究竟是以何种策略进行的呢?也就是发出去的消息一定会被对方接收到吗?如果接收不到会重发吗?有没有可能重复接收消息呢?

实际上,对于消息投递,我们可以有3种不同的策略:

第1种,称为至多一次投递。在这种策略中,每一条消息最多会被投递一次。在这种情况下,可能偶尔会出现消息投递失败,而导致消息丢失。

第2种称为至少一次投递。在这种策略中,每一条消息至少会被投递一次,直到成功为止。因此在一些偶然的场合,接受者可能会收到重复的消息,但不会发生消息丢失。

第3种称为精确的消息投递。也就是所有的消息保证被精确地投递并成功接收一次,既不会有丢失,也不会有重复接收。

很明显,第1种策略是最高性能,最低成本的。因为系统只要负责把消息送出去就可以了,不需要关注是否成功。第2种策略则需要保存消息投递的状态并不断充实。而第3种策略则是成本最高且最不容易实现的。

那我们是否真的需要保证消息投递的可靠性呢?

答案是否定的。实际上,我们没有必要在Akka层保证消息的可靠性。这样做,成本太高了,也是没有必要的。消息的可靠性更应该在应用的业务层去维护,因为也许在有些时候,丢失一些消息完全是符合应用要求的。因此,在使用Akka时,需要在业务层对此进行保证。

此外,对于消息投递Akka可以在一定程度上保证顺序性。比如,Actor A1向A2顺序发送了M1、M2和M3三条消息。Actor A3向A2顺序发送了M4、M5和M6三条消息。那么系统可以保证:

(1)如果M1没有丢失,那它一定先于M2和M3被A2收到。

(2)如果M2没有丢失,那它一定先于M3被A2收到。

(3)如果M4没有丢失,那它一定先于M5和M6被A2收到。

(4)如果M5没有丢失,那它一定先于M6被A2收到。

(5)对A2来说,来自A1和A3的消息可能交织在一起,没有顺序保证。

在这里,值得注意的一点是,这种消息投递规则不具备可传递性,比如:

Actor A向C发送了M1,接着,Actor A向B发送了M2,B将M2转发给Actor C。那么在这种情况下,C收到M1和M2的先后顺序是没有保证的。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文