3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Cloudflare障害(2025/11/18)を再現してみた

Last updated at Posted at 2025-12-01

はじめに

2025 年 11 月 18 日、Cloudflare で大規模な障害が発生しました。
Cloudflare が公開した記事によると、この障害の原因は ClickHouse のアクセス制御変更によるもので、system.columnsへのクエリが二重の結果を返すようになったことでした。

本記事では、この障害のメカニズムを解説し、実際に ClickHouse を使って再現してみます。

障害の概要

何が起きたのか

Cloudflare は 11 月 18 日 11:05(UTC)に「データベースアクセス制御の変更」を展開しました。この変更により、ClickHouse の分散クエリが従来のシステムアカウントから「元のユーザーアカウント」での実行に移行されました。

Cloudflare のアーキテクチャ

Cloudflare は ClickHouse を分散構成で運用しているようです。

名称未設定ファイル.drawio.png

  • シャード(r0, r1, r2など): 実際のデータがあるテーブル
  • 分散テーブル(default: 実際のデータはなく、見せかけだけのテーブル

default には Distributed というテーブルエンジンが存在します。
このテーブルエンジンはユーザーからクエリを受けた時に、実際のデータを持つシャードで r0, r1, r2 などにクエリを振り分けて発行し、結果をまとめて返すことができます。このエンジンのおかげで、複数のシャードをあたかも 1 つのテーブルのよう扱うことができるのです。

障害発生のメカニズム

Cloudflare はデータベースアクセス制御の変更を行いました。
この時実際に行っていたのは、分散クエリをユーザーアカウントが実行できるようにするため、シャードのメタデータをユーザーにもアクセス可能になるようにしたのです。

  • 変更前

    • ユーザーは default のみ見える
    • 分散クエリはシステムアカウントで実行され、シャードはユーザーからは見えない
  • 変更後

    • ユーザーは default が見える
    • 分散クエリを叩くことができる
    • r0 などのシャードをユーザーが見ることができる

問題のクエリ

SELECT name, type FROM system.columns
WHERE table = 'http_requests_features'
ORDER BY name;

権限変更後はユーザーからはdefaultr0のデータベースにhttp_requests_featuresテーブルが存在していることになります。
このクエリはdatabaseを指定していないため、両方のデータベースから情報を返すようになってしまいました。

Cloudflare のボット管理システムは、特徴量(機械学習で使うデータ項目)を ClickHouse から取得していました。システムは最大 200 個の特徴量を想定して
メモリを確保していましたが、クエリ結果が倍増したことで想定を超え、プログラムがクラッシュしました。

検証

実際に ClickHouse で障害を再現してみます。

環境

  • ClickHouse 25.10.3.100(Homebrew)
  • macOS

ClickHouse の構築手順は 12/1 のアドベントカレンダーの内容を参考にしてみてください。

手順

1. ClickHouse サーバーを起動

clickhouse server

別のターミナルでクライアントに接続します。

clickhouse client

2. テスト用のデータベースとテーブルを作成

シャードに相当するr0データベースと、ユーザー向けのdefaultデータベースにテーブルを作成します。

-- r0データベースを作成(シャードに相当)
CREATE DATABASE IF NOT EXISTS r0;

-- r0に実テーブルを作成
CREATE TABLE r0.http_requests_features (
    id UInt64,
    feature_name String,
    feature_type String
) ENGINE = MergeTree()
ORDER BY id;

-- テストデータを挿入
INSERT INTO r0.http_requests_features VALUES
    (1, 'bot_score', 'Float32'),
    (2, 'request_rate', 'Float32'),
    (3, 'user_agent_hash', 'UInt64');

-- defaultデータベースに同じスキーマのテーブルを作成
CREATE TABLE default.http_requests_features AS r0.http_requests_features;

3. 障害を再現(database を指定しないクエリ)

SELECT database, table, name, type
FROM system.columns
WHERE table = 'http_requests_features'
ORDER BY name;

結果

┌─database─┬─table──────────────────┬─name─────────┬─type───┐
│ default  │ http_requests_features │ feature_name │ String │
│ r0       │ http_requests_features │ feature_name │ String │
│ default  │ http_requests_features │ feature_type │ String │
│ r0       │ http_requests_features │ feature_type │ String │
│ default  │ http_requests_features │ id           │ UInt64 │
│ r0       │ http_requests_features │ id           │ UInt64 │
└──────────┴────────────────────────┴──────────────┴────────┘

6 rows in set.

3 カラム × 2 データベース = 6 行 が返ってきました。本来 3 行であるべきところが倍増しています。

4. 修正方法を確認(database を指定するクエリ)

SELECT database, table, name, type
FROM system.columns
WHERE table = 'http_requests_features'
  AND database = 'default'
ORDER BY name;

結果

┌─database─┬─table──────────────────┬─name─────────┬─type───┐
│ default  │ http_requests_features │ feature_name │ String │
│ default  │ http_requests_features │ feature_type │ String │
│ default  │ http_requests_features │ id           │ UInt64 │
└──────────┴────────────────────────┴──────────────┴────────┘

3 rows in set.

database = 'default'を追加することで、正しく 3 行のみが返されるようになりました。

まとめ

Cloudflare の障害は、ClickHouse の権限変更により、ユーザーがシャードのメタデータも見えるようになったことが原因でした。
system.columnsへのクエリでdatabaseを指定していなかったため、同名テーブルの情報が複数データベースから返され、結果が倍増する状態となっていました。
この状態を防ぐ対策として、メタデータを取得するクエリでは、databaseカラムで絞り込みを行うというのが一旦有効そうかと思います。

-- NG
SELECT name, type FROM system.columns WHERE table = 'xxx';

-- OK
SELECT name, type FROM system.columns WHERE table = 'xxx' AND database = 'default';

参考

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?