ActiveMQ传输文件的几种方式原理与优劣
本文討論ActiveMQ傳輸文件的幾種方法的原理及其利弊,作為消息發送、直接傳輸文件、使用ftp或http中轉。最后介紹擴展ActiveMQ實現自定義文件傳輸方式,討論如何實現高效的文件傳輸。
作為消息發送
按照JMS規范,為了保證可靠性,所有的消息都應該是發送到broker,然后交由broker來投遞的。也即是說其實JMS是不建議或不支持傳輸文件的。
對于比較小的文件,簡單的處理方式是先讀取所有的文件成byte[],然后使用ByteMessage,把文件數據發送到broker,像正常的message一樣處理。對于大文件,例如1GB以上的文件,這么搞直接把client或是broker給oom掉了。
這種方式僅僅適用于小文件的傳輸。特別是如果broker端使用數據庫作為存儲,message序列化以后存放于blob字段,文件傳輸頻繁或是稍微有點大,寫入效率極低。
直接傳輸文件
為了解決傳輸大文件的問題,ActiveMQ在jms規范之外引入了jms streams的概念。PTP模式下,連到同一個destination的兩端,可以通過broker中轉來傳輸大文件。
發送端使用connection.createOutputStream打開一個輸出流,往流里寫文件。
OutputStream out =connection.createOutputStream(destination);
接收端則簡單的使用connection.createInputStream拿到一個輸入流,從中讀取文件數據即可。
InputStream in = connection.createInputStream(destination)詳見:http://activemq.apache.org/jms-streams.html
使用非常簡單。ActiveMQ在中間做了什么事情呢?
其實過程蠻曲折的,發送端拿到文件后,首先分片,默認64K文件數據為一個byte message,然后依次把所有的message發送到broker,broker轉發給接收端,最后發送一個空消息作為結束符。
connection上提供了兩個創建OutputStream的方法,一個是createOutputStream創建的是持久化的消息集合,這些數據會寫到磁盤或是數據庫(對大文件來說慢消費也是一件可怕的事兒);一個是createNonPersistOutputStream創建的是非持久化消息集合,不會寫到磁盤上,如果沒有及時消費掉就慘了。
文件片段的byte message的TTL設置為0,就是不會超時進入DLQ。
優勢:簡單直接,處理非常小(不大于64K)的文件非常方便。
劣勢:對大文件,簡直就是噩夢。
文件中轉方式
使用消息的方式來傳遞大文件,明顯不是一個有效率的辦法。文件應該就是按文件的方式去處理。
自己處理中轉
如果自己處理文件的話,一個簡單方式是使用共享或ftp、dfs等方式,先把文件發送到一個大家都可以拿到的地方,然后發送message,payload或properties中包含文件的路徑信息。這樣,consumer拿到文件路徑后去指定的地方,按照給定的方式去獲取文件數據即可。
優勢:這種方式可以用來處理大數據,并且不需要client或broker在內存中持有文件數據本身,非常的節省資源。而且文件是通過額外的方式處理,跟ActiveMQ本身無關,所以符合jms協議、處理的效率也相對比較高。
劣勢:需要自己處理很多文件相關的操作。
BlobMessage對文件中轉的封裝
幸運的是,ActiveMQ把上面繁復的文件處理工作進行了封裝,屏蔽掉文件中轉的整個處理過程,使得我們可以使用類似jms規范的API來簡單操作文件傳輸。
舉個例子來說,典型的使用步驟:
發送端:
1.????????啟動ActiveMQ時,也啟動jetty(即activemq.xml中有import jetty.xml),此時jetty中運行了一個ActiveMQ自帶的http文件服務器
2.????????使用tcp://localhost:61616?jms.blobTransferPolicy.defaultUploadUrl=http://localhost:8161/fileserver/創建connection,然后創建session和producer
3.????????使用如下代碼發送文件:
BlobMessageblobMessage = session.createBlobMessage(file);?
blobMessage.setStringProperty("FILE.NAME",file.getName());?
blobMessage.setLongProperty("FILE.SIZE",file.length());?
producer.send(blobMessage);?
接收端比較簡單,正常的使用jms接收到消息:
InputStream inputStream = blobMessage.getInputStream();
然后直接讀取文件數據即可。文件名和文件大小可以從message的屬性中拿到。
?
這個過程中ActiveMQ做了什么呢?
發送端:producer.send的時候,把文件通過http協議的PUT方法發到jetty中的fileserver(默認128K走http的chunk分片傳輸)。然后把http的url寫入消息中。再把消息發送到broker。
接收端:接收到消息以后,發現是BlobMessage,拿到url,直接使用GET方法獲取文件數據。處理完畢后,使用DELETE方法從fileserver刪除文件。
BlobMessage支持3種文件中轉方式:
FILE
???????? 要求client和broker在同一個機器或者使用同一個共享存儲。發送文件的時候,把文件從本地寫入到指定路徑。接收文件的時候,把文件從此路徑讀出來。
HTTP
???????? 使用http的fileserver,PUT/GET/DELETE方法。ActiveMQ自帶了簡單的實現。就是前面場景中使用的方式。
FTP
???????? 使用一個獨立的ftpserver作為文件中轉方式。發送文件的時候,把文件發送到ftp服務器。接收文件的時候,從ftp把文件讀取下來。
?
詳見:http://activemq.apache.org/blob-messages.html
?
優勢:消息處理與文件處理傳輸分開,極大的提高了文件傳輸的效率。而且可以使用類似jms協議的方式來處理文件發送。
劣勢:FILE方式不太實用。HTTP和FTP方式都需要額外的fileserver。
?
自定義文件傳輸方式
ActiveMQ實現BlobMessage的三種文件中轉方式時,使用了Fa?ade和Strategy模式。ActiveMQBlobMessage需要在發送消息時使用blobUploader上傳文件、接收消息時使用blobDownloader下載文件。每種中轉方式的這兩個操作分別使用BlobUploadStrategy和BlobDownloadStrategy封裝。
所以,我們也可以根據ActiveMQBlobMessage文件傳送的原理,實現自己的定制方式:
1、? 給ActiveMQBlobMessage添加自己的blobDownloader和blobUploader來實現文件的處理。
2、? 擴展這個文件中轉機制,實現BlobUploadStrategy和BlobDownloadStrategy。
?
一個更高效且不需要額外fileserver的實現思路是:broker上再打開一個tcp的監聽端口,用來接收和轉發文件,當發送和接收端都在時,broker僅僅作為一個傳輸代理。接收端不在時,broker把數據存為本地臨時文件,處理完畢后刪除掉。之所以使用一個新的端口來傳輸文件數據而不是已有的transport,是為了避免jms streams這種命令和數據混合的模式??梢詤⒖糵tp協議,作為一種高效的文件傳輸協議,它有一個很大的特點就是命令的處理,和數據傳輸的處理使用不同的端口和連接。而ActiveMQ使用的openwire協議其實就是一個個的操作命令。文件分片、包裝、序列化,到另一頭再反向這個過程,無疑是效率很低下的。
大家有什么想法都可以跟我交流:278008309@qq.com
總結
以上是生活随笔為你收集整理的ActiveMQ传输文件的几种方式原理与优劣的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: struts2 开发
- 下一篇: ssl双向认证和单向认证的区别