Почему MQTT так сильно замедляется с QoS = 1?
Я пытаюсь написать приложение, управляющее роем роботов по протоколу WiFi и MQTT. Я провел несколько тестов, чтобы измерить, будет ли это достаточно быстро для моего приложения. Я хотел бы иметь контрольный цикл (сообщение, идущее от ПК к роботу и обратно), который занимает в среднем не более 25-30 мс.
Я написал приложение с использованием Java-клиента Paho, которое работает на двух машинах. Когда кто-то получает сообщение по теме1, он публикует в теме2. Тема 2 подписана на второй машине, которая, в свою очередь, публикуется в теме 1.
topic1 topic1
M1---------> broker ---------> M2
topic2 topic2
M1 <-------- broker <--------- M2
Когда все публикации и подписки выполнялись с QoS 0, время цикла составляло в среднем около 12 мс. Однако я хотел бы использовать QoS 1, чтобы гарантировать, что команды, отправляемые роботам, всегда будут достигать пункта назначения. Когда я тестировал время цикла, оно составляло в среднем 250 мс.
Что вызывает так много увеличения во времени? Насколько я понимаю, если нет ошибок передачи, количество обмениваемых пакетов просто удваивается с QoS1 (есть PUBACK, отправленные брокером клиентам для каждого сообщения, см. http://www.hivemq.com/mqtt-essentials-part-6-mqtt-quality-of-service-levels/).
Можно ли как-то сократить это время? Я пробовал брокеров Mosquitto и Apache Apollo, оба повторяли одинаковые результаты.
Редактировать:
Я немного изменил процедуру тестирования. Теперь у меня есть два экземпляра клиентов mqtt, работающих на одной машине. Один как издатель, второй как подписчик. Издатель отправляет 1000 сообщений с интервалами в 10 мс, например:
Client publisher = new Client(url, clientId+"pub", cleanSession, quietMode, userName, password);
Client subscriber = new Client(url, clientId+"sub", cleanSession, quietMode, userName, password);
subscriber.subscribe(pubTopic, qos);
while (counter < 1000) {
Thread.sleep(10,0);
String time = new Timestamp(System.currentTimeMillis()).toString();
publisher.publish(pubTopic, qos, time.getBytes());
counter++;
}
Пока абонент просто ждет сообщений и измеряет время:
public void messageArrived(String topic, MqttMessage message) throws MqttException {
// Called when a message arrives from the server that matches any
// subscription made by the client
Timestamp tRec = new Timestamp(System.currentTimeMillis());
String timeSent = new String(message.getPayload());
Timestamp tSent = Timestamp.valueOf(timeSent);
long diff = tRec.getTime() - tSent.getTime();
sum += diff;
counter++;
if (counter == 1000) {
double avg = sum / 1000.0;
System.out.println("avg time: " + avg);
}
}
Брокер (mosquitto с конфигурацией по умолчанию), работает на отдельной машине в той же локальной сети. Результаты, которых я достиг, еще более странные, чем раньше. Теперь для получения сообщения с QoS 1 для подписчика требуется приблизительно 8-9 мс. С QoS 2 это около 20 мс. Однако с QoS 0 я получаю среднее значение. время от 100 до 250 мс! Я предполагаю, что ошибка где-то в моем методе тестирования, но я не могу видеть, где.
2 ответа
Сообщения QoS 0 не обязательно должны сохраняться - они могут храниться полностью в памяти.
Чтобы обеспечить доставку QoS 1 (и QoS 2), сообщения должны быть сохранены в некоторой форме. Это добавляет дополнительное время обработки к сообщениям по сравнению с простым временем передачи по сети.
Смысл двух совершенно разных реализаций брокера, показывающих одинаковые результаты, может заключаться в том, что клиентская часть кода тратит время на ответ с помощью пакета ack.
Вы делаете всю обработку входящего метода в обратном вызове onMessage? Если это так, эта работа будет выполняться в том же потоке, что и вся обработка протокола MQTT, которая может задержать ответ. Для обработки большого объема / высокой скорости сообщения обычно используется шаблон, который использует только обратный вызов onMessage, чтобы поставить в очередь входящее сообщение, чтобы другой поток действительно обработал его.