Компания
241,31
рейтинг
4 июля 2012 в 16:59

Разработка → 11 «рецептов приготовления» MySQL в Битрикс24



Проектируя, разрабатывая и запуская наш новый большой проект — «Битрикс24», мы не только хотели сделать по-настоящему классный сервис для командной работы (к тому же еще и бесплатный — до 12 пользователей), но еще и собрать и накопить опыт по эксплуатации облачных веб-сервисов, «прокачать» свою компетенцию в разработке высоконагруженных отказоустойчивых проектов и — самое главное — поделиться этими знаниями как с нашими партнерами, так и со всеми веб-разработчиками, кому близка тема «хайлоада». :)

Конечно, в одной статье (и даже не в одной) невозможно описать универсальный «рецепт», который бы подошел абсолютно для всех проектов: для кого-то важнее производительность (иногда — даже в ущерб надежности), для кого-то — наоборот, отказоустойчивость превыше всего, где-то много маленьких таблиц, где-то — большой объем данных…

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

Начнем по порядку.

Мы не раз уже говорили и писали о том, что «Битрикс24» развернут в Амазоне. И раз мы так любим и активно используем различные облачные сервисы, первый же вопрос…

1. Почему не используем RDS?

Amazon Relational Database Service (Amazon RDS) — облачная база данных. Есть поддержка MS SQL, Oracle и — что было интересно нам — MySQL.

Долго присматривались, хотели использовать в своем проекте… В итоге отказались от этой идеи. Несколько ключевых причин:

  • Во-первых, система недостаточно гибкая и прозрачная. Например, вы не получаете полноценного root-доступа к базе. А это значит, что какие-то специфичные (конкретно для вашего проекта) настройки, возможно, не получится сделать.
  • Есть риск долгого даунтайма в случае какой-либо аварии. И практика показывает, что риск этот вполне реален. Да, чаще страдают те базы, которые расположены только в одной зоне, и для обеспечения отказоустойчивости можно использовать так называемые Multi-AZ DB Instances. Но — о них далее...
  • При использовании Multi-AZ DB Instances для базы постоянно пишется standby бэкап в другую AZ (Availability Zone), и в случае аварии в первой зоне происходит автоматическое переключение на другую. Но в этом случае один инстанс с базой стоит ровно в два раза дороже. При этом пользователь эффективно использует ресурсы только одной машины (в отличие от схемы с «мастер-мастер» репликацией, о которой мы недавно писали).

Все это не означает того, что RDS — плохой сервис, и его не надо никогда использовать. Это не так. Он не подошел конкретно для нас. И, возможно, для кого-то будет гораздо проще обеспечить масштабирование и отказоустойчивость именно средствами Амазона.

2. Master-Slave? Нет, Master-Master!

Стандартная схема репликации в MySQL «Master-Slave» давно и успешно применяется на многих проектах и решает несколько задач: масштабирование нагрузки (только на чтение) — перераспределение запросов (SELECT'ов) на слейвы, отказоустойчивость.

Но решает — не полностью.

1. Хочется масштабировать и запись.
2. Хочется иметь надежный failover и продолжать работу автоматически в случае каких-либо аварий (в master-slave в случае аварии на мастере нужно один из слейвов в ручном или полу-автоматическом режиме переключить в роль мастера).

Чтобы решить эти задачи, мы используем «мастер-мастер» репликацию. Не буду сейчас повторяться, этой технике у нас недавно был посвящен отдельный пост на Хабре.

3. MySQL? Нет, Percona Server!

Первые несколько месяцев (на прототипах, в процессе разработки, в начале закрытого бета-тестирования сервиса) мы работали на стандартном MySQL. И чем дольше работали, тем больше присматривались к различным форкам. Самими интересными, на наш взгляд, были Percona Server и MariaDB.

Выбрали мы в итоге Перкону — конечно, из-за похожего «перевернутого» логотипа. ;)



