Комментарии 64
золотые слова в итоге! гуглить правильно — это дополнительный скилл — сам давно наступал на эти грабли!
Жесть, конечно.
А не рассматривался вариант обратной миграции? Ведь если было видно, что проблема не в вашем коде, а в Tomcat, то это явный сигнал, что «лучшее — враг хорошего».
После того, как мы мигрировали в продакшене один из компонентов системы (единственный, работающий на Tomcat) на новую версию томката, неожиданно саппорт запаниковал, увидев в логах полуторасекундные запуски GC.
А не рассматривался вариант обратной миграции? Ведь если было видно, что проблема не в вашем коде, а в Tomcat, то это явный сигнал, что «лучшее — враг хорошего».
Ну, проблема в том, что система уже работает, ей пользуются — обратная миграция означает даунтайм, который мы не можем себе позволить во время торгов. Разумеется если б решение не было б найдено за пару часов (а именно столько у меня заняло гугление и эксперименты), то был бы откат на старую версию на старом томкате.
Простите за, может быть, глупость… но я немного не понял, как вы все таки решили проблему «ежечасных Full GC»?? Т.е. вы избавились от «ежечасности»? Проблема, в таком случае, не решена. Если в какие-то моменты таки наступает Full GC, то скорее всего где-то генерится куча короткоживущих/ненужных объектов, не?
По пунктам:
— Решили проблему тем, что теперь DGC вызывается раз в 292471208 лет, как мы его и просили изначально. То есть теперь томкат не меняет произвольно этот интервал, и FullGC у нас не происходит (за иключением случаев, описанных в посте в Лирическом отступлении).
— Full GC наступает, когда генерится куча НЕкороткоживущих объектов, ибо короткоживущие и ненужные собираются в процессе ParNew GC (Minor collection так называемые). Мы стараемся не допускать Major GC в течение дня (и у нас получается пока).
— Решили проблему тем, что теперь DGC вызывается раз в 292471208 лет, как мы его и просили изначально. То есть теперь томкат не меняет произвольно этот интервал, и FullGC у нас не происходит (за иключением случаев, описанных в посте в Лирическом отступлении).
— Full GC наступает, когда генерится куча НЕкороткоживущих объектов, ибо короткоживущие и ненужные собираются в процессе ParNew GC (Minor collection так называемые). Мы стараемся не допускать Major GC в течение дня (и у нас получается пока).
>Самое главное — учитесь правильно формулировать запросы к гуглу!
Офигеть! Прошли, оказывается, те времена, когда человек взял бы нормальный дебаггер, прицепился к процессу и попытался понять, кто и когда меняет этот интервал. Или написал бы свой мок, который сделал тоже самое. Или попытался бы в месте вызова gc() пройтись туда-сюда по памяти и стеку, попытавшись понять, что этот вызов вызвало. Или посмотреть на висящие в системе таймеры. Или хотя бы элементарным поиском по бинарникам томката найти этот интервал в ресурсах. Ну, в общем, хоть какой-то инженерный подход применить! Дык нет, «самое главное — учитесь правильно формулировать запросы к гуглу». А завтра напороться на проблему, которая на SO ещё не описана — и что — полностью слиться, закрыть продукт и уйти в дворники?
Офигеть! Прошли, оказывается, те времена, когда человек взял бы нормальный дебаггер, прицепился к процессу и попытался понять, кто и когда меняет этот интервал. Или написал бы свой мок, который сделал тоже самое. Или попытался бы в месте вызова gc() пройтись туда-сюда по памяти и стеку, попытавшись понять, что этот вызов вызвало. Или посмотреть на висящие в системе таймеры. Или хотя бы элементарным поиском по бинарникам томката найти этот интервал в ресурсах. Ну, в общем, хоть какой-то инженерный подход применить! Дык нет, «самое главное — учитесь правильно формулировать запросы к гуглу». А завтра напороться на проблему, которая на SO ещё не описана — и что — полностью слиться, закрыть продукт и уйти в дворники?
я полагаю, что в данном случае автор нагуглил быстрее, чем написал этот пост, и существенно быстрее чем разобрался бы с помощью дебаггера.
я бы первым делом пошёл искать по трекеру используемого продукта проблему, потому что после первого самого шага (подмены класса) уже очевидно, что проблема где-то на уровне библиотеки. И если у вас нет досканального знания этой библиотеки, но при этом вы ей доверяете — почему бы не поискать сначала, а уж после доставать с полки топор, лом и молоток в виде дебаггера, чтобы выпустить патч?..
Еще сомнения вызывает то, что автор использует как я понимаю не последнюю версию Tomcat'а. Зная только это, можно заподозрить библиотеку, а в силу того, что эта версия не первый день в релизном состоянии, то по ней собралась значительная история «эксплуатации».
я бы первым делом пошёл искать по трекеру используемого продукта проблему, потому что после первого самого шага (подмены класса) уже очевидно, что проблема где-то на уровне библиотеки. И если у вас нет досканального знания этой библиотеки, но при этом вы ей доверяете — почему бы не поискать сначала, а уж после доставать с полки топор, лом и молоток в виде дебаггера, чтобы выпустить патч?..
Еще сомнения вызывает то, что автор использует как я понимаю не последнюю версию Tomcat'а. Зная только это, можно заподозрить библиотеку, а в силу того, что эта версия не первый день в релизном состоянии, то по ней собралась значительная история «эксплуатации».
Я полностью согласен с тем, что путь автора быстрее. Я не согласен с выводом, что умение гуглить — это самое главное. Умению думать головой и выбирать правильные инструменты для решения задач — вот главное. Если сегодня нужным инструментом оказался гугл — ок. Но завтра он может им не оказаться.
Полностью согласен. Уважаемый Vlad911 правильно сказал — так было быстрее. Проблема в том, что банк — это такая огромная неповоротливая структура, в которой очень иногда глупое разделение труда. Я самостоятельно ничего с томкатом сделать не могу, поддержкой томката занимается отдельное подразделение, для каждого, извините, пука в сторону томката мне необходимо создать тикет, чтобы кто-то из их команды мне помог. Поэтому подцепиться дебаггером к процессу заняло бы кучу времени чисто с точки зрения организации. К тому же, пришлось бы ждать час до следующего запуска…
Возможно, сейчас в меня полетят помидоры, но я вместо вывода про Гугл сделал бы вывод о том, что системы реального времени или по требованиям приближенные к ним, где необходимо гарантировать отклик не больше заданного временного интервала, надо писать не на языках со сборкой мусора, рефлекшеном и прочими bells and whistles, а на более подходящих для этого и более предсказуемых — C, C++, других компилируемых в нативный код языках без сборщика мусора…
Человек пишет про жирный лоснящийся ынтерпрайз… какой еще c, c++?
Он также пишет, что «любой запуск GC больше 50 миллисекунд (ms) вызывает беспокойство саппорта», и что это трейдинговая платформа, где время в буквальном смысле — деньги. Мне кажется, ядро для неё вполне можно было написать на чём-то без сборщика мусора, чтобы улучшить отзывчивость.
Кроме скорости, в подобных системах огромную роль играет стоимость разработки и поддержки, и — что даже более важно — стоимость расширения. К несчастью, найти хорошего С/С++ разработчика для банковской системы почти нереально, а стоимость разработки на С/С++ будет зашкаливать по причине отсутствия огромного количества библиотек с поддержкой необходимых финансовых протоколов. И кстати, безопасность тоже играет большую роль (имеется в виду отсутствие сегфолтов и тому подобных веселых результатов ручного управления памятью, а не различные уязвимости).
Мне кажется, что трейдинговые системы как раз не являются жирным лоснящимся энтерпрайзом. Там другие требования к программам, и во главу угла ставится скорость. Я сам с такими системами не работал, но по прочитанному и докладам на данную тематику сложилось такое ощущение. И в данной задаче уже приходится очень плотно разбираться с тем, как работает jvm, сборщик мусор и другие низкоуровневые компоненты.
Писать с нуля на C/C++ такие системы, да ещё с soft-RT это смертоубийство. Вот Erlang — другое дело, конечно. Так и сборщик мусора и прогнозируемость и мультизадачность.
А в С++ уже появилась явная модель памяти? Не только специфицированная, но и корректно реализованная хотя бы парочкой-тройкой распространенных компиляторов хотя бы на 2-3 основных платформах? И отлаженная парой-тройкой лет активного использования сообществом? ;) — потому что у явы-то такая модель есть, и она в работе уже с 2005 года. Лет через 5 Сx0 и сможет по этому параметру с явой соперничать, вряд ли раньше
Главное отличие C от Java на мой взгляд — это вовсе не GC. Главное отличие, это то, что в java нет такого понятия, как undefined behavior. Результат выполнения любого кода можно предсказать по спецификации. Во многих случаях это ценнее, чем 10-20% прироста производительности, который дает хорошо написанный С++ код по сравнению с хорошо написанным java-кодом.
Главное отличие C от Java на мой взгляд — это вовсе не GC. Главное отличие, это то, что в java нет такого понятия, как undefined behavior. Результат выполнения любого кода можно предсказать по спецификации. Во многих случаях это ценнее, чем 10-20% прироста производительности, который дает хорошо написанный С++ код по сравнению с хорошо написанным java-кодом.
Начиная с C++11 и C11 есть модель памяти. Она в целом соответствует тому, что большинство компиляторов уже и так реализовывали. Разница в очень небольших деталях, и эти изменения уже внесены в современные версии компиляторов.
Этой модели памяти всего год. Насколько мне известно, идеально ее не реализует ни один из компиляторов. Плюс время на обкатку — в яве баги в реализации concurrency вылезают до сих пор — вы думаете, разработчики gcc как-то принципиально безошибочнее разработчиков явы?
Эта модель памяти обсуждалась уже давно, почитайте рабочие документы комитета WG21 прежде чем делать такие заявления.
Вот, например, документ аж из 2004-го:
www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1680.pdf
Кроме того, при разработке этой модели учтены все грабли, по которой прошлась Java. Кроме того, когда разрабатывалась первая JMM Intel ещё не выпустил в паблик информацию о модели памяти x86.
Примеры багов, связанных с неправильной реализацией модели памяти в gcc или clang — в студию.
Вот, например, документ аж из 2004-го:
www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1680.pdf
Кроме того, при разработке этой модели учтены все грабли, по которой прошлась Java. Кроме того, когда разрабатывалась первая JMM Intel ещё не выпустил в паблик информацию о модели памяти x86.
Примеры багов, связанных с неправильной реализацией модели памяти в gcc или clang — в студию.
>Примеры багов, связанных с неправильной реализацией модели памяти в gcc или clang — в студию.
А их нет? И вас это не тревожит? При том, что модель памяти С++ сложнее явовской, при том, что модель памяти явы за 8 лет реального (а не в черновиках) использования все еще не освободилась от багов, при том, что ява принципиально многопоточный язык (в вашей программе будет 5-6 потоков даже если вы ни одного не запускали — в отличие от С), при том, что ява раза в полтора популярнее С…
… вы правда верите в то, что в реализации С11 модели памяти нет ошибок?
Лично я реально подхожу к оценке: многопоточность — очень сложная тема. Реализовывать модели памяти (тем более кроссплатформенно) — очень сложно. Делать это без ошибок — невозможно. Если в реализации такой сложности системы не замечено ни одной ошибки — это просто значит, что их никто не заметил. И именно поэтому модель памяти С11 — сырая. Вот когда ей будет лет 5-7, и в багтрекере будет 250 заведенных багов в ММ, и 150 исправленных — тогда можно будет говорить о зрелости. А пока это, фактически, черновик — хоть формально и чистовик
А их нет? И вас это не тревожит? При том, что модель памяти С++ сложнее явовской, при том, что модель памяти явы за 8 лет реального (а не в черновиках) использования все еще не освободилась от багов, при том, что ява принципиально многопоточный язык (в вашей программе будет 5-6 потоков даже если вы ни одного не запускали — в отличие от С), при том, что ява раза в полтора популярнее С…
… вы правда верите в то, что в реализации С11 модели памяти нет ошибок?
Лично я реально подхожу к оценке: многопоточность — очень сложная тема. Реализовывать модели памяти (тем более кроссплатформенно) — очень сложно. Делать это без ошибок — невозможно. Если в реализации такой сложности системы не замечено ни одной ошибки — это просто значит, что их никто не заметил. И именно поэтому модель памяти С11 — сырая. Вот когда ей будет лет 5-7, и в багтрекере будет 250 заведенных багов в ММ, и 150 исправленных — тогда можно будет говорить о зрелости. А пока это, фактически, черновик — хоть формально и чистовик
Отвечайте, пожалуйста на поставленный вопрос. Пока я вижу только FUD. Может быть сырая и прочие теории заговора.
При чем здесь теории заговора? Вы считаете недоверие к системе, которая не пожила хотя бы пару лет — теорией заговора? Я полагаю это реализмом.
Я не знаю о багах в gcc. Но давайте прикинем — каков объем кода, созданного с с использованием утвержденной С11 модели памяти, и который работает в высоконагруженном продакшене? Огромная часть программ на С — либо однопоточные, либо используют элементарщину вроде pthread, либо (как ядра ОС) используют свои собственные низкоуровневые примитивы для работы с синхронизацией. Как вы оцениваете объем кода, который использует именно С11 ММ — актуальной версии которой, я напомню, всего полтора года? Сколько по времени этот код проработал в продакшене?
А теперь сравните это с явой, в которой большинство приложений многопоточные. В которой просто нет других примитивов синхронизации, кроме предусмотренных JMM — и поэтому каждая многопоточная программа использует только их. В которой актуальная версия JMM актуальна уже 8 лет и пережила 3-й мажорный релиз JVM. И в которой до сих пор находятся баги.
Вы можете придумать разумную теорию, которая объяснит, как это так вышло, что при реализации гораздо более сложной модели памяти, в гораздо более сложном языке, с на порядок меньшим временем на обкатку, и на порядок меньшим объемом обкатываемого кода — не было допущено ни одной ошибки? С точки зрения тервера это крайне маловероятно. Скорее кажется нерациональной ваша вера в безгрешность разработчиков gcc.
Я не знаю о багах в gcc. Но давайте прикинем — каков объем кода, созданного с с использованием утвержденной С11 модели памяти, и который работает в высоконагруженном продакшене? Огромная часть программ на С — либо однопоточные, либо используют элементарщину вроде pthread, либо (как ядра ОС) используют свои собственные низкоуровневые примитивы для работы с синхронизацией. Как вы оцениваете объем кода, который использует именно С11 ММ — актуальной версии которой, я напомню, всего полтора года? Сколько по времени этот код проработал в продакшене?
А теперь сравните это с явой, в которой большинство приложений многопоточные. В которой просто нет других примитивов синхронизации, кроме предусмотренных JMM — и поэтому каждая многопоточная программа использует только их. В которой актуальная версия JMM актуальна уже 8 лет и пережила 3-й мажорный релиз JVM. И в которой до сих пор находятся баги.
Вы можете придумать разумную теорию, которая объяснит, как это так вышло, что при реализации гораздо более сложной модели памяти, в гораздо более сложном языке, с на порядок меньшим временем на обкатку, и на порядок меньшим объемом обкатываемого кода — не было допущено ни одной ошибки? С точки зрения тервера это крайне маловероятно. Скорее кажется нерациональной ваша вера в безгрешность разработчиков gcc.
> либо используют элементарщину вроде pthread
Ага, конечно. Уважаемый cheremin, прочитайте, хотя бы основные статьи у Hans Boehm по данной теме и выясните, какие проблемы решает C++11 MM. И будет ли работать pthread если C++ MM поломана, и хотя бы Threads Cannot be Implemented as a Library. Во всех реализациях C++ уже была рабочая модель памяти, достаточная для pthread. Да, были разрешены некоторые оптимизации, которые корректны в однопоточных программах, но создают data race на пустом месте в многопоточных. Но почти все эти баги закрыты до формализации модели памяти, потому что иначе даже «элементарщина», как вы выразились, не работала бы.
> Но давайте прикинем — каков объем кода, созданного с с использованием утвержденной С11 модели памяти, и который работает в высоконагруженном продакшене?
Весь многопоточный C++, даже не использующий C++11 threads, даже написанный до формализации этой модели памяти. Основной принцип модели памяти, SC-DRF, был всем очевиден давно, и именно на него ориентировались, просто в C++11 он формализован для этого языка.
> гораздо более сложной модели памяти
Вы разбираетесь в обоих моделях памяти настолько, что можете легко сравнить их сложность для реализации?
Ага, конечно. Уважаемый cheremin, прочитайте, хотя бы основные статьи у Hans Boehm по данной теме и выясните, какие проблемы решает C++11 MM. И будет ли работать pthread если C++ MM поломана, и хотя бы Threads Cannot be Implemented as a Library. Во всех реализациях C++ уже была рабочая модель памяти, достаточная для pthread. Да, были разрешены некоторые оптимизации, которые корректны в однопоточных программах, но создают data race на пустом месте в многопоточных. Но почти все эти баги закрыты до формализации модели памяти, потому что иначе даже «элементарщина», как вы выразились, не работала бы.
> Но давайте прикинем — каков объем кода, созданного с с использованием утвержденной С11 модели памяти, и который работает в высоконагруженном продакшене?
Весь многопоточный C++, даже не использующий C++11 threads, даже написанный до формализации этой модели памяти. Основной принцип модели памяти, SC-DRF, был всем очевиден давно, и именно на него ориентировались, просто в C++11 он формализован для этого языка.
> гораздо более сложной модели памяти
Вы разбираетесь в обоих моделях памяти настолько, что можете легко сравнить их сложность для реализации?
То, что описал автор в топике и есть махровейший undefined behavior, только незадокументированный никак, потому что сам язык даёт возможность вставлять какие угодно костыли через reflection, что в итоге «хвост виляет собакой» — Tomcat решает, когда вызывать GC в трейдинговом приложении… Выходит, что лучше вообще не полагаться на сторонние Java-библиотеки, потому что неизвестно, что они там делают под капотом с reflection и GC.
Undefined behavior в C/C++ по моему опыту весьма редкая штука, если не забивать на предупреждения компилятора. Главное правило везде и всегда в любом языке: забыл или не знаешь, как правильно (какой приоритет у операций, и т.д.) — смотри документацию, потому что разновидность undefined behavior также может быть «на уровень выше» — например, результат работы какого-то метода будет неопределённым в поведении класса, если класс не был инициализирован правильно.
Мне кажется, главное в данном случае — какие-то гарантии отзывчивости при работе с памятью. C/C++ может это гарантировать и имеет инструменты для оптимизации (можно свой аллокатор написать), а Java не может.
Мне вообще кажется, что на managed-языке писать высоконагруженные и/или работающие 24/7 программы тяжелее, чем на C/C++, потому что очень многое начинает зависеть от настроек GC, в тонкостях которых разобраться посложнее, чем с умными указателями или всякими RAII. :) Вот и выходит, что всё равно требуется много усилий по настройке, но и они не гарантируют факапов.
Undefined behavior в C/C++ по моему опыту весьма редкая штука, если не забивать на предупреждения компилятора. Главное правило везде и всегда в любом языке: забыл или не знаешь, как правильно (какой приоритет у операций, и т.д.) — смотри документацию, потому что разновидность undefined behavior также может быть «на уровень выше» — например, результат работы какого-то метода будет неопределённым в поведении класса, если класс не был инициализирован правильно.
Мне кажется, главное в данном случае — какие-то гарантии отзывчивости при работе с памятью. C/C++ может это гарантировать и имеет инструменты для оптимизации (можно свой аллокатор написать), а Java не может.
Мне вообще кажется, что на managed-языке писать высоконагруженные и/или работающие 24/7 программы тяжелее, чем на C/C++, потому что очень многое начинает зависеть от настроек GC, в тонкостях которых разобраться посложнее, чем с умными указателями или всякими RAII. :) Вот и выходит, что всё равно требуется много усилий по настройке, но и они не гарантируют факапов.
Прошу прощения, не гарантируют отсутствия факапов. :)
Вы, возможно, удивитесь, но собственный «аллокатор» — точнее, пул объектов — можно написать и на яве. Некоторые так и делают, хотя мало кому удается действительно обойти по скорости родную аллокацию + new gen GC (ибо инженеры оракла далеко не дураки). Гарантии, которые дает С++ не выше — даже С-библиотека обращается, в конце-концов, к операционке, которая, в общем случае, realtime гарантий не дает, и все, что делает С-stdlib так это кэширует запрошенную у операционки память. Это ровно то же, что пул объектов в яве.
То, что описал автор — это ожидаемое поведение. В конце-концов, когда операционка выгружает ваше супер-пупер оптимизированное С++ приложение в своп — вы ж не начинаете утверждать, что С++ не подходит для приложений, требующих высокую отзывчивость? Я не знаю такой среды/фреймворка, который бы обеспечивал полную предсказуемость по всему стеку технологий начиная от железа. Все равно приходится засучивать рукава, а где-то и просто молиться великому Тьюрингу (только тссс об этом!).
Честный realtime требует сильного изменения подхода к разработке. Это окупается в довольно узких диапазонах бизнес-требований. Мягкий realtime, кмк, требует примерно одинаковой степени изобретательности, что на С, что на яве. Но ява сама по себе проще как язык, и разработчиков под нее больше — что немаловажно.
>потому что очень многое начинает зависеть от настроек GC, в тонкостях которых разобраться посложнее, чем с умными указателями или всякими RAII
Я сильно сомневаюсь, что разобраться с умными указателями в случае многопоточных приложений будет проще (и они будут эффективнее), чем с GC. Немаловажно и то, что изменения в настройках GC — это именно настройки. Изменения в политике использования памяти в С++ — это изменения в коде приложения. Со всем сопутствующим риском.
То, что описал автор — это ожидаемое поведение. В конце-концов, когда операционка выгружает ваше супер-пупер оптимизированное С++ приложение в своп — вы ж не начинаете утверждать, что С++ не подходит для приложений, требующих высокую отзывчивость? Я не знаю такой среды/фреймворка, который бы обеспечивал полную предсказуемость по всему стеку технологий начиная от железа. Все равно приходится засучивать рукава, а где-то и просто молиться великому Тьюрингу (только тссс об этом!).
Честный realtime требует сильного изменения подхода к разработке. Это окупается в довольно узких диапазонах бизнес-требований. Мягкий realtime, кмк, требует примерно одинаковой степени изобретательности, что на С, что на яве. Но ява сама по себе проще как язык, и разработчиков под нее больше — что немаловажно.
>потому что очень многое начинает зависеть от настроек GC, в тонкостях которых разобраться посложнее, чем с умными указателями или всякими RAII
Я сильно сомневаюсь, что разобраться с умными указателями в случае многопоточных приложений будет проще (и они будут эффективнее), чем с GC. Немаловажно и то, что изменения в настройках GC — это именно настройки. Изменения в политике использования памяти в С++ — это изменения в коде приложения. Со всем сопутствующим риском.
Под гарантиями отзывчивости я в первую очередь имел ввиду то, что в C/C++ чётко определено, когда объект будет удалён, в отличие от managed-языков. Это означает, что ситуация с лагами по 1.5 секунды из-за сборки мусора принципиально невозможна. Если опускаться на уровень операционной системы, то приложения и на Java, и на C++, и любые другие приложения, написанные на других языках, имеют дело со свопом и особенностями выделения памяти в ОС, поэтому конфигурировать ОС приходится в любом случае, только в случае managed-языков к этому добавляется и GC.
Если есть серьёзные требования к realtime — ну что же, тогда нужна RTOS типа QNX, а ещё желательно, чтобы и программа была как минимум lock-free, но это уже совсем другой разговор и другой ценник (хотя для трейдинговых платформ именно так и надо всё реализовывать, на мой взгляд).
Если есть серьёзные требования к realtime — ну что же, тогда нужна RTOS типа QNX, а ещё желательно, чтобы и программа была как минимум lock-free, но это уже совсем другой разговор и другой ценник (хотя для трейдинговых платформ именно так и надо всё реализовывать, на мой взгляд).
>Под гарантиями отзывчивости я в первую очередь имел ввиду то, что в C/C++ чётко определено, когда объект будет удалён
И smart-pointer-ы тоже четко определяют, когда объект будет удален? Не может такого случиться, что вот так сейчас звезды легли, что именно в этом маленьком методе завершили свою жизнь SP на 150 объектов сразу, и потому этот маленький метод вдруг стал в 150 раз тяжелее, чем обычно? И чем это отличается от GC в момент вызова того же метода?
И накладные расходы на аллокацию так уж четко определены? Разве чтобы это все действительно было четко определено, вам не придется действительно написать свои собственные аллокаторы, и использовать только стековую, или явную аллокацию/деаллокацию, без всяких smart-p? А это еще увеличит стоимость разработки.
Ну и потом — настраивая GC можно адаптировать приложение к разным объемам доступной памяти, к количеству свободных ядер на сервере, пытаться балансировать между пропускной способностью и временем отклика — в С вам все это придется делать, скорее всего, через изменения в коде.
В общем, мне кажется, что «преимущество» С здесь преувеличено. GC писали не дураки. Обойти их с явной схемой аллокации не так-то просто — это возможно, конечно, но требует инженеров уровня заметно выше среднего. А когда речь идет о соревновании экспертов, то важен уже не инструмент, а люди. Две экспертные команды, разрабатывающие на С и яве дадут результаты, пропорциональные мастерству команд, а не языку. Я так считаю :)
> программа была как минимум lock-free,
Вот как раз для lock-free алгоритмов GC часто является спасением — многопоточная аллокация/освобождение памяти + ABA делают многие алгоритмы, простые на managed-языках, очень сложными на unmanaged.
И smart-pointer-ы тоже четко определяют, когда объект будет удален? Не может такого случиться, что вот так сейчас звезды легли, что именно в этом маленьком методе завершили свою жизнь SP на 150 объектов сразу, и потому этот маленький метод вдруг стал в 150 раз тяжелее, чем обычно? И чем это отличается от GC в момент вызова того же метода?
И накладные расходы на аллокацию так уж четко определены? Разве чтобы это все действительно было четко определено, вам не придется действительно написать свои собственные аллокаторы, и использовать только стековую, или явную аллокацию/деаллокацию, без всяких smart-p? А это еще увеличит стоимость разработки.
Ну и потом — настраивая GC можно адаптировать приложение к разным объемам доступной памяти, к количеству свободных ядер на сервере, пытаться балансировать между пропускной способностью и временем отклика — в С вам все это придется делать, скорее всего, через изменения в коде.
В общем, мне кажется, что «преимущество» С здесь преувеличено. GC писали не дураки. Обойти их с явной схемой аллокации не так-то просто — это возможно, конечно, но требует инженеров уровня заметно выше среднего. А когда речь идет о соревновании экспертов, то важен уже не инструмент, а люди. Две экспертные команды, разрабатывающие на С и яве дадут результаты, пропорциональные мастерству команд, а не языку. Я так считаю :)
> программа была как минимум lock-free,
Вот как раз для lock-free алгоритмов GC часто является спасением — многопоточная аллокация/освобождение памяти + ABA делают многие алгоритмы, простые на managed-языках, очень сложными на unmanaged.
Быть может Вы хотели сказать инженеры Sun?
Как то обидно, когда у них забирают почести…
Как то обидно, когда у них забирают почести…
Точно такая же мысль появилась. Есть же системы реального времени с гарантированным временем обработки события — чем они не подходят? Ядро на этой системе, а всякие гуи и веб-сервисы можно и на Java.
НЛО прилетело и опубликовало эту надпись здесь
Я не могу сказать, какой латентность будет, но я могу сказать, какой она точно не будет. Она не будет 1.5 секунды, как у автора. Ну то есть в теории, если очень постараться, можно написать такой говнокод, который будет способен лагать и по 10 секунд, но мы же не будем из-за этого делать вывод, что GC лагает меньше, чем прямая работа с памятью?
НЛО прилетело и опубликовало эту надпись здесь
Ничего себе не считается. :) Не считается, если программа работает пару минут, а не 24 часа 7 дней в неделю.
Гарантий в этой жизни нет. На сервер может упасть метеорит, могут выключить электричество, и так далее. Но если не исключить, то хотя бы минимизировать факапы можно ведь? Лично мне спокойнее от того, что если программа вдруг упадёт или память закончится, то это будет по моей вине, а не по вине кривого веб-сервера, внезапно решившего собрать мусор. А если по моей вине, то я лучше буду контролировать процесс решения проблемы, потому что знаю свой код гораздо лучше говнокода какого-то веб-сервера, и я быстрее её устраню, раз и навсегда.
Reflection + GC — сила и слабость Java, потому что теряется контроль за освобождением памяти и за control flow (труднее понять, кто и когда вызывает методы), а терять контроль в системах (мягкого) реального времени это, я считаю, чревато.
Гарантий в этой жизни нет. На сервер может упасть метеорит, могут выключить электричество, и так далее. Но если не исключить, то хотя бы минимизировать факапы можно ведь? Лично мне спокойнее от того, что если программа вдруг упадёт или память закончится, то это будет по моей вине, а не по вине кривого веб-сервера, внезапно решившего собрать мусор. А если по моей вине, то я лучше буду контролировать процесс решения проблемы, потому что знаю свой код гораздо лучше говнокода какого-то веб-сервера, и я быстрее её устраню, раз и навсегда.
Reflection + GC — сила и слабость Java, потому что теряется контроль за освобождением памяти и за control flow (труднее понять, кто и когда вызывает методы), а терять контроль в системах (мягкого) реального времени это, я считаю, чревато.
Самое главное — учитесь правильно формулировать запросы к гуглу!Давно хочу прочитать какую-нибудь толстую фундаментальную книгу по поиску в интернете. Базовые приёмы, методологии, тонкости и секреты. Существует такая?
Что-нибудь по SEO-оптимизации.
Можете начать с powersearchingwithgoogle.com.
Имхо сейчас проще всего в автора начать кидаться помидорами типа Ява говно и т.п. Проблемы с GC решаются и другими путями. Посыл автора мне понятен и с. Ним я согласен что дешевле искать в гугле а потом уже дебажить и втыкать логи и тому подобное.
P.s. Java в плане скорости разработки/поддаваемомти рефакторигу и скорости работы находиься на мой взгляд в той золотой середине
P.s. Java в плане скорости разработки/поддаваемомти рефакторигу и скорости работы находиься на мой взгляд в той золотой середине
А почему такая критичность ко времени?
50 ms — это весьма немного, на мой взгляд. Если что-то в своп уйдёт — легко может получиться больше.
50 ms — это весьма немного, на мой взгляд. Если что-то в своп уйдёт — легко может получиться больше.
За своп юникс-админа кастрируют, что он не предупредил о приближении к лимиту физической памяти. От свопа мы всегда выставляем swappiness в 0.
А по поводу 50 мс — например, политика многих наших клиентов-ECN (типа bloomberg, reuters и т.п.) — отключать тех liquidity providers, задержки обработки ордера у которых превышают ms, где N как правило порядка 100. Так что 50 мс на сборку мусора — это очень-очень много для одного компонента, ведь в процессе обработки ордер пролетает через 3-4 компонента, а еще и полезное что-то надо делать… Обработка собственно ордера у нас занимает порядка 20 мс.
PS прошу прощения за обилие английских терминов, но я действительно не знаю, как они переводятся на русский…
А по поводу 50 мс — например, политика многих наших клиентов-ECN (типа bloomberg, reuters и т.п.) — отключать тех liquidity providers, задержки обработки ордера у которых превышают ms, где N как правило порядка 100. Так что 50 мс на сборку мусора — это очень-очень много для одного компонента, ведь в процессе обработки ордер пролетает через 3-4 компонента, а еще и полезное что-то надо делать… Обработка собственно ордера у нас занимает порядка 20 мс.
PS прошу прощения за обилие английских терминов, но я действительно не знаю, как они переводятся на русский…
Ничего страшного, мне даже удобнее работать с терминологией на языке оригинала.
Интересно биржи устроены, спасибо за информацию!
На досуге почитаю внимательнее.
Интересно биржи устроены, спасибо за информацию!
На досуге почитаю внимательнее.
Я дико недоумеваю и извиняюсь, но о каком FX trading platform можно говорить, если работаете под кошкой (tomcat)?
Кроме того, я не верю, в то, что подобная проблема не воспроизводится на тестовом стенде. Моё недоумение растёт к вопросу о downtime — что за компонент такой, что является single point of failure и не работающий в active-active режиме, который позволяет мало того, что вести балансировку нагрузки, так ещё и плавно откатывать изменения при необходимости.
Словом, не надо тут винить ни java, ни tomcat. Молодцы, что хотя бы мониторинг приложений есть.
Кроме того, я не верю, в то, что подобная проблема не воспроизводится на тестовом стенде. Моё недоумение растёт к вопросу о downtime — что за компонент такой, что является single point of failure и не работающий в active-active режиме, который позволяет мало того, что вести балансировку нагрузки, так ещё и плавно откатывать изменения при необходимости.
Словом, не надо тут винить ни java, ни tomcat. Молодцы, что хотя бы мониторинг приложений есть.
Странная особенность некоторых людей — рубить с плеча, не разобравшись.
Это единственный компонент нашей системы, который работает на томкате, и предоставляет веб-сервис, к которому обращается клиентский GUI. И да, мы от него очень хотим избавиться и перейти на что-нибудь типа Jetty, но наша долбанутая служба ИБ не дает пока добро. Разумеется, он active-active, спрятан за лоад-балансером, у нас нет никаких SPoF в принципе — система с оборотом в сотню миллиардов долларов в день не может их себе позволить.
Но даунтайм в данном случае — от прогрева (при рестарте системы, первый цикл проходит очень медленно, виной тому — instrumentation, пардон, снова не знаю подходящего перевода). Он допустим в случае реального фейловера, но мы стараемся и его избежать, ибо каждая задержка потенциально — упущенная сделка, и упущенные деньги.
Это единственный компонент нашей системы, который работает на томкате, и предоставляет веб-сервис, к которому обращается клиентский GUI. И да, мы от него очень хотим избавиться и перейти на что-нибудь типа Jetty, но наша долбанутая служба ИБ не дает пока добро. Разумеется, он active-active, спрятан за лоад-балансером, у нас нет никаких SPoF в принципе — система с оборотом в сотню миллиардов долларов в день не может их себе позволить.
Но даунтайм в данном случае — от прогрева (при рестарте системы, первый цикл проходит очень медленно, виной тому — instrumentation, пардон, снова не знаю подходящего перевода). Он допустим в случае реального фейловера, но мы стараемся и его избежать, ибо каждая задержка потенциально — упущенная сделка, и упущенные деньги.
Мне можно не объяснять спецификую IB-приложений, но дизайн вашей системы меня шокирует.
Web Services и FX, опять же instrumentation и FX… И что касается прогрева сервера — почему его нельзя на время прогрева иметь как не активный, второстепенный, чтобы на него не уходили запросы до поры до времени…
Видимо, мы в очень разных мирах работаем.
Web Services и FX, опять же instrumentation и FX… И что касается прогрева сервера — почему его нельзя на время прогрева иметь как не активный, второстепенный, чтобы на него не уходили запросы до поры до времени…
Видимо, мы в очень разных мирах работаем.
Ну, если вы немного разбираетесь в специфике IB-приложений, то должны знать понятие legacy, и как тяжело иногда это legacy победить. Веб-сервис — это как раз legacy, которое «работает — не трожь». Ну и как бы хватает, он не используется для high-frequency операций, типа прайсинга.
Instrumentation — видимо, действительно не в том мире работаете, обычно в мире high-load очень хотят знать, как же у нас там с производительностью, и что на нее влияет, в реальном времени, тем более в наш век существования zero-impact instrumentation (типа CA Wily Introscope).
Instrumentation — видимо, действительно не в том мире работаете, обычно в мире high-load очень хотят знать, как же у нас там с производительностью, и что на нее влияет, в реальном времени, тем более в наш век существования zero-impact instrumentation (типа CA Wily Introscope).
Странная особенность некоторых людей — рубить с плеча, не разобравшись.
Вы не согласны с тезисом
не верю, в то, что подобная проблема не воспроизводится на тестовом стенде
?
Кстати, были ли какие-то убеждения не добавить ключик
-XX:+DisableExplicitGCк запуску приложения?
Были, они описаны в топике в Лирическом отступлении — мы руками вызываем FullGC по ночам.
Не прочитал его, как-то не привычны ещё дополнительные сноски. Но не суть.
Есть дикий dirty hack — таки отключить System.gc(), однако, если запустить напротив процесса jmap — то он вызовет full gc внутри jvm.
Есть дикий dirty hack — таки отключить System.gc(), однако, если запустить напротив процесса jmap — то он вызовет full gc внутри jvm.
Это бы не исправило проблему, правда ведь? Вы бы стали использовать грязные хаки на прод-системе?
Скажем так — у нас таких проблем нет, и почти везде стоит -XX:+DisableExplicitGC
Ну, а мы везде вызываем FullGC ночью. И тому много причин, главная — бюрократия…
Разница в том, что вы его вызываете явно — оставив возможность любой другой сторонней библиотеке сделать то же самое, только тогда, когда ей в голову взбредёт.
Мы такую возможность напрочь отключаем — у нас FullGC не случается и не случится за всё время работы приложений (5 дней).
Наблюдение с jmap — исключительно из общего опыта — и если выбирать — что использовать в prod'е — System.gc или jmap я выбрал бы jmap
Мы такую возможность напрочь отключаем — у нас FullGC не случается и не случится за всё время работы приложений (5 дней).
Наблюдение с jmap — исключительно из общего опыта — и если выбирать — что использовать в prod'е — System.gc или jmap я выбрал бы jmap
Ну, каждому — своё… Спор можно продолжать бесконечно.
ИМХО, вызов System.gc() (или более близкий сердцу моему GC.Collect()) не есть зло, если он производится в периоды бездействия приложения или в случаях, когда достоверно известно, что было создано очень много объектов. А ещё есть Concurrent Mark-Sweep.
CMS имеет total-stop-the-world фазы, и я что-то сильно сомневаюсь, что использовался другой GC, однако это не решение всех проблем.
Вопрос, который ставится, чтобы запуск System.gc() был контроллируем по времени, а не вылезал случайно, как в ситуации, описанной автором статьи — ибо с точки зрения библиотеки (кошки) — пришло время «бездействия приложения» и можно вызвать GC явно.
Вопрос, который ставится, чтобы запуск System.gc() был контроллируем по времени, а не вылезал случайно, как в ситуации, описанной автором статьи — ибо с точки зрения библиотеки (кошки) — пришло время «бездействия приложения» и можно вызвать GC явно.
Ява, томкат, проблемы с памятью и веселые костыли — как предсказуемо!
И эти люди в потоках про Node.js рассказывают, что у него лаги из-за garbage collectior-а.
НЛО прилетело и опубликовало эту надпись здесь
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
История одного garbage collection'а