Обновить
170
0
Андрей @apangin

Пользователь

Отправить сообщение
В нашем случае механизм поддержки через Oracle или, тем более, через третьестороннюю компанию работать не будет.

Во-первых, это очень долго. Работая в Sun, впоследствии Oracle, я сидел в одной комнате с ребятами из Java Sustaining, и видел, как эскалации заказчиков могли решаться месяцами. И вовсе не по вине ребят, а из-за бюрократизированных процессов и длинной цепочки коммуникаций по email.

Во-вторых, очень сложно предоставить сторонней компании проблемный сценарий. Как правило, JVM баги воспроизводятся только на продакшне под высокой нагрузкой, и без доступа к нашим серверам и к нашему коду отладка практически невозможна.

Наконец, основная проблема не в том, чтобы спортировать фикс и пересобрать JDK (это как раз быстро и просто), а в том, чтобы разобраться, что бага именно в HotSpot, а не в нашем коде или библиотеках. А уж покопаться в коде HotSpot — по мне так милое дело, здесь я коллегам из Азула ещё фору дам ;)
Авторы PVS-Studio пишут, что как раз-таки trunk версию обычно проверяют. По мне так больше нового кода — больше интересных случаев для анализа.
О! Как раз это же хотел предложить!
Только уточню, что не сам OpenJDK (который на 95% состоит из Java кода), а его конкретную часть — HotSpot JVM. На мой вкус, это один из самых замысловатых и любопытных проектов на C/C++, где грань между ошибкой и умыслом разработчика порой очень тонкая :)
Нет такого понятия как однопоточная или многопоточная сложность. Алгоритмическая сложность — она одна. Параллелизация может сократить время лишь в константное число раз, но никогда не сделает O(1) из O(n).

Если даже обнулением занимается фоновый поток, если даже операция совмещена с другой, всё равно, количество работы, которое нужно выполнить, кратно n. Пусть поток main у тебя сверхбыстрый, но если фоновых вычислений ассимптотически больше, это значит, что в какой-то момент main просто будет вынужден остановиться, чтобы дождаться другого потока.
Непонятно, о чём вы спорите. Очевидно, что при создании объекта в общем случае нужно его обнулить. Причём неважно, когда и кем выполняется обнуление: инлайном в скомилированном коде, при выделении TLAB, во время GC или вообще в ядре ОС. В любом случае, обнулить надо ровно столько, сколько выделяется, не считая заголовка объекта. Таким образом, средняя сложность выделения получается O(n). Исключения составляют случаи, когда JVM знает, что обнулять не надо, например, в Arrays.copyOf или Object.clone.

Кстати, по умолчанию в HotSpot TLAB не обнуляется, см. опцию ZeroTLAB.
Упражнение: догадайся, почему.
Из условий лицензии:
Licensee agrees not to disassemble, decompile or reverse engineer the Object Code
Так я писал: сразу после запуска сервера, когда он входит в кластер, на него прилетает несколько тысяч запросов, содержащих разные дочерние классы ImmutableList. Во время десериализации запросов происходит инициализация классов (поскольку до этого они не использовались). Дедлок происходит, когда несколько разных классов из одной иерархии начинают одновременно инициализироваться. Одного обращения к ImmutableList недостаточно.
Именно так. HotSpot JVM распознаёт паттерн new StringBuilder().append()...toString() (или то же самое со StringBuffer), и компилирует это как одно целое. Регулируется опцией -XX:+OptimizeStringConcat, по умолчанию включено.
Используйте метод concat, если слияние нужно провести только один раз, для остальных случаев рекомендовано использовать или оператор "+" или StringBuffer / StringBuilder.
Никогда не используйте concat. Обычный "+" или StringBuilder всегда будет эффективней, даже всего для двух строк. Просто потому, что JVM оптимизирует "+" специальным образом (это JVM intrinsic), а concat — нет (это обычный Java метод).
Кстати, к вопросу о других решениях. NGINX мы тоже тестировали, хотели использовать в качестве прокси. Не вышло: уже при трафике в 3 Гбит/с CPU usage улетал в 100%. Деталей, к сожалению, не знаю, могу потом у коллег уточнить. Просто о неудачах редко когда рассказывают на конференциях :) Хотя, согласен, отрицательный опыт тоже порой очень интересен.
По-моему, вы сейчас пытаетесь на ходу придумать оправдания, почему кеширование в /dev/shm плохо. Не хотите так делать — не надо, кто-нибудь другой сделает. Я ж не принуждаю, а просто делюсь положительным опытом.

При этом столкнулись с проблемой вытеснения данных из кэша, до того, как отработает sendfile() и никак эту проблему не решили.
Решили тривиальным reference counter'ом.

И ещё ни разу не видел, чтобы при наличии свободных страниц ядро начинало бы свопить если не преодолен рубеж swappiness.
А я, вот, видел, как при swappiness=0 Linux вместо освобождения page cache иногда начинает свопить полезную память. В тоже время со свопом кеша из /dev/shm проблем нет. Тем более, что кеш этот — одна непрерывная область, которая легко лочится через mlock. Так что метафора про «тыкву» неуместна.

В свою очередь с за'map'ленными в память файлами есть серьезная проблема. Сейчас если у нас происходит ошибка чтения с диска
С какого диска? Мы мапим файл из tmpfs, он целиком в памяти.

Если мы будем копировать с диска в /dev/shm, то будет дополнительная работа
Серьёзно? Если данные востребованы, и мы хотим их закешировать в памяти, как это можно сделать проще, не делая read?

