背景:当我们的设备更新完成,大量的设备重新连接到EMQ,导致EMQ 的cpu直接到100%,此时
错误日志:
info日志
在上述两张日志中,可以发现我publish消息时,错误日志为“客户端未连接”,但是在下面的info中,却发现在2毫秒后,仍然又receiver,那么客户端应该连接了。
背景:
那么真正的问题是,短时间内大量client连接到EMQ,导致EMQ的cpu达到100%,是的EMQ与我的服务器断开连接,服务器走断开重连,却一直没有走完client 连接 broker 的整个连接,所以我的服务器陷入了一直等待。
bug原因
先修知识:
心跳机制:
keep Alive 指定连接最大空闲时间T,当客户端检测道连接空闲时间超过T时,必须向Borker发送心跳报文PINGREQ, Broker收到心跳请求后返回心跳响应PINGRESP.若Broker超过1.5T时间没手法哦心跳请求则断开连接,并且投递遗嘱消息到订阅者,同样,若客户端超过一定时间仍没有收到心跳响应PINGRESP则断开连接。
(一)、为什么在EMQ压力大的时候,client 会与EMQ 断开连接??
EMQ与我的服务器有一个心跳机制,通过这个心跳机制来检测client与broker是否正常连接,在一定时间内心跳检测失败,则断开连接。EMQ因为cpu到大100%,消息处理不了,则对服务器的心跳PINGREQ,一直没有PINGRESP 回复,则EMQ提出client,服务器断开重连。
MQTT底层源码解析
1. mqtt 源码底层有一个心跳协议,起了一个pingTask的任务一直检测心跳活性
private class PingTask extends TimerTask {
private static final String methodName = "PingTask.run";
public void run() {
//@Trace 660=Check schedule at {0}
log.fine(CLASS_NAME, methodName, "660", new Object[]{Long.valueOf(System.nanoTime())});
comms.checkForActivity(); //检测心跳活性
}
}
2.通过心跳协议,检测当前客户端活性
public MqttToken checkForActivity(){
return this.checkForActivity(null);
}
public MqttToken checkForActivity(IMqttActionListener pingCallback){
MqttToken token = null;
try{
token = clientState.checkForActivity(pingCallback); //检测心跳超时等待
}catch(MqttException e){
handleRunException(e);
}catch(Exception e){
handleRunException(e);
}
return token;
}
3检测心跳超时等待
long nextPingTime = this.keepAlive;
if (connected && this.keepAlive > 0) {
long time = System.nanoTime();
int delta = 100000;
synchronized (pingOutstandingLock) {
if (pingOutstanding > 0 && (time - lastInboundActivity >= keepAlive + delta)) {
ExceptionHelper.createMqttException(MqttException.REASON_CODE_CLIENT_TIMEOUT);
}
(二)、为什么我们的服务器会在重连EMQ时,一直卡在Connect??
MQTT客户端与EMQ主机连接过程如图所示: