【MQ】RabbitMQ 集羣高可用(四)

(前提: 已經搭建了 三個磁盤節點的鏡像集羣)

完整的RabbitMQ鏡像集羣 + HA Proxy + keepalived 搭建過程:

1. 鏡像集羣 + HA Proxy:

1.1 結構圖:

1.2 在 10.20.61.135 安裝 HA Proxy:

yum -y install haproxy  #使用 yum 安裝,簡單省心


vim /etc/haproxy/haproxy.cfg # 修改配置文件,默認路徑 /etc/haproxy/

1.3 修改配置:配置文件原有內容不用修改,在文件最後添加:

#######################HAproxy監控頁面#########################
listen http_front                   
        bind *:1080                 #監聽端口
        stats refresh 30s           #統計頁面自動刷新時間
        stats uri /                 #統計頁面url
        stats realm Haproxy Manager #統計頁面密碼框上提示文本
        stats auth guest:guest      #統計頁面用戶名和密碼設置
        stats hide-version          #隱藏統計頁面上HAProxy的版本信息

#####################RabbitMQ服務代理###########################################
listen rabbitmq_cluster *:5673
    mode tcp
    stats enable
    balance roundrobin
    option tcpka
    option tcplog
    timeout client 3h
    timeout server 3h
    timeout connect 3h
    #balance url_param userid
    #balance url_param session_id check_post 64
    #balance hdr(User-Agent)
    #balance hdr(host)
    #balance hdr(Host) use_domain_only
    #balance rdp-cookie
    #balance leastconn
    #balance source //ip
    server   rabbit_ca 10.20.83.245:5672 check inter 5s rise 2 fall 3      # check inter 2000 是檢測心跳頻率,
    server   rabbit_bogon 10.20.61.135:5672 check inter 5s rise 2 fall 3   # rise 2是2次正確認爲服務器可用,
    server   tabbit_jy_157 10.20.61.157:5672 check inter 5s rise 2 fall 3  # fall 3是3次失敗認爲服務器不可用

需要把 listen rabbitmq_cluster 內容中的 server 修改爲 你自己的地址。

1.4 啓動HAProxy :

service haproxy start  # CentOS 6

systemctl start haproxy  # CentOS 7

啓動成功,可以通過 ip + 1080 訪問監控服務:

2. 鏡像集羣 + 2 * HA Proxy:

2.1 結構圖:

2.2  在 10.20.61.157 上安裝 HA Proxy ,與 2.1 完全一致,

2.3 修改配置,配置信息與 1.3 完全一致,

2.4 啓動服務,與 1.4 完全一致,

啓動之後,通過 10.20.61.157:1080  和 10.20.61.135:1080 瀏覽器訪問,能看到同樣的頁面:

3.  鏡像集羣 +  2 * HA Proxy +  2 * KeepAlived :

3.1 結構圖:

3.1 在 10.20.61.135 和 10.20.61.157 上安裝 Keepalived :


yum install keepalived  # yum 安裝keepalived

3.2 修改配置:配置文件在  /etc/keepalived/

10.20.61.135 的 配置文件:

! Configuration File for keepalived

global_defs {
   notification_email {
	 [email protected]
   }
}

# 集羣資源監控,組合track_script進行
vrrp_script check_haproxy {
	script "killall -0 haproxy"
	interval 2
}

vrrp_instance HAPROXY_HA {
	state MASTER                  # Master  BackUp
	interface eth0
	virtual_router_id 135         # 兩個服務保持一致
	unicast_src_ip 10.20.61.135   # 順序相反
	unicast_peer {
		10.20.61.157
	}
	priority 100                  # 優先級高的爲 Master
	advert_int 2
	# 設置主備節點間的通信驗證類型及密碼,同一個VRRP實例中需一致
	authentication {
		auth_type PASS
		auth_pass 1234
	}
	track_script {
		check_haproxy
	}
	virtual_ipaddress {
		10.20.61.158  #虛擬ip配置完之後就用它訪問
	}
}

10.20.61.157的配置文件:

! Configuration File for keepalived

global_defs {
   notification_email {
	 [email protected]
   }
}
# 集羣資源監控,組合track_script進行
vrrp_script check_haproxy {
	script "killall -0 haproxy"
	interval 2
}
vrrp_instance HAPROXY_HA {
	state BACKUP
	interface eth0
	virtual_router_id 135
	unicast_src_ip 10.20.61.157
	unicast_peer {
		10.20.61.135
	}
	priority 80
	advert_int 2
	# 設置主備節點間的通信驗證類型及密碼,同一個VRRP實例中需一致
	authentication {
		auth_type PASS
		auth_pass 1234
	}
	track_script {
		check_haproxy
	}
	virtual_ipaddress {
		10.20.61.158  #虛擬ip配置完之後就用它訪問
	}
}

配置完成,啓動服務,(前提是 三個 ribbitMQ 已啓動,兩個 HAproxy 已啓動)

service keepalived start    # CentOS 6

systemctl start keepalived  # CentOS 7

啓動之後,通過 ip addr 查看 10.20.61.135 的ip信息:(不要用 ifconfig ,看不到的)

在 10.20.61.135 的 Master 機器上:(可以看到 eth0 網卡上的 10.20.61.158 虛地址就是 配置文件的虛地址)

在10.20.61.157 的 BackUp 的機器上看:(沒有 158 的IP綁定)

在 10.20.61.135 的Master機器上 停止 keepalived 服務,觀察 IP 漂移:(再次啓動Master會搶佔 VIP ,因爲優先級高)

