大规模数据处理实战
蔡元楠
硅谷资深工程师
41608 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 46 讲
大规模数据处理实战
15
15
1.0x
00:00/00:00
登录|注册

08 | 发布/订阅模式:流处理架构中的瑞士军刀

Log offset机制
Topic
Consumer
Producer
Apache Kafka
AWS的Amazon Simple Notification Service(SNS)
Google的Cloud Pub/Sub平台
发送方无需接收方实时响应
系统的发送方需要向大量的接收方广播消息
不能保证数据一定送达订阅者
简洁的系统组件间通信
高伸缩性
松耦合
发布者和订阅者解耦
发布者异步发送消息给不同组件
消息发送方发送消息至队列,接收方确认后删除
持久化缓冲作用
可以是任意格式的
分布式架构中的组件沟通
Apache Kafka
适用平台
适用场景
缺点
优点
发布/订阅模式
消息队列
消息
发布/订阅模式

该思维导图由 AI 生成,仅供参考

你好,我是蔡元楠。
今天我想要与你分享的是在处理大规模数据中十分流行的一种设计模式:发布 / 订阅模式(Publish/Subscribe Pattern),有些地方也称它为 Pub/Sub。
在了解发布 / 订阅模式之前,我想先简单介绍几个基础概念——消息(Message)和消息队列(Message Queue)。

消息

消息是什么呢?
在分布式架构里,架构中的各个组件(Component)需要相互联系沟通。组件可以是后台的数据库,可以是前端的浏览器,也可以是公司内部不同的服务终端(Service Endpoint)。
而各个组件间就是依靠通过发送消息互相通讯的。如下图所示。
消息可以是任意格式的。例如,我们可以利用 JSON 格式来传输一个消息,也能利用 XML 格式来传输一个消息,甚至可以使用一种自己定义的格式。

消息队列

知道了消息的含义后,你知道消息队列有什么作用吗?
消息队列在发布 / 订阅模式中起的是一个持久化缓冲(Durable Buffer)的作用。
消息的发送方可以发送任意消息至这个消息队列中,消息队列在接收到消息之后会将消息保存好,直到消息的接收方确认已经从这个队列拿到了这个消息,才会将这条消息从消息队列中删除。
有的消息系统平台如 Apache Kafka,它能够让用户自己定义消息队列对消息的保留时间,我将会在介绍 Apache Kafka 的时候讲到。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

