• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

WEB сервер на ESP32 с данными на SD

pvvx

Активный участник сообщества
Добрый день, получается из выше перечисленных самый стабильный RTL8711AM модуль? Что посоветуете для Web сервера из модулей (максимально стабильного).
Тут сложно что либо указать, т.к. очень много зависимостей.
Этот тест на скорость при максимальной загрузке, чего у них не бывает в реальной эксплуатации.
Но и при одиночных запросах распределение модулей по "скорости" остается той-же.

RTL8711AM быстрее за счет того, что у него код выполняется из SRAM и у него для TCP стека и прочего есть где разгуляться - RAM (SRAM+DDRAM) у него 2.5 МБайта.
RTL8710BN медленнее почти в 2 раза, хотя для данного теста RAM ему достаточно, но код у него выполняется из SPI-Flash через систему отображения её в память через "кеш" (как у ESP).
Далее в тесте идут модули с Linux. Там исполняемого кода на 95% больше и ресурсоемкость запроса файла больше... Весь код исполняется из RAM и от её скорости зависит общая скорость.

Ранее вы писали "Каждое чтение SPIFFS - опустошение программной "кеш"", подскажите как бороться с опустошением кеш, если небольшой сайт записан в область SPIFFS и волей-неволей приходится к ней обращаться?
Ничего вы не сделаете, если у задачи код вылезает за рамки "кеш" подсистемы отображения SPI-Flash в адресное пространство CPU. Если ещё и данные берутся от туда, то "кеш" почти не работает и производительность CPU падает как если бы он работал на 8..10 MHz (на оба ядра!).
Надежность (кол-во ошибок) определяется объемом кода. Чтобы достигнуть нормальной производительности и надежности в задаче малого web на ESP32 потребуется переписать (оптимизировать) всю SDK с нуля и обязательно выкинуть тормозной SPIFFS. Но на такие действия никто не пойдет, т.к. архитектура у обоих ESP неудачная для web.
SPIFFS создан не для скорости, а для минимального использования RAM за счет большого программного кода (замедления исполнения)... Размен объема RAM на скорость (на размер кода)...
 

pvvx

Активный участник сообщества
Подсчитайте объем исполняемого кода в Arduino на одиночный запрос файла. В нем участвует драйвер WiFi, стек TCP Lwip, части библиотеки Arduino c либой “web”, код SPIFFS, код RTOS. Этот объем больше чем имеющийся “кеш” в IRAM у ESP. В итоге, при множественных запросах скорость обработки проседает во много раз и CPU не в состоянии полноценно обрабатывать WiFi и вся дурь двух ядер еле успевает отрабатывать переключение задач и прочие семафоры в RTOS. В итоге все буфера переполняются и связь падает. Никто не рассчитывал RTOS на ESP32 при условии что CPU при загрузке работает на 10MHz. На такой производительности он еле успевает отрабатывать тики таймера переключения задач в RTOS. На остальное у CPU не хватает производительности.

И это критический режим, т.е. тут любая ошибка или неверное распределение приоритетов в подзадачах сразу вылезет в обвал системы. Что вы и наблюдаете.
 

pvvx

Активный участник сообщества
Элементарный пример с подтверждения WDT в процессе IDLE. Если у CPU в RTOS нет свободного времени – исполняются более приоритетные потоки, то процесс IDLE не вызовется пока идет такая загрузка. Следовательно сработает WDT и система перезагрузится.
 

pvvx

Активный участник сообщества
Я не делал тестов работоспособности WiFi системы Arduino ESP32 в зависимости от CLK CPU, но делал такой тест на RTL871x. Там проще переключить CLK CPU на ходу и нет зависимостей от скорости работы SPI Flash, а код с RTOS примерно одинаков.

В итого – при 12 MHz WiFi становится неработоспособным. Т.е. соединение ещё как-то держит, но при запросах-ответах возможно “отваливание” от AP и прочие нестабильности. Не успевает, т.к. вся производительность CPU уходит на обработку RTOS. Процессы соединения отваливаются по таймаутам… Но на норме – 166 MHz процессы (код) RTOS в реальных задачах отъедают не более 15% производительности (при большой загрузке), что компенсируется наличием “многозадачности”...

