消息中間件的使用已經越來越廣泛,基本上具有一定規模的系統都會用到它,在大數據領域也是個必需品,但為什么使用它呢?一個技術的廣泛使用必然有它的道理。
背景與問題
以前一些傳統的系統,基本上都是“用戶——系統——數據庫”一條線,拿下單做例子,用戶下單,系統接受並處理請求,把數據存到數據庫。
這樣的好處就是簡單,但隨着需求越來越多,用戶量越來越大,系統需要承載的壓力就越大;如果需要擴展系統,修改代碼,牽一發動全身,麻煩滴很。
消息隊列可以解決這些問題,它是一個存放消息的隊列,生產者往隊列推數,消費者從隊列取數。
優點
解耦
一個系統一般都有很多個模塊,但業務發展起來,系統的體量就跟着變大,就需要多做幾個模塊,然而每拓展一個模塊就要多各種調用。
以一個交易系統為例,當完成一次交易,系統需要通知推薦系統、廣告系統等。當多出一個模塊,系統就要增加一個調用,從而需要修改代碼。
要是你覺得改改代碼不麻煩,可是改完,后面有一個模塊出問題了咋辦,一點一點排查,改錯地方了還影響到了其他模塊。
如果增加消息中間件,各個模塊只需要完成各自的工作,然后將消息發到消息隊列,由其他模塊去取或者消息隊列推送,就可以解決耦合的問題了。
異步
傳統系統的話,一條路走到底,比如購買商品,完了扣除優惠券,再給你積點分。這每個流程可能就花一點時間,但合起來就很久了。
加上消息隊列,我直接完成我的工作,再給隊列,隊列再通知其他模塊,這不僅省事兒,還減少了不必要的時間浪費。
削峰
還是以傳統系統為例,當並發量大的時候直接懟到數據庫,數據庫承受的壓力得多大呀這是。欸,那就加個消息隊列,把請求扔到消息隊列,慢慢處理
缺點
技術嘛,總是有好有壞,剛才說了它的優點,現在簡單嘮嘮它的缺點。
首先,降低了系統的可用性,好好的一個系統,加一個中間件,如果它掛了,后面不得涼涼。
為了防止它掛掉或者掛掉了修復它,是不是得維護?是不是增加了運維成本?
不僅如此,還要考慮數據一致性問題,以及重復消費的問題,還要保證消息的可靠傳輸。要考慮的東西有多少,系統的復雜性就有多高。
消費模式
消息中間件一般有兩種消費模式,一種是點對點模式,一種是發布訂閱模式。
點對點是一種一對一的模式,一般消息只由一個消費者消費,導致消息沒法復用;
發布訂閱模式是一種常見的模式。消費者訂閱,當有消息來的時候通知消費者。這種模式也分為兩種情況,一種是由消息隊列推送,類似公眾號訂閱一樣,只要消費者訂閱了,消息一來就推給訂閱了的消費者。
但是這種方法也有缺點,因為消費者的處理速度不一樣,有快有慢,容易出現問題。比如消息隊列推送的速度為100M/s,消費者A處理速度為10M/s,消費者B處理速度為500M/s,這時候A就崩了,對於B來說,又造成資源浪費。
所以由消費者主動拉取的方式誕生了,由消費者主動拉數據,解決了上面的問題,但技術有優點的同時,一般都存在缺點。由於消費者要主動拉取,需要維護一個長輪洵去詢問隊列,但當遇到長時間沒有消息的情況,就造成了資源浪費。
本文的主角 Kafka 是基於拉取的發布訂閱模式。
講了這么多,是時候請上主角,有請 Kafka 登場!
Kafka 的基礎架構
Producer:生產者,發布消息的對象,將消息推到 Kafka 集群
Consumer:消費者,消費消息的對象
Consumer Group:消費者組,Kafka 中可以將多個 Consumer 分為一個組,從整體上可以將它看作是一個Consumer
Broker:一台 Kafka 服務器就是一個 Broker,多個 Broker 組成一個 Cluster
Topic:消息的主題,可以理解為一個消息隊列
Partition:分區,一個 Topic 可以分為多個 Partition,這樣的好處是負載均衡;同時,一個 Partition 可以有多個副本,提高可靠性。對於 Consumer Group 來說,一個消費者組中的消費者只能訂閱同一個 Topic 的不同分區,可以提高效率,又避免重復消費。
Leader & Follower:對於同一個 Partition 而言,消費者只讀取 Leader 的消息,而不會讀取 Follower 的消息,Follower 是 Leader 的副本,在 Leader 掛掉的時候 Follower 可成為 Leader
Zookeeper: Kafka 是基於 zk 的,用於集群管理
為什么 Kafka 要這樣設計
如果消息中間件只有一台機,哪天突然宕機了,整個系統就崩了。因此需要整一個集群,搞多台服務器,所以我們搞幾個 Broker。
然后生產者准備發送消息了,如果正巧所有的消息都隨機地發到其中某一台機器上,流量全上去了,生產者消費者都來找他,看着其他機器都在摸魚,它突然不干了。
於是要合理分配工作,整出了 Partition,每個 Topic 對應每個生產者和消費者,同一個 Topic 又分成多個分區,分別在不同的 Broker,分擔了單台節點的壓力。
不過現在又有一個問題,如果一台 Broker 宕機,該節點上的分區數據也沒了。為了防止單節點故障造成數據丟失,每個分區存幾個副本保存在其它 Broker。
但消費者只能訪問其中一個分區,不然會造成重復消費的現象,所以要區分好 Leader 和 Follower,並使消費者只能訪問 Leader,而 Follower 需要在 Leader 發生故障的時候成為新的 Leader。