Dockerで始めるStarRocksハンズオン:リアルタイム分析向けOLAPデータウェアハウスの構築

Database tutorial - IT technology blog
Database tutorial - IT technology blog

背景&なぜシステムに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を本番パイプラインへ導入する前に、手軽にパフォーマンスベンチマークを実施できる理想的な検証環境が整います。

Share: