Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015)

Материал из 0x1.tv

Аннотация

Докладчик
Леонид Юрьев.jpg
Леонид Юрьев

Производственная необходимость и обстоятельства подтолкнули Петер-Сервис использовать OpenLDAP в своих решениях, а затем заставили добиться «от этого кошмара» надёжной работы в нагруженном кластере.

Увы и ах, но общеизвестный проект с открытым исходным кодом и 25-летней историей, лежащий в основе LDAP как технологии, оказался хорошим примером «так делать НЕ надо». Но отступать нам было не с руки…

В результате мы сделали клон исходного проекта и за год получили LDAP-сервер относительно пригодный для промышленной эксплуатации в сфере телекоммуникаций: десятки и сотни миллионов записей, высокие нагрузки, высокая доступность, 24×7.


Видео

Слайды

Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf Кластерный LDAP для Больших Телекомов (Леонид Юрьев, OSSDEVCONF-2015).pdf

Расширенные тезисы

Вход в кротовую нору: Как мы умудрились этим заняться?

Компания Петер-Сервис является разработчиком и поставщиком решений для для крупных операторов связи более 20 лет.

В свою очередь, LDAP «прописан» в стандартах и рекомендациях как интерфейс взаимодействия многих Telco-подсистем, а сервер LDAP является одним из необходимых «кубиков». Поэтому мы решили получить свой «кубик».

В нашем случае к LDAP-серверу предъявляется несколько далеко не рядовых требований:

  • Производительность порядка 10–100К запросов в секунду по-чтению и порядка 5–50К по-записи,

с перспективой роста.

  • Возможность построения географически разнесенного кластера, как минимум из четырёх узлов (2+2), с сохранением

производительности.

  • Высокие требования к стабильности…

Но прежде чем делать свой «велосипед» решили посмотреть на готовые решения, особенно с открытым кодом.

Критерии выбора были следующе: производительность, поддержка multi-master репликации, достаточно широкое использование и приемлемая история проекта. В список кандидатов попали: 389DS, OpenLDAP, ApacheDS и OpenDJ.

При тестировании производительности ни один из кандидатов не справился с нагрузкой как нам хотелось. Но в фавориты вышел OpenLDAP, так как показал [1] самую высокую производительность по-чтению. И в отличие от всех других кандидатов, не деградировала при подаче нагрузки по-записи.

Такое отличие хорошо объяснялось теоретически, так как в OpenLDAP доступен собственный движок LMDB, работающий в модели MVCC и показывающий в тестах рекордную [2] производительность по-чтению.

Дополнительно в пользу OpenLDAP сыграли ещё два немаловажных момента:

  1. OpenLDAP позволяет разделить данные между несколькими разнородными хранилищами, в том числе реализовать

кэширование и т.п.

  1. LMDB имеет режим работы, в котором не фиксирует данные на диске непосредственно после каждой транзакции, а

перепоручает это механизму виртуальной памяти ОС (mmap/msync с флагом MS\_ASYNC). Это дает сверхбыстрое хранилище, которое будет сохранено ядром ОС при крахе приложения, OOM или kill -9.

Так мы залезли в кротовую нору…

Исходная диспозиция: Сказочная стабильность, facepalm от исходного кода

Задействовать OpenLDAP начали в одном из проектов. В то время сам OpenLDAP мы не дорабатывали, просто взяли последний релиз.

В ходе разработки были замечены первые проблемы, а при тестировании ситуация стала критической. Постепенно был выявлен букет всевозможных проблем:

  • Падения: в коде сервера LDAP, в коде движка LMDB, при активации MALLOC\_CHECK, при проблемах в опорной сети или

перезапуске отдельных узлов кластера...

  • Утечки памяти, много.
  • Пробуксовка репликации, иногда кластер часами не мог синхронизироваться.
  • Оперативное переполнение БД, когда в стационарном состоянии свободно более половины.

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

Нет смысла перечислять все замеченные «особенности» исходного кода OpenLDAP, мы просто озвучим наши выводы:

  • OpenLDAP --- это один из образцов как НЕ следует разрабатывать программное обеспечение.
  • Имея открытую лицензию, OpenLDAP не ориентирован на развитие силами сообщества.
  • Объём технического долга и непрозрачность стиля кодирования, не только затрудняют какое-либо участие (очень плохая

кривая обучения), но и отбивают желание стоять рядом.

К сожалению, в ответ на умеренную критику и замечания авторы выдавали перлы: «coverity смешон», «отключите предупреждения, они не нужны», «Вы не понимаете деталей дизайна, вникайте».

