在业务中使用Pub/Sub消息模型的困难之处
首先/起初
这是未来Advent Calendar 2019的第4天,但我迟到了,现在写到了第5天。
在这篇文章中,我总结了在尝试将Pub/Sub应用于业务时的困难之处,并简要记述了所经历的一些挣扎。
我有机会考虑如何使用Go创建能从mosquitto或kafka等Pub/Sub代理进行发布或订阅的应用程序,并以何种方式在业务中使用。
发布/订阅消息模型是什么?
这是一个由以下三个要素构成的模型。
-
- メッセージを仲介するBroker
-
- メッセージをためている部分
-
- Topicという論理的なチャンネルにメッセージを紐付けて管理する
-
- メッセージを発信するPublisher
-
- Topicを指定してメッセージをBrokerに投げる
-
- メッセージを受信する(取りに行く)Subscriber
- Topicを指定して(指定しないで取れるBrokerもある)メッセージを取りに行く
发布/订阅消息模型的好处.
一般的的Pub/Sub消息模型有以下两个优点:
疎結合
プロトコルとTopicのみ知っていればPublisherとSubscriberは相互に知らなくてもやりとりが可能である
スケールがしやすい
PublisherとSubscriberはそれぞれ別々に動的にスケール可能である
Brokerの仕様次第ではあるが、1つのTopicを複数のパーティションに分けることによって並列にメッセージを処理できる
发布/订阅消息模型的复杂性
- 順序制御が難しい
为了提高性能,可能会将Topic的分区进行分割,但这样很容易打乱顺序。
在业务使用中,经常需要控制顺序,这种情况下可以考虑使用先进先出的队列服务。
- スケールが可能であるとはいえスケール可能な設計が難しい
出版者和订阅者都可以动态增加,但在业务中更常与其他系统和服务进行协作,实际上扩展性的利用程度取决于设计,而该设计非常困难。
- PubとSubの間はPubからSubへの経路しかないため、リトライなどがしにくい
没有通知Publisher方的功能,即使Subscriber方出现错误,因此只能进行单向通信。
- 多くのPub/SubデフォルトのQos1だと重複してデータがBrokerに入る可能性がある
需要在订阅者端实现允许重复的功能。
可以很容易地在業務中採用Pub/Sub消息模型的情況
虽然被问及是否可以进行商业使用,但实际上,只要能克服上述困难,就可以考虑使用。
-
- 順序制御がいらないケース
-
- 直前の状態に左右されない、例えば通知システムであれば利用は可能であると思われます。
-
- 0,1の状態を繰り返し直前の状態に左右されるようなシステムでは利用は難しいですが、例えばメールのPUSH通知など一つ一つのメッセージが独立して意味があるケースでは利用可能です。
-
- メッセージの流量が多くないケース
-
- ピークがあるようなシステムだと難しいです。
- ただ流量が少なくパーティションが1でも処理できるようなケースであれば順序が乱れることも少なく、安定して運用することは可能ではないかと考えられます。
从外部支持发布/订阅消息模型
- Publisherの前で順番をメッセージに振り、Subscriberで受け取ったメッセージを順序通り次処理に投げれるようにになるまで滞留させる
如果在Sub侧的系统上进行延迟处理,我认为可以按顺序进行并将其投递给下一个步骤(虽然我没有尝试过)。但是,由于Qos0可能会无限等待,所以取决于使用的Broker的协议和配置,可能会有陷阱。
- Subscriber側で流量を制限する
订阅方处理完毕之前,将阻塞接收下一条消息。但需要注意的是,如果发布的消息始终多于订阅的消息,那么发布方会持续不断地发布,导致订阅方处理时间逐渐延长。
- Publisherの前にAPIサーバを構える
考虑到安全性和验证的情况下,由于Broker无法对每个用户的权限进行控制,且它可能允许接受任何类型的消息,所以在与外部系统进行协作时,考虑建立API服务器也是一种选择。
- Subscriber側で重複許容処理をいれる
如果原本处理可以重复没有问题的话那就好,但如果不允许重复的情况下,希望在发布端添加一个机制,使订阅端可以排除相同的id。
在实际情况下遇到了哪些困扰的地方?
在创建一个像工厂物联网一样能够通知设备故障的系统时,我在加入项目之前,工厂方面决定在工厂进行发布,服务器进行订阅的方向。
我负责服务器端的开发。作为功能,它很简单,就是在设备在正常和异常之间发生变化时进行通知。
然后,在这里我遇到了一个无休止地在正常和异常之间循环的测试程序的困境。
在服务器上收到的消息(假设为):正常-> 异常-> 正常-> 异常-> 正常-> 异常-> 正常-> 异常-> 正常
没有通知→通知→通知→通知→通知→通知→通知→通知→通知
在服务器收到的消息(实际)
正常→异常→正常→异常→正常→正常→异常→异常→正常
无出现通知→出现通知→出现通知→出现通知→出现通知→无出现通知→出现通知→无出现通知→出现通知
顺便一提,实际上只有预计数量的大约70%的通知被发送出去了。
不过,一旦调低tps,通知次数就会与预期的一致,
这表明在负荷较高时,分区可能会被堵塞,这是一个重要的因素。
尽管在这种情况下,没有问题,因为问题在实际预计的理论值上得到了解决,
但如果负荷很大,那可能会变得困难。
总结
在使用Pub/Sub消息模型时,由于其松散耦合的特性无疑非常有吸引力,所以找到合适的应用情境并加以利用是很有用的。然而,我觉得如果只是跟风而无理由地使用的话,或许对个人来说还可以作为业余爱好,但如果在业务中使用,则需要进行仔细的设计。
余談一下,我的一位在另一家公司工作的朋友甚至不太喜欢使用队列,他害怕尽量不使用同步处理。
实际上,如果我不需要考虑松耦合,我也经常会避免使用发布/订阅,并且陷入了不想使用它的困境。
因为顺序混乱会打乱宇宙的规律…