приходится пробовать различные подходы, работать с вендорами жестких дисков, оптимизировать прошивку, драйвера, различные подсистемы ядра и сетевой стек, изобретать новый алгоритм для congestion control в TCP
Вот, как раз про всё это вас было бы очень интересно послушать :)
А при добавлении третьей строчки у меня вообще весело получается:
    test(new StringBuffer("")); // StringBuffer: 5020ms.
    test(new StringBuilder("")); // StringBuilder: 14041ms.
    test(new StringBuilder("")); // StringBuilder: 10716ms.
А теперь запустите тот же тест с -XX:BiasedLockingStartupDelay=0:
StringBuffer: 5590ms.
StringBuilder: 5493ms.

И чего в итоге померили?

Также изменения коснулись hashCode (новый алгоритм hashing)
Оппа! Как такое может быть, если алгоритм хеширования для String строго прописан в спецификации?
Решение, конечно же, должно быть опциональным и конфигурируемым. Я ведь не говорю, что нужно по умолчанию его использовать везде, включая FreeBSD, с которым, как вы утверждаете, и так всё хорошо. Или на системах, где кеш вообще бесполезен (у нас есть и такие — мы в это случае просто ставим в сервер дюжину SSD накопителей, и с кешами даже не заморачиваемся). Но в ряде случаев, как раз для раздачи тяжёлого медиаконтента с характерным профилем популярности, это и будет той серебряной пулей для Linux, о которой вы писали.

Про затраты на разработку никто не спорит. Я лишь делюсь опытом, что этот подход: а) востребован, б) относительно просто реализуем, в) приносит пользу.

Помимо прочего, кеширование в user space открывает широкое поле для различного рода улучшений. Например, вы можете явно управлять тем, какой контент как долго живёт и как вытесняется. Например, контент средней степени популярности мы при вытеснении складываем в кеш второго уровня на SSD, а непопулярный выкидываем совсем.

Дисковый же кеш очень непредсказуем. Скажем, Linux может вдруг решить, что в данный момент кеш важнее хипа приложения, и выгрузить хип в своп, несмотря на любые настройки /proc/sys/vm.

А что насчёт HTTPS? Как вам тут поможет дисковый кеш и sendfile? В нашем же случае мы без лишних копирований отправляем данные из того же кеша, заменив только sendfile на SSL_write. Конечно, 40 Гбит/с тут уже не будет, но 25 Гбит шифрованного трафика тоже немало.
Мда, я так выразился, что вы, наверное, подумали, будто у нас всего один download сервер :) Не, их много. И они генерируют львиную долю трафика, пусть и не Штатов, но хотя бы Рунета.
Прошу прощения, писал ночью — грубовато получилось. Просто искренне удивился, что лежащая на поверхности идея, которую я и сам не раз упоминал в докладах про архитектуру ОК, оказывается, до недавнего времени, в NGINX не была реализована. Думал, может, какие-то подводные камни были. Ну, раз просто было не нужно — то ладно.

Ручное кеширование не отменяет sendfile. Я ж не зря ссылку на презентацию дал — там всё наглядно рассказано и показано. Создаёте один большой файл в /dev/shm, мапите в адресное пространство процесса. Работаете как с обычной памятью, разбиваете на блоки, вытесняемые по принципу LRU. А в сеть отдаёте блоки через sendfile, минуя user space.

40 Гбит/с, поверьте, у нас тоже не суперкомпьютеры раздают. Понятно, что это ближе к верхушке нашей линейки, но я про то, что это не экспериментальный стенд, а commodity оборудование, стоящее на эксплуатации.
Чудо! Не могу поверить, что в самом популярном сервере поддержка пула потоков для длительных операций появилась только в 2015 году. При том, что паттерн Proactor известен науке по меньшей мере с 90-х.

Забавно, что автор винит ОС в том, что нет возможности узнать, какие данные закешированы, а какие нет.
Кешируйте сами — делов-то!

Именно так работает, например, video download сервер известной социальной сети. То, что закешировано в памяти, он отдаёт сразу из потока-селектора. А за тем, чего в кеше нет, обращается асинхронно из отдельного пула. В результате один сервер отдаёт наружу до 40 Гбит/с, причём сам сервер написан даже не на C, а на «тормозной» Java.
Да, возможно. Только там куча вариантов, все запаришься перечислять: Stream.parallel(), Collection.parallelStream(), Arrays.parallelSort(), Arrays.parallelSetAll() и т.д.
100 мкс — это уже порядок систем реального времени. Вот, только Java таковой не является. Что говорить про оптимизации в микросекунды, если средняя safepoint пауза может составлять 1-10 миллисекунд. Да даже Linux не даёт тебе таких гарантий: поток может запросто проснуться на миллисекунду позже, чем попросишь. Сетевой раундтрип — плюс миллисекунда. Обращение к диску — еще пара миллисекунд.

Я не говорю сейчас про трейдеров, которые насилуют Java похлеще нашего high load. Но в большинстве случаев распараллеливание настолько коротких задач не оправдывает себя. Тем более, что параллельные алгоритмы как правило сложнее и опаснее (всмомни хотя бы пример с дедлоком из-за параллельного стрима).
Комментарии
  1. Не совсем. Никаких synchronized и локов внутри Math.random нет.
  2. Действительно, будет метод-аксессор, но JIT ведь умеет простые методы инлайнить, чтоб не было никакого оверхеда.
  3. Да, всё так.

Информация

В рейтинге
Не участвует
Откуда
Санкт-Петербург, Санкт-Петербург и область, Россия
Работает в
Зарегистрирован
Активность