leyou的商品詳情和搜尋服務開發完成之後,發現存在下面的問題:
商品的原始資料儲存在資料庫中,增删改查都在資料庫中完成。
搜尋服務資料來源是索引庫,如果資料庫商品發生變化,索引庫不能及時更新
商品詳情做了頁面靜态化,靜态頁面資料也不會随着資料庫商品發生變化
如果在背景修改了商品的價格,搜尋頁面和商品詳情頁面顯示的依然是舊的價格,顯然不對,該如何解決?
商品服務對商品增删改以後,無需去操作索引庫或靜态頁面,隻是發送一條消息,也不關心消息被誰接收。
搜尋服務和靜态頁面服務接收消息,分别去處理索引庫和靜态頁面
消息隊列,即MQ,MessageQueue
MQ全稱為Message Queue,消息隊列(MQ)是一種應用程式對應用程式的通信方法。應用程式通過讀寫出入隊列的消息(針對應用程式的資料)來通信,而無需專用連接配接來連結他們。消息傳遞指的是程式之間通過在消息中發送資料進行通信,而不是通過直接調用彼此來通信,直接調用通常是用于諸如 遠端過程調用 的技術。排隊指的是應用程式通過隊列來通信。隊列的使用除去了接收和發送應用程式同時執行的要求。
其中較為成熟的MQ産品有 IBM WEBSPHERE MQ等。
消息隊列是典型的:生産者,消費者模型。
生産者不斷向消息隊列中生産消息,消費者不斷的從隊列中擷取消息。因為消息的生産和消費都是異步的,而且隻關心消息的發送和接收,沒有業務邏輯的侵入,這樣就實作了生産者和消費者的解耦。
AMQP和JMS
MQ是消息通信的模型,并不是具體實作,java中實作 MQ的有兩種流行方式:AMQP,JMS。
AMQP:(Advanced Message Queuing Protocol)一個提供統一消息服務的應用層标準進階消息隊列協定,是應用層協定的一個開放标準,為面向消息的中間件設計。基于此協定的用戶端與消息中間件可傳遞消息,并不受用戶端/中間件不同産品,不同的開發語言等條件的限制。
Erlang 中的實作有RabbitMQ等。
JMS:(Java MessageService)實際上是指JMS API。JMS是由Sun公司早期提供的消息标準,是為了給Java應用提供統一的消息操作,包括create,send,receive等。
JMS已經成為java Enterprise Edition的一部分,從使用角度看,JMS和JDBC 擔任差不多的角色,使用者都是根據相應的接口可以和實作了JMS的服務進行通信,進行相關的操作。
常見的MQ産品
• ActiveMQ:基于JMS
• RabbitMQ:基于AMQP協定,erlang語言開發,穩定性好
• RocketMQ:基于JMS,阿裡巴巴産品,目前交由Apache基金會
Kafka:分布式消息系統,高吞吐量
RabbitMQ是一個消息代理:它接受和轉發消息。可以把它想象成一個郵局:當你把郵件放在郵箱裡時,你可以确定郵差先生最終會把郵件發送給你的收件人。RabbitMQ是郵政信箱,郵局和郵差。
RabbitMQ與郵局的主要差別是它不處理紙張,而是接受,存儲和轉發資料消息的二進制資料塊。

P(producer):生産者,一個發送消息的使用者應用程式
C(consumer):消費者,消費和接收有類似的意思,消費者是一個主要用來等待接收消息的使用者應用程式。
隊列(紅色區域):rabbitMQ内部類似于郵箱的一個概念。雖然消息流經rabbitMQ和應用程式,但是他們隻能存儲在隊列中。隊列隻受主機的記憶體和磁盤限制,實質上是一個大的消息緩沖區。
許多生産者可以發送消息到一個隊列,許多消費者可以嘗試從一個隊列中接收消息。
總之:生産者将消息發送到隊列,消費者從隊列中擷取消息,隊列是存儲消息的緩沖區。
1、釋出訂閱fanout
工作隊列背後的假設是:每個任務隻被傳遞給一個從業人員。
釋出/訂閱:傳遞一個資訊給多個消費者。
訂閱模型示意圖:
1. 一個生産者,多個消費者
2. 每一個消費者都有自己的一個隊列
3. 生産者沒有将消息直接發送到隊列,而是發送到了交換機
4. 每個隊列都要綁定到交換機
5. 生産者發送的消息,經過交換機到達隊列,實作一個消息被多個消費者擷取的目的。
X(Exchanges):交換機一方面:接收生産者發送的消息。另一方面:知道如何處理消息,例如遞交給某個特别的隊列,遞交給所有隊列,或是将消息丢棄。具體如何操作,取決于Exchange的類型。
Fanout:即廣播模式
Exchange(交換機)隻負責轉發消息,不具備存儲消息的能力,是以如果沒有任何隊列與Exchange綁定,或者沒有符合路由規則的隊列,那麼消息會丢失。
2、訂閱模型-Direct
有選擇性的接收消息
在訂閱模式中,生産者釋出消息,所有消費者都可以擷取所有消息。
在路由模式中,隻能訂閱一部分消息。
例如:我們隻能将重要的錯誤消息引導到日志檔案(以節省磁盤空間),同時仍然能在控制台上列印所有的日志消息。
在某些場景下,我們希望不同的消息被不同的隊列消費。這時要用到Direct類型的Exchange。
在Direct模型下,隊列與交換機的綁定,不能是任意綁定了,而是要指定一個RoutingKey(路由key)
消息的發送方在向Exchange發送消息時,也必須指定消息的routing key
P :生産者,向Exchange發送消息,發送消息時,會指定一個routing key
X :Exchange(交換機),接收生産者的消息,然後把消息遞交給routing key完全比對的隊列
C1:消費者,其所在隊列指定了需要routing key 為error的消息
C2:消費者,其所在隊列指定了需要routing key 為info error warning的消息
3、訂閱模型-Topic
Topic類型的Exchange與Direct相比,都是可以根據routingkey 把消息路由到不同的隊列。隻不過Topic類型Exchange可以讓隊列在綁定Routing key的時候使用通配符。
Routingkey 一般都是有一個或多個單詞組成,多個單詞之間以 “.”分割。
例如:item.insert
如何避免消息丢失?——持久化
消費者的ACK确認機制,可以防止消費者丢失資訊。但是如果在消費者消費之前,MQ就當機了,消息就沒了。要将消息持久化,前提是:隊列,Exchange都持久化。
幾種模型的整理