… и нескольких фич, которые оказались крайне важными для нас:

  • Percona Server оптимизирован для работы с медленными дисками. И это очень актуально для «облака» — диски там почти всегда традиционно медленнее (к сожалению), чем обычные диски в «железном» сервере. Проблему неплохо решает организация софтверного рейда (мы используем RAID-10), но и оптимизация со стороны серверного ПО — только в плюс.
  • Рестарт базы (при большом объеме данных) — дорогая долгая операция. В Перконе есть ряд фич, которые позволяют делать рестарт гораздо быстрее — Fast Shut-Down, Buffer Pool Pre-Load. Последняя позволяет сохранять состояние буфер-пула при рестарте и за счет этого получать «прогретую» базу сразу после старта (а не тратить на это долгие часы).
  • Множество счетчиков и расширенных отчетов (по пользователям, по таблицам, расширенный вывод SHOW ENGINE INNODB STATUS и т.п.), что очень помогает находить, например, самых «грузящих» систему клиентов.
  • XtraDB Storage Engine — обратно совместим со стандартным InnoDB, при этом гораздо лучше оптимизирован для хайлоад проектов.

Полный список можно посмотреть на сайте в разделе «Percona Server Feature Comparison».

Важный момент — переход со стандартного MySQL на Percona Server вообще не потребовал изменения какого-либо кода или логики приложения.

А, вот, сам процесс «переезда» был достаточно интересным. И благодаря использованию схемы с «мастер-мастер» репликацией, прошел совершенно незаметно для наших пользователей. Даунтайма просто не было.

Схема переезда была такой:

  • «Нулевой» шаг — подняли тестовый стенд их снэпшота машины с базой с реальными данными. И на нем стали отлаживать конфигурацию для стабильной работы. Ну и, конечно, подбирать специфичные для Перконы опции в конфигурационном файле.
  • Получив стабильную конфигурацию, переключили весь траффик на один ДЦ, а базу без нагрузки выключили из репликации.
  • На этой базе осуществили переход на Percona Server.
  • Включили базу в репликацию (стандартный MySQL и Percona Server совместимы).
  • Дождались синхронизации данных.
  • После этого проделали ту же процедуру со второй базой.


4. MyISAM? InnoDB?

Тут все просто.

  • На долгих запросах в MyISAM лочится вся таблица. В InnoDB — только те строки, с которыми работаем. Соответственно, в InnoDB долгие запросы в меньшей степени влияют на другие запросы и не отражаются на работе пользователей.
  • На больших объемах данных и при высокой нагрузке таблицы MyISAM «ломаются». Это — известный факт. В нашем сервисе это недопустимо.
  • Ну, и раз уж у нас есть «улучшенный» InnoDB — XtraDB, конечно, мы будем использовать именно этот storage engine. :)

* * *

Переходим от архитектурных вопросов к более практическим. :)

5. Все ли данные нужно реплицировать? Нет, не все.

Почти в любом проекте есть некритичные для потери или восстанавливаемые данные. В том числе — и в базе данных.

В нашем случае такими данными были сессии. Что было плохого в том, что реплицировалось все подряд?

  • В таблицах сессий наряду с SELECT'ами много операций записи (INSERT, UPDATE, DELETE). Это значит, что мы даем лишнюю нагрузку на slave базу. Ту нагрузку, которую можно избежать.
  • Кроме того, при достаточно большом значении query_cache_size мы столкнулись с тем, что активная работа с этими таблицами и их участие в репликации приводят к тому, что многие треды «подвисают» в состоянии «waiting for query cache lock» (видно в SHOW PROCESSLIST). Далее это чревато повышенной нагрузкой на CPU и общей деградацией производительности.

Исключение этих данных из репликации полностью решило проблему.

Как исключать? Есть разные способы.

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

SET sql_log_bin = 0;

2. Более простой и понятный способ — указать исключение в конфигурационном файле MySQL.

replicate-wild-ignore-table = %.b_sec_session

Такая конструкция исключает из репликации таблицы b_sec_session во всех базах.

Все немножко более сложно в том случае, если вам нужна более сложная логика. Например, не реплицировать таблицы table во всех базах, кроме базы db.

В таком случае вам придется немного порисовать схемки наподобие тех, которые дает MySQL, чтобы составить правильную комбинацию опций — фильтров.


6. Тип репликации.

Много споров вызывает вопрос, использовать ли STATEMENT-based или ROW-based репликацию. И тот, и другой вариант обладают и плюсами, и минусами.

