MariaDB

MySQLからフォークしたオープンソースリレーショナルデータベース。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メンテナンス環境の構築が完了しました"