В итоге, вся реклама о производительном CPU в ESP32 есть чистый пиар обман. В реальности на нем чем больше загрузка, тем медленнее работает. С потреблением та-же история – растет при падении производительности. Это такая ‘фича’ его архитектуры во имя дешевизны. Забудьте о каких-то реальных задачах на ESP32…

ESP8266 его перегоняет в простых задачах. Т.к. для решения тех-же задач RTOS + стеки и семафоры на 2 ядра требуют более четырехкратного увеличения объема RAM (как и увеличения кода). А этого в SoC ESP32 не наблюдается.
 

nikolz

Well-known member
не совсем по теме, но для сравнения производительности.
делал сервер на одноядерном процессоре и тестил скорость и загрузку канала
TCP загружает канал в 2 раза больше, чем UDP
на UDP получил скорость 60 тысяч соединений в секунду.
ограничение было связано с каналом связи а не с процессором.
 

sharikov

Active member
Тесты веб сервера
chmorgan/esphttpd-freertos

В архиве собранный бинарник (CPU: 240MHz FLASH: 80MHz_QIO SDK: 4.0), Jmeter test plan и результаты тестирвания.
Больше 7 потоков не тянет - валится lwip.

Разъяснение по результатам:
testcgi - генерирует псевдослучайный ответ без обращения к флэш. Показывает скорость работы сервера и tcp стека без вклада ФС.
3 small files - запрос одновременно трех разных маленьких файлов в два потока. Выполнен как с компрессией так и без (как выяснилось компрессия heatshrink не влияет на скорость).
Large file - запрос большого файла (jpeg картинка) в 7 потоков. Показывает влияние чтения espfs.

Из сравнения testcgi 14000 bytes 7 thread и Large file 7 threads видно что чтение espfs не замедляет вообще (немного быстрее потому что улучшилась связь с AP в этот момент).

---
Еще пробовал examples/protocols/http_server/file_serving
Там все совсем-совсем печально. SPIFFS это ужас.
 

Вложения

pvvx

Активный участник сообщества
Больше 7 потоков не тянет - валится lwip.
Lwip то тут при чем? Что у него то падает?
Ограничения по кол-ву соединений в Lwip нет. Он типа 'однопоточный' - один тред на обработку событий.
Если код пользователя успевает отрабатывать события до переполнения входных буферов (низкоуровневых от драйвера WiFi к LwIP), то ограничений и нет.
Разъяснение по результатам:
Где там счет ошибок в %? Типа сколько соединений неудачных. Или все удачные? (такие установки теста)

А по цифрам в итого всё нормально. На *nix задержки гораздо хуже при тех-же уровнях CLK ядер.
 

pvvx

Активный участник сообщества
@sharikov
Lwip работает примерно так – у него есть входной поток пакетов. Ему почти без разницы сколько там соединений уровня HTTP. Есть тред, который смотрит - пришел пакет на открытый порт – он вызвал назначенный на нем калбак. Калбак отработал – тред ждет следующее событие. Всё. Если калбаки выполняются дольше, чем поступают входные пакеты -> входной буфер у Lwip занят и переполняются буфера WiFi (обычно пакет откидывается).

Конечно всё не так примитивно, т.к. Lwip тянет ещё TCP стек, но там ограничения по объему выделенной ему RAM. И если HTTP сессия не Keep Alive, то и проблем нет. По этому, в своей web-свалке для малых SoC, я не использую Keep Alive.

У ESP32 писателей ограничено кол-во открытых TCP соединений, а не кол-во поступивших пакетов. Например, до 7-ми. По этому, если открыли 7 соединений, то 8-ому будет ответ – пошел подальше, т.е. закрыть TCP соединение… Им видимо сложно выделить динамический буфер на соединения и открытые файлы с ограничением по остатку свободной памяти. Типа лучше статически сразу выесть эту память :)