По умолчанию в MySQL (Percona) 5.5 используется STATEMENT-based репликация.

На нашем приложении в такой конфигурации мы регулярно видели в логах строки: «Statement may not be safe to log in statement format».

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

В MySQL есть интересное решение, которое нас полностью устроило — использовать MIXED формат бинлога:

binlog-format = mixed

В этом случае по умолчанию репликация идет в режиме STATEMENT и переключается в ROW как раз в случае таких небезопасных операций.

7. Репликация сломалась. Что делать?

Репликация иногда все-таки ломается. Особенно страшно (поначалу :)) это звучит при работе с «мастер-мастер».

На самом деле, ничего страшного нет. Правда. :)

В первую очередь нужно помнить о том, что описанная схема «мастер-мастер» репликации — это на самом деле просто две обычные «master-slave» репликации. Да, с некоторыми нюансами, но большинство практик, используемых в стандартной схеме, работают и здесь.

Самая простая (и самая часто случающаяся) проблема — ошибка вида «1062 Error 'Duplicate entry'».

Причины могут быть разными. Например, мы в случае какой-либо аварии с базой переключаем траффик на другой ДЦ. Если запрос уже был выполнен в ДЦ 1, но не успел среплицироваться в ДЦ 2 и был выполнен там повторно — да, получим именно такую ошибку.

Лечится выполнением вот таких команд на слейве:

STOP SLAVE;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
START SLAVE;

Тем самым пропускаем лишний запрос. Далее смотрим состояние репликации:

SHOW SLAVE STATUS\G

Если требуется, повторяем процедуру.

* * *

Да, мы сейчас детально рассматриваем самый простой вариант. Все бывает значительно хуже — рассыпается файловая система, бьются файлы и т.п.

Универсального рецепта «как все починить» нет. Но всегда важно помнить следующее:

  • Не паниковать.
  • Видеть состояние слейва с помощью SHOW SLAVE STATUS\G.
  • Видеть состояние мастера с помощью SHOW MASTER STATUS.
  • Всегда вести лог (log-error = /var/log/mysqld.log) — в нем очень много полезной информации. Например, данные о том, до какой позиции слейв дочитал бинлог мастера. Очень помогает при авариях.
  • Если все совсем сломалось — подниматься из бэкапа.

8. Как поднимать из бэкапа один из серверов в «мастер-мастер» репликации?

Что же делать, если в схеме с двумя мастерами все-таки что-то пошло не так (например, во время аварии в Амазоне несколько дней назад у нас необратимо повредились файловые системы на нескольких серверах)?

Решение «в лоб» — перелить данные из одного сервера на другой и запустить репликацию с нуля — слишком долго.

В Амазоне мы используем механизмы снэпшотов дисков и создание образов (AMI) целых машин. Это позволяет очень быстро развернуть полную копию нужного сервера — например, по состоянию на несколько часов назад.

Если мы просто развернем машину из бэкапа, мы получим интересный эффект: мы начнем читать данные из бинлогов «живого» мастера (с момента, когда создавался бэкап), но прочитаем лишь половину их, так как по умолчанию записи с сервера с тем же server-id (из «будущего» относительно времени бэкапа) реплицироваться не будут. Это делается для того, чтобы избежать «зацикливаний» в «мастер-мастер».

Поступаем так:

1. Весь траффик идет на «живой» ДЦ. На тот сервер, который мы восстанавливаем нагрузки нет.
2. На сервере, поднятом из бэкапа, сразу останавливаем mysqld и вписываем в конфиг:

skip-slave-start 
replicate-same-server-id 
#log-slave-updates = 1 ; комментируем!

3. Запускаем mysqld и стартуем репликацию.
4. После того, как данные синхронизированы, возвращаем конфиг в исходное состояние:

#skip-slave-start 
#replicate-same-server-id 
log-slave-updates = 1 

5. Так как у нас — «мастер-мастер», нам нужно запустить репликацию и в обратную сторону. Останавливаем репликацию на том сервере, который мы восстанавливали, и выполняем:

SHOW MASTER STATUS;

Если репликацию не остановим, данные будут меняться.
6. Стартуем с нужной позиции репликацию на первом (живом) сервере:

