6g下載網
當前位置: 主頁 > 軟件教程 > 云計算 >

架構設計:系統間通信(25)——ActiveMQ集群方案(上)

時間: 2016-04-17 17:40 來源: 本站整理

分享到:

1、綜述

通過之前的文章,我們討論了ActiveMQ的基本使用,包括單個ActiveMQ服務節點的性能特征,關鍵調整參數;我們還介紹了單個ActiveMQ節點上三種不同的持久化存儲方案,并討論了這三種不同的持久化存儲方案的配置和性能特點。但是這還遠遠不夠,因為在生產環境中為了保證讓我們設計的消息服務方案能夠持續工作,我們還需要為消息中間件服務搭建集群環境,從而在保證消息中間件服務可靠性和處理性能。

2、ActiveMQ多節點方案

集群方案主要為了解決系統架構中的兩個關鍵問題:高可用和高性能。ActiveMQ服務的高可用性是指,在ActiveMQ服務性能不變、數據不丟失的前提下,確保當系統災難出現時ActiveMQ能夠持續提供消息服務,高可靠性方案最終目的是減少整個ActiveMQ停止服務的時間

ActiveMQ服務的高性能是指,在保證ActiveMQ服務持續穩定性、數據不丟失的前提下,確保ActiveMQ集群能夠在單位時間內吞吐更高數量的消息、確保ActiveMQ集群處理單條消息的時間更短、確保ActiveMQ集群能夠容納更多的客戶端穩定連接。

下面我們分別介紹如何通過多個ActiveMQ服務節點集群方式,分別提供熱備方案和高性能方案。最后我們討論如何將兩種方案結合在一起,最終形成在生成環境下使用的推薦方案。

2-2、ActiveMQ高性能方案

ActiveMQ的多節點集群方案,主要有動態集群和靜態集群兩種方案。所謂動態集群就是指,同時提供消息服務的ActiveMQ節點數量、位置(IP和端口)是不確定的,當某一個節點啟動后,會通過網絡組播的方式向其他節點發送通知(同時接受其他節點的組播信息)。當網絡中其他節點收到組播通知后,就會向這個節點發起連接,最終將新的節點加入ActiveMQ集群;所謂靜態集群是指同時提供消息服務的多個節點的位置(IP和端口)是確定的,每個節點不需要通過廣播的方式發現目標節點,只需要在啟動時按照給定的位置進行連接。

靜態集群方案

架構設計:系統間通信(25)——ActiveMQ集群方案(上)

動態集群方案

架構設計:系統間通信(25)——ActiveMQ集群方案(上)

2-1-1、基于組播(multicast)的節點發現

在使用動態集群配置時,當某個ActiveMQ服務節點啟動后并不知道整個網絡中還存在哪些其他的服務節點。所以ActiveMQ集群需要規定一種節點與節點間的發現機制,以保證能夠解決上述問題。ActiveMQ集群中,使用“組播”原理進行其他節點的發現

組播(multicast)基于UDP協議,它是指在一個可連通的網絡中,某一個數據報發送源向一組數據報接收目標進行操作的過程。在這個過程中,數據報發送者只需要向這個組播地址(一個D類IP)發送一個數據報,那么加入這個組播地址的所有接收者都可以收到這個數據報。組播實現了網絡中單點到多點的高效數據傳送,能夠節約大量網絡帶寬,降低網絡負載。

架構設計:系統間通信(25)——ActiveMQ集群方案(上)

在IP協議中,規定的D類IP地址為組播地址。224.0.0.0~239.255.255.255這個范圍內的IP都是D類IP地址,其中有一些IP段是保留的有特殊含義的:

224.0.0.0~224.0.0.255:這個D類IP地址段為保留地址,不建議您在開發過程中使用,因為可能產生沖突。例如224.0.0.5這個組播地址專供OSPF協議(是一種路由策略協議,用于找到最優路徑)使用的組播地址;224.0.0.18這個組播地址專供VRRP協議使用(VRRP協議是虛擬路由器冗余協議)。

