MariaDB
MySQLからフォークしたオープンソースリレーショナルデータベース。MySQL互換性を保ちながら独自機能を追加。企業レベルの機能を無料で提供。
データベースサーバー
MariaDB
概要
MariaDBは、MySQLの創設者Michael Wideniusによって2009年に開発された、オープンソースのリレーショナルデータベース管理システムです。MySQLとの完全な互換性を保ちながら、エンタープライズレベルの機能、セキュリティ強化、パフォーマンス最適化を実現した次世代データベースとして、世界中の企業から信頼を得ています。Linux各ディストリビューション、クラウドプラットフォーム、コンテナ環境で標準採用され、既存のMySQLアプリケーションからシームレスな移行が可能です。MariaDB 2025年版では、11.6系列の安定版として新しいストレージエンジン、強化されたJSON機能、改良されたレプリケーション、AI・機械学習統合により、現代のデータドリブンアプリケーションに必要な全ての機能を包括的に提供しています。
詳細
MariaDB 11.6(2024年11月リリース)は、従来のMySQLを大幅に進化させた包括的なデータベースプラットフォームです。最新版では、デフォルト文字セットがlatin1からutf8mb4への変更、TIMESTAMPの範囲拡張(2106年まで対応)、S3ストレージ統合、強化されたALTER TABLE処理、新しいセキュリティ機能が導入されています。MariaDB Foundationによるオープンソース開発とMariaDB Corporationによるエンタープライズサポートの両輪により、コミュニティ版から商用版まで幅広いニーズに対応。ColumnStore(分析処理)、Galera Cluster(分散処理)、MaxScale(データベースプロキシ)などの独自技術により、単一のデータベースから大規模分散システムまでスケーラブルに対応します。Amazon RDS、Google Cloud SQL、Microsoft Azureでのマネージドサービス提供により、クラウドネイティブ環境での運用も最適化されています。
主な特徴
- MySQL完全互換: 既存のMySQLアプリケーションからの移行がゼロダウンタイムで可能
- 豊富なストレージエンジン: InnoDB、MyISAM、ColumnStore、Spider、S3など目的別最適化
- 高可用性: Galera Clusterによるマルチマスター構成と自動フェイルオーバー
- エンタープライズセキュリティ: データマスキング、監査ログ、ロールベースアクセス制御
- クラウド最適化: 主要クラウドプラットフォームでのマネージドサービス対応
- オープンソース: GPL v2ライセンスによる自由な利用と改変
メリット・デメリット
メリット
- MySQL 8.0より高速なクエリ実行性能と最適化されたストレージエンジン
- オープンソースによる透明性と自由度、ベンダーロックインの回避
- 豊富なストレージエンジンによる用途別最適化(分析、分散、アーカイブ等)
- Galera Clusterによる真のマルチマスターレプリケーションと線形スケーラビリティ
- Oracle主導のMySQLに対する独立性とコミュニティ主導の開発
- 主要Linuxディストリビューションでの標準パッケージ提供
デメリット
- MySQL 8.0との機能差により一部の最新MySQL機能の利用不可
- エンタープライズ機能の一部が商用ライセンス(MariaDB Enterprise)必要
- Oracle MySQL Clusterとの互換性制限
- 大規模分散環境での運用には専門知識と追加コンポーネントが必要
- MySQL InnoDB Clusterとの直接互換性なし
- 一部のMySQLツールやクラウドサービスとの完全互換性に制限
参考ページ
書き方の例
インストールと基本セットアップ
# Ubuntu/Debian系でのMariaDBインストール
# MariaDB公式リポジトリ追加
curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version=11.6
# MariaDBサーバーとクライアントのインストール
sudo apt update
sudo apt install -y mariadb-server mariadb-client
# MariaDBサービス開始と自動起動設定
sudo systemctl enable mariadb
sudo systemctl start mariadb
sudo systemctl status mariadb
# セキュリティ設定スクリプト実行
sudo mariadb-secure-installation
# Docker Composeを使用した環境構築
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
mariadb:
image: mariadb:11.6
container_name: mariadb
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: testdb
MYSQL_USER: testuser
MYSQL_PASSWORD: testpassword
MARIADB_AUTO_UPGRADE: 1
ports:
- "3306:3306"
volumes:
- mariadb_data:/var/lib/mysql
- ./conf.d:/etc/mysql/conf.d
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
phpmyadmin:
image: phpmyadmin/phpmyadmin:latest
container_name: phpmyadmin
restart: unless-stopped
environment:
PMA_HOST: mariadb
PMA_PORT: 3306
PMA_USER: root
PMA_PASSWORD: rootpassword
ports:
- "8080:80"
depends_on:
- mariadb
volumes:
mariadb_data:
driver: local
EOF
# サービス起動
docker-compose up -d
# 設定ファイル最適化
sudo tee /etc/mysql/conf.d/optimization.cnf << 'EOF'
[mysql]
default-character-set = utf8mb4
[mysqld]
# 基本設定
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init-connect = 'SET NAMES utf8mb4'
# パフォーマンス設定
innodb_buffer_pool_size = 2G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
innodb_file_per_table = 1
innodb_purge_batch_size = 127
# セキュリティ設定
bind-address = 127.0.0.1
skip-networking = 0
local-infile = 0
# 接続設定
max_connections = 200
max_user_connections = 50
EOF
# MariaDB再起動
sudo systemctl restart mariadb
基本的なデータベース操作
-- データベース接続
mysql -u root -p
-- データベース作成と選択
CREATE DATABASE company_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE company_db;
-- テーブル作成(MariaDB 11.6の新機能を活用)
CREATE TABLE employees (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) UNIQUE NOT NULL,
department VARCHAR(50),
salary DECIMAL(10,2),
hire_date DATE,
metadata JSON,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_department (department),
INDEX idx_hire_date (hire_date)
) ENGINE=InnoDB;
-- サンプルデータ挿入
INSERT INTO employees (name, email, department, salary, hire_date, metadata) VALUES
('田中太郎', '[email protected]', 'Engineering', 75000.00, '2023-01-15',
JSON_OBJECT('skills', JSON_ARRAY('Python', 'SQL', 'Docker'), 'level', 'senior')),
('山田花子', '[email protected]', 'Marketing', 65000.00, '2023-03-20',
JSON_OBJECT('skills', JSON_ARRAY('Analytics', 'SEO', 'Content'), 'level', 'mid')),
('佐藤次郎', '[email protected]', 'Engineering', 80000.00, '2022-06-10',
JSON_OBJECT('skills', JSON_ARRAY('Java', 'Kubernetes', 'AWS'), 'level', 'senior'));
-- 基本的なクエリ
SELECT * FROM employees WHERE department = 'Engineering';
-- JSON機能を使用したクエリ
SELECT name, JSON_EXTRACT(metadata, '$.skills') as skills
FROM employees
WHERE JSON_EXTRACT(metadata, '$.level') = 'senior';
-- 集計クエリ
SELECT
department,
COUNT(*) as employee_count,
AVG(salary) as avg_salary,
MAX(salary) as max_salary
FROM employees
GROUP BY department;
-- ユーザー管理
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'secure_password';
GRANT SELECT, INSERT, UPDATE, DELETE ON company_db.* TO 'app_user'@'localhost';
FLUSH PRIVILEGES;
-- バックアップ
mysqldump -u root -p company_db > company_db_backup.sql
-- 復元
mysql -u root -p company_db < company_db_backup.sql
Python統合プログラミング
import pymysql
import json
from datetime import datetime, date
from contextlib import contextmanager
import logging
class MariaDBManager:
def __init__(self, host='localhost', port=3306, user='root',
password='password', database='company_db', charset='utf8mb4'):
"""MariaDB接続管理クラス"""
self.connection_params = {
'host': host,
'port': port,
'user': user,
'password': password,
'database': database,
'charset': charset,
'autocommit': True,
'cursorclass': pymysql.cursors.DictCursor
}
self.connection = None
@contextmanager
def get_connection(self):
"""接続コンテキストマネージャー"""
try:
self.connection = pymysql.connect(**self.connection_params)
yield self.connection
except Exception as e:
logging.error(f"Database connection error: {e}")
if self.connection:
self.connection.rollback()
raise
finally:
if self.connection:
self.connection.close()
def execute_query(self, query, params=None):
"""クエリ実行(SELECT用)"""
with self.get_connection() as conn:
with conn.cursor() as cursor:
cursor.execute(query, params)
return cursor.fetchall()
def execute_update(self, query, params=None):
"""更新クエリ実行(INSERT/UPDATE/DELETE用)"""
with self.get_connection() as conn:
with conn.cursor() as cursor:
cursor.execute(query, params)
conn.commit()
return cursor.rowcount
def insert_employee(self, name, email, department, salary, hire_date, skills=None, level='junior'):
"""従業員データ挿入"""
metadata = {
'skills': skills or [],
'level': level,
'created_by': 'system'
}
query = """
INSERT INTO employees (name, email, department, salary, hire_date, metadata)
VALUES (%s, %s, %s, %s, %s, %s)
"""
params = (name, email, department, salary, hire_date, json.dumps(metadata))
return self.execute_update(query, params)
def get_employees_by_department(self, department):
"""部署別従業員取得"""
query = """
SELECT id, name, email, department, salary, hire_date,
JSON_EXTRACT(metadata, '$.skills') as skills,
JSON_EXTRACT(metadata, '$.level') as level
FROM employees
WHERE department = %s
ORDER BY hire_date
"""
return self.execute_query(query, (department,))
def get_salary_statistics(self):
"""給与統計取得"""
query = """
SELECT
department,
COUNT(*) as employee_count,
ROUND(AVG(salary), 2) as avg_salary,
MIN(salary) as min_salary,
MAX(salary) as max_salary,
ROUND(STDDEV(salary), 2) as salary_stddev
FROM employees
GROUP BY department
ORDER BY avg_salary DESC
"""
return self.execute_query(query)
def search_employees_by_skill(self, skill):
"""スキル別従業員検索"""
query = """
SELECT name, email, department,
JSON_EXTRACT(metadata, '$.skills') as skills
FROM employees
WHERE JSON_SEARCH(metadata, 'one', %s, NULL, '$.skills[*]') IS NOT NULL
"""
return self.execute_query(query, (skill,))
# 使用例とパフォーマンステスト
def performance_test():
"""パフォーマンステスト"""
db = MariaDBManager(
host='localhost',
user='app_user',
password='secure_password',
database='company_db'
)
# 大量データ挿入テスト
import time
start_time = time.time()
batch_data = []
for i in range(1000):
batch_data.append((
f'Employee_{i}',
f'emp_{i}@company.com',
'Engineering' if i % 2 == 0 else 'Marketing',
50000 + (i * 100),
date(2023, 1, 1),
json.dumps({
'skills': ['Python', 'SQL'] if i % 2 == 0 else ['Marketing', 'Analytics'],
'level': 'senior' if i % 10 == 0 else 'junior'
})
))
# バッチ挿入
with db.get_connection() as conn:
with conn.cursor() as cursor:
query = """
INSERT INTO employees (name, email, department, salary, hire_date, metadata)
VALUES (%s, %s, %s, %s, %s, %s)
"""
cursor.executemany(query, batch_data)
conn.commit()
insertion_time = time.time() - start_time
print(f"1000件挿入時間: {insertion_time:.2f}秒")
# 検索パフォーマンステスト
start_time = time.time()
results = db.get_employees_by_department('Engineering')
search_time = time.time() - start_time
print(f"検索時間: {search_time:.4f}秒, 結果件数: {len(results)}")
# JSON検索テスト
start_time = time.time()
skill_results = db.search_employees_by_skill('Python')
json_search_time = time.time() - start_time
print(f"JSON検索時間: {json_search_time:.4f}秒, 結果件数: {len(skill_results)}")
if __name__ == "__main__":
# データベース管理オブジェクト作成
db_manager = MariaDBManager()
try:
# 従業員データ挿入
db_manager.insert_employee(
name="新井三郎",
email="[email protected]",
department="Engineering",
salary=85000.00,
hire_date=date(2023, 8, 15),
skills=["Go", "Docker", "Kubernetes"],
level="senior"
)
print("従業員データを挿入しました")
# 部署別従業員取得
engineering_employees = db_manager.get_employees_by_department("Engineering")
print(f"Engineering部門の従業員数: {len(engineering_employees)}")
# 給与統計
salary_stats = db_manager.get_salary_statistics()
print("給与統計:")
for stat in salary_stats:
print(f" {stat['department']}: 平均 {stat['avg_salary']}円 ({stat['employee_count']}名)")
# パフォーマンステスト実行
performance_test()
except Exception as e:
print(f"エラーが発生しました: {e}")
レプリケーションとクラスター設定
# Galera Clusterによるマルチマスター構成設定
# ノード1の設定 (/etc/mysql/conf.d/galera.cnf)
sudo tee /etc/mysql/conf.d/galera.cnf << 'EOF'
[galera]
# Galera Provider Configuration
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
# Galera Cluster Configuration
wsrep_cluster_name="production_cluster"
wsrep_cluster_address="gcomm://10.0.1.1,10.0.1.2,10.0.1.3"
# Galera Synchronization Configuration
wsrep_sst_method=rsync
# Galera Node Configuration
wsrep_node_address="10.0.1.1"
wsrep_node_name="node1"
# InnoDB Configuration
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
innodb_doublewrite=1
innodb_flush_log_at_trx_commit=2
# Binary Logging
binlog_format=row
log-bin=mysql-bin
EOF
# 最初のノードでクラスター初期化
sudo galera_new_cluster
# MariaDBサービス開始
sudo systemctl start mariadb
# ノード2,3でMariaDB開始
sudo systemctl start mariadb
# クラスター状態確認
mysql -u root -p -e "SHOW STATUS LIKE 'wsrep%'"
# レプリケーション設定(マスター-スレーブ構成)
# マスター設定
sudo tee -a /etc/mysql/conf.d/master.cnf << 'EOF'
[mysqld]
log-bin=mysql-bin
server-id=1
binlog-do-db=production_db
binlog-ignore-db=mysql
EOF
# レプリケーションユーザー作成
mysql -u root -p << 'EOF'
CREATE USER 'replica'@'%' IDENTIFIED BY 'replica_password';
GRANT REPLICATION SLAVE ON *.* TO 'replica'@'%';
FLUSH PRIVILEGES;
SHOW MASTER STATUS;
EOF
# スレーブ設定
sudo tee -a /etc/mysql/conf.d/slave.cnf << 'EOF'
[mysqld]
server-id=2
relay-log=mysql-relay-bin
read-only=1
EOF
# スレーブでレプリケーション開始
mysql -u root -p << 'EOF'
CHANGE MASTER TO
MASTER_HOST='10.0.1.1',
MASTER_USER='replica',
MASTER_PASSWORD='replica_password',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=1234;
START SLAVE;
SHOW SLAVE STATUS\G
EOF
パフォーマンス監視と最適化
# MariaDBパフォーマンス監視設定
# Performance Schemaの有効化
sudo tee -a /etc/mysql/conf.d/performance.cnf << 'EOF'
[mysqld]
# Performance Schema
performance_schema=ON
performance_schema_max_table_instances=40000
performance_schema_max_table_handles=40000
# Slow Query Log
slow_query_log=1
slow_query_log_file=/var/log/mysql/slow.log
long_query_time=2
log_queries_not_using_indexes=1
# General Log
general_log=0
general_log_file=/var/log/mysql/general.log
# Binary Log Settings
expire_logs_days=7
max_binlog_size=100M
sync_binlog=1
# InnoDB Monitoring
innodb_monitor_enable=all
EOF
# パフォーマンス監視クエリ
mysql -u root -p << 'EOF'
-- 現在のプロセス確認
SHOW PROCESSLIST;
-- スロークエリの確認
SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 10;
-- データベースサイズ確認
SELECT
table_schema as 'Database',
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) as 'Size (MB)'
FROM information_schema.tables
GROUP BY table_schema;
-- テーブル使用状況確認
SELECT
table_name,
ROUND(((data_length + index_length) / 1024 / 1024), 2) as 'Size (MB)',
table_rows,
ROUND(((data_length + index_length) / table_rows), 2) as 'Avg Row Size'
FROM information_schema.tables
WHERE table_schema = 'company_db'
ORDER BY (data_length + index_length) DESC;
-- インデックス使用状況
SELECT
object_schema,
object_name,
index_name,
count_read,
count_write,
count_fetch,
count_insert,
count_update,
count_delete
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE object_schema = 'company_db'
ORDER BY count_read DESC;
EOF
# 自動バックアップスクリプト
cat > /etc/cron.daily/mariadb-backup << 'EOF'
#!/bin/bash
# 設定
DB_USER="backup_user"
DB_PASS="backup_password"
BACKUP_DIR="/var/backups/mariadb"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=7
# バックアップディレクトリ作成
mkdir -p $BACKUP_DIR
# データベース一覧取得(システムDB除外)
DBS=$(mysql -u$DB_USER -p$DB_PASS -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|mysql|sys)")
# 各データベースのバックアップ
for db in $DBS; do
echo "バックアップ中: $db"
mysqldump -u$DB_USER -p$DB_PASS \
--single-transaction \
--routines \
--triggers \
--events \
--hex-blob \
$db | gzip > $BACKUP_DIR/${db}_$DATE.sql.gz
done
# 古いバックアップファイル削除
find $BACKUP_DIR -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete
echo "バックアップ完了: $(date)"
EOF
chmod +x /etc/cron.daily/mariadb-backup
# リアルタイムモニタリングツール
cat > mariadb_monitor.py << 'EOF'
#!/usr/bin/env python3
import pymysql
import time
import os
from datetime import datetime
def monitor_mariadb():
"""MariaDBリアルタイム監視"""
connection = pymysql.connect(
host='localhost',
user='root',
password='password',
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor
)
try:
while True:
with connection.cursor() as cursor:
# 基本統計
cursor.execute("SHOW GLOBAL STATUS LIKE 'Threads_connected'")
connections = cursor.fetchone()
cursor.execute("SHOW GLOBAL STATUS LIKE 'Queries'")
queries = cursor.fetchone()
cursor.execute("SHOW GLOBAL STATUS LIKE 'Uptime'")
uptime = cursor.fetchone()
# InnoDB統計
cursor.execute("SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_data'")
buffer_data = cursor.fetchone()
cursor.execute("SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_total'")
buffer_total = cursor.fetchone()
# レプリケーション状態(スレーブの場合)
try:
cursor.execute("SHOW SLAVE STATUS")
slave_status = cursor.fetchone()
except:
slave_status = None
# 表示
os.system('clear')
print(f"=== MariaDB Monitor - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ===")
print(f"接続数: {connections['Value']}")
print(f"総クエリ数: {queries['Value']}")
print(f"稼働時間: {int(uptime['Value']) // 3600}時間")
if buffer_total and buffer_data:
buffer_usage = int(buffer_data['Value']) / int(buffer_total['Value']) * 100
print(f"InnoDB Buffer Pool使用率: {buffer_usage:.1f}%")
if slave_status:
print(f"レプリケーション状態: {slave_status.get('Slave_SQL_Running', 'Unknown')}")
print("\n--- 直近のプロセス ---")
cursor.execute("SHOW PROCESSLIST")
processes = cursor.fetchmany(5)
for proc in processes:
if proc['Command'] != 'Sleep':
print(f"ID:{proc['Id']} User:{proc['User']} DB:{proc['db']} Time:{proc['Time']}s")
time.sleep(5)
except KeyboardInterrupt:
print("\n監視を終了します")
finally:
connection.close()
if __name__ == "__main__":
monitor_mariadb()
EOF
chmod +x mariadb_monitor.py
高可用性とセキュリティ設定
# SSL/TLS設定
# SSL証明書生成
sudo mysql_ssl_rsa_setup --uid=mysql --datadir=/var/lib/mysql
# SSL設定追加
sudo tee -a /etc/mysql/conf.d/ssl.cnf << 'EOF'
[mysqld]
# SSL Configuration
ssl-ca=/var/lib/mysql/ca.pem
ssl-cert=/var/lib/mysql/server-cert.pem
ssl-key=/var/lib/mysql/server-key.pem
# Require SSL for all connections
require_secure_transport=ON
# TLS versions
tls_version=TLSv1.2,TLSv1.3
EOF
# 高度なセキュリティ設定
sudo tee -a /etc/mysql/conf.d/security.cnf << 'EOF'
[mysqld]
# Security Settings
local-infile=0
skip-symbolic-links
secure_file_priv="/var/lib/mysql-files/"
# Audit Plugin
plugin_load_add=server_audit
server_audit_logging=ON
server_audit_events=CONNECT,QUERY,TABLE
# User Account Security
validate_password_plugin=FORCE_PLUS_PERMANENT
validate_password_length=12
validate_password_mixed_case_count=1
validate_password_number_count=1
validate_password_special_char_count=1
# Connection Security
max_user_connections=100
max_connections_per_hour=1000
max_queries_per_hour=10000
EOF
# 監査ログ設定とローテーション
sudo tee /etc/logrotate.d/mariadb-audit << 'EOF'
/var/lib/mysql/server_audit.log {
daily
missingok
rotate 52
compress
notifempty
create 640 mysql mysql
postrotate
/bin/kill -HUP `cat /var/run/mysqld/mysqld.pid 2> /dev/null` 2> /dev/null || true
endscript
}
EOF
# ファイアウォール設定
sudo ufw allow from 10.0.1.0/24 to any port 3306
sudo ufw allow from 192.168.1.0/24 to any port 3306
sudo ufw deny 3306
# データベース暗号化設定
mysql -u root -p << 'EOF'
-- テーブル暗号化
CREATE TABLE sensitive_data (
id INT AUTO_INCREMENT PRIMARY KEY,
customer_name VARCHAR(100) ENCRYPTED=YES,
ssn VARCHAR(20) ENCRYPTED=YES,
credit_card VARCHAR(20) ENCRYPTED=YES,
data JSON,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB ENCRYPTED=YES ENCRYPTION_KEY_ID=1;
-- 暗号化されたバックアップ
SET @backup_key = 'backup_encryption_key_123456789';
EOF
# 自動フェイルオーバー用のHeartbeat設定
sudo apt install -y heartbeat
sudo tee /etc/ha.d/ha.cf << 'EOF'
logfile /var/log/ha-log
logfacility local0
keepalive 2
deadtime 30
warntime 10
initdead 120
udpport 694
ucast eth0 10.0.1.2
auto_failback on
node node1
node node2
EOF
sudo tee /etc/ha.d/haresources << 'EOF'
node1 10.0.1.100/24/eth0 mariadb
EOF
# VIP管理スクリプト
cat > /usr/local/bin/mariadb_vip_manager.sh << 'EOF'
#!/bin/bash
VIP="10.0.1.100"
INTERFACE="eth0"
MYSQL_USER="root"
MYSQL_PASS="password"
check_mysql() {
mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SELECT 1" >/dev/null 2>&1
return $?
}
add_vip() {
ip addr add $VIP/24 dev $INTERFACE
echo "VIP $VIP added"
}
remove_vip() {
ip addr del $VIP/24 dev $INTERFACE
echo "VIP $VIP removed"
}
case "$1" in
start)
if check_mysql; then
add_vip
else
echo "MySQL is not running"
exit 1
fi
;;
stop)
remove_vip
;;
status)
if ip addr show dev $INTERFACE | grep -q $VIP; then
echo "VIP is active"
exit 0
else
echo "VIP is not active"
exit 1
fi
;;
*)
echo "Usage: $0 {start|stop|status}"
exit 1
;;
esac
EOF
chmod +x /usr/local/bin/mariadb_vip_manager.sh
運用とメンテナンス
# 包括的なメンテナンススクリプト
cat > /usr/local/bin/mariadb_maintenance.sh << 'EOF'
#!/bin/bash
LOG_FILE="/var/log/mariadb_maintenance.log"
DB_USER="root"
DB_PASS="password"
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> $LOG_FILE
}
# データベース最適化
optimize_databases() {
log_message "データベース最適化開始"
DBS=$(mysql -u$DB_USER -p$DB_PASS -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|mysql|sys)")
for db in $DBS; do
log_message "最適化中: $db"
mysql -u$DB_USER -p$DB_PASS -e "USE $db; OPTIMIZE TABLE \`$(mysql -u$DB_USER -p$DB_PASS -e "USE $db; SHOW TABLES;" | tail -n +2 | tr '\n' '`,`' | sed 's/,`$//')\`;"
done
log_message "データベース最適化完了"
}
# 統計情報更新
update_statistics() {
log_message "統計情報更新開始"
mysql -u$DB_USER -p$DB_PASS -e "ANALYZE TABLE mysql.user, mysql.db, mysql.tables_priv;"
log_message "統計情報更新完了"
}
# ログローテーション
rotate_logs() {
log_message "ログローテーション開始"
mysql -u$DB_USER -p$DB_PASS -e "FLUSH LOGS;"
log_message "ログローテーション完了"
}
# テーブル修復チェック
check_tables() {
log_message "テーブルチェック開始"
mysql -u$DB_USER -p$DB_PASS << 'SQL'
SELECT
table_schema,
table_name,
ROUND(((data_length + index_length) / 1024 / 1024), 2) AS 'Size (MB)'
FROM information_schema.tables
WHERE table_schema NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys')
ORDER BY (data_length + index_length) DESC;
SQL
log_message "テーブルチェック完了"
}
# 実行
case "$1" in
optimize)
optimize_databases
;;
statistics)
update_statistics
;;
logs)
rotate_logs
;;
check)
check_tables
;;
all)
optimize_databases
update_statistics
rotate_logs
check_tables
;;
*)
echo "Usage: $0 {optimize|statistics|logs|check|all}"
exit 1
;;
esac
log_message "メンテナンス処理完了: $1"
EOF
chmod +x /usr/local/bin/mariadb_maintenance.sh
# 週次メンテナンスのcron設定
echo "0 2 * * 0 /usr/local/bin/mariadb_maintenance.sh all" | sudo crontab -
# MariaDB健康診断スクリプト
cat > /usr/local/bin/mariadb_health_check.py << 'EOF'
#!/usr/bin/env python3
import pymysql
import json
import sys
from datetime import datetime
def health_check():
"""MariaDB健康診断"""
try:
connection = pymysql.connect(
host='localhost',
user='root',
password='password',
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor
)
health_status = {
'timestamp': datetime.now().isoformat(),
'overall_status': 'HEALTHY',
'issues': [],
'recommendations': []
}
with connection.cursor() as cursor:
# 接続数チェック
cursor.execute("SHOW GLOBAL STATUS LIKE 'Threads_connected'")
connections = int(cursor.fetchone()['Value'])
cursor.execute("SHOW GLOBAL VARIABLES LIKE 'max_connections'")
max_connections = int(cursor.fetchone()['Value'])
connection_usage = (connections / max_connections) * 100
if connection_usage > 80:
health_status['issues'].append(f"高い接続使用率: {connection_usage:.1f}%")
health_status['overall_status'] = 'WARNING'
# スロークエリチェック
cursor.execute("SHOW GLOBAL STATUS LIKE 'Slow_queries'")
slow_queries = int(cursor.fetchone()['Value'])
cursor.execute("SHOW GLOBAL STATUS LIKE 'Queries'")
total_queries = int(cursor.fetchone()['Value'])
if total_queries > 0:
slow_query_ratio = (slow_queries / total_queries) * 100
if slow_query_ratio > 5:
health_status['issues'].append(f"スロークエリ比率が高い: {slow_query_ratio:.2f}%")
health_status['overall_status'] = 'WARNING'
# InnoDB Buffer Pool使用率
cursor.execute("SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_data'")
buffer_data = int(cursor.fetchone()['Value'])
cursor.execute("SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_total'")
buffer_total = int(cursor.fetchone()['Value'])
buffer_usage = (buffer_data / buffer_total) * 100
if buffer_usage > 90:
health_status['issues'].append(f"InnoDB Buffer Pool使用率が高い: {buffer_usage:.1f}%")
health_status['recommendations'].append("Buffer Poolサイズの増加を検討")
# レプリケーションステータス
try:
cursor.execute("SHOW SLAVE STATUS")
slave_status = cursor.fetchone()
if slave_status:
if slave_status['Slave_SQL_Running'] != 'Yes':
health_status['issues'].append("スレーブSQLスレッドが停止")
health_status['overall_status'] = 'CRITICAL'
if slave_status['Slave_IO_Running'] != 'Yes':
health_status['issues'].append("スレーブIOスレッドが停止")
health_status['overall_status'] = 'CRITICAL'
except:
pass # マスターまたはレプリケーション未設定
# テーブルサイズとフラグメンテーション
cursor.execute("""
SELECT
table_schema,
table_name,
ROUND(data_length/1024/1024, 2) as data_mb,
ROUND(data_free/1024/1024, 2) as free_mb,
ROUND((data_free/(data_length+data_free))*100, 2) as fragmentation_pct
FROM information_schema.tables
WHERE table_schema NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys')
AND data_free > 0
AND (data_free/(data_length+data_free))*100 > 20
ORDER BY fragmentation_pct DESC
LIMIT 5
""")
fragmented_tables = cursor.fetchall()
if fragmented_tables:
health_status['recommendations'].append(f"{len(fragmented_tables)}個のテーブルで20%以上のフラグメンテーション")
# 最終判定
if health_status['issues']:
if health_status['overall_status'] != 'CRITICAL':
health_status['overall_status'] = 'WARNING'
# 結果出力
print(json.dumps(health_status, indent=2, ensure_ascii=False))
# 終了コード
if health_status['overall_status'] == 'CRITICAL':
sys.exit(2)
elif health_status['overall_status'] == 'WARNING':
sys.exit(1)
else:
sys.exit(0)
except Exception as e:
error_status = {
'timestamp': datetime.now().isoformat(),
'overall_status': 'ERROR',
'error': str(e)
}
print(json.dumps(error_status, indent=2, ensure_ascii=False))
sys.exit(3)
finally:
if 'connection' in locals():
connection.close()
if __name__ == "__main__":
health_check()
EOF
chmod +x /usr/local/bin/mariadb_health_check.py
# 1時間ごとの健康診断
echo "0 * * * * /usr/local/bin/mariadb_health_check.py > /var/log/mariadb_health.log" | sudo crontab -e
echo "MariaDBメンテナンス環境の構築が完了しました"