STOP SLAVE;
CHANGE MASTER TO MASTER_LOG_FILE='...', MASTER_LOG_POS = ...;
START SLAVE;

Вписываем данные, полученные в пункте 5.
7. Стартуем репликацию и на втором сервере.

9. Где баланс между производительностью и надежностью репликации?

Есть много опций в MySQL / Percona, которые позволяют кардинально повысить надежность и сохранность данных в случае, например, внезапных ребутов. Практически все они столь же кардинально снижают быстродействие системы.

Мы для себя нашли баланс в такой комбинации опций:
sync_binlog = 1
sync_master_info = 0
sync_relay_log = 0
sync_relay_log_info = 0
innodb-flush-log-at-trx-commit  = 2

Бинлог для нас критически важен, поэтому sync_binlog = 1. Но при этом бинлоги хранятся на отдельном диске в системе, поэтому запись на этот диск не снижает производительность системы в целом.

10. Как вообще оценивать производительность системы?

Если у нас есть большие «тяжелые» запросы, то, конечно, мы банально ориентируемся на время их выполнения.

Чаще же (и в нашем случае — именно так) система обрабатывает много-много мелких запросов.

Конечно, можно использовать различные синтетические тесты для оценки производительности системы. И некоторую оценку они дадут. Но ведь хочется иметь какие-то реальные показатели (желательно — в цифрах :)), которые можно было бы применять «в бою».

В Percona Server есть замечательный инструмент:

SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;

+----------------+-------+----------------+
| time           | count | total          |
+----------------+-------+----------------+
|       0.000001 |     0 |       0.000000 |
|       0.000010 |  6555 |       0.024024 |
|       0.000100 | 56132 |       2.326873 |
|       0.001000 | 23165 |       6.686421 |
|       0.010000 |  9755 |      39.737027 |
|       0.100000 |  1437 |      40.831493 |
|       1.000000 |   141 |      31.785571 |
|      10.000000 |     9 |      17.891514 |
|     100.000000 |     0 |       0.000000 |
|    1000.000000 |     0 |       0.000000 |
|   10000.000000 |     0 |       0.000000 |
|  100000.000000 |     0 |       0.000000 |
| 1000000.000000 |     0 |       0.000000 |
| TOO LONG       |     0 | TOO LONG       |
+----------------+-------+----------------+
14 rows in set (0.00 sec)

Такая гистограмма распределения времени выполнения запросов очень хорошо помогает оценивать общее состояние системы.

Например, мы для себя определили некий критический порог — не более 5% запросов (от общего числа) с временем выполнения более 0.01 сек.

Чтобы отслеживать это состояние в динамике, написали простой плагин к Munin'у, который как раз и рисует график по данному соотношению. Очень удобно, и — главное — это живая понятная метрика.

11. Сбалансированность по памяти.

Настройки MySQL должны быть такими, чтобы потребление памяти было сбалансировано!

Вроде, простое и понятное правило, но о нем часто забывают. Каюсь, сами пару раз (в начале, на прототипе :)) получили OOM (Out of memory) и — как следствие — «убитый» операционной системой процесс mysqld.

В идеале — процесс mysqld должен работать так, чтобы полностью помещаться в оперативной памяти и не оперировать свопом.

Обязательно — все процессы системы должны помещаться в память+swap.

Зачастую подсчеты, сколько памяти может потребить mysqld, оказываются для многих неочевидными.

Формула примерно такова:

  • Размер глобальных буферов: key_buffer_size + tmp_table_size + innodb_buffer_pool_size + innodb_additional_mem_pool_size + innodb_log_buffer_size + query_cache_size
  • Размер буфера для одного коннекта: read_buffer_size + read_rnd_buffer_size + sort_buffer_size + thread_stack + join_buffer_size
  • Максимально возможное использование памяти: глобальные буферы + буферы подключений * максимальное число коннектов

Если не очень хотите считать :), можно воспользоваться скриптом mysqltuner.pl, который помимо этой информации покажет много других данных по системе, безопасности, производительности и т.п.

# wget mysqltuner.pl
# perl mysqltuner.pl


* * *

Спасибо, что дочитали до этого места! :)



