背景&なぜシステムにOLAPが必要なのか
上司が四半期フィルターを切り替えるたびに、売上ダッシュボードが30秒も読み込み中のまま回り続ける。時には504 Gateway Timeoutエラーが発生することさえある――これはデータ量が肥大化し始めた多くの開発チームでよく見られるお馴染みの光景です。
最初にとられがちな対策は、MySQLにインデックスを追加したり、PostgreSQLサーバーのRAMを16GBから64GBへ増設したりすることでしょう。しかし、このような対症療法は数週間程度しか持ちこたえられません。データ量が2,000万〜5,000万行を超えると、再び同じボトルネックに直面します。
問題の本質はストレージアーキテクチャにあります。
- トランザクション指向データベース(OLTP – MySQL、PostgreSQL):行指向(Row-oriented)でデータを保存します。この仕組みは新規注文の追加や特定ユーザー情報の参照(2ms未満)には極めて最適です。しかし、数千万件ものレコードに対して集計処理(SUM、COUNT、AVGなど)を実行する場合、ディスクから全データページを読み出す必要があります。その結果、ディスクI/Oは100%に達し、CPUは即座に過負荷に陥ります。
- 分析指向データベース(OLAP – StarRocks):カラム単位でデータを保存する列指向(Columnar storage)を採用しています。
priceやorder_dateといったカラムの全データが高圧縮され、連続したブロックとしてまとめられます。売上合計を算出したい場合、StarRocksは価格カラムのみを読み取り、不要なカラムはすべてスキップします。これにより、読み込むデータ量を80%〜95%も削減できます。
StarRocksは、CPUのSIMD命令を活用したVectorized Engineアーキテクチャにより、これらのタスクを超高速で処理します。MySQLでは20秒かかっていた複雑な分析クエリも、StarRocksなら通常150ms未満で結果を返します。さらに、StarRocksはMySQLプロトコルと完全な互換性を持っています。クエリを書き直したり接続ライブラリを変更したりすることなく、ポート9030経由でMetabase、Apache Superset、Tableauなどを直接接続可能です。
DockerによるStarRocksクラスターの構築
StarRocksのシステムは主に2つのコンポーネントに分離されています。
- Frontend (FE):クライアントからの接続受付、SQL文のパース、最適化された実行計画の生成、およびクラスターメタデータの管理を担当します。
- Backend (BE):カラム型データブロックを実際に保存し、並列計算処理の負荷を一手に担います。
ローカル環境で最も手軽に検証環境を立ち上げるには、Docker Composeを利用するのが最適です。まず作業ディレクトリを作成します。
mkdir starrocks-lab && cd starrocks-lab
touch docker-compose.yml
docker-compose.ymlに以下の設定を記述します。
version: '3.8'
services:
starrocks-fe:
image: starrocks/fe-ubuntu:3.2-latest
container_name: starrocks-fe
hostname: starrocks-fe
environment:
- HOST_TYPE=IP
ports:
- "8030:8030" # Web UI
- "9020:9020" # FE edit log
- "9030:9030" # MySQLクライアント接続ポート
- "9242:9242" # 内部RPC
networks:
starrocks-net:
ipv4_address: 172.20.0.2
starrocks-be:
image: starrocks/be-ubuntu:3.2-latest
container_name: starrocks-be
hostname: starrocks-be
environment:
- HOST_TYPE=IP
ports:
- "8040:8040" # BE Webサーバー
- "9050:9050" # ハートビートサービスポート
- "9060:9060" # BEサービスポート
networks:
starrocks-net:
ipv4_address: 172.20.0.3
depends_on:
- starrocks-fe
networks:
starrocks-net:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
以下のコマンドを実行してクラスターを起動します。
docker compose up -d
両方のコンテナがブートストラップ処理を完了するまで30〜45秒ほど待ちます。この時点ではFEとBEは独立して動作しており、互いをまだ認識していません。MySQLクライアントを使ってFEのポート9030に接続します。
# デフォルトのアカウントはroot、パスワードは空です
mysql -h 127.0.0.1 -P 9030 -u root
ホストマシンにMySQLクライアントがインストールされていない場合は、コンテナ内のバイナリを直接実行することも可能です。
docker exec -it starrocks-fe mysql -P 9030 -u root
内部IPアドレスとハートビートポート(9050)を指定して、BEノードをクラスターに登録します。
-- BEをFEの管理リストに追加
ALTER SYSTEM ADD BACKEND "172.20.0.3:9050";
テーブル設計とサンプルデータのロード
StarRocksは主に4種類のテーブルモデル(Duplicate Key、Aggregate Key、Unique Key、Primary Key)をサポートしています。注文履歴やアクセスログなど、各行の明細データをそのまま保持する必要があるユースケースでは、Duplicate Keyが最高の書き込みおよびスキャン性能を発揮します。
データベースとEコマース注文管理テーブルを作成します。
CREATE DATABASE IF NOT EXISTS retail_analytics;
USE retail_analytics;
CREATE TABLE IF NOT EXISTS orders (
order_id BIGINT NOT NULL,
order_date DATE NOT NULL,
customer_id INT NOT NULL,
category VARCHAR(50) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
quantity INT NOT NULL,
region VARCHAR(30) NOT NULL
)
ENGINE=OLAP
DUPLICATE KEY(order_id, order_date)
PARTITION BY RANGE(order_date) (
START ("2024-01-01") END ("2024-12-31") EVERY (INTERVAL 1 MONTH)
)
DISTRIBUTED BY HASH(order_id) BUCKETS 4
PROPERTIES (
"replication_num" = "1"
);
主要な設定パラメータの技術的な意味は以下の通りです。
ENGINE=OLAP:専用の列指向ストレージエンジンを有効化します。PARTITION BY RANGE:テーブルを月単位で分割(パーティショニング)します(データプルーニング)。例えば3月のデータを検索する際、エンジンは残り11か月分を自動的にスキップするため、スキャンデータ量を大幅に削減できます。DISTRIBUTED BY HASH ... BUCKETS 4:各パーティションを4つの分散タブレット(Tablet)に分割します。適切なバケット数を設定することで、CPUのマルチコア処理性能を最大限に引き出せます。replication_num = 1:今回の検証環境はBEが1ノードのみであるためレプリカ数を1に設定しています。最低3ノードで構成される本番環境(Production)では、耐障害性(高可用性 / High Availability)を確保するためにこの値を3に設定してください。
テスト用レコードをいくつか挿入します。
INSERT INTO orders VALUES
(1001, '2024-03-01', 501, 'Electronics', 1200.00, 1, 'Hanoi'),
(1002, '2024-03-02', 502, 'Home & Kitchen', 45.50, 3, 'HCM'),
(1003, '2024-03-02', 503, 'Electronics', 350.00, 2, 'Danang'),
(1004, '2024-03-05', 504, 'Fashion', 85.00, 4, 'Hanoi'),
(1005, '2024-03-10', 505, 'Electronics', 2100.00, 1, 'HCM');
ダッシュボードでよく使われる売上集計クエリを実行します。
SELECT
category,
region,
COUNT(order_id) AS total_orders,
SUM(price * quantity) AS total_revenue,
ROUND(AVG(price), 2) AS average_item_price
FROM orders
WHERE order_date >= '2024-03-01'
GROUP BY category, region
ORDER BY total_revenue DESC;
運用&モニタリング
分散システムでは、高負荷な処理を受け付ける前にノードの状態を綿密に確認しておく必要があります。
1. MySQL CLIによるクラスターのヘルスチェック
FEノードおよびBEノードの一覧とステータスを確認します。
-- Frontendノード一覧の確認
SHOW PROC '/frontends';
-- Backendノード一覧の確認
SHOW PROC '/backends'\G;
BEの実行結果において、Aliveがtrue、ErrCodeが0になっているかを特に注意して確認してください。もしAlive: falseとなっている場合は、Dockerサブネットのネットワーク疎通状況やポート9050のログを再確認してください。
2. Web UIによるメトリクス監視
組み込みのWeb UIを使用することで、リソース状況を視覚的に把握できます。ブラウザを開いて以下にアクセスします。
http://localhost:8030
ユーザー名root(パスワードなし)でログインします。ここでは、各ノードのディスク使用量やRAM消費量、リアルタイムで実行中のクエリ一覧などを監視できます。
3. Query Profileを活用したパフォーマンス分析
数十GBにおよぶデータセットで低速なクエリが発生した場合は、Profiling機能を有効にして各フェーズの実行状況を分析します。
-- 現在のセッションでプロファイリングを有効化
SET enable_profile = true;
-- ボトルネックを調査したいクエリを実行
SELECT category, SUM(price * quantity) FROM orders GROUP BY category;
Web UIにアクセスし、Queriesタブを選択して直前に実行したQuery IDをクリックします。詳細な実行グラフ(Execution Graph)が表示され、ディスクスキャン時間(OLAP_SCAN_NODE)、集約・グループ化処理時間(AGGREGATION_NODE)、ノード間のネットワークトラフィック量などを一目で把握できます。
システム規模の拡大に伴い、分析ワークロード(OLAP)を運用系データベース(OLTP)から分離することは極めて重要なアプローチです。消費メモリ2GB未満という軽量な今回のDockerクラスターを活用すれば、StarRocksを本番パイプラインへ導入する前に、手軽にパフォーマンスベンチマークを実施できる理想的な検証環境が整います。

