Matomoでアクセス解析データのアーカイブが破損した問題とその解決方法

Matomoの運用中に特定のサイトのデータだけが表示されなくなる問題が発生したので、その原因と解決方法についてｍしておきます。

## 発生した事象

Matomo 5.3.0を使用している環境で、管理画面を開いたところ以下の問題が発生していました：

* 特定サイトのみ、データが突然更新されなくなった
* アクセス数が明らかに少ない
* リアルタイムビジットは更新されている
* グラフに「invalidate period」という表示がされている
* 他のサイトは正常に表示されている

Googleのコアアプデでも食らったのかと思いましたが、「matomo invalidate period」という表示が気になり、調査を始めました。

## 原因の調査

### 1. アーカイブコマンドの確認

まず、Matomoのアーカイブ処理コマンドのヘルプを確認しました：

```
sudo -u nginx sh -c '/usr/bin/php [Matomoのパス]/console help core:archive'
```

出力結果（Claudeによる日本語訳）:

```
説明:
  CLIアーカイバーを実行します。これは一般的なメンテナンスとPiwikの高速性を維持するための重要なツールです。

使用法:
  core:archive [オプション]

オプション:
      --url=URL                                                            このオプションの値をPiwikへのURLとして強制的に使用します。
                                                                           システムがCLIプロセスでのアーカイブをサポートしていない場合、アーカイブHTTPリクエストが希望するURLを使用するためにこれを設定する必要があるかもしれません。
      --skip-idsites[=SKIP-IDSITES]                                        指定した場合、これらのウェブサイトのアーカイブ処理はスキップされます（これらのウェブサイトIDがアーカイブされる予定だった場合）。
      --skip-all-segments                                                  指定した場合、アーカイブ処理中にすべてのセグメントがスキップされます。
      --force-idsites[=FORCE-IDSITES]                                      指定した場合、アーカイブ処理はこれらのサイトIDのみに対して処理されます（カンマ区切り）
      --skip-segments-today                                                指定した場合、セグメントは今日ではなく昨日のみアーカイブされます。セグメントが最近作成または変更された場合、この設定は無視され、そのセグメントは今日もアーカイブされます。
      --force-periods[=FORCE-PERIODS]                                      指定した場合、アーカイブ処理はこれらの期間のみに対して処理されます（カンマ区切り、例：day,week,month,year,range）
      --force-date-last-n[=FORCE-DATE-LAST-N]                              非推奨。代わりに「process_new_segments_from」INI設定オプションを使用してください。
      --force-date-range[=FORCE-DATE-RANGE]                                指定した場合、アーカイブ処理はこの日付範囲に含まれる期間のみに対して処理されます。形式：YYYY-MM-DD,YYYY-MM-DD
      --force-idsegments=FORCE-IDSEGMENTS                                  指定した場合、これらのセグメントのみが処理されます（そのセグメントがそもそもサイトに適用されるべき場合）。
                                                                           セグメント自体ではなく、保存されたセグメントIDを指定します。例：1,2,3。
                                                                           注意：異なるIDを持つ同一のセグメントが存在する場合、1つのIDのみを指定しても両方がスキップされます。
      --concurrent-requests-per-website[=CONCURRENT-REQUESTS-PER-WEBSITE]  ウェブサイトとそのセグメントを処理する際に、並列処理するリクエスト数 [デフォルト: 3]
      --concurrent-archivers[=CONCURRENT-ARCHIVERS]                        並列実行する最大アーカイバー数。アーカイバーをcronjobとして開始する方法によっては、`ps ex`出力に同じプロセスが2回表示される場合、許可するアーカイバー数を2倍にする必要があるかもしれません。[デフォルト: 3]
      --max-websites-to-process=MAX-WEBSITES-TO-PROCESS                    アーカイバーの単一実行中に処理するウェブサイトの最大数。プロセスの寿命を制限するために使用できます（例：メモリ使用量の増加を避けるため）。
      --max-archives-to-process=MAX-ARCHIVES-TO-PROCESS                    アーカイバーの単一実行中に処理するアーカイブの最大数。プロセスの寿命を制限するために使用できます（例：メモリ使用量の増加を避けるため）。
      --stop-processing-after[=STOP-PROCESSING-AFTER]                      ジョブが新しいアーカイブプロセスを開始できる秒数。制限に達すると、現在のプロセスが終了した後にジョブは終了します。[デフォルト: 86400]
      --disable-scheduled-tasks                                            スケジュールされたタスク（スケジュールされたレポートの送信、データベースの最適化など）の実行をスキップします。
      --accept-invalid-ssl-certificate                                     このオプションを使用することは推奨されません。代わりに、有効なSSL証明書を使用すべきです！
                                                                           --url=https://...を指定した場合や、force_ssl=1でPiwikを使用している場合に役立つことがあります。
      --php-cli-options[=PHP-CLI-OPTIONS]                                  PHP設定オプションをPHP CLIコマンドに転送します。例：「-d memory_limit=8G」。注意：これらのオプションは、アーカイバーが実際にCLIを使用し、HTTPを使用しない場合にのみ適用されます。[デフォルト: ""]
      --force-all-websites                                                 すべてのウェブサイトのアーカイブを強制します。
      --force-report[=FORCE-REPORT]                                        指定した場合、特定のプラグインの特定のレポートの無効化のみを処理します。値は「MyPlugin.myReport」の形式でなければなりません。
  -h, --help                                                               指定されたコマンドのヘルプを表示します。コマンドが指定されていない場合はlistコマンドのヘルプを表示します。
  -q, --quiet                                                              メッセージを出力しません。
  -V, --version                                                            このアプリケーションのバージョンを表示します。
      --ansi|--no-ansi                                                     ANSI出力を強制（または--no-ansiで無効化）します。
  -n, --no-interaction                                                     対話的な質問を行いません。
      --matomo-domain[=MATOMO-DOMAIN]                                      Matomo URL（プロトコルとドメイン）例：「http://matomo.example.org」
      --xhprof                                                             XHProfによるプロファイリングを有効にします。
      --ignore-warn                                                        コマンド出力で警告ログやエラーログが検出されても、0の終了コードを返します。
  -v|vv|vvv, --verbose                                                     メッセージの詳細度を上げます：1は通常の出力、2はより詳細な出力、3はデバッグ用。

ヘルプ:
  * スクリプトをオプションなしで実行することをお勧めします。
  * このスクリプトはcrontabを介して毎時実行するか、デーモンとして実行する必要があります。
  * パラメータとしてスーパーユーザー&token_auth=XYZを指定することで、http://経由でも実行できますが（「Webクーロン」）、
    代わりにコマンドライン/CLI経由で実行することをお勧めします。
  * このスクリプトに関する提案がある場合は、feedback@matomo.orgでチームにお知らせください。
  * お楽しみください！
...
```

なんかいろいろかいてあるけどようわからんのですね。
とりあえずこの段階ではアーカイブコマンドだけだと無駄足でした。

### 2. 通常のアーカイブ処理の実行

まず、通常のアーカイブ処理を実行してみました：

```
sudo -u nginx sh -c '/usr/bin/php [Matomoのパス]/console core:archive'
```

ログを確認すると、問題のサイトはAPIリクエスト0件でした。
ほかのサイトは処理していたので、
問題のサイトだけアーカイブ処理が正常に行われていないことがわかりました。

### 3. 強制アーカイブの実行

問題のサイトだけを対象に再処理を試みました：

```
sudo -u nginx sh -c '/usr/bin/php [Matomoのパス]/console core:archive --force-idsites=1 --force-periods=day,week,month,year'
```

しかし、状況は改善しませんでした。
あんまりこのコマンド意味ない気がします。

### 4. 無効化テーブルの確認

困った時はcaludeに、としたところ、matomo_archive_invalidationsを消せをやたらと推します。
検索したんですが、日本語でも英語でもほぼヒットなし。あなたそれ、どこで学習したんですか？

https://matomo.jp/technical/how-do-i-write-sql-queries-to-select-visitors-list-of-pageviews-searches-events-in-the-matomo-database

一応ここには記載のあるテーブルですが…うーん

とはいえ、ほかに手もなかったので確認したところ、20軒ほどレコードがあることが判明しました：

```
SELECT * FROM matomo_archive_invalidations WHERE idsite IN (1);
```

結果を確認すると、多くのエントリに以下の特徴がありました：
- status=0（未完了）のエントリが多数存在
- 一部は処理が開始されたものの、完了していない
- 同じサイトID、同じ期間に対して複数のエントリが存在
- 特につい最近、10件以上増えている

ほんとうにこれか？という確信は無いのですが
これけしたらうごいたのでこれなんでしょう

## 解決策

以下の手順で解決しました：

### ステップ1: 無効化テーブルのクリア

```
DELETE FROM matomo_archive_invalidations;
```

### ステップ2: 問題サイトのアーカイブデータを削除

テーブル名確認します
```
SHOW TABLES LIKE 'matomo_archive_%';
```

直近のデータで問題が起きてたので、該当月のアーカイブを削除。
ちなみにアーカイブ削除だけでトライもしましたが治らず。
さきほどの無効化テーブルを消してからアーカイブ削除でやっと直しました。

```
DROP TABLE matomo_archive_blob_YYYY_MM;
DROP TABLE matomo_archive_numeric_2025_03
```

### ステップ3: 強制的にアーカイブを実行

デバッグモードを有効にして再処理：

```
sudo -u nginx sh -c '/usr/bin/php [Matomoのパス]/console core:archive --force-idsites=1 --force-periods=day,week,month,year --force-all-websites -vvv'
```

### ステップ4: 全サイトの整合性を確保するための後処理

アーカイブを消してしまっているので、全部再アーカイブする必要があります。

```
sudo -u nginx sh -c '/usr/bin/php [Matomoのパス]/console core:archive --force-all-websites'
```

## 結果と考察

上記の手順を実行した結果、データが正常に表示されるようになり、
「invalidate period」という表示も消えました。

原因はmatomo_archive_invalidationsなのか…？
正直このテーブルがなんなのかわかってないのですが、invalidationsなんでしょう
消したら動いたんで多分これなんだと思います。

matomo情報あんまりないんですが
GA4より個人的にこっちのが好きで
誰かの役に立てればとメモ代わりに。

## 参考：core:archiveコマンドの主なオプション

```
--force-idsites=1,2,3      指定したサイトIDのみをアーカイブ処理（カンマ区切り）
--force-periods=day,week   指定した期間のみをアーカイブ処理（day,week,month,year,range）
--skip-all-segments        すべてのセグメントをスキップしてアーカイブ処理
--force-all-websites       すべてのウェブサイトを強制的にアーカイブ処理
--force-date-range         指定した日付範囲のみをアーカイブ処理 YYYY-MM-DD,YYYY-MM-DD
-vvv                       デバッグ情報を詳細に表示
```

アーカイブ処理は定期的にcronで実行されますが、問題が発生した場合は手動で実行して解決することが可能です。