Мы рассмотрели лишь некоторую часть практических вопросов и приемов, которые мы используем в работе «Битрикс24». В том числе благодаря им, сервис растет и развивается.

Надеемся, что наш опыт поможет и вам в создании и развитии ваших проектов.

И уже сейчас видно, что объема одной статьи совершенно недостаточно. В ближайшее время постараемся продолжить тему использования MySQL в больших проектах, поделимся новыми рецептами и опишем наиболее интересные и востребованные темы более подробно.
Автор: @adamant
1С-Битрикс
рейтинг 241,31

Комментарии (35)

  • +7
    Полезный пост с практическими примерами простой реализации критически важных функций MySQL. Чем проще, тем надежнее :-)
  • +4
    Прочитал с интересом, спасибо. Так же уяснил для себя, что я практически не знаю MySQL… ушел учить :)
  • +3
    Спасибо, очень полезно. Пошел теперь читать вашу статью про мастер-мастер, которой не придал должного внимания вначале.
  • +2
    Статья безусловно интересная! Но матчасти можно было и побольше выдать )
    • +1
      Миш, для твоей команды всегда готовы провести скайп-конференцию и ответить на вопросы по тонкостям настройки MySQL :-)
  • –3
    Ребята, хочется разбавить вашу битрикс-тусовку, потому что, мало кому итересно очередное битрикс-мыло. Я считаю, что самая сильная сторона вашего продукта, это конечно же подсветка синтаксиса в редакторе кода. Развивайте это направление и вас ждет успех!
    • +1
      Почему же мыло. Из всех ЦМС наиболее удобная для конечного пользователя да и для разработчиков тоже. Да есть и битрикса свои недостатки. Покажите мне систему, у которой их нет.
    • +1
      Рад, что вам нравится наш редактор с подсветкой! И, кстати, для истинных ценителей есть еще несколько схожих по функционалу модулей в нашем маркетплейсе:

      marketplace.1c-bitrix.ru/solutions/citrus.ace/
      marketplace.1c-bitrix.ru/solutions/cn.highlight/

      Спасибо за добрые пожелания! ;)
      • 0
        а вот кстати редактор с подсветкой совсем не порадовал. слишком замороченный какой-то. также как и визуальный редактор. ченить попроще было лучше :)
      • 0
        Кстати да, редактор сырой если честно
  • +3
    используем сходные решения у себя, пришли к тем же выводам и библиотекам
    но:
    — отказались от хранения сессий в базе. при большой нагрузке удаление сессий из базы становится трудоемкой задачей, да и смысла хранить там данные нет. Как показывает пример вам не очень важна сессия пользователя, превосходно с ее хранением справится мемкешед.
    — чтобы сделать быстрый бекап у перконы есть специальная утилита xtrabackup, его же можно использовать что бы поднять репликацию
    • +3
      — Сессии (в итоге, после разных экспериментов) тоже храним в мемкеше. Правда, потребовалась некоторая доработка логики, чтобы реализовать собственный механизм локировок (в мемкеше его нет).

      — xtrabackup тоже используем, но для других сценариев. Снэпшот и образ машины делаются сильно проще и быстрее. Да и разворачивать их потом тоже легче.
      • 0
        — локировка есть в мемкешеде, называется cas. Правда что-то не пойму зачем она для сессий. Может не так вас понял
        — у нас не амазон, а реальные железки. Приходится изворачиваться (:
    • 0
      Поднятие образа машины из снепшота в амазоне с моментальным снимком данных — работает в принципе не хуже xtrabackup. Иначе использовали бы конечно xtrabackup.
  • –5
    Нет, ребята! Стоп! За годы потоков говна на ваш продукт, вы видимо научились замыливать любые высказывания по поводу вашего «продукта». Как Рыжиков, когда на презентациях что-то не работает ( а у вас всегда что-то не работает. Последнее выступление на партнерской летней конференции вообще было фееричным, смеялись всем офисом), он отшучивается и уводит тему в другое русло.
    Так вот, конечные пользователи вообще не суются в вашу админку и, что бы сменить картинку, звонят разработчикам, а разработчик чертыхаясь лезет туда, думая о том, что пора сваливать из конторы, которая юзает ваш «продукт»( не потому что он удобный, а потому что ваша партнерская программа дает возможность заработать).

    Ну все, не буду разводить снова эту возню вокруг «продукта». Как говориться не трогай, оно и вонять не будет. Всем добра!
    • +3
      Если вы столь искренне переживаете за наш продукт, расскажите о ваших переживаниях там, где это будет уместно. Лично Рыжикову (его e-mail, твиттер, фейсбук не являются тайной; на конструктивную критику он всегда реагирует), на сайте idea.1c-bitrix.ru/ (его читают все наши разработчики), создайте обращение в тех. поддержку или напишите лично ее руководителю (все контакты тоже доступны).

      Эта статья — о практиках использования MySQL. Для любых проектов, на Битриксе они сделаны или нет.

      Если вы как на красную тряпку реагируете именно на слово «битрикс», тут уж ничего не поделаешь — так уж сложилось, что в данном случае практическим опытом делимся именно мы. И очень верю, что для многих он — полезен.
    • –1
      Ваше, безусловно авторитетное мнение, подсказывает, что вы можете привести парочку альтернатив битриксу?
  • 0
    ошибки вида «1062 Error 'Duplicate entry'» можно избежать, сказав серверу использовать автоинкримент со смещением:

    auto_increment_increment
    auto_increment_offset
    dev.mysql.com/doc/refman/5.1/en/replication-options-master.html
    • 0
      Это подразумевается по умолчанию. И об этом как раз говорится в предыдущей статье, на которую я несколько раз ссылался: habrahabr.ru/company/bitrix/blog/146490/

      В противном случае «м-м» в принципе не будет работать.

      Но даже с настроенными auto_increment_increment и auto_increment_offset «Duplicate entry» все равно будут. Один из возможных сценариев появления такой ошибки как раз описан в статье.
  • 0
    Позвольте не согласиться,
    При использовании этих 2-х параметров сервера м-м будут создавать только то значение, которое им позволено и никогда не пересекуться.
    Например
    сервер А:
    auto_increment_increment=10
    auto_increment_offset=1
    сервер В:
    auto_increment_increment=10
    auto_increment_offset=2

    тогда
    Сервер А значения:
    1,11,21,31,41,51
    Сервер В значения:
    2,12,22,32,42,52

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

    Это касается автоинкриментов, но не спасает от Duplicate key — В данном случае поможет:
    --slave-skip-errors={code}|All 
    

    указать, какие типы ошибок игнорировать. В таком случае, методом проб, ошибок и нагоняев программистам достигается устойчивая м-м репликация. Полный список кодов можно посмотреть в share/errmsg.txt

    Другое дело, если вдруг в коде используются конструкции вида Now(), при разрыве реплик — значения будут существенно разными.
  • 0
    mysql_upgrade should be executed each time you upgrade MySQL. dev.mysql.com/doc/refman/5.5/en/mysql-upgrade.html JFYI
  • 0
    Уж что-что, а sql битрикс жрет как ни что другое… Просто кошмар сисадмина какой-то, а не система. Иногда приходится просить разрабов писать собственные sql-запросы для обращения к некоторым инфоблокам, чтобы не видеть в slow-query-log'е 15-этажные JOIN'ы. Самое забавное, когда join_buffer_size = 8G оказывается мало сайту с посещаемостью 5к человек в день. :)
    • 0
      Чтобы не было 15 этажных джойнов, можно делать разумную избыточность в инфоблоках.
      • 0
        Чёрт, что я пишу, если у вас есть некэшируемые(на сто тысяч лет) запросы с 15тью джойнами, то у вас просто напросто криво спроектирована структура инфоблоков, других вариантов нет.
        • +1
          Приведу пример: есть 200000 зареганных юзеров, есть 15 инфоблоков, по которым размазана инфа об этих юзерах. Когда нужно вытянуть это дело в одну таблицу, возникают траблы: не получается красиво разрулить такую ситуацию, руководствуясь правилами построения запроса к инфоблокам Битрикса. Приходится строить свои запросы к базе. Иногда получается что-то оптимизировать средствами битрикса, но чаще приходится самим что-то придумывать (даже писать свое кэширование, например).

          Алсо, наши программисты ни то что читали ни раз всю документацию по Битриксу, но и затерли до дыр все статьи об оптимизации и грамотном программировании к Битрикс на Вашем (и не только) сайте.

          Система хорошая, одна из лучших CMS, почти не глючит, но мееедленная…
          Иногда, копаясь в ядре Битрикс натыкаешься на такой быдлокод, что волосы дыбом встают (в особенности, касаемо SQL-запросов).

          Кстати, за годы разработки под Битрикс, мы написали что-то вроде фреймворка под свои нужды — вот в нем есть много переписанных функций ядра Битрикс, которые позволяют быстрее общаться с нашими БД.
          • +1
            1. насчёт «быдлокода» — в голову не приходила мысль, что это код написан таким образом в силу определённых причин? Например, некоторые куски кода можно, заменить стандартной php функцией, но только при определённых настройках сервера и при работе под mbstring'ом эта самая функция работает не правильно. И поэтому её приходится заменять «странным кодом», только он выглядит странным для прохожего, а как только вникаешь в причину его появления, понимаешь какая огромная работа была проделана.

            2. размазывать информацию о пользователях по 15ти инфоблокам это жёстко! Опять же, для меня как для прохожего, который не знает всех ваших внутренних нюансов и бизнес-процессов, это как раз кажется быдлокодом. Хотя есть вероятность что такой подход, в силу каких то причин в вашем случае оправдан.х.з.

            3. когда кол-во ИБ переваливает за 50, всегда стараюсь делать разумную избыточность, тогда данные можно выбирать без джойнов.

            4. при больших объёмах таблиц, вычисления можно размазывать по времени — например некоторые значения можно рассчитывать при изменении элементов ИБ, это лучше чем пытаться за один проход всё сразу просчитать.

            p.s. прошу прощения если вам покажется, что я пытаюсь объяснить детские истины.
            • +1
              1. Завтра попытаюсь найти sql-запросы из ядра, которые повергли меня в шок. :) Но не обещаю (я мог удалить уже файлик куда я их выписывал)
              2. Ну там очень много параметров… И некоторые инфоблоки содержат по > 100k записей.
              4. Мы так делаем теперь. :)
    • 0
      А как Вы определили, что «join_buffer_size = 8G» — это мало? :)

      И сколько у вас было при этом RAM в системе?
      • 0
        mysqltuner.pl об этом рапортовал.
        На mysql отводилось 12G.
        • +2
                  # Joins
                  if ($mycalc{'joins_without_indexes_per_day'} > 250) {
                          badprint "Joins performed without indexes: $mycalc{'joins_without_indexes'}\n";
                          push(@adjvars,"join_buffer_size (> ".hr_bytes($myvar{'join_buffer_size'}).", or always use indexes with joins)");
                          push(@generalrec,"Adjust your join queries to always utilize indexes");
                  } else {
          ...


          Если не будет индексов (зачастую — составных, которые надо построить самим), то он, видимо, всегда так будет рапортовать. :)

          И «join_buffer_size = 8G» — это в любом случае плохо. Вот неплохое описание (с комментариями), как происходит выделение памяти для join_buffer_size:

          www.mysqlperformanceblog.com/2010/07/05/how-is-join_buffer_size-allocated/
          • +1
            Ценный коммент, спасибо!

            Кстати, по своему опыту (может я и не прав), обнаружил что уменьшение этого буфера с 8 гигабайт до 8 мегабайт никак не влияет на производительность. :)

            Другое дело query_cache_size и особенно innodb_buffer_pool_size.
            • +2
              О… Использование query cache и оптимизация innodb — это вообще отдельные темы, заслуживающие отдельных статей! :)

              Наверное, попробую собраться с мыслями и написать в ближайшее время. :)
  • +1
    Чуть не забыл — спасибо за очень полезную статью.

    Кстати, если репликация сломалась, у нас есть скрипты которые автоматом ее поднимают. Бывает в суматохе сразу и не вспомнишь всю последовательность действий для поднятия репликации с нуля, а скрипт отрабатывает за секунды.
    Но у нас пока тупо master-slave для резервного зеркала.
  • –1
    Отличная статья! Тоже готовимся к большим проектам :)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Самое читаемое Разработка