最近研究 JAVA 集羣技術,看到 jgroups 這個框架,網上有些例子,很是簡單。
能夠參考其官方網址:http://www.jgroups.org/manual/index.html
按捺不住,本身仍是動手寫了一個試試。代碼以下:
html
1 import org.jgroups.JChannel; 2 import org.jgroups.Message; 3 import org.jgroups.ReceiverAdapter; 4 import org.jgroups.View; 5 import org.jgroups.stack.GossipRouter; 6 7 import java.io.BufferedReader; 8 import java.io.InputStreamReader; 9 10 /** 11 * JGroups 測試 12 * 13 * @author hjj2017 14 * @since 2016/1/14 15 * 16 */ 17 public class HelloJGroups extends ReceiverAdapter { // <-- 注意這裏, HelloJGroups 便是消息的發送者又是消息的接收者 18 /** 用戶名稱 */ 19 private String _userName = null; 20 /** JChannel */ 21 private JChannel _channel = null; 22 23 /** 24 * 開始測試 25 * 26 * @throws Exception 27 * 28 */ 29 private void start() throws Exception { 30 // 在這裏生成用戶名, User.00 31 this._userName = "User." + (int)(Math.random() * 100); 32 33 // 建立 JChannel 34 this._channel = new JChannel(); 35 this._channel.setReceiver(this); 36 this._channel.connect("ChatCluster"); 37 38 // 事件循環 39 this.eventLoop(); 40 41 // 事件循環結束以後, 42 // 關閉 JChannel 43 this._channel.close(); 44 } 45 46 /** 47 * 事件循環, 從終端讀取文字 48 * 49 */ 50 private void eventLoop() { 51 // 建立讀入流 52 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 53 54 while (true) { 55 try { 56 // 輸出提示符 57 System.out.print("~> "); 58 System.out.flush(); 59 60 // 從終端讀取文字 61 String ln = br.readLine(); 62 63 if (ln.equalsIgnoreCase("quit") || 64 ln.equalsIgnoreCase("exit")) { 65 // 遇到 quit / exit 時, 66 // 退出當前循環 67 break; 68 } 69 70 // 建立併發送消息, 71 // 消息內容是 "${userName} : ${ln}" 72 Message msg = new Message(null, null, this._userName + " : " + ln); 73 this._channel.send(msg); 74 } catch (Exception ex) { 75 // 輸出錯誤日誌 76 ex.printStackTrace(); 77 } 78 } 79 } 80 81 @Override 82 public void viewAccepted(View v) { 83 System.out.println("viewAccepted : " + v); 84 } 85 86 @Override 87 public void receive(Message msg) { 88 System.out.println(msg.getObject()); 89 } 90 91 /** 92 * 應用程序主函數 93 * 94 * @param args 95 * @throws Exception 96 * 97 */ 98 public static void main(String[] args) throws Exception { 99 new HelloJGroups().start(); 100 } 101 }
這事一個簡單的聊天程序,能夠啓動兩次來觀察結果。
java
------------------------------------------------------------------- GMS: address=WINX-HOME-50829, cluster=ChatCluster, physical address=192.168.1.2:52477 ------------------------------------------------------------------- viewAccepted : [WINX-HOME-50829|0] [WINX-HOME-50829] ~> ------------------------------------------------------------------- GMS: address=WINX-HOME-1927, cluster=ChatCluster, physical address=192.168.1.2:59569 ------------------------------------------------------------------- viewAccepted : [WINX-HOME-50829|1] [WINX-HOME-50829, WINX-HOME-1927] ~>
能夠看到,第二個啓動的「WINX-HOME-1927」發現了第一個啓動的「WINX-HOME-50829」。
注意我是在本地測試的,這個程序啓動時會臨時綁定一個端口。
啓動兩次,綁定兩個不一樣的端口,會話過程是在同一臺機器上的兩個不一樣端口之間進行的。
程序啓動以後,這兩個程序會互相發現對方,這是這個框架一個比較方便的地方。
若是是在同一局域網裏的兩臺不一樣的機器上會是什麼結果呢?
我在家裏的兩臺 PC 機上測試過,兩臺 PC 的 IP 地址不相同(192.168.1.2 和 192.168.1.6),
啓動後仍然能夠發現對方!
固然,這裏面有個前提,兩臺機器鏈接着同一臺路由器。
在真實的服務器環境中,全部的服務器都鏈接同一臺路由器是不可能的!
爲此,咱們能夠啓動 GossipRouter,令全部的 JGroups 程序都鏈接到這個 GossipRouter 上。
咱們大概須要作如下 3 步:
1. 啓動 GossipRouter,綁定了 12001 端口:
java -Djava.net.preferIPv4Stack=true -cp .:commons-logging-1.1.3.jar:log4j-1.2.17.jar:jgroups-2.9.0.GA.jar org.jgroups.stack.GossipRouter -port 12001
2. 建立 myConf.xml 文件,文件內容大體以下:
緩存
1 <?xml version="1.0" encoding="utf-8" ?> 2 <config xmlns="urn:org:jgroups" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/jgroups.xsd"> 5 6 <TCP /> 7 <!--// 我試驗過 TCPPING,可是失敗了 //--> 8 <TCPGOSSIP 9 timeout="3000" 10 initial_hosts="xxx.xxx.xxx.xxx[12001]" <-- 注意這裏的 xxx.xxx.xxx.xxx 須要換成真實 IP 11 num_initial_members="3" 12 /> 13 <VERIFY_SUSPECT timeout="1500" /> 14 <pbcast.NAKACK 15 use_mcast_xmit="false" 16 retransmit_timeout="300,600,1200,2400,4800" 17 discard_delivered_msgs="true" 18 /> 19 <pbcast.STABLE 20 stability_delay="1000" 21 desired_avg_gossip="50000" 22 max_bytes="400000" 23 /> 24 <pbcast.GMS 25 print_local_addr="true" 26 join_timeout="5000" 27 view_bundling="true" 28 /> 29 30 </config>
3. 修改 JChannel 建立代碼,這是最後一步服務器
// 只能使用文件絕對路徑, // 使用相對路徑, JChannel 會產生歧義 final String xmlAbsPath = ClassLoader.getSystemResource(".").getPath() + "myConf.xml"; this._channel = new JChannel(xmlAbsPath);
關於 JGroups,目前我沒有進行「大消息包」和「大集羣量」的測試,還沒法肯定其性能表現。
若是性能方面表現良好,JGroups 放在遊戲項目中,實現跨服聊天、跨服 PK 及分佈式緩存,仍是至關容易的。
併發