具體錯誤信息:
2018-05-04 11:21:48.116 ERROR 60848 --- [.168.0.202:8001] o.s.a.r.c.CachingConnectionFactory : Channel shutdown: connection error
2018-05-04 11:21:48.116 ERROR 60848 --- [.168.0.202:8001] o.s.a.r.c.CachingConnectionFactory : Channel shutdown: connection error
2018-05-04 11:21:48.125 INFO 60848 --- [nge.consumer1-8] o.s.a.r.l.SimpleMessageListenerContainer : Restarting Consumer@5196e177: tags=[{amq.ctag-d_wIlZIGxM3f0fsxkmYQfA=my_test_exchange.consumer1}], channel=Cached Rabbit Channel: AMQChannel(amqp://admin@192.168.0.202:8001/,1), conn: Proxy@25a73de1 Shared Rabbit Connection: SimpleConnection@25fca927 [delegate=amqp://admin@192.168.0.202:8001/, localPort= 56258], acknowledgeMode=AUTO local queue size=0
2018-05-04 11:21:48.126 INFO 60848 --- [nge.consumer1-9] o.s.a.r.c.CachingConnectionFactory : Attempting to connect to: [manager1:8001]
2018-05-04 11:21:48.393 INFO 60848 --- [nge.consumer1-9] o.s.a.r.c.CachingConnectionFactory : Created new connection: rabbitConnectionFactory#2b8bd14b:12/SimpleConnection@3fb9795a [delegate=amqp://admin@192.168.0.202:8001/, localPort= 56260]
2018-05-04 11:21:49.059 INFO 60848 --- [nge.consumer1-8] o.s.a.r.l.SimpleMessageListenerContainer : Restarting Consumer@58b42519: tags=[{amq.ctag-T1HyrOd5Ykr_VQZDwxRslA=stream_exchange.consumer1}], channel=Cached Rabbit Channel: AMQChannel(amqp://admin@192.168.0.202:8001/,2), conn: Proxy@25a73de1 Shared Rabbit Connection: SimpleConnection@3fb9795a [delegate=amqp://admin@192.168.0.202:8001/, localPort= 56260], acknowledgeMode=AUTO local queue size=0
Spring Boot 配置 RabbitMQ(使用 HAProxy 負載均衡):
spring:
application:
name: stream-rabbitmq-producer
rabbitmq:
host: manager1
port: 8001
username: admin
password: admin123456
最近使用 RabbitMQ 集群的時候(HAProxy 負載均衡),頻繁的出現上面錯誤信息,但是消息可以正常被消費掉,如果只使用單機版 RabbitMQ 的話(不使用 HAProxy),是沒有任何錯誤的。
被這個問題困擾了很久,Google 找了很多資料,也沒有找到解決方案,無意間找到一篇文章:RabbitMQ and HAProxy: a timeout issue
文章說,如果使用 HAProxy 配置 RabbitMQ 高可用集群的話,則會遇到客戶端連接超時問題。
為什么會出現此問題呢?因為 HAProxy 配置了客戶端連接超時參數(timeout client ms
),如果客戶端連接超過配置的此參數,那么 HAProxy 將會刪除這個客戶端連接。
RabbitMQ 客戶端使用永久連接到代理,從不超時,那為什么還會出現問題?因為如果 RabbitMQ 在一段時間內處於非活動狀態,那么 HAProxy 將自動關閉連接(有點坑呀😂)。
那如何解決這個問題呢?我們看到 HAProxy 提供了一個clitcpka
參數配置,它可以從客戶端發送TCP keepalive
數據包。
我們就使用它,但發現配置了之后,還是出現了上面的問題。
為什么呢?
[…]the exact behaviour of tcp keep-alive is determined by the underlying OS/Kernel configuration[…]
什么意思?意思就是TCP keepalive
數據包的發送,取決於操作系統/內核配置。
我們可以使用命令查看(HAProxy 所在服務器中的tcp_keepalive_time
配置):
[root@manager1 ~]# cat /proc/sys/net/ipv4/tcp_keepalive_time
7200
tcp_keepalive_time
默認配置時間 2 個小時,表示發送TCP keepalive
數據包的間隔時間是 2 個小時,或者說每隔 2 個小時發送TCP keepalive
數據包。
這么說就清楚了吧,雖然我們在 HAProxy 中,配置了clitcpka
參數,但因為系統發送TCP keepalive
數據包的間隔時間過長,遠遠超過 HAProxy 中的 timeout client
超時時間(默認好像是 2 秒),所以客戶端連接每隔 2 秒,就被 HAProxy 無情的給刪除掉,然后不斷的被重建。
說了那么多,我們該怎么解決此問題呢?
兩種方案:
- 修改系統的
tcp_keepalive_time
配置,間隔時間低於 HAProxy 配置的timeout client
超時時間(因為有可能影響其他系統服務,不推薦)。 - 修改 HAProxy 中的
timeout client
超時時間,配置大於系統的tcp_keepalive_time
間隔時間(推薦)
因為系統tcp_keepalive_time
發送TCP keepalive
數據包間隔時間是 2 個小時,所以,我們將 HAProxy 中的timeout client
超時時間,設置為 3 個小時:
timeout client 3h
timeout server 3h
完整示例配置:
[root@manager1 ~]# cat /etc/haproxy/haproxy.cfg
global
log 127.0.0.1 local0 info
global
log 127.0.0.1 local1 notice
daemon
global
maxconn 4096
defaults
log global
mode tcp
option tcplog
option dontlognull
retries 3
option abortonclose
maxconn 4096
timeout connect 5000ms
timeout client 3000ms
global
timeout server 3000ms
balance roundrobin
listen private_monitoring
bind 0.0.0.0:8000
mode http
option httplog
stats refresh 5s
stats uri /stats
stats realm Haproxy
stats auth admin:admin
listen rabbitmq_admin
bind 0.0.0.0:8002
server manager1 manager1:15672
server manager2 manager2:15672
server manager3 manager3:15672
listen rabbitmq_cluster
bind 0.0.0.0:8001
mode tcp
option tcplog
balance roundrobin
timeout client 3h
timeout server 3h
server manager1 manager1:5672 check inter 5000 rise 2 fall 3
server manager2 manager2:5672 check inter 5000 rise 2 fall 3
server manager3 manager3:5672 check inter 5000 rise 2 fall 3
重新運行 HAProxy,然后 RabbitMQ 測試成功: