(前提: 已經搭建了 三個磁盤節點的鏡像集羣)
完整的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.....
有任何問題,直接評論,時不時會看的。