Сократил оверхед до 56 МИКРОсекунд на запрос (т.е. запрос отдаётся в среднем медленнее на это время, чем если бы подсоединялись напрямую). Для сравнения, у Mysql Proxy это значение заявлено в 400 МИКРОсекунд, т.е. 7 раз больше. Но у меня практически никакого анализа пакетов не делается, только выясняю подсоединившегося пользователя и собираю статистику. Считал скриптом:
time perl -MDBI -e ‘$dsn = “DBI:mysql:database=mysql;host=127.0.0.1;port=5501″;$dbh = DBI->connect($dsn, “user”, “анунеподглядывай”);for(0..100000){$s = $dbh->selectall_arrayref(”select repeat(100000000000000000, 10)”);}’
Во время выполнения, oProxy ел около 31% CPU, MySQL 25% Perl 50%. Ещё есть куда расти.
Как этого добился:
1. Прежде всего выяснил, что очень большие задержки происходят при чтении из сокета. Исследование показало, что я всегда перед этим делаю двойную запись в сокет (отдельно заголовок пакета, и отдельно содержимое), как следствие включается дополнительное ожидание данных ядром от программы, а удалённая сторона некоторое время ничего не получает и не отвечает. Слил всё в один write, ситуация улучилась раза в 4. Но всё равно плохо.
2. Далее обнаружил, что иногда из-за особенностей протокола MySQL, данные опять отправляются несколькими исходящими пакетами подряд (пакет-заголовок датасета, описание поля, описание поля …, пакет конец описаний, данные, данные, …, конец данных). Всё-таки поставил Ocaml 3.11 и включил для сокета опцию Unix.TCP_NODELAY. Стало ещё лучше, но всё равно не то.
2.5. (в этом месте выясняется, что 80% времени программа проводит в обработке той кучи дебага, что есть в коде. Логи были стремительно сокращены :)
3. Часовое разглядывание вывода tcpdump’а привело к интересному результату: оказывается, последовательности своих пакетов, MySQL склеивает в одно целое и отправляет одним TCP пакетом. Только сейчас в описании протокола вижу ключевую фразу: The description is of logical packets. Не стал мудрствовать лукаво, тоже начал склеивать последовательности, сократив таким образом количество write’ов в сокет до возможного минимума. С этим пунктом, TCP_NODELAY начинает иметь смысл только при отправке больших массивов данных, поэтому временно упразднён и всё возвращено обратно на Ocaml 3.10.2.