发布/订阅模式:大规模数据处理的瑞士军刀 发布/订阅模式是流处理架构中的得力工具,通过消息队列实现消息的异步发送和接收,实现了发布者和订阅者的松耦合。这种设计模式在处理大规模数据时十分流行。通过发布/订阅模式,消息的发送方可以将消息异步地发送给系统中不同的组件,而无需知道接收方是谁。这种模式的优点包括松耦合、高伸缩性和简洁的系统组件间通信,适用于需要向大量接收方广播消息、与多个独立开发的组件或服务进行通信、不需要实时响应和支持最终一致性模型的场景。知名的云平台和开源平台如Google的Cloud Pub/Sub、AWS的Amazon SNS和Apache Kafka都广泛使用了发布/订阅模式。对于处理数据时需要满足上述场景的读者来说,了解和应用发布/订阅模式将会是一种技术上的得益。 总结:发布/订阅模式是流处理架构中的得力工具,通过消息队列实现消息的异步发送和接收,实现了发布者和订阅者的松耦合。这种模式的优点包括松耦合、高伸缩性和简洁的系统组件间通信,适用于需要向大量接收方广播消息、与多个独立开发的组件或服务进行通信、不需要实时响应和支持最终一致性模型的场景。知名的云平台和开源平台如Google的Cloud Pub/Sub、AWS的Amazon SNS和Apache Kafka都广泛使用了发布/订阅模式。对于处理数据时需要满足上述场景的读者来说,了解和应用发布/订阅模式将会是一种技术上的得益。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《大规模数据处理实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(49)

  • 最新
  • 精选
  • 挖矿的小戈
    盆友圈适合使用pub/sub模式 原因1:消息发送方需要向多个接收方(n个可以看自己盆友圈的好友)广播消息 原因2:多消费者组(微信朋友圈数据应该不仅仅只是用于社交,可能还有其他作用吧,所以可能会有多个模块需要用到这份数据) 原因3:发送方发送消息之后是不需要接收方立即进行响应的(异步),所以用消息队列可以有效起到解耦的作用 原因4:微信朋友圈对于数据而言,满足最终一致性的

    作者回复: 谢谢你的答案,观点基本我都是赞同的!

    2019-05-03
    4
    33
  • paradox
    1. 微博粉丝订阅机制 由于存在流量明星,针对不同情况的用户,系统可以区别对待,在线用户采用“推”模式,尽量及时更新订阅者的timeline;不在线的用户采用“拉”模式,在该用户上线后更新timeline。 2. 微信朋友圈机制 由于不太可能存在微博这种超级发布者,因此可仅采用“推”模式。 3. 两款产品的共同点 a) 发布者必须实时同步处理,因为发布成功后需要直接看到自己生产的消息。 b) 订阅者可以异步处理,只要保证系统满足最终一致性即可。

    作者回复: 谢谢你的留言!总结得很到位啊!

    2019-05-05
    2
    22
  • NEVER SETTLE
    老师,当今有许多很好的开源MQ,响Kafka,RabbitMQ等等,但是在看许多技术分享大会,为什么许多公司还会自己开发MQ呢?

    作者回复: 谢谢你的留言提问!个人觉得即便公司会开发自己的MQ,很多都是建立在这些开源项目之上的。一方面可能因为开源项目的一些属性并不能满足到自身的应用场景,所以加以改进。另一方面如果是大厂的话,可以打造出自己的一套生态圈,开发接口更加适合内部使用。

    2019-05-03
    17
  • LJK
    老师好,有一点模糊的地方,请问观察者模式和发布/订阅模式的区别从消息的传递上来看就是是否通过消息队列传递数据么?另外消息队列是对接收者push消息还是接收者主动从消息队列中pull消息出来呢?谢谢老师

    作者回复: 你好呀,感谢你的提问! 其实在观察者模式下,你也可以通过消息队列去传递消息。但是更本质的区别是在观察者模式下,观察者必须知道被监听者的存在。就像例子所示,观察者必须调用被监听者的接口。而发布/订阅模式下,两者是解耦的,互相都不用知道对方的存在。 消息队列中既可以使用push模式也可以使用pull模式,关键在于应用场景的考虑。例如如果消息跟新发布频繁,而下游的接收者能够处理的qps不高,那可能会更加倾向于采取pull模式。

    2019-05-03
    2
    13
  • Chn.K
    log offset类似tcp的滑动窗口机制,有个问题:如例子讲的10003,在第一次由于某种原因未被消费者消费,生产者又发了一次10003,然后第一次发送的10003又到了消费者,那么10003会被消费者消费两次,这种情况kafka会有什么处理机制吗?

    作者回复: 谢谢你的留言提问!一般来说,这种发送机制叫做at least once delivery,这种情况需要消费者自身具备Idempotency,也就是幂等性。消费者需要自己知道哪些消息是duplicate的,从而知道怎么处理这些重复消息。

    2019-05-06
    2
    12
  • J Zhang
    感觉没啥内容啊

    作者回复: 哈哈哈,感觉你的基本功很扎实啊,那这一讲你可以当作是复习章节,当然也可以留言和我讨论更高级的内容。我的专栏也希望能对初学者友好一点,对于初学者来说,这一讲是全新的内容呢。

    2019-05-05
    12
  • cl
    如果接收方读取数据之后回应消息队列它接收的 Log offset 是 10000、10001 和 10003,那么消息队列就会认为接收方最多只接收了消息 10000 和 10001,剩下的消息 10002、10003 和 10004 则会继续发送给接收方,直到接收方回应接收了消息 10002、10003 和 10004。 第一句接收的log offset有10003吗?

    作者回复: 谢谢你的提问!如果我没理解错你的问题的话,你是想问接收方是否回复了10000、10001和10003这三个Log offset对吧?是的,接收的log offset有10003。因为消息队列需要接收到连续的log offset才会判定接收方接收到消息,这里因为log offset从10002断开了,所以消息队列会认为接收方从10002开始往后的消息都没有接收到。

    2019-05-09
    2
    11
  • 老师好,对于消息队列中的消息存储有一个问题。在一个发布订阅模式下的消息队列中消息会被保存多久呢?具体情景是如果有五个接收方订阅了一个队列的消息,其中四个成功接收了,第五个总也无法接收,这条消息会一直保存在队列中,并且不断尝试发给第五个订阅者吗?还是会设置最多重复次数?另一个情景,在发布者发送消息至队列后,新增加了一个订阅者,这时新的订阅者可以收到队列里已放入的消息吗?谢谢。

    作者回复: 涵你好,谢谢你的留言与提问! 第一个问题,一般不同的系统有不同的机制去确定消息队列中消息会被保存多久。像Apache Kafka中可以通过设定Retention Period来确定消息被保存多久,甚至可以设置Retention Period为Forever来永久保存。 第二个问题,只要没有超过保留期,消息会一直保存在队列并且一直尝试发送给第五个订阅者。当然订阅者也可以自己设定retry times,如果第五个订阅者告诉消息队列只需要重试一次,那这条消息就不会再发送给第五个订阅者了。如果你要保证操作一定成功,就要考虑用RPC来调用了。 第三个问题还是要看系统设计了,设计上收到与不收到都可以做到,像Apache Kafka可以通过重设Log Offset的位置去实现新的订阅者收取队列里面旧的消息。如果你使用开源项目的话,文档里应该会有说明的。

    2019-05-04
    6
  • 每天晒白牙
    微信朋友圈适合用消息发布-订阅模式 1.系统的发送方需要向大量的接收方广播消息。一个人打朋友圈,需要向有好友关系的多方发消息 2.朋友圈的数据会被多个独立的业务方使用,比如做数据分析用于投放朋友圈广告,进行用户行为分析,构建用户画像 3.系统的发送方在向接收方发送消息之后无需接收方进行实时响应。因为朋友圈这种业务应该使用pull模式,当A发朋友圈时,A的好友B C D,只有当B C D进行刷新朋友圈时,会去pull数据 4.朋友圈对数据一致性只会要求最终一致性 所以朋友圈很适合消息发布-订阅模式

    作者回复: 谢谢你的答案!分析得很详细,基本上我都是赞同的!

    2019-05-03
    5
  • purh
    谢谢老师的答复,我的问题没表述完整,kafka后面接关系数据库可以重做这些日志以落地数据,并进一步用sql处理数据,但是如果Kafka后面接流处理引擎比如Flink等,Kafka里面存的redo日志,传给流引擎,在流引擎里面如何处理这些日志?比如分别针对一个表执行了insert update delete,流引擎会去重做类似关系数据库对这些DML日志的操作,再基于结果数据做分析么,还是直接操作这些增量日志。 我没有流计算的实战经验,问题可能比较菜,请老师见谅。

    作者回复: 谢谢你的提问! 我的理解是两者都会有。作为底层实现的话,流处理的数据是无限的,流引擎也不可能无止境地等待数据到来,所以一般处理这种无限流数据的话都需要定义window和trigger。所谓window就是你希望处理数据的时间窗口多大,trigger定义了什么时候你想处理时间窗口内的数据。就如你所举的例子,如果Kafka后面接的是Flink的话,Flink会将这些数据抽象成DataStream,一个时间窗口内的数据你可以把它看作就是传统数据库中已有的数据,可以做类似关系数据库的操作。Flink会监听Kafka新传来的数据,等到下一个trigger开始了,Flink又会像之前一样计算这些新传来的在一定时间窗口内的数据。 希望这能帮助你理解到你所问的问题。

    2019-05-07
    4
收起评论
显示
设置
留言
49
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部