При этом вступая в дискуссии и делая ошибки, которые ставят под сомнение глубокое владение темой. Так например, до демонстрации проблем (ITS#7969 Globally shared fields of meta-data are not 'volatile'.), ITS\#7970 Critical Heisenbug --- Inconsistent reading \& SIGSEGV due to the race condition.) утверждалось, что в движке LMDB, который работает по принципам lockfree в разделяемой памяти, не нужны барьеры памяти (memory barriers) и спецификаторы volatile.

Но отступать мы не собирались и решили продолжить битву. Однако, достаточно быстро получили отказ вливать наши изменения, и это заставило нас задуматься о создании собственного клона проекта.

Почему форк, зачем ещё один клон?

Дело в том, что при сборке OpenLDAP генерируется около 5000 (Пять тысяч, Карл! Пять тысяч!) предупреждений[1]. Один из наших первых патчей устранял из них порядка 90%, за счёт использования variadic macros из набора C99. В результате становились заметны реальные ошибки, которые ранее просто терялись в море предупреждений.

В качестве причины отказа было названо использование именно variadic macros\из C99, что конфликтовало с целями целях проекта, где зафиксирована поддержка самого широкого спектра платформ и C89.

В ответ мы предоставили краткий обзор компиляторов C, из которого следовало:

  • В настоящее время нет поддерживаемых платформ или компиляторов, в которых не было бы поддержки variadic

macros.

  • В большинстве компиляторов возможность variadic macros поддерживаются более 10 лет.

Но это не дало результата и мы пришли к решению сделать форк проекта. При этом было решено отбросить максимум «старья», не распыляться и сосредоточиться только на поддержке наиболее актуальной платформы: компиляторов gcc и clang (либо совместимых) и современных[2] версий Linux[3]

В продолжение (или в преддверие) дискуссии о целесообразности и оптимальности создания клона проекта, хочется отметить:

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

ошибках, не были проанализированы и остались в OpenLDAP на своих местах.

  • Выяснилось что OpenLDAP никак не тестируется на устаревших платформах, с которыми декларируется совместимость. Нет

никакой информации о последних успешных сборках, о попытках таких сборок.

  • Весьма вероятно, что для всех платформ, на которых может работать OpenLDAP доступен[4] компилятор

gcc или другой альтернативный с поддержкой variadic macros. Поэтому, весьма вероятно, что вливание патча всё равно позволило бы собрать OpenLDAP для устаревших систем.

Таким образом, вместо наведения элементарного порядка в проекте и создания условий для выявления ошибок, в OpenLDAP в приоритете «абстрактная» совместимость с устаревшими, реально не эксплуатируемыми платформами. Причем эта мнимая «совместимость» никак не тестируется, никак не отслеживается её востребованность и вообще какая-либо необходимость.

Поэтому мы считаем и настаиваем, что в OpenLDAP произошло замещение исходных полезных целей проекта мнимыми, и обеспечение совместимости с «неуловимым Джо» яркий тому пример. Just non reasonable.

Год сурка: Тестирование, корки, медитация, правки

На устранение проблем и доработки было затрачено около года. За это время устранено порядка полусотни различных проблем. Некоторые [3]/[4] («SIGSEGV while disconnect/abandon») из ошибок ждали нас в багтрекере OpenLDAP по многу лет.

Оказалось, что наш сценарий использования отстоит очень далеко от обычных режимов работы OpenLDAP. Соответственно, мы наступили на большинство «грабель», которые проявляются при высокой нагрузке (race conditions), больших объёмах данных (повреждение памяти), стрессовых ситуациях (разрывы соединений), мульти-мастер репликации (логика).

Часть из исправленных проблем задокументированы как issues на github, но многие мы исправили молча. Особенно это относится к проблемам инфраструктуры и тестам.

Отдельно можно упомянуть про механизм репликации. Кроме технических ошибок, в нём оказалось несколько высокоуровневых изъянов [5] в логике алгоритмов.

После исправления ошибок текущая версия ReOpenLDAP не падает в условиях стрессового нагрузочного тестирования. Это банальный, но очень труднодостижимый результат. Как уже отмечалось, стиль кодирования не располагает к анализу исходного кода — очень часто это ребус в виде спагетти написанный на птичьем языке.

Не так давно на «Хабре» удачно опубликовали руководство[5] по стилю кодирования для OpenLDAP.

Но я убежден, после завершения проекта ещё останется достаточно материала для написания книги «Как НЕ надо делать софт».

Результаты доработок

Сделанные доработки можно разделить на шесть групп:

  • Наведение минимального порядка. Проект успешно собирается с опциями {}-Wall -Werror. При этом было выявлено более

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

  • Исправление ошибок. Перечислять их скучно и малопонятно. Их много, и многие потрясают «а как вообще могло

работать». Механизм репликации частично переписан.

  • Доработка инфраструктуры, как например стабилизация тестов или встроенный контроль динамической памяти. Пришлось

потрудиться чтобы тесты можно было зациклить и они «не падали» через 5–10 итераций из-за своих собственных проблем.

  • Специфические доработки заказанные нашей службой эксплуатации. Так например, в конфигурации сервера можно задать

предел использования оперативной памяти и включить запись backtrace вместо создания сoredump.

  • Доработка внутренностей движка LMDB. Собственно это отдельная тема, которой будет посвящен

доклад[6] на конференции Highload. Здесь можно кратко перечислить: полностью переписан путь сброса данных на диск с устранением двух принципиальных дефектов, steady и weak точки фиксации, OOM-handler при исчерпании места в БД, LIFO-режим для Garbage Collector, утилита mdb_chk для проверки образа БД.

  • Доработки slapd, в том числе механизма репликации и механизма манипуляции данными основанного на LMDB.

В последнем пункте есть несколько ключевых доработок, на которых хочется остановиться чуть подробнее:

Механизмы oom-handler и dreamcatcher
без пенальти полностью решают так называемую «проблему отставших

читателей».

Суть проблемы в том, что в LMDB любая долгая (открытая, приостановленная) транзакция чтения на фоне изменения данных может приводить к быстрому исчерпанию места в БД и отказу сервиса. Проблема усугубляется тем, что такими «медленными читателями» является процедура горячего резервного копирования и процессы репликации.

Поэтому без этих механизмов OpenLDAP не пригоден для промышленной эксплуатации.

Механизм biglock
Название отражает суть, это «большая блокировка по записи».

К сожалению в OpenLDAP есть неустранимый архитектурный дефект, который может приводить к неверной репликации. Biglock позволяет защитить фазу трансляции UUID в DN-ключи и последующие операции, гарантируя этим целостность.

Включение Biglock даёт небольшой пенальти (рекурсивный мьютекс) для операций записи/модификации, но это крайне незначительная величина, так как сам движок LMDB поддерживает только одного «писателя»и всё равно сериализует все транзакции записи.

Механизм «Кворума» репликации
Кавычки здесь крайне важны поскольку никакого протокола или алгоритма

согласования (Paxos) не используется. Однако «кворум» позволяет перевести узел кластера в readonly-режим при нарушении связанности, во избежания дальнейшего расхождения данных на узлах кластера.

Ограничение конкуренции сеансов синхронизации
Это отдельная «вишенка на торте» в возможностях «Кворума», которая позволяет в разы уменьшить пиковое использование оперативной памяти и CPU, сократить время синхронизации

кластера при восстановлении связанности.

Автоматическое формирование контрольных точек
сброс данных на диск, как по объёму накопившихся

изменений, так и периодически с секундной точностью.

Комбинация всех доработок, включая допеределку LMDB, позволяет получить производительность в 5–50 раз больше оригинального OpenLDAP. Дабы не ввести в заблуждение, специально отмечу, что такой разгон возможен:

  • За счёт пакетной фиксации транзакций на диске (управляемый компромисс);
  • При наличии у дисковой подсистемы кэша обратной записи, который начинает «работать» благодаря доработкам LMDB

(LIFO Reclaiming, Checkpoints).

  • В стадии тестирования находится доработка устраняющая лишние обновления набора отметок contextCSN в ходе

репликации. В зависимости от конфигурации кластера это может в 2-3 раза снижать количество фиксируемых транзакций. Соответственно, пропорционально снижается write amplification, нагрузка на диски и повышается интегральная производительность.

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

Отдельно хочется поблагодарить Егора Левинца за предоставленный перевод man-страниц.

Что дальше?

Мы вложили массу сил и времени в реанимацию ReOpenLDAP и вывод его на орбиту. В наших сценариях использования этот проект гораздо более стабильный и работоспособный в сравнении с исходным OpenLDAP, особенно переработанный механизм репликации.

Но к сожалению, субъективная оценка качества исходного кода и объёма технического долга заставляет сделать вывод о том, что OpenLDAP следует не чинить и развивать, а похоронить или переписать с чистого листа.

Стратегически Петер-Сервис уже решил в перспективе мигрировать на более стабильные по дизайну решения, и с более качественным исходным кодом. Так в качестве LDAP-платформы рассматривается OpenDJ, а в качестве оперативного хранилища Tarantool. Возможно, будет принято решение о подключении к ним движка WiterTiger или собственного, основанного на идеях LMDB.

Какое-то время ReOpenLDAP будет поддерживаться силами Петер-Сервис. Мы планируем исправлять замеченные ошибки, а также портировать исправления из OpenLDAP. Скорее всего, эта работа будет продолжаться до момента вывода из эксплуатации сервисов работающих на основе ReOpenLDAP.

После мы постараемся передать проект сообществу, если конечно будет соответствующая заинтересованность.

Примечания и отзывы

  1. При использовании компиляторов gcc версий 4.4.7-5.2.1 и clang 3.3-3.6, с установками генерации предупреждений по-умолчанию.
  2. Имеются в виду активно эксплуатируемые версии, грубо говоря не старше RHEL6.
  3. Поддержка FreeBSD также рассматривалась, но меинтейнера не нашлось.
  4. Это утверждение не удалось ни опровергнуть, ни подтвердить, по причине отсутствия у нас необходимого парка оборудования и ПО
  5. [http://habrahabr.ru/company/friifond/blog/268063/ Как писать код, который никто не сможет сопровождать]
  6. Highload++2015, Движок LMDB --- особенный чемпион

Plays:58   Comments:0