У *nix с памятью проблем нет - там запросы на обработку накапливаются под нагрузкой увеличивается время до ответа.
 

sharikov

Active member
Lwip то тут при чем? Что у него то падает?
Ограничения по кол-ву соединений в Lwip нет.
Ограничения на количество соединений в lwip esp-idf есть. Если превысить - валится на каком то assert внутри lwip. Возможно перестанет если поменять cpu affinity а может баг. текущий SDK 4.1 из git вообще неработоспособен: в режиме Station при наличии трафика регулярно падает через 39-45 сек даже если это ping.

Где там счет ошибок в %? Типа сколько соединений неудачных. Или все удачные? (такие установки теста)
Ноль ошибок. Я этот столбец выкинул чтобы не загружать таблицу. В csv файлах есть.


А по цифрам в итого всё нормально. На *nix задержки гораздо хуже при тех-же уровнях CLK ядер.
nginx на arm926 300MHz я тоже проверил. на коротких файлах около 180 запросов / сек а на длинных он всех уделывает и загружает ethernet по полной.
 

pvvx

Активный участник сообщества
Эксплорер всегда открывает одно соединение с Keep Alive, которое не закрывается и в него не идут никакие запросы. Это типа контроля соединения с сервером. Для обработки эксплорер открывает другие соединения. И так, если у вас 2 пользователя, то будет вечно открыто 2 ненужных соединения, пока не закроете все страницы в эксплорере. В момент открытия-загрузки страницы эксплорер создаст ещё столько соединений, сколько вызовов внешних ресурсов на этой странице по мере обработки.

7 соединений – это минимум для отработки одной HTML страницы школьника, в которую он напихал десяток сторонних вызовов картинок и прочей лабуды. Без Keep Alive это выразиться в открытии до 5-ти соединений одновременно и последовательном последующем открытии-закрытии дополнительных соединений… Скорость обработки эксплорером низкая – десятки мс и по мере обработки соединения успевают отдать контекст и закрыться, что не вызывает обвала. И пофиг сколько клиентов, если запросы распределены по времени и сокеты успевают открываться-закрываться. При Keep Alive – всё гораздо хуже – увеличивается кол-во одновременно постоянно открытых соединений и уже 3-му пользователю, при ограничении в 7-мь, вылезет страница с ошибками (неподгрузками какого контекста). О чем и пишут счастливые обладатели Arduino на ESP32 :)
 

pvvx

Активный участник сообщества
Ограничения на количество соединений в lwip esp-idf есть. Если превысить - валится на каком то assert внутри lwip. Возможно перестанет если поменять cpu affinity а может баг. текущий SDK 4.1 из git вообще неработоспособен: в режиме Station при наличии трафика регулярно падает через 39-45 сек даже если это ping.
Это явно баги (скорее всего в реализации socket). Ограничения только по TCP стек - пока идет набор окна... Т.е. сказывается от времени ping и на освобождении буферов стека - на реализации алгоритмов отработки калбаков от Lwip.
nginx на arm926 300MHz я тоже проверил. на коротких файлах около 180 запросов / сек а на длинных он всех уделывает и загружает ethernet по полной.
180 - это при 7-ми тредах? У них зависимость: больше запросов - больше время ответа (в итоге падает кол-во соединений в сек). Другого там нет, т.к. достигнуть ограничения по отрытым файлам сложно (если явно кто не сделал ограничений), а глубина стеков и буферов определяется мегабайтами...
 

pvvx

Активный участник сообщества
@sharikov
ESP8266 имеет за 300 открытий-закрытий HTTP соединений в сек. RTL - за 500.
Сравни это с Keep Alive - выйдет в предел до десятка при спец условиях и занятой всей памяти.
В итоге скорость обработки реальных HTTP/HTML страниц без Keep Alive на малых SoC быстрее.
 

pvvx

