可信送達,即確保消息總是送達,即使系統(tǒng)中的某部分掛掉(網(wǎng)絡(luò)問題,防火墻,硬件問題,程序出錯)。
連接失敗
這種情況,客戶端需要重新建立一個連接,之前建立的所有通道都會自動關(guān)閉并重新打開。一般來說,會拋出異常,可以建立失敗回調(diào)處理。
ack
連接失敗發(fā)生時,消息可能正在傳輸中(正在生成消息、在操作系統(tǒng)的緩存中、在網(wǎng)絡(luò)上),那么消息就會丟失,收不到ack則會通知發(fā)送方進行重發(fā)。ack又可以分為兩種情況:客戶端通知服務(wù)器已經(jīng)收到消息了,服務(wù)器通知客戶端收到消息了(這種也叫做confirm,也就是消息中間人開始負責(zé)處理這些消息了)。
當(dāng)然,TCP可以保證消息的送達,但是這是網(wǎng)絡(luò)層面的,ack保證的是消息的接受和執(zhí)行,它確認的是消息是否被接受同時轉(zhuǎn)交所有權(quán),接收者接下里負責(zé)處理它。所以,接受者不應(yīng)該在工作未完成之前發(fā)送ack。
心跳
tcp連接的超時時間一般較長(例如linux默認為11分鐘),所以amqp協(xié)議提供了心跳,使得可以在應(yīng)用層發(fā)現(xiàn)連接錯誤。
作為中間人
中間件需要考慮的問題是服務(wù)器重啟、硬件錯誤或者自身崩潰。為了確保消息在重啟后還存在,則需要把消息存儲在磁盤上。包含exchange、隊列、消息的持久化,
集群和高可用性
如果想保證中間件在硬件錯誤時仍能工作,則需要使用rabbitmq集群。在集群中,所有的東西(exchange、bind、user等 除了隊列需要額外的配置)都是在各個機器間共享的,所有結(jié)點都可以獲得。因為這些內(nèi)容在集群中的每個結(jié)點上都有,那么可以允許結(jié)點掛掉但是不會造成信息丟失。
作為發(fā)送者
如果使用了confirm,那么發(fā)送者會重發(fā)所有沒有收到服務(wù)器ack的消息??赡軙邢⒅貜?fù)的情況,即中間件已經(jīng)發(fā)了ack但是發(fā)送者沒有收到(網(wǎng)絡(luò)問題),那么接收者需要處理這種重復(fù)的情況或者它本身是等冪的。
確保消息被傳送
有一些情況需要確保消息被傳送到了隊列中,當(dāng)然大多數(shù)情況發(fā)送者只是發(fā)送,如果沒有接收者在等待消息可以被安全的丟棄。而為了確定消息可以被傳送到隊列里,發(fā)送者可以先聲明該隊列再發(fā)送。如果不能簡單的聲明隊列,可以在發(fā)送時增加mandatory標(biāo)記,確保在沒有傳送到隊列時會得到通知。
作為接收者
接收者需要考慮的就是會收到重復(fù)消息(網(wǎng)絡(luò)錯誤時),最好是接收者的操作是等冪的則不需要額外的操作。RabbitMQ在沒有收到接收者的ack并進行重發(fā)時,會帶上redelivered標(biāo)記。(但是如果遇到了發(fā)送者發(fā)了重復(fù)消息的情況則不能處理)
另外如果接收者發(fā)現(xiàn)他不能處理該消息,可以發(fā)送reject。
分布式
聯(lián)邦和shovel都是使用amqp的,所以他們也可以啟用ack,在必要時可以重傳消息。