本文来源于公众号:胖滚猪学编程。转载请注明出处!
一个风度翩翩,穿着格子衬衣的中年男子,拿着一个满是划痕的mac向她走来,看着铮亮的头,胖滚猪心想,这肯定是顶级架构师吧!完了
结果面试官第一个问题,就让胖滚猪内心暗喜
面试官:消息队列这东西,你还熟悉吧?消息队列在企业中的应用场景有哪些?
(这么基础的问题,手到擒来好吗?原来阿里不过如此。)
胖滚猪:嗯嗯,还挺熟悉的,可以用于流量削峰、应用解耦、异步处理。
面试官:就这三种吗?能不能再多说几个应用。起码八种吧。
(胖滚猪火冒三丈,尼玛八种哪来的?玩我呢?但是出于礼貌,还是毕恭毕敬的回答面试官)
胖滚猪:额。。有这么多吗?不好意思,一时之间想不起来了呢。
面试官:哎。。大家都知道的我们不屑,就想听听不一样的。回家去吧
胖滚猪内心挫败,平时五毛钱都舍不得花的抠猪,豪掷100大洋打了飞车来到导师胖滚熊家里求助。
胖滚熊:我先给你归纳了消息队列八种场景,如图所示,接下来我们再仔细说说每种场景的应用方案。
首先还是要介绍一下流量削峰、应用解耦、异步处理的具体应用,虽然网上文章到处都有,不过毕竟它们是老大,老大不出场小二也不敢乱动。如果你很熟悉了,可以直接跳过!
应用解耦:
某电商系统架构如图,用户下单之后首先进入订单系统,之后订单系统又将订单信息发送给物流系统和短信系统:
码农胖滚猪很快就写完了相关代码:
OrderInfo orderInfo = new OrderInfo();
//省略组装订单信息
sendToMessage(orderInfo);//发送给短信系统
sendToLogistics(orderInfo);//发送给物流系统
一切就这么平安无事过了大半月,领导又要搞啥实时大屏,实时展示当天订单量,于是订单系统又要将订单信息发送给实时大屏系统
也没关系,码农胖滚猪又改了订单系统的代码,重新上线:
OrderInfo orderInfo = new OrderInfo();
//省略组装订单信息
sendToMessage(orderInfo);//发送给短信系统
sendToLogistics(orderInfo);//发送给物流系统
sendToRealTimeSys();//发送给实时分析系统
随着公司业务的壮大,订单信息又要发送给监控系统、数据挖掘系统。。。这会胖滚猪不淡定了“到底何时是个头呀!”
不仅如此,一旦下游某个系统异常,直接导致订单系统也异常了,时常收到顾客的投诉 “你们这电商系统!不用了!”
嗨,胖滚猪,早知如此何必当初呢?在1.0版本你就不应该让系统之间相耦合呀!如图:
订单系统只管将订单信息发到消息队列中,其他系统都从消息队列中拿数据。这样一来:
1、订单系统再也不用关心谁要用了,即使增加、减少下游系统或是下游系统需求如何变化,订单服务都无需做任何更改,实现了订单服务与下游服务的解耦!可以一个人自由飞翔了~
2、其他系统即便挂了或者请求超时,都跟订单系统无关,只跟消息队列有关。
哇,这样真是太爽了!和花钱一样爽!
异步处理
最近胖滚猪负责的用户系统一直被投诉,原因是太慢了!点击确认注册之后要1s才返回结果。你看看人家阿里的系统,点击注册10ms就可以返回结果了!
可是胖滚猪表示很无能为力,注册之后要写数据库、要发短信、还要发邮件,你让我怎么快呢?阿里的机器比我们好,才比我们快的!
嗨,胖滚猪,你可别把锅甩给机器啊,明明是你自己的设计缺陷呐,看我给你改改:
这样是不是觉得清爽了很多呢??
注册是主要的业务,而发短信和邮件通知用户已经注册成功是非主要的业务,甚至无关紧要,何必让无关的东西影响主要的东西呢?
假设三个业务节点每个使用100ms,不考虑网络等其他开销,则串行方式的时间是300ms,并行的时间可能是150ms。
透心凉心飞扬,这回省了不少时间,可以用来撩妹了。
流量削峰
胖滚猪在公司平安无事的呆了大半年,睡觉从没被电话骚扰,直到2020.5.20这天,xx明星po出结婚照,瞬间几千万的流量,撑爆了微博,而明星同款520T恤的热卖,也瞬间压垮了胖滚猪的电商系统。
胖滚猪好吃好喝大半年,没想到好日子还是终结了,半夜爬起来处理服务器故障,第二天无精打采的,太难受了。。
嗨,胖滚猪,早知如此,当初就应该考虑仔细呀!一个电商系统,秒杀场景是迟早会出现的!
上下游对于事情的处理能力是不同的。比如,Web前端每秒承受上千万的请求,并不是什么神奇的事情。但数据库的处理能力却十分有限,即使使用SSD加分库分表,单机的处理能力仍然在万级。由于成本的考虑,我们不能奢求数据库的机器数量追上前端。所以,利用中间系统转储两个系统的通信内容,并在下游系统有能力处理这些消息的时候,再处理这些消息,是一套相对较通用的方式。
我们需要设计一套足够健壮的架构来将后端的服务保护起来。设计思路是,使用消息队列隔离网关和后端服务,以达到流量控制和保护后端服务的目的。
我再给你画张图吧:
这样一来,用户的请求,服务器接收后,首先写入消息队列。假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面。而业务系统根据消息队列中的请求信息,再做后续处理。
这种设计的优点是:能根据下游的处理能力自动调节流量,达到“削峰填谷”的作用
任务依赖
胖滚猪的公司有了高大上的数据中台,其中一个子系统叫做数据同步,只需要在前端页面勾选表,就可以自助化完成mysql到hive的同步。
但其中有个节点是工单审核。在同步系统中发起表同步申请,首先会调用工单系统,领导层在工单系统审核成功后,同步系统才可以完成接下来的同步任务。最开始,胖滚猪是这么设计的:
同步系统启了一个定时任务,每五分钟去查一下工单系统的接口,拿到审核结果。这种做法完全可行。
可是业务人员小甲不干了,小甲是个急性子,他觉得太慢了!提个需求:必须要准实时!即领导审核成功后你要马上给我同步!
这时候,胖滚猪又想到了消息队列,灵机一动,有了2.0优化版本:
这下,小甲这种急性子也不用不耐烦了,只要领导一批准,马上同步系统就会开始工作!
广播
胖滚猪加入产品中心的第一天,就给了它一个任务:产品中心需要频繁发布产品变更,而关心产品的系统多达10来个。每次变更,都要联调一次新接口,实在是太!麻!烦!了!
胖滚猪分析了一下,这就好像你妈喊你吃饭、还要喊你爸吃饭、喊你爷吃饭,她需要单独给你们每个人发微信通知,有点麻烦。可是如果她直接在家族群@你们,就把消息广播给大家了!
同理,产品系统相当于也要实现一个广播的功能,产品变动之后需要广播给其他系统。有了之前的经验,很快想到了可以用消息队列来实现。
在这里,消息队列就像我们的微信群一样,有了消息队列,我们只需要关心消息是否送达了队列,至于谁关心它谁希望去订阅,是下游的事情,无疑极大地减少了开发和联调的工作量。
数据采集
胖滚猪又接了个数据采集的活,1、需要实时收集日志、2、需要实时采集业务库binlog。
经过一番调研,胖滚猪明白了,采集binlog一般用到canal、采集日志一般可以用Flume和Logstash。
那么采集之后数据丢到哪儿呢?胖滚猪看了看官方架构图,咦,又有熟悉的消息队列,原来消息队列也可以用来数据采集呀!
所有主流的采集工具,都支持落地到Kafka等消息队列。也就是说,消息队列在数据采集这一块,也有举足轻重的作用。当然了,也不是必须要选择消息队列,要根据具体场景来选择。如果要对接流计算任务,或者多个系统都需要用到采集到的数据,那么选消息队列就没错了;如果只是想单纯存储起来,比如一些日志,那么可以不用消息队列。
连接流计算任务和数据
用消息队列(主要指Kafka)来连接流计算任务和数据,这在大数据领域是非常通用的一个架构了。火爆的流计算框架,Flink和Spark都优先选择Kafka作为数据源头并提供了完美的支持。
我们看一下oppo的架构图、简直了。三次用到Kafka!这地位无敌了!为啥oppo要三次用到Kafka呢?我相信根据上面的应用场景和优势你完全可以自行分析出来!
消息通讯
最后说一下消息通讯。。消息队列可以应用在消息通讯中,比如聊天室。
你可能会吐槽,你这不废话吗?凑数呢?我当然知道消息队列可用于消息通讯,小学生看名字都知道!
额,其实我只是想说明一下消息队列在消息通讯的两种场景罢了:点对点模型和发布订阅模型。
点对点通讯:系统 A 发送的消息只能被系统 B 接收,其他任何系统都不能读取 A 发送的消息。日常生活的例子比如电话客服就属于这种模型:同一个客户呼入电话只能被一位客服人员处理,第二个客服人员不能为该客户服务。
发布 / 订阅模型:与上面不同的是,它有一个主题(Topic)的概念,这个模型可能存在多个发布者向相同的主题发送消息,而订阅者也可能存在多个,它们都能接收到相同主题的消息。生活中的报纸订阅就是一种典型的发布 / 订阅模型。
劲酒虽好,可不要贪杯哦
消息队列确实有着非常广泛的应用,但它也有缺点!劲酒虽好,可不要贪杯哦,贪杯会出问题的哦!
- 消息队列会带来一定的延迟问题;
- 降低了数据的一致性;如果要保证强一致性则需要高代价的补偿,如分布式事务、对账。
- 有数据丢失的风险;比如宕机重启,如果要保证高可用需要额外的机制如双活容灾。
因此:
- 不适合要求实时响应的系统、
- 不适合要求数据强一致性的系统(比如直接和钱有关系的系统 银行转账 第三方支付)、
- 不适合不能容忍数据丢失的系统
本文来源于公众号:胖滚猪学编程。用漫画形式让编程so easy and interesting!欢迎关注