Возникла небольшая прикладная задача. Нужно было периодически с одного mysql сервера перекидывать дамп одной таблицы из базы на другой сервер в такую же базу. Решений этой задачи может быть много. Я взял и решил в лоб набором простых команд на bash. Делюсь с вами итоговым скриптом. Даже если он вам не нужен в рамках этой задачи, то можете взять какие-то моменты для использования в другой.
Скрипт простой, можно легко подогнать под свои задачи. Наверное эту задачу смог бы решить и ChatGPT, но я не проверял. Сделал по старинке сам.
Отдельно отмечу для тех, кто не в курсе, что можно вот так запросто тут же после подключения по ssh выполнять какие-то команды в автоматическом режиме. Это удобно и часто пригождается.
#mysql #bash #script
#!/bin/bash
# Дамп базы с заменой общего комплексного параметра --opt, где используется ключ --lock-tables на набор отдельных ключей, где вместо lock-tables используется --single-transaction
/usr/bin/mysqldump --add-drop-database --add-locks --create-options --disable-keys --extended-insert --single-transaction --quick --set-charset --routines --events --triggers --comments --quote-names --order-by-primary --hex-blob --databases database01 -u'userdb' -p'password' > /mnt/backup/sql/"$(date +%Y-%m-%d)"-database01.sql
# Из общего дампа вырезаю дамп только данных таблицы table01. Общий дамп тоже оставляю, потому что он нужен для других задач
/usr/bin/cat /mnt/backup/sql/"$(date +%Y-%m-%d)"-database01.sql | /usr/bin/awk '/LOCK TABLES `table01`/,/UNLOCK TABLES/' > /mnt/backup/sql/"$(date +%Y-%m-%d)"-table01.sql
# Сжимаю оба дампа
/usr/bin/gzip /mnt/backup/sql/"$(date +%Y-%m-%d)"-database01.sql
/usr/bin/gzip /mnt/backup/sql/"$(date +%Y-%m-%d)"-table01.sql
# Копирую дамп таблицы на второй сервер, аутентификация по ключам
/usr/bin/scp /mnt/backup/sql/"$(date +%Y-%m-%d)"-table01.sql.gz sshuser@10.20.30.45:/tmp
# Выполняю на втором сервере ряд заданий в рамках ssh сессии: распаковываю дамп таблицы, очищаю таблицу на этом сервере, заливаю туда данные из дампа
/usr/bin/ssh sshuser@10.20.30.45 '/usr/bin/gunzip /tmp/"$(date +%Y-%m-%d)"-table01.sql.gz && /usr/bin/mysql -e "delete from database01.table01; use database01; source /tmp/"$(date +%Y-%m-%d)"-table01.sql;"'
# Удаляю дамп
/usr/bin/ssh sshuser@10.20.30.45 'rm /tmp/"$(date +%Y-%m-%d)"-table01.sql'
Скрипт простой, можно легко подогнать под свои задачи. Наверное эту задачу смог бы решить и ChatGPT, но я не проверял. Сделал по старинке сам.
Отдельно отмечу для тех, кто не в курсе, что можно вот так запросто тут же после подключения по ssh выполнять какие-то команды в автоматическом режиме. Это удобно и часто пригождается.
#mysql #bash #script
🎓 У хостера Selectel есть небольшая "академия", где в открытом доступе есть набор курсов. Они неплохого качества. Где-то по верхам в основном теория, а где-то полезные практические вещи. Я бы обратил внимание на два курса, которые показались наиболее полезными:
⇨ PostgreSQL для новичков
⇨ MySQL для новичков
Там небольшой структурированный материал по основам: установка, работа в консоли, бэкап/восстановление, сброс пароля и т.д. Ничего особенного, но в целом уровень выше, чем у обычной статьи в интернете от условного автора, типа меня, который подобное может написать из энтузиазма. Хотя последнее время вообще не встречаю в интернете подробные авторские статьи хоть от кого-нибудь. В основном на видео все переключились.
Вообще, мне нравится такой маркетинг, когда даётся реальная польза, а в материал вставлены уместные ссылки на свои сервисы, на базе которых написана статья. Это ситуация, которая понятна и не раздражает навязчивостью или заманухой. Хостера могу порекомендовать. У меня никто не просил писать этот пост и рефку свою не оставляю. Я давно с ним работаю, поэтому пишу искренне.
#обучение #mysql #postgresql
⇨ PostgreSQL для новичков
⇨ MySQL для новичков
Там небольшой структурированный материал по основам: установка, работа в консоли, бэкап/восстановление, сброс пароля и т.д. Ничего особенного, но в целом уровень выше, чем у обычной статьи в интернете от условного автора, типа меня, который подобное может написать из энтузиазма. Хотя последнее время вообще не встречаю в интернете подробные авторские статьи хоть от кого-нибудь. В основном на видео все переключились.
Вообще, мне нравится такой маркетинг, когда даётся реальная польза, а в материал вставлены уместные ссылки на свои сервисы, на базе которых написана статья. Это ситуация, которая понятна и не раздражает навязчивостью или заманухой. Хостера могу порекомендовать. У меня никто не просил писать этот пост и рефку свою не оставляю. Я давно с ним работаю, поэтому пишу искренне.
#обучение #mysql #postgresql
Для быстрого доступа к СУБД Mysql очень удобно использовать небольшой скрипт Adminer, который представляет из себя ровно один php файл и запускается на любом хостинге. Я бы не писал о нём в очередной раз, если бы не столкнулся на днях с некоторыми нюансами при его использовании, так что решил оформить в заметку, чтобы самому потом не забыть.
С помощью Adminer можно создать пользователя и базу данных, назначить или изменить права, посмотреть содержимое таблиц, выгрузить или загрузить дамп. Лично мне для административных целей больше ничего и не надо. Разработчики, работая над сайтом, обычно просят phpmyadmin. Я не очень его люблю, потому что он монструозный, для него надо ставить дополнительные расширения php, поддерживать это дело.
Если я пользуюсь сам, то обычно просто закидываю adminer на сайт, делаю, что мне надо и потом сразу удаляю. В этот раз решил оставить на некоторое время и закрыть через basic_auth в Nginx (на самом деле в Angie). Вроде бы нет ничего проще:
Закрываем паролем. Создаём файл с учёткой:
Добавляем в Nginx:
Перезапускаю Nginx, проверяю. Пароль не спрашивает, доступ прямой. Всё внимательно проверяю, ошибок нет. Я 100 раз это проделывал. Тут нет никаких нюансов. Но не работает.
Быстро догадался, в чём тут дело. В Nginx есть определённые правила обработки locations. Я с этой темой когда-то разбирался подробно и кое-что в памяти осело. Ниже для php файлов уже есть location:
Он с регулярным выражением, поэтому обрабатывается раньше и при первом же совпадении поиск прекращается. Так что до моего location с паролем очередь просто не доходит. Сделать надо так:
Тут надо указать все те же настройки, что у вас стоят для всех остальных php файлов в
Затем nginx проверяет location’ы, заданные регулярными выражениями, в порядке их следования в конфигурационном файле. При первом же совпадении поиск прекращается и nginx использует совпавший location.
Вообще, это очень важная тема, так как сильно влияет на безопасность и многие другие вещи. Есть проект сложный с множеством locations, надо очень аккуратно их описывать и располагать в конфигурационном файле.
#webserver #nginx #mysql
С помощью Adminer можно создать пользователя и базу данных, назначить или изменить права, посмотреть содержимое таблиц, выгрузить или загрузить дамп. Лично мне для административных целей больше ничего и не надо. Разработчики, работая над сайтом, обычно просят phpmyadmin. Я не очень его люблю, потому что он монструозный, для него надо ставить дополнительные расширения php, поддерживать это дело.
Если я пользуюсь сам, то обычно просто закидываю adminer на сайт, делаю, что мне надо и потом сразу удаляю. В этот раз решил оставить на некоторое время и закрыть через basic_auth в Nginx (на самом деле в Angie). Вроде бы нет ничего проще:
# wget https://github.com/vrana/adminer/releases/download/v4.8.1/adminer-4.8.1-mysql-en.php
# mv adminer-4.8.1-mysql-en.php /var/www/html/adminer.php
Закрываем паролем. Создаём файл с учёткой:
# htpasswd -c /etc/nginx/.htpasswd admineruser21
Добавляем в Nginx:
location /adminer.php {
auth_basic "Administrator’s Area";
auth_basic_user_file /etc/nginx/.htpasswd;
}
Перезапускаю Nginx, проверяю. Пароль не спрашивает, доступ прямой. Всё внимательно проверяю, ошибок нет. Я 100 раз это проделывал. Тут нет никаких нюансов. Но не работает.
Быстро догадался, в чём тут дело. В Nginx есть определённые правила обработки locations. Я с этой темой когда-то разбирался подробно и кое-что в памяти осело. Ниже для php файлов уже есть location:
location ~ \.php$ {
....
}
Он с регулярным выражением, поэтому обрабатывается раньше и при первом же совпадении поиск прекращается. Так что до моего location с паролем очередь просто не доходит. Сделать надо так:
location ~ adminer.php {
auth_basic "Administrator’s Area";
auth_basic_user_file /etc/nginx/.htpasswd;
.......................
}
Тут надо указать все те же настройки, что у вас стоят для всех остальных php файлов в
location ~ \.php$
. И расположить location с adminer выше location для остальных php файлов. Это важно, так как судя по документации:Затем nginx проверяет location’ы, заданные регулярными выражениями, в порядке их следования в конфигурационном файле. При первом же совпадении поиск прекращается и nginx использует совпавший location.
Вообще, это очень важная тема, так как сильно влияет на безопасность и многие другие вещи. Есть проект сложный с множеством locations, надо очень аккуратно их описывать и располагать в конфигурационном файле.
#webserver #nginx #mysql
Посмотрел на днях очень полезное с практической точки зрения видео на тему различий между форками СУБД MySQL.
⇨ Сравнение форков СУБД MYSQL: Oracle MySQL, Percona Server for MySQL и MariaDB
Для тех, кому не хочется или некогда смотреть полный ролик, я сделал краткий конспект основной информации. У меня самого нет чёткого понимания, какой сервер лучше всего использовать для MySQL. После просмотра видео, понимание появилось.
Для начала назовём основные отличия трёх указанных продуктов.
🔹Oracle Mysql Community Edition - изначальная версия MySQL, которую купила компания Oracle вместе с Sun и продолжила развивать, сделав акцент на развитии движка InnoDB. В качестве кластерного решения используется InnoDB Cluster.
🔹Percona server for Mysql - в основе оракловский Mysql, а поверх установлен набор патчей для оптимизации и мониторинга производительности. Помимо СУБД компания развивает собственный комплект софта для мониторинга (Percona Monitoring and Management), бэкапа (XtraBackup), кластеризации (Percona XtraDB Cluster) и т.д.
🔹MariaDB - самостоятельный сервер, который уже значительно отличается от MySQL. Разрабатывается разработчиками первых версий MySQL, которые ушли из Oracle. Начиная с версии MySQL 5.7 нет прямой совместимости между Oracle MySQL и MariaDB. Переключаться между ними можно только через логический дамп. Продукт проповедует более открытую для сообщества модель развития. В современных дистрибутивах Linux для баз данных MySQL в основном ставится MariaDB. Используется своё кластерное решение - Galera Cluster. В отличие от MySQL, в MariaDB сохранена поддержка технологии Query Cache. Для бэкапов есть свой продукт - mariabackup.
Автор ролика собрал стенд из идентичных виртуальных машин. Установил на каждую свою СУБД, установил примерно одинаковые базовые настройки, остальные оставил по умолчанию, как они были изначально. Подготовил тест с использованием sysbench. Исходники теста выложил в репозиторий:
⇨ https://github.com/Nickmob/mysql_bench
Если есть сомнения в результатах, можно повторить у себя и проверить. Все результаты приводить не буду, чтобы не загромождать заметку цифрами. Если вам интересно, посмотрите в конце ролика.
Наиболее высокие результаты показала MariaDB, Oracle разных версий и Percona показали сопоставимые результаты, а MariaDB в паре тестов явно показывает лучшую производительность.
Так что если вы сомневаетесь и не знаете, какую СУБД взять для баз MySQL, берите MariaDB. По умолчанию скорее всего она заработает как минимум не хуже форков, а возможно и лучше. Внизу скриншот результатов. Левый столбец - чем выше метрика, тем лучше, правый наоборот - чем меньше отклик, тем лучше.
#mysql
🦖 Selectel — дешёвые и не очень дедики с аукционом!
⇨ Сравнение форков СУБД MYSQL: Oracle MySQL, Percona Server for MySQL и MariaDB
Для тех, кому не хочется или некогда смотреть полный ролик, я сделал краткий конспект основной информации. У меня самого нет чёткого понимания, какой сервер лучше всего использовать для MySQL. После просмотра видео, понимание появилось.
Для начала назовём основные отличия трёх указанных продуктов.
🔹Oracle Mysql Community Edition - изначальная версия MySQL, которую купила компания Oracle вместе с Sun и продолжила развивать, сделав акцент на развитии движка InnoDB. В качестве кластерного решения используется InnoDB Cluster.
🔹Percona server for Mysql - в основе оракловский Mysql, а поверх установлен набор патчей для оптимизации и мониторинга производительности. Помимо СУБД компания развивает собственный комплект софта для мониторинга (Percona Monitoring and Management), бэкапа (XtraBackup), кластеризации (Percona XtraDB Cluster) и т.д.
🔹MariaDB - самостоятельный сервер, который уже значительно отличается от MySQL. Разрабатывается разработчиками первых версий MySQL, которые ушли из Oracle. Начиная с версии MySQL 5.7 нет прямой совместимости между Oracle MySQL и MariaDB. Переключаться между ними можно только через логический дамп. Продукт проповедует более открытую для сообщества модель развития. В современных дистрибутивах Linux для баз данных MySQL в основном ставится MariaDB. Используется своё кластерное решение - Galera Cluster. В отличие от MySQL, в MariaDB сохранена поддержка технологии Query Cache. Для бэкапов есть свой продукт - mariabackup.
Автор ролика собрал стенд из идентичных виртуальных машин. Установил на каждую свою СУБД, установил примерно одинаковые базовые настройки, остальные оставил по умолчанию, как они были изначально. Подготовил тест с использованием sysbench. Исходники теста выложил в репозиторий:
⇨ https://github.com/Nickmob/mysql_bench
Если есть сомнения в результатах, можно повторить у себя и проверить. Все результаты приводить не буду, чтобы не загромождать заметку цифрами. Если вам интересно, посмотрите в конце ролика.
Наиболее высокие результаты показала MariaDB, Oracle разных версий и Percona показали сопоставимые результаты, а MariaDB в паре тестов явно показывает лучшую производительность.
Так что если вы сомневаетесь и не знаете, какую СУБД взять для баз MySQL, берите MariaDB. По умолчанию скорее всего она заработает как минимум не хуже форков, а возможно и лучше. Внизу скриншот результатов. Левый столбец - чем выше метрика, тем лучше, правый наоборот - чем меньше отклик, тем лучше.
#mysql
Please open Telegram to view this post
VIEW IN TELEGRAM
При обновлении кода сайта или веб сервиса легко сделать проверку изменений или выполнить откат в случае каких-то проблем. Задача сильно усложняется, когда обновление затрагивает изменение в структуре базы данных. Если вы накатили изменение, которое затрагивает базу данных, не получится просто откатить всё назад на уровне кода. Нужно откатывать и состояние базы. Для таких ситуация придумали миграции базы данных.
Сразу покажу на примере, как это работает. Существует популярная open source утилита для этих целей - migrate. Она поддерживает все наиболее распространённые СУБД. Миграции можно выполнять с помощью готовой библиотеки на Go, либо в консоли через CLI. Я буду использовать CLI, СУБД PostgreSQL и ОС Debian 12.
Для Migrate собран deb пакет, хотя по своей сути это одиночный бинарник. Можно скачать только его. Для порядка ставим из пакета, который берём в репозитории:
Для удобства добавим строку на подключение к локальной базе данных в переменную:
Я подключаюсь без ssl к базе данных test_migrations под учёткой postgres с паролем pass123. С рабочей базой так делать не надо, чтобы пароль не улетел в history.
Принцип работы migrate в том, что создаются 2 файла с sql командами. Первый файл выполняется, когда мы применяем обновление, а второй - когда мы откатываем. В своём примере я добавлю таблицу test01 с простой структурой, а потом удалю её в случае отката.
В директории были созданы 2 файла. В первый файл с up в имени добавим sql код создания таблицы test01:
А во второй с down - удаление:
Проверим, как это работает:
Смотрим, появилась ли таблица:
Вы должны увидеть структуру таблицы test01. Теперь откатим наше изменение:
Проверяем:
Таблицы нет. Принцип тут простой - пишем SQL код, который исполняем. На деле, конечно, изменения бывают сложные, особенно когда не добавляются или удаляются таблицы, а меняется структура существующих таблиц с данными. Инструменты типа migrate позволяют описать все изменения и проработать процесс обновления/отката в тестовых средах. В простых случаях можно обойтись и своими bash скриптами, но migrate упрощает эту задачу, так как, во-первых поддерживает множество СУБД. Во-вторых, автоматически нумерует миграции и исполняет последовательно. В-третьих, может, к примеру, забирать миграции напрямую из git репозитория.
Для каждой СУБД в репозитории Migrate есть примеры настройки миграций.
❗️Если заметка вам полезна, не забудьте 👍 и забрать в закладки.
⇨ Исходники
#postgresql #mysql
Сразу покажу на примере, как это работает. Существует популярная open source утилита для этих целей - migrate. Она поддерживает все наиболее распространённые СУБД. Миграции можно выполнять с помощью готовой библиотеки на Go, либо в консоли через CLI. Я буду использовать CLI, СУБД PostgreSQL и ОС Debian 12.
Для Migrate собран deb пакет, хотя по своей сути это одиночный бинарник. Можно скачать только его. Для порядка ставим из пакета, который берём в репозитории:
# wget https://github.com/golang-migrate/migrate/releases/download/v4.18.1/migrate.linux-amd64.deb
# dpkg -i migrate.linux-amd64.deb
Для удобства добавим строку на подключение к локальной базе данных в переменную:
# export POSTGRESQL_URL='postgres://postgres:pass123@localhost:5432/test_migrations?sslmode=disable'
Я подключаюсь без ssl к базе данных test_migrations под учёткой postgres с паролем pass123. С рабочей базой так делать не надо, чтобы пароль не улетел в history.
Принцип работы migrate в том, что создаются 2 файла с sql командами. Первый файл выполняется, когда мы применяем обновление, а второй - когда мы откатываем. В своём примере я добавлю таблицу test01 с простой структурой, а потом удалю её в случае отката.
# cd ~ && mkdir migrations
# migrate create -ext sql -dir migrations -seq create_test01_table
~/migrations/000001_create_test01_table.up.sql
~/migrations/000001_create_test01_table.down.sql
В директории были созданы 2 файла. В первый файл с up в имени добавим sql код создания таблицы test01:
CREATE TABLE IF NOT EXISTS test01(
user_id serial PRIMARY KEY,
username VARCHAR (50) UNIQUE NOT NULL,
password VARCHAR (50) NOT NULL,
email VARCHAR (300) UNIQUE NOT NULL
);
А во второй с down - удаление:
DROP TABLE IF EXISTS test01;
Проверим, как это работает:
# migrate -database ${POSTGRESQL_URL} -path migrations up
1/u create_test01_table (24.160815ms)
Смотрим, появилась ли таблица:
# psql ${POSTGRESQL_URL} -c "\d test01"
Вы должны увидеть структуру таблицы test01. Теперь откатим наше изменение:
# migrate -database ${POSTGRESQL_URL} -path migrations down
Are you sure you want to apply all down migrations? [y/N]
y
Applying all down migrations
1/d create_test01_table (15.851045ms)
Проверяем:
# psql ${POSTGRESQL_URL} -c "\d test01"
Did not find any relation named "test01".
Таблицы нет. Принцип тут простой - пишем SQL код, который исполняем. На деле, конечно, изменения бывают сложные, особенно когда не добавляются или удаляются таблицы, а меняется структура существующих таблиц с данными. Инструменты типа migrate позволяют описать все изменения и проработать процесс обновления/отката в тестовых средах. В простых случаях можно обойтись и своими bash скриптами, но migrate упрощает эту задачу, так как, во-первых поддерживает множество СУБД. Во-вторых, автоматически нумерует миграции и исполняет последовательно. В-третьих, может, к примеру, забирать миграции напрямую из git репозитория.
Для каждой СУБД в репозитории Migrate есть примеры настройки миграций.
❗️Если заметка вам полезна, не забудьте 👍 и забрать в закладки.
⇨ Исходники
#postgresql #mysql
Провозился вчера некоторое время над банальной задачей. Нужно было добавить нового пользователя в mysql базу через консольный клиент. Задача простая, но я реально запутался в версиях mysql и используемых плагинах аутентификации. У меня была версия Mariadb 10.11, нужна была аутентификация по сети по паролю, а не через сокет.
Открыл свою шпаргалку, нашёл команду:
Не работает. Сначала пробовал разные варианты, потом вспомнил, что ALTER меняет пароль у существующего пользователя, а мне нужно создать нового. Немного погуглил, нашёл, как создать пользователя, использующего пароль:
Нормально, пользователя создал. Пробую ещё раз первую команду, чтобы задать пароль:
Опять не работает. Перебираю разные варианты и нахожу рабочий:
Честно говоря не понял, почему мой исходный вариант не сработал. Раньше точно работал, сейчас перестал. С MySQL в этом плане сейчас геморно стало. Проще сразу поставить adminer или phpmyadmin. Из-за того, что у mysql появилось несколько форков, плюс разные плагины аутентификации: unix_socket и mysql_native_password, комбинации команд по управлению пользователями стали отличаться в разных версиях. Это создаёт неудобства и только тратит время на поиск работающего варианта.
Я в основном с MariaDB работаю. Вот небольшая шпаргалка для консольного клиента этой СУБД.
📌 Первичная настройка сразу после установки, где можно выбрать тип плагин для аутентификации и задать пароль root:
📌 Создание базы данных:
📌 Создание пользователя с паролем:
📌 Назначаем пользователю права на базу данных (полные и выборочные):
📌 Список пользователей и их прав:
📌 Загрузить дамп в базу zabbix:
или
📌 Удалить базу:
📌 Список активных соединений:
📌 Посмотреть значение конкретного параметра (innodb_buffer_pool_size):
📌 Изменение параметра (max_connections):
Эти команды покрывают 95% моих задач, которые приходится выполнять в консольном клиенте mysql. Есть ещё несколько, касающихся репликации, но это отдельная тема.
Напоминаю, что у меня есть публикация с подборкой заметок по теме MySQL сервера. Там затрагиваются вопросы настройки, мониторинга, бэкапа и эксплуатации сервера MySQL.
❗️Если заметка вам полезна, не забудьте 👍 и забрать в закладки.
#mysql
Открыл свою шпаргалку, нашёл команду:
> ALTER USER 'zbx_monitor'@'10.30.52.9' IDENTIFIED WITH mysql_native_password BY 'XkRy1bRRgLIB';
ERROR 1064 (42000): You have an error in your SQL syntax;
Не работает. Сначала пробовал разные варианты, потом вспомнил, что ALTER меняет пароль у существующего пользователя, а мне нужно создать нового. Немного погуглил, нашёл, как создать пользователя, использующего пароль:
> CREATE USER 'zbx_monitor'@'10.30.52.9' IDENTIFIED VIA mysql_native_password;
Query OK, 0 rows affected (0.075 sec)
Нормально, пользователя создал. Пробую ещё раз первую команду, чтобы задать пароль:
> ALTER USER 'zbx_monitor'@'10.30.52.9' IDENTIFIED WITH mysql_native_password BY 'XkRy1bRRgLIB';
ERROR 1064 (42000): You have an error in your SQL syntax;
Опять не работает. Перебираю разные варианты и нахожу рабочий:
> ALTER USER 'zbx_monitor'@'10.30.52.9' IDENTIFIED BY 'XkRy1bRRgLIB';
Query OK, 0 rows affected (0.114 sec)
Честно говоря не понял, почему мой исходный вариант не сработал. Раньше точно работал, сейчас перестал. С MySQL в этом плане сейчас геморно стало. Проще сразу поставить adminer или phpmyadmin. Из-за того, что у mysql появилось несколько форков, плюс разные плагины аутентификации: unix_socket и mysql_native_password, комбинации команд по управлению пользователями стали отличаться в разных версиях. Это создаёт неудобства и только тратит время на поиск работающего варианта.
Я в основном с MariaDB работаю. Вот небольшая шпаргалка для консольного клиента этой СУБД.
📌 Первичная настройка сразу после установки, где можно выбрать тип плагин для аутентификации и задать пароль root:
# mysql_secure_installation
📌 Создание базы данных:
> CREATE DATABASE zabbix CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
📌 Создание пользователя с паролем:
> CREATE USER 'zabbix'@'10.30.52.9' IDENTIFIED VIA mysql_native_password;
> ALTER USER 'zabbix'@'10.30.52.9' IDENTIFIED BY 'PassWORD123';
📌 Назначаем пользователю права на базу данных (полные и выборочные):
> GRANT ALL PRIVILEGES on zabbix.* to 'zabbix'@'10.30.52.9';
> GRANT USAGE,REPLICATION CLIENT,PROCESS,SHOW DATABASES,SHOW VIEW ON *.* TO 'zbx_monitor'@'10.30.52.9';
📌 Список пользователей и их прав:
> SELECT user,authentication_string,plugin,host FROM mysql.user;
📌 Загрузить дамп в базу zabbix:
> USE zabbix;
> SOURCE my_dump.sql;
или
> \. my_dump.sql;
📌 Удалить базу:
> DROP DATABASE zabbix;
📌 Список активных соединений:
> SHOW FULL PROCESSLIST;
📌 Посмотреть значение конкретного параметра (innodb_buffer_pool_size):
> SHOW GLOBAL VARIABLES LIKE 'innodb_buffer_pool_size';
📌 Изменение параметра (max_connections):
> SET GLOBAL max_connections = 200;
Эти команды покрывают 95% моих задач, которые приходится выполнять в консольном клиенте mysql. Есть ещё несколько, касающихся репликации, но это отдельная тема.
Напоминаю, что у меня есть публикация с подборкой заметок по теме MySQL сервера. Там затрагиваются вопросы настройки, мониторинга, бэкапа и эксплуатации сервера MySQL.
❗️Если заметка вам полезна, не забудьте 👍 и забрать в закладки.
#mysql
Если у вас есть большой MySQL сервер, то лишний раз трогать его не хочется, особенно если у него большой аптайм, настраивали его не вы, а у вас вообще разовая задача к нему. Нужно временно посмотреть или залогировать запросы и желательно с IP адресом тех, кто эти запросы делает. Могу предложить неочевидный способ.
Напомню, что включение штатного механизма query_log через файл конфигурации потребует перезапуска службы субд, что может занимать в некоторых случаях непрогнозируемое время. Если у вас есть рутовый дост к консоли севера, то можно сделать и без остановки:
В файле mysql.log будет фиксироваться время запроса и сам запрос. Адрес клиента не увидим. Для того, чтобы фиксировать адрес клиента, хранить лог запросов нужно будет в в отдельной таблице mysql.general_log. Это уже будет немного другая настройка, для которой понадобится перезапуск. Но заметку я хотел написать не об этом.
Мы можем посмотреть содержимое запросов в сетевых пакетах через tcpdump. Сразу важное дополнение. Сработает это только для нешифрованных соединений с СУБД. Внутри локальной инфраструктуры это чаще всего так. Догадался я до этого не сам, а подсмотрел в очень старой заметке на opennet.
Запускаем на любой машине, через которую проходит трафик к MySQL серверу. Можно прямо на нём:
Ждём, когда посыпятся запросы. Можно с соседней машины подключиться и позадавать их:
В файле tcpdump.out будет собран raw трафик в формате pcap. Распарсить его можно тут же в консоли с помощью tshark:
Получится файл, где всё содержимое будет удалено, кроме mysql запросов. Но при этом останутся пустые строки. Чистим их:
Можно поступить немного проще, преобразовав трафик сразу в обычные строки с помощью stdbuf и strings, а потом уже грепнуть по нужным запросам:
Если нужны метки времени, то добавляем с помощью awk:
Если хочется привязать запросы к IP адресам клиентов, то задача усложняется. Можно вывести содержимое пакетов вместе с остальной информацией, в том числе и об адресате пакета:
Но дальше уже нетривиальная задача по при вязке адресата к самому запросу, так как между ними постоянно возникает разное количество строк с информацией в бинарном виде. Проще будет вернуться к pcap и оттуда пытаться это вытаскивать и сопоставлять. А если нет задачи сохранять в лог файле, можно просто забрать к себе на машину и посмотреть дамп через Wireshark. Там отлично видно и адресатов, и запросы.
❗️Если заметка вам полезна, не забудьте 👍 и забрать в закладки.
#mysql #tcpdump
Напомню, что включение штатного механизма query_log через файл конфигурации потребует перезапуска службы субд, что может занимать в некоторых случаях непрогнозируемое время. Если у вас есть рутовый дост к консоли севера, то можно сделать и без остановки:
> SET GLOBAL general_log_file = '/var/log/mysql/mysql.log';
> SET GLOBAL general_log = 'ON';
В файле mysql.log будет фиксироваться время запроса и сам запрос. Адрес клиента не увидим. Для того, чтобы фиксировать адрес клиента, хранить лог запросов нужно будет в в отдельной таблице mysql.general_log. Это уже будет немного другая настройка, для которой понадобится перезапуск. Но заметку я хотел написать не об этом.
Мы можем посмотреть содержимое запросов в сетевых пакетах через tcpdump. Сразу важное дополнение. Сработает это только для нешифрованных соединений с СУБД. Внутри локальной инфраструктуры это чаще всего так. Догадался я до этого не сам, а подсмотрел в очень старой заметке на opennet.
Запускаем на любой машине, через которую проходит трафик к MySQL серверу. Можно прямо на нём:
# tcpdump -i ens18 port 3306 -s 1500 -w tcpdump.out
Ждём, когда посыпятся запросы. Можно с соседней машины подключиться и позадавать их:
# mysql -h 10.20.1.36 -u user01 -p
> use database;
> select * from users;
В файле tcpdump.out будет собран raw трафик в формате pcap. Распарсить его можно тут же в консоли с помощью tshark:
# apt install tshark
# tshark -r tcpdump.out -d tcp.port==3306,mysql -T fields -e mysql.query > query_log.out
Получится файл, где всё содержимое будет удалено, кроме mysql запросов. Но при этом останутся пустые строки. Чистим их:
# sed -i '/^$/d' query_log.out
Можно поступить немного проще, преобразовав трафик сразу в обычные строки с помощью stdbuf и strings, а потом уже грепнуть по нужным запросам:
# tcpdump -i ens18 -s 0 -U -w - dst port 3306 | stdbuf -i0 -o0 -e0 strings | grep -iE --line-buffered "(SELECT|UPDATE|INSERT|DELETE|SET|SHOW|COMMIT|ROLLBACK|CREATE|DROP|ALTER)"
Если нужны метки времени, то добавляем с помощью awk:
# tcpdump -i ens18 -s 0 -U -w - dst port 3306 | stdbuf -i0 -o0 -e0 strings | grep -iE --line-buffered "(SELECT|UPDATE|INSERT|DELETE|SET|SHOW|COMMIT|ROLLBACK|CREATE|DROP|ALTER)" | awk -W interactive '{print strftime("%F %T")" "$0}'
Если хочется привязать запросы к IP адресам клиентов, то задача усложняется. Можно вывести содержимое пакетов вместе с остальной информацией, в том числе и об адресате пакета:
# tcpdump -i ens18 -s 0 -A -Q in port 3306
Но дальше уже нетривиальная задача по при вязке адресата к самому запросу, так как между ними постоянно возникает разное количество строк с информацией в бинарном виде. Проще будет вернуться к pcap и оттуда пытаться это вытаскивать и сопоставлять. А если нет задачи сохранять в лог файле, можно просто забрать к себе на машину и посмотреть дамп через Wireshark. Там отлично видно и адресатов, и запросы.
❗️Если заметка вам полезна, не забудьте 👍 и забрать в закладки.
#mysql #tcpdump
В одном интервью человека, который занимается наймом системных администраторов, услышал мельком вопрос, который он иногда задаёт на собеседованиях.
❓У вас непрогнозируемо и очень быстро растёт размер базы данных. Что вы будете экстренно предпринимать в связи с этим?
Ответа там не было, как и конкретики, какая СУБД имеется ввиду. Решил немного порассуждать на эту тему на примере MySQL, как наиболее простой и популярной СУБД. Сразу скажу, что я так вот сходу не знаю, как быстро решать такие проблемы. Просто немного подумал и прикинул, что бы я стал делать.
1️⃣ Первым делом я бы зашёл на сервере в консоль, открыл mysql клиент и запустил там:
или так, чтобы было удобнее смотреть:
Это первое, что приходит в голову. В нагруженном сервере список будет очень большой и по нему понять, что происходит, не всегда возможно. Если это какой-нибудь Битрикс, то там будут длиннющие запросы от одного и того же клиента в виде веб сервера. Тем не менее, получить какое-то представление о том, что происходит на сервере можно. Тем более, если там много баз данных, то можно заметить, что есть аномально большое количество запросов к одной из них.
Так как у нас стоит вопрос о росте базы данных, имеет смысл отфильтровать запросы по типу, оставив только UPDATE и INSERT. По идее именно они загружают данные в таблицы:
2️⃣ Для более детального просмотра активности в режиме реального времени можно запустить Mytop и посмотреть информацию там. Можно быстро фильтрануть по клиентам и базам данных, чтобы быстрее определить аномалии.
3️⃣ Параллельно я бы посмотрел размер таблиц. Можно просто отсортировать файлы по размеру в директории
У меня есть отдельная заметка по таким прикладным запросам.
Таким образом у нас есть информация о клиентах, которые подключаются к базе данных и информация о том, какие таблицы или таблица растут. Подключения клиентов можно посчитать, если на глазок не видно, от кого их больше всего.
Если тут уже получилось догадаться, кто заливает информацию в базу, то можно либо какую-то функциональность починить, если она сломалась, либо можно изменить пароль пользователя, чтобы отключить его, или забанить его по IP на файрволе и дальше разбираться.
Если причина роста базы в том, что кто-то просто заливает туда много данных, то по идее нам полученной информации достаточно, чтобы это прекратить. На этом моя фантазия по расследованию кончилась.
В памяти всплыло ещё то, что размер базы раздувают индексы. Возможно кто-то их лепит на автомате, что приводит к росту базы. По идее это всё тоже будет видно в списке процессов как запросы с
Если вам есть, чем дополнить заметку и ответить на поставленный вопрос, с удовольствием почитаю. Кстати, этот вопрос в разных интерпретациях позадавал ChatGPT. Ничего содержательного не ответил. Я потихоньку стал им пользоваться, а то столько восторженных отзывов слышал. Если честно, лично я не впечатлён. Точные ответы он знает на то, что и так быстро ищется через поисковики. А если где-то надо подумать, то там в основном вода.
#mysql
❓У вас непрогнозируемо и очень быстро растёт размер базы данных. Что вы будете экстренно предпринимать в связи с этим?
Ответа там не было, как и конкретики, какая СУБД имеется ввиду. Решил немного порассуждать на эту тему на примере MySQL, как наиболее простой и популярной СУБД. Сразу скажу, что я так вот сходу не знаю, как быстро решать такие проблемы. Просто немного подумал и прикинул, что бы я стал делать.
1️⃣ Первым делом я бы зашёл на сервере в консоль, открыл mysql клиент и запустил там:
> SHOW FULL PROCESSLIST;
или так, чтобы было удобнее смотреть:
# mysql -e "SHOW FULL PROCESSLIST;" > ~/processlist.txt
Это первое, что приходит в голову. В нагруженном сервере список будет очень большой и по нему понять, что происходит, не всегда возможно. Если это какой-нибудь Битрикс, то там будут длиннющие запросы от одного и того же клиента в виде веб сервера. Тем не менее, получить какое-то представление о том, что происходит на сервере можно. Тем более, если там много баз данных, то можно заметить, что есть аномально большое количество запросов к одной из них.
Так как у нас стоит вопрос о росте базы данных, имеет смысл отфильтровать запросы по типу, оставив только UPDATE и INSERT. По идее именно они загружают данные в таблицы:
> SELECT * FROM information_schema.processlist WHERE `INFO` LIKE 'UPDATE %';
> SELECT * FROM information_schema.processlist WHERE `INFO` LIKE 'INSERT %';
2️⃣ Для более детального просмотра активности в режиме реального времени можно запустить Mytop и посмотреть информацию там. Можно быстро фильтрануть по клиентам и базам данных, чтобы быстрее определить аномалии.
3️⃣ Параллельно я бы посмотрел размер таблиц. Можно просто отсортировать файлы по размеру в директории
/var/lib/mysql/database_name
. В MySQL чаще всего каждая таблица в отдельном файле. Либо можно зайти клиентом и посмотреть там:> SELECT table_schema as `Database`, table_name AS `Table`, round(((data_length + index_length) / 1024 / 1024), 2) `Size in MB` FROM information_schema.TABLES WHERE table_schema = "database_name" ORDER BY (data_length + index_length) DESC;
У меня есть отдельная заметка по таким прикладным запросам.
Таким образом у нас есть информация о клиентах, которые подключаются к базе данных и информация о том, какие таблицы или таблица растут. Подключения клиентов можно посчитать, если на глазок не видно, от кого их больше всего.
Если тут уже получилось догадаться, кто заливает информацию в базу, то можно либо какую-то функциональность починить, если она сломалась, либо можно изменить пароль пользователя, чтобы отключить его, или забанить его по IP на файрволе и дальше разбираться.
Если причина роста базы в том, что кто-то просто заливает туда много данных, то по идее нам полученной информации достаточно, чтобы это прекратить. На этом моя фантазия по расследованию кончилась.
В памяти всплыло ещё то, что размер базы раздувают индексы. Возможно кто-то их лепит на автомате, что приводит к росту базы. По идее это всё тоже будет видно в списке процессов как запросы с
CREATE INDEX
. Проблемного клиента можно отключить, индексы удалить, базу оптимизировать. Но тут я уже темой не владею. Не знаю, сколько и как этих индексов можно насоздавать и реально ли это может привести к лавинообразному росту объема занимаемого пространства на диске. Если вам есть, чем дополнить заметку и ответить на поставленный вопрос, с удовольствием почитаю. Кстати, этот вопрос в разных интерпретациях позадавал ChatGPT. Ничего содержательного не ответил. Я потихоньку стал им пользоваться, а то столько восторженных отзывов слышал. Если честно, лично я не впечатлён. Точные ответы он знает на то, что и так быстро ищется через поисковики. А если где-то надо подумать, то там в основном вода.
#mysql
Telegram
ServerAdmin.ru
Для мониторинга загрузки сервера MySQL в режиме реального времени есть старый и известный инструмент - Mytop. Из названия понятно, что это топоподобная консольная программа. С её помощью можно смотреть какие пользователи и какие запросы отправляют к СУБД.…
Недавно была заметка про знание СУБД. Видел комментарии, мол пусть DBA разбираются в нюансах СУБД, а админам это ни к чему. Расскажу про один случай, который со мной на днях случился. Сразу скажу, что это не будет рекомендацией к действиям, так как сам я ситуацию хоть и разрешил, но не лучшим образом. Плюс, понервничал немного.
Приходит уведомление в мониторинг, что дамп базы выполнен с ошибкой. База MySQL, размер дампа ~10ГБ. Так как размер позволяет, я бэкаплю её дампом несколько раз в день. Он проходит быстро, проблем не вызывает. Как настроен мониторинг, рассказывал отдельно.
Смотрю ошибку в логе дампа:
В таблицу постоянно что-то пишется. Движок сайта по кронам сам её чистит. Судя по всему, что-то пошло не так. Сделал дамп без этой таблицы, добавив ключ
Первым делом хотел поднять копию виртуалки и попробовать разобраться там. Но, к сожалению, виртуалка очень большая. Восстанавливаться будет долго. Захотелось решить проблему здесь и сейчас, потому что было время и возможность. На первый взгляд она не особо критичная и грозит только потерей таблицы в худшем случае. Забегая вперёд скажу, что этот худший случай и произошёл.
Захожу в консоль mysql и смотрю:
Ничего хорошего. Пробую починить автоматически:
В логе mariadb куча ошибок:
Для надёжности зажмурился и перезапустил службу mariadb. Перезапуск прошёл штатно, база поднялась, но таблица не ожила. Всё те же ошибки. Причём данные в неё, судя по всему, записывались.
Тут я немного приуныл, так как знаний не хватает решить проблему. Не понятна причина. Я узнал, что хранится в таблице и понял, что эти данные не представляют ценности и могут быть потеряны. Дальше поискал инфу в гугле и поговорил с chatgpt. Последний не предложил ничего нового из того, что я видел в гугле, но накидал неактуальных рекомендаций для движка MyISAM, хотя у меня InnoDB.
Нашёл следующие варианты решения проблемы:
1️⃣ Удалить и пересоздать все индексы.
2️⃣ Создать пустую таблицу с аналогичной структурой, скопировать туда данные, исходную удалить, новую таблицу переименовать.
3️⃣ Запустить сервер с активным параметром
4️⃣ Пересобрать таблицу командой:
Судя по отзывам, последняя команда будет выполняться очень долго. Третья может привести к долгому старту службы или ещё каким-то проблемам. Не хотелось запускать их на работающем сервере. Решил пересоздать индексы. Их там всего два, но один PRIMARY. Его нельзя просто взять и удалить. Вычитал на stackoverflow один совет. Зайти через phpmyadmin, убрать чекбокс Auto Increment на столбце с этим индексом, сохранить, потом зайти, вернуть AI. Возможно на живой таблице это и сработало бы, но у меня вылетела ошибка, ничего не сохранилось, таблица вообще умерла.
С этого момента некоторые юзеры начали получать ошибку MySQL Query Error! Дальше не стал экспериментировать, грохнул таблицу и создал заново. Структуру посмотрел в живом дампе. Всё сразу заработало, данные потекли в таблицу, дамп нормально создаётся.
Если у кого-то есть советы по теме, с удовольствием выслушаю. Ещё раз уточню, что стал делать опасные манипуляции, когда понял, что данные позволительно потерять. И я мог себе позволить простой в 10-15 минут.
#mysql
Приходит уведомление в мониторинг, что дамп базы выполнен с ошибкой. База MySQL, размер дампа ~10ГБ. Так как размер позволяет, я бэкаплю её дампом несколько раз в день. Он проходит быстро, проблем не вызывает. Как настроен мониторинг, рассказывал отдельно.
Смотрю ошибку в логе дампа:
mysqldump: Error 1034: Index for table 'b_stat_session_data' is corrupt; try to repair it when dumping table `b_stat_session_data` at row: 329011
В таблицу постоянно что-то пишется. Движок сайта по кронам сам её чистит. Судя по всему, что-то пошло не так. Сделал дамп без этой таблицы, добавив ключ
--ignore-table=dbname.b_stat_session_data
. Потом сразу проверил более старые дампы и бэкап виртуалки. Всё на месте, можно разбираться.Первым делом хотел поднять копию виртуалки и попробовать разобраться там. Но, к сожалению, виртуалка очень большая. Восстанавливаться будет долго. Захотелось решить проблему здесь и сейчас, потому что было время и возможность. На первый взгляд она не особо критичная и грозит только потерей таблицы в худшем случае. Забегая вперёд скажу, что этот худший случай и произошёл.
Захожу в консоль mysql и смотрю:
> CHECK TABLE b_stat_session_data;
Warning | InnoDB: The B-tree of index PRIMARY is corrupted. |
Warning | InnoDB: Index IX_GUEST_MD5 is marked as corrupted |
error | Corrupt
Ничего хорошего. Пробую починить автоматически:
> OPTIMIZE TABLE b_stat_session_data;
note | Table does not support optimize, doing recreate + analyze instead
error | Got error 106 "Transport endpoint is already connected" from storage engine InnoDB
status | Operation failed
В логе mariadb куча ошибок:
[ERROR] mariadbd: Index for table 'b_stat_session_data' is corrupt; try to repair it
Для надёжности зажмурился и перезапустил службу mariadb. Перезапуск прошёл штатно, база поднялась, но таблица не ожила. Всё те же ошибки. Причём данные в неё, судя по всему, записывались.
Тут я немного приуныл, так как знаний не хватает решить проблему. Не понятна причина. Я узнал, что хранится в таблице и понял, что эти данные не представляют ценности и могут быть потеряны. Дальше поискал инфу в гугле и поговорил с chatgpt. Последний не предложил ничего нового из того, что я видел в гугле, но накидал неактуальных рекомендаций для движка MyISAM, хотя у меня InnoDB.
Нашёл следующие варианты решения проблемы:
innodb_force_recovery
. alter table b_stat_session_data engine = innodb
Судя по отзывам, последняя команда будет выполняться очень долго. Третья может привести к долгому старту службы или ещё каким-то проблемам. Не хотелось запускать их на работающем сервере. Решил пересоздать индексы. Их там всего два, но один PRIMARY. Его нельзя просто взять и удалить. Вычитал на stackoverflow один совет. Зайти через phpmyadmin, убрать чекбокс Auto Increment на столбце с этим индексом, сохранить, потом зайти, вернуть AI. Возможно на живой таблице это и сработало бы, но у меня вылетела ошибка, ничего не сохранилось, таблица вообще умерла.
С этого момента некоторые юзеры начали получать ошибку MySQL Query Error! Дальше не стал экспериментировать, грохнул таблицу и создал заново. Структуру посмотрел в живом дампе. Всё сразу заработало, данные потекли в таблицу, дамп нормально создаётся.
Если у кого-то есть советы по теме, с удовольствием выслушаю. Ещё раз уточню, что стал делать опасные манипуляции, когда понял, что данные позволительно потерять. И я мог себе позволить простой в 10-15 минут.
#mysql
Please open Telegram to view this post
VIEW IN TELEGRAM
Моя недавняя история с ошибкой MySQL таблицы получила неожиданное продолжение. Оно меня настолько удивило, что решил написать об этом отдельно. Напомню, что там побилась одна таблица базы движка InnoDB. Я попытался её починить, но когда понял, что данные можно потерять, просто удалил и пересоздал её, так как не хотелось на работающем сервере эксперименты ставить.
Сама ситуация для меня разрешилась благополучно, но не считаю, что оптимально. В следующий раз данные могут быть нужны. Поэтому я решил её проработать и записать решение, которое не приведёт к потере данных. Для этого я пометил бэкап виртуалки за ту ночь, как неудаляемый. А через некоторое время нашёл место, где её можно спокойно развернуть и поработать с ней.
☝️ Бэкап, кстати, почти всю ночь восстанавливался. И это очень долго. Поэтому я всегда делаю отдельно бэкапы данных внутри виртуалок. Систему можно поднять быстро, залить основные данные, нужные для запуска сервиса, а остальное копировать по ходу дела. Это если архитектура сервиса и данных позволяет.
Виртуалку я восстановил, запустил, убедился, что она работает и выключил. Позже появилось время с ней поработать более внимательно. Настроил там сеть, подключился и стал смотреть. Каково же было моё удивление, когда этой ошибки я там не обнаружил. СУБД работает нормально,
Сначала подумал, что перепутал версии бэкапа. Но нет. Создание дампа логируется локально. Посмотрел лог бэкапа, там последняя операция завершилась с ошибкой именно на той таблице. В логе службы mariadb за то время тоже видны ошибки с таблицей. Смотрю прямо на сервере:
После последней ошибки сервер пару раз перезагружался и вуаля, таблица починилась сама. Хотя никаких встроенных процедур по исправлению ошибок для InnoDB в MariaDB не предусмотрено. И по логам не видно, чтобы что-то делалось.
На основном сервере саму виртуалку я не перезагружал, но службу mariadb перезапускал. Мне тогда это не помогло.
Расстроился из-за этой ситуации, так как потратил кучу времени и всё без толку. Никаких рабочих рецептов не придумал. В следующий раз придётся опять разбираться, когда с этим столкнусь.
Как сказал один читатель к заметке про проблемы с СУБД. В базе иногда происходит какая-то неведомая хрень. Сразу понятен уровень специалиста. Знает, о чём говорит. Теперь я тоже знаю.
#mysql
Сама ситуация для меня разрешилась благополучно, но не считаю, что оптимально. В следующий раз данные могут быть нужны. Поэтому я решил её проработать и записать решение, которое не приведёт к потере данных. Для этого я пометил бэкап виртуалки за ту ночь, как неудаляемый. А через некоторое время нашёл место, где её можно спокойно развернуть и поработать с ней.
☝️ Бэкап, кстати, почти всю ночь восстанавливался. И это очень долго. Поэтому я всегда делаю отдельно бэкапы данных внутри виртуалок. Систему можно поднять быстро, залить основные данные, нужные для запуска сервиса, а остальное копировать по ходу дела. Это если архитектура сервиса и данных позволяет.
Виртуалку я восстановил, запустил, убедился, что она работает и выключил. Позже появилось время с ней поработать более внимательно. Настроил там сеть, подключился и стал смотреть. Каково же было моё удивление, когда этой ошибки я там не обнаружил. СУБД работает нормально,
CHECK TABLE
отрабатывает нормально, дамп делается. Сначала подумал, что перепутал версии бэкапа. Но нет. Создание дампа логируется локально. Посмотрел лог бэкапа, там последняя операция завершилась с ошибкой именно на той таблице. В логе службы mariadb за то время тоже видны ошибки с таблицей. Смотрю прямо на сервере:
2024-11-23T20:22:17.678755+03:00 mariadbd[738]: 2024-11-23 20:22:17 7451105 [Note] InnoDB: You can use CHECK TABLE to scan your table for
corruption. Please refer to https://mariadb.com/kb/en/library/innodb-recovery-modes/ for information about forcing recovery.
2024-11-23T20:22:17.678779+03:00 mariadbd[738]: 2024-11-23 20:22:17 7451105 [ERROR] InnoDB: We detected index corruption in an InnoDB type table. You have to dump + drop + reimport the table or, in a case of widespread corruption, dump all InnoDB tables and recreate the whole tablespace. If the mariadbd server crashes after the startup or when you dump the tables. Please refer to https://mariadb.com/kb/en/library/innodb-recovery-modes/ for information about forcing recovery.
2024-11-23T20:22:17.678805+03:00 mariadbd[738]: 2024-11-23 20:22:17 7451105 [ERROR] Got error 126 when reading table 'b_stat_session_data'
2024-11-23T20:22:17.678833+03:00 mariadbd[738]: 2024-11-23 20:22:17 7451105 [ERROR] mariadbd: Index for table 'b_stat_session_data' is corrupt; try to repair it
После последней ошибки сервер пару раз перезагружался и вуаля, таблица починилась сама. Хотя никаких встроенных процедур по исправлению ошибок для InnoDB в MariaDB не предусмотрено. И по логам не видно, чтобы что-то делалось.
На основном сервере саму виртуалку я не перезагружал, но службу mariadb перезапускал. Мне тогда это не помогло.
Расстроился из-за этой ситуации, так как потратил кучу времени и всё без толку. Никаких рабочих рецептов не придумал. В следующий раз придётся опять разбираться, когда с этим столкнусь.
Как сказал один читатель к заметке про проблемы с СУБД. В базе иногда происходит какая-то неведомая хрень. Сразу понятен уровень специалиста. Знает, о чём говорит. Теперь я тоже знаю.
#mysql
Telegram
ServerAdmin.ru
Недавно была заметка про знание СУБД. Видел комментарии, мол пусть DBA разбираются в нюансах СУБД, а админам это ни к чему. Расскажу про один случай, который со мной на днях случился. Сразу скажу, что это не будет рекомендацией к действиям, так как сам я…
Для тех, кто много работает с базами данных, есть простой и удобный инструмент для их проектирования – dbdiagram.io. Мы не разработчики, тем не менее, покажу, как этот сервис может быть полезен. У него удобная визуализация структуры базы данных. Намного удобнее, чем, к примеру, в привычном phpmyadmin.
Можно выгрузить обычный дам из СУБД без данных и загрузить его в dbdiagram. Получите наглядную схему базы. При желании, её можно отредактировать, или просто экспортнуть в виде картинки. Покажу на примере MySQL. Выгружаем дамп базы postfix без данных, только структуру:
Передаём к себе на комп полученный дамп. В dbdiagram.io открываем Import ⇨ From MySQL ⇨ Upload .sql ⇨ Submit. Наблюдаем схему базы данных со всеми связями. Причём она сразу отформатирована по таблицам так, что все их наглядно видно.
При желании можно что-то изменить в структуре и выгрузить новый sql файл уже с изменениями. Если выбрать Export ⇨ To PNG, то сразу же получите аккуратную картинку со схемой, без лишних вопросов. Очень быстро и удобно, если нужно куда-то приложить схему базы данных.
⇨ 🌐 Сайт
❗️Если заметка вам полезна, не забудьте 👍 и забрать в закладки.
#mysql #postgresql
Можно выгрузить обычный дам из СУБД без данных и загрузить его в dbdiagram. Получите наглядную схему базы. При желании, её можно отредактировать, или просто экспортнуть в виде картинки. Покажу на примере MySQL. Выгружаем дамп базы postfix без данных, только структуру:
# mysqldump --no-data -u dbuser -p postfix > ~/schema.sql
Передаём к себе на комп полученный дамп. В dbdiagram.io открываем Import ⇨ From MySQL ⇨ Upload .sql ⇨ Submit. Наблюдаем схему базы данных со всеми связями. Причём она сразу отформатирована по таблицам так, что все их наглядно видно.
При желании можно что-то изменить в структуре и выгрузить новый sql файл уже с изменениями. Если выбрать Export ⇨ To PNG, то сразу же получите аккуратную картинку со схемой, без лишних вопросов. Очень быстро и удобно, если нужно куда-то приложить схему базы данных.
⇨ 🌐 Сайт
❗️Если заметка вам полезна, не забудьте 👍 и забрать в закладки.
#mysql #postgresql
На днях разбирался с одной относительно простой задачей, но из-за того, что затупил, потратил на неё очень много времени. Так как проделал множество всевозможных операций, решил всё подробно описать. Пригодится в других похожих историях.
Есть MySQL сервер, у которого, как мне показалось, очень большая нагрузка по CPU. Проект немного стух, записи в базу должно быть мало и мне было странно видеть высокую нагрузку от СУБД. Решил разобраться, в чём там дело.
Для начала просто посмотрел нагрузку через
В таких случаях часто помогает strace. Можно подцепиться к процессу и посмотреть, что он пишет:
В моём случае я не получил результата. В выводе просто было пусто. Я не понял, почему. Стал разбираться дальше. Смотрю потоки процесса:
Вижу, что CPU нагружает сильно больше всех остальных один поток с SPID 19547. Смотрю по нему информацию:
В выводе только цифры и отсылка к основному потоку mysqld. То есть вообще не понятно, что там реально происходит.
Тут до меня доходит подцепиться к потоку через strace:
Вижу системные вызовы futex (синхронизацией потоков), io_submit (асинхронные операции ввода-вывода) и некоторые другие.
Смотрю, в какие файлы пишет mysqld:
Это
А на серваке выполнялись десятки простых SELECT за считанные миллисекунды или ещё быстрее. Не отслеживал. И они тупо не попадали в вывод. И я думал, что запросов мало, а их было дохрена. Они и давали нагрузку на CPU.
Запросы увидел так. Не перезапуская сервер выполнил в консоли mysql:
Так же это было видно в выводе:
В разделе I/O. Эти потоки отвечают за асинхронные операции ввода-вывода (AIO).
Достаточно было на несколько секунд запустить, чтобы понять всю картину. Потом сразу отключил, чтобы не нагружать диски.
Осталось разобраться, а что на диск то записывается. Вроде как файлы
xb_doublewrite - это некий буфер InnoDB для повышения надёжности хранения, отключать не рекомендуется, хотя можно.
В общем, время я по сути потратил впустую, если не считать вот эту заметку итоговым результатом. Думаю, она мне ещё понадобится. Времени уже не оставалось дальше разбираться с этой историей. В целом, нагрузка там рабочая, абсолютно некритичная, так что разбираться с ней дальше большой нужды не было. Но я всё равно планирую подумать, как её снизить. И вообще не совсем понятно, почему её так много, с учётом того, что сайт активно кэшируется. Надо будет разбираться.
Отдельно отмечу, что очень активно нагружал этой темой DeepSeek, но он особо не помог. Да, много всякой информации давал и анализировал мои результаты, но фактически я сам догадался в чём причина. Он как-то больше по кругу ходил и всякие команды накидывал.
❗️Если заметка вам полезна, не забудьте 👍 и забрать в закладки.
#mysql #perfomance
Есть MySQL сервер, у которого, как мне показалось, очень большая нагрузка по CPU. Проект немного стух, записи в базу должно быть мало и мне было странно видеть высокую нагрузку от СУБД. Решил разобраться, в чём там дело.
Для начала просто посмотрел нагрузку через
top
. Mysql почти постоянно кушает одно ядро и периодически остальные дёргает. Дополнительно смотрю в iotop и pidstat и вижу постоянно запись со стороны службы mysqld с pid 19535:# iotop -obPat
# pidstat -p 19535 -d 1
В таких случаях часто помогает strace. Можно подцепиться к процессу и посмотреть, что он пишет:
# strace -e trace=write -p 19535
В моём случае я не получил результата. В выводе просто было пусто. Я не понял, почему. Стал разбираться дальше. Смотрю потоки процесса:
# ps -L -o spid,%mem,%cpu,cmd 16005
Вижу, что CPU нагружает сильно больше всех остальных один поток с SPID 19547. Смотрю по нему информацию:
# cat /proc/19535/task/19547/stat
# cat /proc/19535/task/19547/statu
sВ выводе только цифры и отсылка к основному потоку mysqld. То есть вообще не понятно, что там реально происходит.
Тут до меня доходит подцепиться к потоку через strace:
# strace -p 19547
Вижу системные вызовы futex (синхронизацией потоков), io_submit (асинхронные операции ввода-вывода) и некоторые другие.
Смотрю, в какие файлы пишет mysqld:
# inotifywait -m /var/lib/mysql
Это
ib_logfile0
и xb_doublewrite
. Никак не могу понять, почему он туда активно пишет, когда запросов к базе особо нет. И вот тут я как раз и затупил. Я смотрел запросы через mytop и SHOW FULL PROCESSLIST;
И там их было очень мало. Эти команды показывают запросы в моменте.А на серваке выполнялись десятки простых SELECT за считанные миллисекунды или ещё быстрее. Не отслеживал. И они тупо не попадали в вывод. И я думал, что запросов мало, а их было дохрена. Они и давали нагрузку на CPU.
Запросы увидел так. Не перезапуская сервер выполнил в консоли mysql:
> SET GLOBAL general_log = 'ON';
> SET GLOBAL general_log_file = '/var/log/mysql/general.log';
Так же это было видно в выводе:
> SHOW ENGINE INNODB STATUS;
В разделе I/O. Эти потоки отвечают за асинхронные операции ввода-вывода (AIO).
Достаточно было на несколько секунд запустить, чтобы понять всю картину. Потом сразу отключил, чтобы не нагружать диски.
Осталось разобраться, а что на диск то записывается. Вроде как файлы
ib_logfile0
это файлы журналов транзакций InnoDB, а разве SELECT вызывает транзакции? Я тут сильно не погружался, но мельком глянул информацию и понял, что всякие очистки устаревших данных, обновление статистики, индексов, хэшей могут тоже провоцировать запись, а точнее обновление этого файла.xb_doublewrite - это некий буфер InnoDB для повышения надёжности хранения, отключать не рекомендуется, хотя можно.
В общем, время я по сути потратил впустую, если не считать вот эту заметку итоговым результатом. Думаю, она мне ещё понадобится. Времени уже не оставалось дальше разбираться с этой историей. В целом, нагрузка там рабочая, абсолютно некритичная, так что разбираться с ней дальше большой нужды не было. Но я всё равно планирую подумать, как её снизить. И вообще не совсем понятно, почему её так много, с учётом того, что сайт активно кэшируется. Надо будет разбираться.
Отдельно отмечу, что очень активно нагружал этой темой DeepSeek, но он особо не помог. Да, много всякой информации давал и анализировал мои результаты, но фактически я сам догадался в чём причина. Он как-то больше по кругу ходил и всякие команды накидывал.
❗️Если заметка вам полезна, не забудьте 👍 и забрать в закладки.
#mysql #perfomance
У меня уже были заметки про фишки LVM, сегодня расскажу про ещё одну, которая может пригодиться. С помощью LVM и снепшотов можно делать консистентные бэкапы баз данных Mysql на уровне файлов, а не дампов, практически без простоя. Для таких задач в СУБД Percona есть инструмент под названием XtraBackup, а вот если у вас обычная бесплатная MySQL или MariaDB, то с бэкапами на уровне файлов там не так всё просто, особенно если вы уже не можете делать дампы из-за их больших размеров.
Идея там вот в чём. Мы закрываем все открытые таблицы, сбрасываем кэш, блокируем изменение данных, после этого делаем снепшот раздела с базами данных и сразу отключаем блокировки. Это занимает буквально пару секунд, на которые блокируются все базы, а потом спокойно копируем файлы сервера, примонтировав снепшот.
Это всё хорошо работало до появления движка InnoDB. У него есть нюансы, когда блокировки не предотвращают изменение данных в таблицах. Нужно дополнительно сбрасывать на диск так называемые dirty_pages. Покажу всё это на практике. Способ немного костыльный и вряд ли подойдёт для прода, так как есть много нюансов. Но в каких-то ситуациях может помочь быстро снять консистентную копию без остановки сервера.
Для того, чтобы всё получилось, раздел, где хранятся данные MySQL сервера, должен располагаться на LVM, а в Volume Group должно быть свободное место для снепшотов. Проверяем так:
Если места нет, надо добавить. Не буду на этом останавливаться, рассказывал ранее. Первым делом заходим в консоль mysql, сбрасываем кэш и включаем блокировки:
Если база не сильно большая и нагруженная, кэш быстро сбросится. Наблюдать можно так:
Следим за значением
После этого возвращаем обратно настройку с dirty_pages в исходное значение (по умолчанию 90) и снимаем блокировки:
Когда это делается автоматически скриптом, всё это происходит быстро. Но есть нюансы. Команда блокировки дожидается завершения всех запросов. Если у вас там есть какие-то очень длинные запросы, то вся база будет заблокирована, пока они не завершатся. Так что имейте это ввиду.
Монтируем снепшот и копируем данные:
После копирования снепшот надо обязательно удалить.
Получили консистентный бэкап всех баз данных практически без остановки сервера, но с кратковременной блокировкой изменений.
Я собрал всё это в скрипт и протестировал на сервере с MariaDB и Zabbix Server. Сохранил бэкап локально, потом остановил MariaDB, полностью удалил директорию
Скрипт особо не отлаживал, так что аккуратнее с ним. Просто убедился, что работает. Сначала немного накосячил, так как после включения блокировки закрывал сессию, делал снепшот и подключался снова. Так нельзя, потому что команда
Такой вот небольшой трюк в копилку LVM, который можно применять не только к СУБД, но и другим данным.
❗️Если заметка вам полезна, не забудьте 👍 и забрать в закладки.
#lvm #mysql #backup
Идея там вот в чём. Мы закрываем все открытые таблицы, сбрасываем кэш, блокируем изменение данных, после этого делаем снепшот раздела с базами данных и сразу отключаем блокировки. Это занимает буквально пару секунд, на которые блокируются все базы, а потом спокойно копируем файлы сервера, примонтировав снепшот.
Это всё хорошо работало до появления движка InnoDB. У него есть нюансы, когда блокировки не предотвращают изменение данных в таблицах. Нужно дополнительно сбрасывать на диск так называемые dirty_pages. Покажу всё это на практике. Способ немного костыльный и вряд ли подойдёт для прода, так как есть много нюансов. Но в каких-то ситуациях может помочь быстро снять консистентную копию без остановки сервера.
Для того, чтобы всё получилось, раздел, где хранятся данные MySQL сервера, должен располагаться на LVM, а в Volume Group должно быть свободное место для снепшотов. Проверяем так:
# pvs
Если места нет, надо добавить. Не буду на этом останавливаться, рассказывал ранее. Первым делом заходим в консоль mysql, сбрасываем кэш и включаем блокировки:
> SET GLOBAL innodb_max_dirty_pages_pct = 0;
> FLUSH TABLES WITH READ LOCK;
Если база не сильно большая и нагруженная, кэш быстро сбросится. Наблюдать можно так:
> SHOW ENGINE INNODB STATUS\G;
Следим за значением
Modified db pages
. Оно должно стать 0
. После этого можно делать снэпшот:# lvcreate --size 5G --snapshot --name mysql_snapshot /dev/vgroup/root
После этого возвращаем обратно настройку с dirty_pages в исходное значение (по умолчанию 90) и снимаем блокировки:
> SET GLOBAL innodb_max_dirty_pages_pct = 90;
> UNLOCK TABLES;
Когда это делается автоматически скриптом, всё это происходит быстро. Но есть нюансы. Команда блокировки дожидается завершения всех запросов. Если у вас там есть какие-то очень длинные запросы, то вся база будет заблокирована, пока они не завершатся. Так что имейте это ввиду.
Монтируем снепшот и копируем данные:
# mkdir /mnt/mysql_backup
# mount /dev/vgroup/mysql_snapshot /mnt/mysql_backup
# rsync -avz --delete /mnt/mysql_backup/var/lib/mysql/ user@10.20.1.5:/mnt/backup/mysql/
После копирования снепшот надо обязательно удалить.
# umount /mnt/mysql_backup
# lvremove -f /dev/vgroup/mysql_snapshot
Получили консистентный бэкап всех баз данных практически без остановки сервера, но с кратковременной блокировкой изменений.
Я собрал всё это в скрипт и протестировал на сервере с MariaDB и Zabbix Server. Сохранил бэкап локально, потом остановил MariaDB, полностью удалил директорию
/var/lib/mysql
и восстановил из бэкапа. Потом запустил СУБД. Запустилось без проблем, никаких ошибок. Бэкап получается консистентный.Скрипт особо не отлаживал, так что аккуратнее с ним. Просто убедился, что работает. Сначала немного накосячил, так как после включения блокировки закрывал сессию, делал снепшот и подключался снова. Так нельзя, потому что команда
FLUSH TABLES WITH READ LOCK
живёт, пока открыто соединение. Надо в рамках него делать всё необходимое. Запустил lvcreate через SYSTEM. Такой вот небольшой трюк в копилку LVM, который можно применять не только к СУБД, но и другим данным.
❗️Если заметка вам полезна, не забудьте 👍 и забрать в закладки.
#lvm #mysql #backup