在 BakcUp 的機器查看 IP : (發現 158 的 ip 漂移到 157 的機器上)

因爲 Master 的 keepalived 服務停止了,所以生成的 VIP 發生 IP 漂移,轉移到 BackUp 的機器上,(原理應該是 157 去訪問了 135的服務,發現不通了,所以就主動綁定了 VIP (10.20.61.158))。

到這裏: 3 * rabbitMQ  + 2 * HAProxy  + 2 * keepalived 全部啓動成功了。

這個結構不太正確的,正常的結構應該是  3個 rabbitMQ 在三臺不同 ip的機器上。所以應該用 5 臺機器。

三臺機器每臺運行一個 rabbitMQ , 剩下的兩臺機器 每臺都是 HAProxy + keepalived 的結構。

 

通過瀏覽器訪問 rabbitMQ 和 HAProxy 的端口,測試所有的服務是不是都正常運行。

最後通過 client 代碼訪問 VIP的方式,訪問到 RabbitMQ服務:

附上一份 簡單的 Java 代碼:

生產者:

package test.RabbitMQ;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;

/***
 * @ClassName: Producer1
 */
public class Test_rabbitMQ_p {

	private static int size = 1000;
	private static final String Queue = "test";
	private static String message = "hello maxchen";
	private static Channel channel;

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		ExecutorService es = Executors.newFixedThreadPool(10);
		final CountDownLatch cdl = new CountDownLatch(size);
		init_connection();
		for (int a = 0; a < size; a++) {
			es.execute(new Runnable() {
				public void run() {
					try {
						sendMessage();
					} catch (Exception e) {
						e.printStackTrace();
					}
					cdl.countDown();
				}
			});
		}
		cdl.await();
		es.shutdown();
		long time = System.currentTimeMillis() - start;
		System.out.println("插入" + size + "條JSON,共消耗:" + (double) time / 1000 + " s");
		System.out.println("平均:" + size / ((double) time / 1000) + " 條/秒");
	}

	public static void init_connection() throws Exception {
		ConnectionFactory connectionFactory = new ConnectionFactory();
		//connectionFactory.setHost("10.20.83.245");
		connectionFactory.setHost("10.20.61.158");
		connectionFactory.setPort(5673);
		//connectionFactory.setUsername("guest");
		//connectionFactory.setPassword("guest");
		connectionFactory.setVirtualHost("/");
		
		Connection connection = null;
		connection = connectionFactory.newConnection();
		
		channel = connection.createChannel();
		Map<String,Object> map = new HashMap<String, Object>();
		map.put("x-ha-policy", "all");
		
		channel.queueDeclare(Queue, true, false, false, map); // queue  持久化
		channel.confirmSelect();
		
		// 添加一個確認監聽
        channel.addConfirmListener(new ConfirmListener() {
            public void handleAck(long deliveryTag, boolean multiple) {
            }
            public void handleNack(long deliveryTag, boolean multiple) {
            	 System.err.println(deliveryTag);
                 System.err.println("-------no ack!-----------");
            }
        });
	}

	public static void sendMessage() throws Exception {

		channel.basicPublish("", Queue, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes()); // 消息持久化
		//channel.basicPublish("", Queue, null, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
	}

	public static void addConfirmListener(Channel channel) {
		
	}
	
}

消費者:

package test.RabbitMQ;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

public class Test_rabbitMQ_c {

	private static int size = 400000;
	private static final String Queue = "test";
	private static Channel channel;
	private static Consumer consumer;

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		ExecutorService es = Executors.newFixedThreadPool(10);
		final CountDownLatch cdl = new CountDownLatch(size);
		init_connection();
		for (int a = 0; a < size; a++) {
			es.execute(new Runnable() {
				public void run() {
					try {
						receiver_Message();
					} catch (Exception e) {
						e.printStackTrace();
					}
					cdl.countDown();
				}
			});
		}
		cdl.await();
		es.shutdown();
		long time = System.currentTimeMillis() - start;
		System.out.println("插入" + size + "條JSON,共消耗:" + (double) time / 1000 + " s");
		System.out.println("平均:" + size / ((double) time / 1000) + " 條/秒");
	}

	public static void init_connection() throws Exception {
		ConnectionFactory connectionFactory = new ConnectionFactory();
		connectionFactory.setHost("10.20.61.157");
		//connectionFactory.setHost("10.20.61.135");
		connectionFactory.setPort(5672);
		//connectionFactory.setUsername("guest");
		//connectionFactory.setPassword("guest");
		connectionFactory.setVirtualHost("/");
		
		Connection connection = null;
		connection = connectionFactory.newConnection();
		
		channel = connection.createChannel();
		channel.queueDeclare(Queue, true, false, false, null); // queue  持久化 
		channel.confirmSelect();
		
		consumer = new DefaultConsumer(channel) {
			@Override
			public void handleDelivery(String consumerTag, Envelope envelope, 
							AMQP.BasicProperties properties, byte[] body) throws IOException {
				//System.out.println("recv message: " + new String(body));
				channel.basicAck(envelope.getDeliveryTag(), false);
			}
		};
	}
	public static void receiver_Message() throws Exception {

		channel.basicConsume(Queue, consumer);
		
	}

	public static void addConfirmListener(Channel channel) {
		
	}
	
}

訪問前的 RabbiMQ隊列:

生產者通過 訪問 VIP地址 : 10.20.61.158 訪問 RabbitMQ  服務:

再看RabbitMQ:

 

over.....

 

有任何問題,直接評論,時不時會看的。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章