Активный участник сообщества
Кол-во одновременно открытых соединений растет от времени ping.
Но, обычно, используется местная интрасеть, где задержки в среднем не более 3-х ms.
*nix и всякие RTOS дают большую задержку - часто определяется тиком системы. Если тик RTOS 1 ms - средняя дополнительная задержка стремиться к 2..3 ms (зависит от реализации алгоритмов обработки программистом и самой OS).
У ESP8266 такой задержки нет. Она в us. Т.к. нет никаких ожиданий переключений тредов и семафоров..
 

pvvx

Активный участник сообщества
В итоге эти задержки и влияют на отзывчивость сервера при загрузке. Они и определяют максимальное кол-во сессий в сек при тесте в Jmeter на минимальный запрос.
 

pvvx

Активный участник сообщества
Как пример.

На MIPS4kc 320MHz из https://esp8266.ru/forum/threads/web-server-na-esp32-s-dannymi-na-sd.4525/#post-64696 выходит 77 сессий-запросов-соединений для HTTP в сек, и на нем-же – за 10 тысяч запросов-ответов в паре TCP соединений для ModbusTCP с обработкой (ну такая у него специализация – web второстепенен :)).

И достичь сильно большего при открытии-закрытии TCP не удается, но в потоке уже открытого TCP– значительно больше. От туда и растут ноги Keep Alive.

Если измерять тик реал-тайм у той системы – он к 5 ms.

А на мелких SoC тик реал-тайма лучше, т.к. огрызок (задач мало и примитивны). И без RTOS достигает минимальных значений в несколько us. C RTOS – минимум = тику системы. В *nxi = примерно нескольким fork().
 

pvvx

Активный участник сообщества
Почему взят fork() – т.к. он в распространенных реализациях *nix равен созданию нового потока.

Вообще это всё к тому: “Pavel-67 сказал(а): думал перейти на более мощную платформу.

Что переход на более мощную платформу не всегда оптимален и требует гораздо больших знаний и времени, чтобы достичь лучших результатов в простой задаче.

О ESP32 и Arduino разговор не идет – это игрушка для блогеров и не более.
 

sharikov

Active member
180 - это при 7-ми тредах? У них зависимость: больше запросов - больше время ответа (в итоге падает кол-во соединений в сек).
Я вчера неправильно измерил производительность nginx. У этой платы rootfs была смонтирована на nfs. Вот когда фс во флэш:

nginx запрос статического файла 613 байт

с keep-alive
1 поток: 439 запросов/сек
2 потока: 567 запросов/сек
20 потоков: 566 запросов/сек
100 потоков: 566 запросов/сек

без keep-alive
1 поток: 237
2 потока: 243
20 потоков: 258
100 потоков: 253

Как видим производительность nginx от количества потоков почти не зависит.
 

pvvx

Активный участник сообщества
Я вчера неправильно измерил производительность nginx. У этой платы rootfs была смонтирована на nfs. Вот когда фс во флэш:

nginx запрос статического файла 613 байт

с keep-alive
1 поток: 439 запросов/сек
2 потока: 567 запросов/сек
20 потоков: 566 запросов/сек
100 потоков: 566 запросов/сек

без keep-alive
1 поток: 237
2 потока: 243
20 потоков: 258
100 потоков: 253

Как видим производительность nginx от количества потоков почти не зависит.
Зато зависит от keep-alive, как и описал. Без keep-alive больше переключений потоков (внутренних переключений через OS) -> ниже скорость обработки.
Протестируйте web обычных пользовательских роутеров :) Там циферки ужасны.
 

pvvx

Активный участник сообщества
nginx: На 10 000 неактивных HTTP keep-alive соединений расходуется около 2.5M памяти
А сколько TCP стека?
Для TCP в TIME_WAIT сколько?
Предположим, что DDOS в виде запроса по которому сервер закрывает соединение. Тогда TCP уходит в TIME_WAIT на 120 сек. Это значит, что задействованный TCP порт уже не открыть в течении 120 сек.
При 500 таких запросов в секунду имеем исчерпание портов (возьмем 50000 портов из максимальных 65535 - другие на других сервисах) за 100 сек. Дальше все порты на данном IP будут исчерпаны и соединений не будет ещё 20 секунд :p
 
Сверху Снизу