Сегодня на hh.ru работает около 150 человек.
У нас много интересных команд, каждая из которых вносит значительный вклад. Но в этой статье я расскажу только об одном из них.
Потому что я руководитель ее команды.
И на это есть несколько причин:
- часто кандидаты не понимают, чем мы занимаемся;
- иногда этого не знают даже сотрудники внутри компании, потому что в нашей команде нет продакт-менеджера, своего бизнес-направления и перечня сервисов, которые мы поддерживаем.
;
- наши заслуги чаще всего остаются в тени;
- ведь «если хочешь что-то понять, попробуй объяснить это кому-нибудь» :)
Начнем с самого общего, то есть с приоритетов, их два:
- системное обеспечение надежности и отказоустойчивости нашей платформы.
Здесь стоит обратить внимание на слово «системный» — оно означает, что мы не исправляем конкретные дефекты производительности, а разрабатываем общие правила и закономерности, закрепляем их в фреймворках, автоматических проверках и т. д., чтобы это работало для всех.
- развитие ориентировано на бизнес-логику.
То есть, чем меньше разработчик думает о поддержке надежности, архитектуры и т. д. — тем лучше.
Понятно, что полностью избавить коллег от подобных мыслей довольно вредно, но разумный баланс сохранять имеет смысл.
0. Поддержка и развитие архитектуры
hh.ru — это 5-6к rps от пользователей, на пике доходящий до 10к, который при выходе на бэкенды вырастает на порядок.Это более 1500 инстансов, на которых работает около 150 сервисов в 3-х ДЦ.
Так да, в первую очередь это те самые висящие диаграммы с квадратиками, баночками и стрелочками: кто куда идет, где все должно быть.
Мы, конечно, не рисуем диаграммы – мы закрываем свои потребности автоматизацией, логированием и мониторингом, но наши школьники Мы пугали, например, такими вещами:
Мы действительно несем ответственность за поиск и устранение узких мест и негибких решений в архитектуре, а также за ее развитие в соответствии с потребностями.
Позволь мне привести пример: hh.ru работает уже много лет, и одно время казалось хорошей идеей иметь отдельную машину для выполнения фоновых задач по расписанию — на нее можно было бы выделить больше ресурсов и на ней не было бы гонок.
Но что мы имеем в итоге:
- точка отказа для всех задач
- уникальная конфигурация, которую можно воспроизвести только в производстве
- задачи, логика которых рассчитана на выделенное выполнение на отдельной толстой машине и не масштабируется по горизонтали
1. Стандартизация костылей
Прежде всего, это наши фреймворки и инструменты для быстрой разработки сервисов: гайки и болты И фронтик .И вообще jклиент и многие другие библиотеки, открытые в нашем github возникла идея о том, что имеет смысл агрегировать опыт различных технологий.
Это позволяет нам культивировать те ограничения, закономерности конструкции и поведения, которые мы отработали в бою и считать наиболее подходящими, понятными и надежными.
Помимо таких очевидных примеров стандартизации, есть и такие, в которых имеет смысл обобщить частные решения.
Например, в какой-то момент у нас стала периодически возникать необходимость с гарантией отправлять сообщения в RabbitMQ (хотя бы один раз).
Проблемы раз за разом решались самописными очередями на базе, и раз за разом администраторы базы говорили, как СИЛЬНО они любят очереди на базе, особенно загруженные.
В конце концов стало очевидно, что необходимо стандартное решение, которое было бы приемлемо для dba, обеспечивало бы надежную доставку и было бы удобно для разработки — поэтому мы написали собственную библиотеку для интеграции.
пгк и кроликmq. Теперь есть большая вероятность, что мы также будем использовать pgq совместно с kafka.
1.0. Ошибки
Баги также могут быть глобальными.Например, в какой-то момент мы обнаружили, что наш фреймворк Python регистрируется в consul в каждом рабочем процессе, причем делает это еще до того, как приложение будет готово принимать запросы.
После исправления в платформе изменения постепенно распространятся на все сервисы по мере их обновления.
Я говорил о еще одной распространенной ошибке, связанной с настройками JVM на демонстрационный этап jpoint 2019 .
Что, например, делать с багом, который воспроизводится раз в неделю на одном из инстансов, лечится перезапуском, но ни нагрузка, ни синтетика его не воспроизводят? Суть бага в том, что экземпляры java-сервисов периодически деградировали.
Судя по дампу потока, это был базовый код: "qtp1778300121-22" #22 prio=5 os_prio=0 cpu=797.67ms elapsed=11737.06s tid=0x00007f5890139000 nid=0x26 waiting for monitor entry [0x00007f58922c7000]
но позже еще один тупик показал стог в глубине родника:
java.lang.Thread.State: BLOCKED (on object monitor)
at ch.qos.logback.core.AppenderBase.doAppend(AppenderBase.java:63)
- waiting to lock <0x00000000e86acad0> (a ru.hh.nab.logging.HhSyslogAppender)
at ru.hh.nab.logging.HhMultiAppender.doAppend(HhMultiAppender.java:47)
at ru.hh.nab.logging.HhMultiAppender.doAppend(HhMultiAppender.java:21)
at ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:51) "qtp1778300121-22" #22 prio=5 os_prio=0 cpu=5718.81ms elapsed=7767.14s tid=0x00007f1537dba000 nid=0x24 waiting for monitor entry [0x00007f153d2b9000]
а потом и вовсе в глубине Джексона:
java.lang.Thread.State: BLOCKED (on object monitor)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent([email protected]/ConcurrentHashMap.java:1723)
- waiting to lock <0x00000000e976a668> (a java.util.concurrent.ConcurrentHashMap$Node)
at org.springframework.beans.factory.BeanFactoryUtils.transformedBeanName(BeanFactoryUtils.java:86) "qtp1778300121-23" #23 prio=5 os_prio=0 cpu=494.19ms elapsed=7234.32s tid=0x00007f6c01218800 nid=0x25 waiting for monitor entry [0x00007f6c07cfa000]
Судя по графикам использования памяти, каждый раз перед дедлоком было видно увеличение Code Cache:
java.lang.Thread.State: BLOCKED (on object monitor)
at org.glassfish.jersey.jackson.internal.jackson.jaxrs.base.ProviderBase._endpointForWriting(ProviderBase.java:711)
- waiting to lock <0x00000000e9f94c38> (a org.glassfish.jersey.jackson.internal.jackson.jaxrs.util.LRUMap)
at org.glassfish.jersey.jackson.internal.jackson.jaxrs.base.ProviderBase.writeTo(ProviderBase.java:588)
Поиск ошибок java не дал результатов.
Однако обновление версии Java, похоже, каким-то образом решает проблему.
Локализовать его не удалось, поэтому от дальнейших исследований мы отказались.
1.1. Общие решения
Иногда можно найти стандартные решения до того, как проблема станет серьезной.Примеры здесь включают проблему обработки логов, о которой рассказал наш Влад Сенин.
в том же jpoint 2019 или задача управления таймаутами в нашем http-клиенте.
Смысл его в том, что полезно определять разумный таймаут не на стороне клиента, а на стороне сервера.
Что касается сервера, у нас есть данные о том, как быстро он отвечает на свои конечные точки.
В настоящее время наш клиент поддерживает один тайм-аут для службы.
Но очевидно, что не все конечные точки службы реагируют одинаково — некоторые занимают больше времени, некоторые быстрее.
Я хотел бы иметь возможность использовать разные таймауты.
В противном случае возникает ситуация, подобная этой:
Пока такие ситуации возникают только при нагрузочном тестировании, но хочется их решить до того, как это станет проблемой.
1.2. Открытые вопросы
Но не все проблемы объясняются какими-то ошибками и сложными ручными процессами.Далее я приведу несколько примеров вопросов, которые также входят в область наших приоритетов, но при этом носят гораздо менее детерминированный характер.
Поэтому я опишу лишь исходные данные, а варианты решения при желании можно обсудить в комментариях.
Итак, первый пример: теперь становится понятно, что существует проблема с интеграцией наших сервисов друг с другом.
Интеграция, скажем, дескриптора веб-сайта в API может занять больше времени, чем первоначальная его разработка.
Еще один пример подобной проблемы, наверняка знакомый многим, – распиловка монолита.
Все понимают, что монолит, обросший большим количеством легаси, усложняет разработку и эксплуатацию.
Но кто может сказать, сколько? Стоит ли жертвовать другими задачами технического долга в пользу распиловки, каждый кусочек которого в отдельности имеет исчезающе малую ценность?
Масштаб этих и подобных проблем таков, что для их решения порой требуется выйти далеко за технические границы и погрузиться в совершенно новые области рабочего процесса.
С одной стороны, это пугает, а с другой – дает невероятную свободу в выборе решений.
2. Как мы работаем
Рассказ о направлениях нашей работы будет неполным без описания того, КАК мы со всем этим работаем.Начну с того, что привлекло меня в работе в «Архитектуре» и что мотивирует всех нас: мы действительно работаем на качество.
И прежде чем в меня закидают камнями, я попытаюсь объяснить, что я имею в виду.
Я считаю, что ни один разработчик сознательно не экономит на качестве.
Дело в техническом долге: если мы говорим о куске бизнес-логики, который не планируется использовать повторно, то, скорее всего, сумма долга от не такого уж идеального решения со временем будет медленно расти, если вообще будет расти.
Это позволяет немного остудить свой перфекционизм — поставить задачу дежурству и перейти к следующей итерации.
Но если мы говорим о фреймворке или инструменте подготовки глобальной конфигурации, который используется в сотнях приложений и закрепляет определенные шаблоны дизайна или именования, то скорость роста долга от его неудачного решения может перекрыть вообще любые выгоды.
Понятно, что бывают ситуации, когда даже самое лучшее решение по мере использования обнаруживает недостатки, но это случается не часто.
Под конец хотелось бы поговорить о препятствиях, которые еще возникают на нашем пути.
Без этого рассказ о нашей работе не был бы справедливым.
Так.
2.0. Сложность оценки задач.
Я уже говорил выше, что мы не можем оценить полезный эффект для всех задач.
Насколько уменьшится время релиза задач при выходе «коробочного» решения для какой-то функции? Какую из двух проблемных областей кода следует реорганизовать в первую очередь? Чтобы выработать адекватную систему оценки задач, мы встречались пару раз в неделю на протяжении нескольких месяцев, но это тема для отдельного поста.
2.1. Коллективное бессознательное
Координировать что-то для 150 человек – задача непростая.Наша очень децентрализованная организационная структура часто показывает свои лучшие стороны, но для «Архитектуры» это порой является серьезным препятствием.
Существует очень мало соглашений, которые можно достичь, и еще меньше соглашений, которые можно затем отслеживать.
И все изменения должны внедряться плавно.
Сервис может месяцами не обновляться, да еще и монолит. Ну хватит о грустном.
Итак, мы поговорили
Надеюсь, после моего рассказа стало немного понятнее, чем занимается «Архитектура» на hh.ru. И если мне удалось пробудить у вас интерес к нашему творчеству, это просто фантастика.Более того, прямо сейчас наша команда открыта вакансия .
Мы будем очень рады свежим идеям, которые помогут нам добиться наших скрытых от праздных взглядов, но таких важных побед. з.
ы.
оригинальный КДПВ это, оказывается, иллюстрация здесь этот мужчина .
Надеюсь, он не против использовать свои изображения в качестве CDPV. Теги: #архитектура #Микросервисы #Системный анализ и проектирование #проектирование #проектирование и рефакторинг
-
Химические Элементы
19 Dec, 24 -
День Закрытия: 3 Мая 2008 Г.
19 Dec, 24 -
Internet Explorer 9: Первые Подробности
19 Dec, 24 -
Зачем Использовать Клоны?
19 Dec, 24 -
Циклические Контейнеры В Objective-C
19 Dec, 24