224.0.1.0~224.0.1.255:這個D類IP地址為公用組播地址,用于在整個Internet網絡上進行組播。除非您有頂級DNS的控制/改寫權限,否則不建議在局域網內使用這個組播地址斷。

239.0.0.0~239.255.255.255:這個D類IP地址段為推薦在局域網內使用的組播地址段。注意,如果要在局域網內使用組播功能,需要局域網中的交換機/路由器支持組播功能。幸運的是,目前市面上只要不是太過低端的交換機/路由器,都支持組播功能(組播功能所使用的主要協議為IGMP協議,關于IGMP協議的細節就不再進行深入了)。

下面我們使用java語言,編寫一個局域網內的組播發送和接受過程。以便讓各位讀者對基于組播的節點發現操作有一個直觀的理解。雖然ActiveMQ中關于節點發現的過程,要比以下的示例復雜得多,但是基本原理是不會改變的。

組播數據報發送者:

  1. package multicast;  
  2.  
  3. import java.net.DatagramPacket;  
  4. import java.net.InetAddress;  
  5. import java.net.MulticastSocket;  
  6. import java.util.Date;  
  7.  
  8. public class SendMulticast {  
  9.     public static void main(String[] args) throws Throwable {  
  10.         // 組播地址  
  11.         InetAddress group = InetAddress.getByName("239.0.0.5");  
  12.         // 組播端口,同時也是UDP 數據報的發送端口  
  13.         int port = 19999;  
  14.         MulticastSocket mss = null;    
  15.  
  16.         // 創建一個用于發送/接收的MulticastSocket組播套接字對象  
  17.         mss = new MulticastSocket(port);  
  18.         // 創建要發送的組播信息和UDP數據報  
  19.         // 攜帶的數據內容,就是這個activeMQ服務節點用來提供Network Connectors的TCP/IP地址和端口等信息  
  20.         String message = "我是一個活動的activeMQ服務節點(節點編號:yyyyyyy),我的可用tcp信息為:XXXXXXXXXX : ";    
  21.         byte[] buffer2 = message.getBytes();   
  22.         DatagramPacket dp = new DatagramPacket(buffer2, buffer2.length, group, port);  
  23.         // 使用組播套接字joinGroup(),將其加入到一個組播  
  24.         mss.joinGroup(group);  
  25.  
  26.         // 開始按照一定的周期向加入到224.0.0.5組播地址的其他ActiveMQ服務節點進行廣播  
  27.         Thread thread = Thread.currentThread();  
  28.         while (!thread.isInterrupted()) {  
  29.             // 使用組播套接字的send()方法,將組播數據包對象放入其中,發送組播數據包  
  30.             mss.send(dp);  
  31.             System.out.println(new Date() + "發起組播:" + message);  
  32.             synchronized (SendMulticast.class) {  
  33.                 SendMulticast.class.wait(5000);  
  34.             }  
  35.         }  
  36.  
  37.         mss.close();  
  38.     }  

組播數據報接收者:

  1. package multicast;  
  2.  
  3. import java.net.DatagramPacket;  
  4. import java.net.InetAddress;  
  5. import java.net.MulticastSocket;  
  6.  
  7. /**  
  8.  * 測試接收組播信息  
  9.  * @author yinwenjie  
  10.  */ 
  11. public class AcceptMulticast {  
  12.     public static void main(String[] args) throws Throwable {  
  13.         // 建立組播套接字,并加入分組  
  14.         MulticastSocket multicastSocket = new MulticastSocket(19999);  
  15.         // 注意,組播地址和端口必須和發送者的一直,才能加入正確的組  
  16.         InetAddress ad = InetAddress.getByName("239.0.0.5");  
  17.         multicastSocket.joinGroup(ad);  
  18.  
  19.         // 準備接收可能的組播信號  
  20.         byte[] datas = new byte[2048];  
  21.         DatagramPacket data = new DatagramPacket(datas, 2048 ,ad , 19999);  
  22.         Thread thread = Thread.currentThread();  
  23.  
  24.         // 開始接收組播信息,并打印出來  
  25.         System.out.println(".....開始接收組播信息.....");  
  26.         while(!thread.isInterrupted()) {  
  27.             multicastSocket.receive(data);  
  28.             int leng = data.getLength();  
  29.             System.out.println(new String(data.getData() , 0 , leng , "UTF-8"));  
  30.         }  
  31.  
  32.         multicastSocket.close();  
  33.     }  

另外,我們之前講過的DUBBO框架中,也有基于“組播”的發現/注冊管理。具體可參考DUBBO框架中的com.alibaba.dubbo.registry.multicast.MulticastRegistry類和其引用類(以下為MulticastRegistry類中,創建組播套接字和接受組播數據報的關鍵代碼段):

  1. ......  
  2. mutilcastAddress = InetAddress.getByName(url.getHost());  
  3. mutilcastPort = url.getPort() <= 0 ? DEFAULT_MULTICAST_PORT : url.getPort();  
  4. mutilcastSocket = new MulticastSocket(mutilcastPort);  
  5. mutilcastSocket.setLoopbackMode(false);  
  6. mutilcastSocket.joinGroup(mutilcastAddress);  
  7. Thread thread = new Thread(new Runnable() {  
  8.     public void run() {  
  9.         byte[] buf = new byte[2048];  
  10.         DatagramPacket recv = new DatagramPacket(buf, buf.length);  
  11.         while (! mutilcastSocket.isClosed()) {  
  12.             try {  
  13.                 mutilcastSocket.receive(recv);  
  14.                 String msg = new String(recv.getData()).trim();  
  15.                 int i = msg.indexOf('\n');  
  16.                 if (i > 0) {  
  17.                     msg = msg.substring(0, i).trim();  
  18.                 }  
  19.                 MulticastRegistry.this.receive(msg, (InetSocketAddress) recv.getSocketAddress());  
  20.                 Arrays.fill(buf, (byte)0);  
  21.             } catch (Throwable e) {  
  22.                 if (! mutilcastSocket.isClosed()) {  
  23.                     logger.error(e.getMessage(), e);  
  24.                 }  
  25.             }  
  26.         }  
  27.     }  
  28. }, "DubboMulticastRegistryReceiver");  
  29. thread.setDaemon(true);  
  30. thread.start();  
  31. ...... 

2-1-2、橋接Network Bridges

為了實現ActiveMQ集群的橫向擴展要求和高穩定性要求,ActiveMQ集群提供了Network Bridges功能。通過Network Bridges功能,技術人員可以將多個ActiveMQ服務節點連接起來。并讓它們通過配置好的策略作為一個整體對外提供服務。

這樣的服務策略主要包括兩種:主/從模式和負載均衡模式。對于第一種策略我們會在后文進行討論。本節我們要重點討論的是基于Network Bridges的負載均衡模式。

架構設計:系統間通信(25)——ActiveMQ集群方案(上)

2-1-3、動態Network Connectors

既然已經講述了ActiveMQ中的動態節點發現原理和ActiveMQ Network Bridges的概念,那么關于ActiveMQ怎樣配置集群的方式就是非常簡單的問題了。我們先來討論如何進行基于組播發現的ActiveMQ負載均衡模式的配置——動態網絡連接Network Connectors;再來討論基于固定地址的負載均衡模式配置——靜態網絡連接Network Connectors。

要配置基于組播發現的ActiveMQ負載均衡模式,其過程非常簡單。開發人員只需要在每一個ActiveMQ服務節點的主配置文件中(activemq.xml),添加/更改 以下配置信息即可:

  1. ......  
  2. <transportConnectors>  
  3.     <!-- 在transportConnector中增加discoveryUri屬性,表示這個transportConnector是要通過組播告知其它節點的:使用這個transportConnector位置連接我 -->  
  4.     <transportConnector name="auto" uri="auto+nio://0.0.0.0:61616?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600&amp;org.apache.activemq.transport.nio.SelectorManager.corePoolSize=20&amp;org.apache.activemq.transport.nio.SelectorManager.maximumPoolSize=50&amp;consumer.prefetchSize=5" discoveryUri="multicast://239.0.0.5" />  
  5. </transportConnectors>  
  6.  
  7. ......  
  8.  
  9. <!-- 關鍵的networkConnector標簽, uri屬性標示為組播發現-->  
  10. <networkConnectors>  
  11.     <networkConnector uri="multicast://239.0.0.5" duplex="false"/>  
  12. </networkConnectors>  
  13.  
  14. ...... 

2-1-3-1:networkConnector標簽

如果使用ActiveMQ的組播發現功能,請在networkConnector標簽的uri屬性中添加如下格式的信息:

  1. multicast://[組播地址][:端口] 

例如,您可以按照如下方式使用ActiveMQ默認的組播地址來發現網絡種其他ActiveMQ服務節點:

  1. #ActiveMQ集群默認的組播地址(239.255.2.3):  
  2. multicast://default 

也可以按照如下方式,指定一個組播地址——這在高安全級別的網絡中很有用,因為可能其他的組播地址已經被管理員禁用。注意組播地址只能是D類IP地址段:

  1. #使用組播地址239.0.0.5  
  2. multicast://239.0.0.5 

以下是通過抓包軟件獲得的的組播UDP報文:

架構設計:系統間通信(25)——ActiveMQ集群方案(上)

從上圖中我們可以獲得幾個關鍵信息:

192.168.61.138和192.168.61.139這兩個IP地址分別按照一定的周期(1秒一次),向組播地址239.0.0.5發送UDP數據報。以便讓在這個組播地址的其它服務節點能夠感知自己的存在

另外,以上UDP數據報文使用的端口是6155。您也可以更改這個端口信息通過類似如下的方式:

  1. #使用組播地址239.0.0.5:19999  
  2. multicast://239.0.0.5:19999 

每個UDP數據報中,包含的主要信息包括本節點ActiveMQ的版本信息,以及連接到自己所需要使用的host名字、協議名和端口信息。類似如下:

  1. default.ActiveMQ-4.ailve%localhost%auto+nio://activemq:61616 

2-1-3-2:transportConnector標簽的關聯設置

任何一個ActiveMQ服務節點A,要連接到另外的ActiveMQ服務節點,都需要使用當前節點A已經公布的transportConnector連接端口,例如以下配置中,能夠供其它服務節點進行連接的就只有兩個transportConnector連接中的任意一個:

  1. ......  
  2. <transportConnectors> 
  3.     <!-- 其它ActiveMQ服務節點,只能使用以下三個連接協議和端口進行連接 --> 
  4.     <!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB --> 
  5.     <transportConnector name="tcp" uri="tcp://0.0.0.0:61614?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/> 
  6.     <transportConnector name="nio" uri="nio://0.0.0.0:61618?maximumConnections=1000" /> 
  7.     <transportConnector name="auto" uri="auto://0.0.0.0:61617?maximumConnections=1000" />     
  8. </transportConnectors> 
  9. ...... 

那么要將哪一個連接方式通過UDP數據報向其他ActiveMQ節點進行公布,就需要在transportConnector標簽上使用discoveryUri屬性進行標識,如下所示:

  1. ......  
  2. <transportConnectors> 
  3.     ......  
  4.     <transportConnector name="ws" uri="ws://0.0.0.0:61614?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/> 
  5.     <transportConnector name="auto" uri="auto+nio://0.0.0.0:61616?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600" discoveryUri="multicast://239.0.0.5" /> 
  6. </transportConnectors> 
  7.  
  8. ......  
  9. <networkConnectors> 
  10.     <networkConnector uri="multicast://239.0.0.5"/> 
  11. </networkConnectors> 
  12. ...... 

2-1-3-3:其他注意事項

關于防火墻:請記得關閉您Linux服務器上對需要公布的IP和端口的限制;

關于hosts路由信息:由于基于組播的動態發現機制,能夠找到的是目標ActiveMQ服務節點的機器名,而不是直接找到的IP。所以請設置當前服務節點的hosts文件,以便當前ActiveMQ節點能夠通過hosts文件中的IP路由關系,得到機器名與IP的映射:

  1.  
  2. # hosts文件  
  3.  
  4. ......  
  5. 192.168.61.139          activemq1  
  6. 192.168.61.138          activemq2  
  7. ...... 

關于哪些協議能夠被用于進行Network Bridges連接:根據筆者以往的使用經驗,只有tcp頭的uri格式(openwire協議)能夠被用于Network Bridges連接;當然您可以使用auto頭,因為其兼容openwire協議;另外,您還可以指定為附加nio頭。

2-1-4、靜態Network Connectors

相比于基于組播發現方式的動態Network Connectors而言,雖然靜態Network Connectors沒有那樣靈活的橫向擴展性,但是卻可以適用于網絡環境受嚴格管理的情況。例如:管理員關閉了交換機/路由器的組播功能、端口受到嚴格管控等等。

配置靜態Network Connectors的ActiveMQ集群的方式也很簡單,只需要更改networkConnectors標簽中的配置即可,而無需關聯改動transportConnectors標簽。但是配置靜態Network Connectors的ActiveMQ集群時,需要注意非常關鍵的細節:每一個節點都要配置其他所有節點的連接位置

為了演示配置過程,我們假設ActiveMQ集群由兩個節點構成,分別是activemq1:192.168.61.138 和 activemq2:192.168.61.139。那么配置情況如下所示:

192.168.61.138:需要配置activemq2的位置信息以便進行連接:

  1. ......  
  2. <transportConnectors> 
  3.     <transportConnector name="auto" uri="auto+nio://0.0.0.0:61616?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600&amp;consumer.prefetchSize=5"/> 
  4. </transportConnectors> 
  5. ......  
  6.  
  7. <!-- 請注意,一定需要192.168.61.139(activemq2)提供了這樣的連接協議和端口 --> 
  8. <networkConnectors> 
  9.     <networkConnector uri="static:(auto+nio://192.168.61.139:61616)"/> 
  10. </networkConnectors> 
  11. ...... 

192.168.61.139:需要配置activemq1的位置信息以便進行連接:

  1. ......  
  2. <transportConnectors> 
  3.     <transportConnector name="auto" uri="auto+nio://0.0.0.0:61616?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600&amp;consumer.prefetchSize=5"/> 
  4. </transportConnectors> 
  5.  
  6. ......  
  7. <!-- 請注意,一定需要192.168.61.138(activemq1)提供了這樣的連接協議和端口 --> 
  8. <networkConnectors> 
  9.    <networkConnector uri="static:(auto+nio://192.168.61.138:61616)"/> 
  10. </networkConnectors> 
  11. ...... 

同理,如果您的ActiveMQ集群規劃中有三個ActiveMQ服務節點,那么任何一個節點都應該配置其它兩個服務節點的連接方式。在配置格式中使用“,”符號進行分割:

  1. ......  
  2. <networkConnectors> 
  3.     <networkConnector uri="static:(tcp://host1:61616,tcp://host2:61616,tcp://..)"/> 
  4. </networkConnectors> 
  5. ...... 

以下是配置完成后可能的效果:

192.168.61.138(activemq1):

架構設計:系統間通信(25)——ActiveMQ集群方案(上)

192.168.61.139(activemq2):

架構設計:系統間通信(25)——ActiveMQ集群方案(上)

2-1-5、其他配置屬性

下表列舉了在networkConnector標簽中還可以使用的屬性以及其意義。請特別注意其中的duplex屬性。如果只從字面意義理解該屬性,則被稱為“雙工模式”;如果該屬性為true,當這個節點使用Network Bridge連接到其它目標節點后,將強制目標也建立Network Bridge進行反向連接。其目的在于讓消息既能發送到目標節點,又可以通過目標節點接受消息,但實際上大多數情況下是沒有必要的,因為目標節點一般都會自行建立連接到本節點。所以,該duplex屬性的默認值為false。

架構設計:系統間通信(25)——ActiveMQ集群方案(上)

架構設計:系統間通信(25)——ActiveMQ集群方案(上)

(責任編輯:6g下載網)

分享到:

------分隔線----------------------------
? 35选7福利彩票