mcpField
M
magento-indexing-caching

magento-indexing-caching

github.com/finsilabs開発6075 回インストール6 日前に更新
リポジトリ

magento-indexing-caching について

Magento のインデックスとキャッシュを管理する開発者・運用担当者向けのスキルです。インデクサー、Varnish のフルページキャッシュ、Redis、キャッシュ無効化の調査を扱います。

主な機能

  1. 01インデクサーの状態とモードの確認・管理
  2. 02部分的または全件の再インデックス
  3. 03Varnish フルページキャッシュの設定
  4. 04Redis キャッシュとセッションストレージの設定
  5. 05キャッシュタグによる対象ページの無効化

活用シーン

  1. 01価格の誤りや商品非表示の調査
  2. 02本番環境での Varnish と Redis の設定
  3. 03大規模カタログのインデックス実行管理
  4. 04カタログや CMS 更新後のキャッシュ無効化

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill magento-indexing-caching

インストール後、Claude Code で/magento-indexing-cachingを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

tile.json
evals/custom-module-cache-tag-invalidation/
criteria.json
task.md
evals/indexer-production-configuration/
criteria.json
task.md
evals/redis-cache-and-session-configuration/
criteria.json
task.md

詳細

Magentoのインデックス作成とキャッシュ

概要

Magentoのパフォーマンスアーキテクチャは、2つの異なるレイヤーに依存しています。1つは、非正規化データ(商品価格、検索インデックス、カテゴリパス)をフラットテーブルに事前計算するインデクサー、もう1つは、レンダリング済みのHTMLページ全体を保存するフルページキャッシュ(FPC)です。本番環境では、Magento組み込みのファイルベースキャッシュに代わり、VarnishをFPCバックエンドとして使用することが推奨されています。アプリケーションキャッシュ、セッションストレージ、デフォルトキャッシュ(ブロックHTML、設定、レイアウト)のバックエンドには、Redisが推奨されています。インデックスの設定ミスや古いインデックスは、価格の誤りや商品の表示問題を引き起こす最も一般的な原因のひとつです。

このスキルを使用する場面

  • カタログの更新後に、商品価格が正しくない、または商品が表示されない場合
  • Magento本番サーバーに初めてVarnishを導入する場合
  • オンザフライの価格計算が原因でカテゴリページの読み込みが遅い場合に診断するとき
  • Magentoのセッションおよびブロックキャッシュストレージ用にRedisを設定するとき
  • Magentoのキャッシュタグを使用して、カタログまたはCMSの更新後にキャッシュを無効化する設定を行うとき
  • 大規模なカタログ(商品数が50,000を超える)で、全件再インデックスによるロックを防ぐためにインデクサーのスケジュールを管理するとき

基本手順

  1. Magentoのインデクサーとモードを理解する

    # List all indexers and their status
    bin/magento indexer:info
    bin/magento indexer:status
    
    # Example output:
    # catalog_category_product    Category Products    valid    Update on Save
    # catalog_product_category    Product Categories   valid    Update on Save
    # catalog_product_price       Product Price        invalid  Update by Schedule
    # catalogsearch_fulltext      Catalog Search       valid    Update by Schedule
    # catalogrule_product         Catalog Rule Product invalid  Update on Save
    

    チェックアウトのブロックを防ぐため、本番環境のすべてのインデクサーをUpdate by Scheduleモードに設定します。

    bin/magento indexer:set-mode schedule catalog_category_product
    bin/magento indexer:set-mode schedule catalog_product_price
    bin/magento indexer:set-mode schedule catalogsearch_fulltext
    bin/magento indexer:set-mode schedule catalog_product_flat
    bin/magento indexer:set-mode schedule catalog_category_flat
    
    # Verify modes
    bin/magento indexer:show-mode
    
  2. インデクサーと部分的な再インデックスを管理する

    # Reindex a single indexer (less disruptive than full reindex)
    bin/magento indexer:reindex catalog_product_price
    
    # Reindex all (avoid on production during business hours)
    bin/magento indexer:reindex
    
    # Reset indexer to "invalid" to force next scheduled run
    bin/magento indexer:reset catalog_product_price
    
    # Check mview (materialized view) changelog tables — lists pending rows to process
    bin/magento indexer:show-changelog
    

    非常に大規模なカタログでは、並列インデックス作成を使用します。

    # app/etc/env.php — enable parallel processing
    # In Admin → System → Index Management → Indexers → Configure
    # Or via config:
    bin/magento config:set dev/grid/async_indexing 1
    
    <?php
    // app/etc/env.php
    return [
        // ...
        'indexer' => [
            'batch_size' => [
                'catalog_product_price' => ['simple' => 200, 'configurable' => 50],
                'catalogsearch_fulltext' => ['simple' => 500],
            ],
        ],
    ];
    
  3. フルページキャッシュとしてVarnishを設定する

    # In Admin → System → Configuration → Advanced → System → Full Page Cache
    # Set Caching Application: Varnish Cache
    # Export Varnish configuration:
    bin/magento varnish:vcl:generate --export-version=6 --output-file=/etc/varnish/magento.vcl
    

    生成されたVCLで理解しておくべき主なセクションは次のとおりです。

    # /etc/varnish/magento.vcl (excerpts from generated config)
    
    sub vcl_recv {
        # Do not cache if private cookie is set (logged-in customer)
        if (req.http.cookie ~ "X-Magento-Vary=") {
            # Magento sets this cookie to vary cache by context (customer group, currency)
            # The cookie value changes only when the context changes — not per session
        }
    
        # Strip _ga, fbclid, utm_* params from cache key to prevent cache fragmentation
        set req.url = regsuball(req.url, "(\?|&)(utm_[^&]+|fbclid|gclid|mc_[^&]+)(&|$)", "\1");
    }
    
    sub vcl_hash {
        # Include Magento's context cookie in the cache hash
        if (req.http.cookie ~ "X-Magento-Vary=") {
            hash_data(regsub(req.http.cookie, ".*X-Magento-Vary=([^;]+).*", "\1"));
        }
    }
    
    sub vcl_backend_response {
        # Respect Magento's Cache-Control headers
        if (beresp.http.Cache-Control ~ "no-store") {
            set beresp.uncacheable = true;
            set beresp.ttl = 120s;
        }
    
        # Strip Set-Cookie on cacheable responses
        if (beresp.ttl > 0s) {
            unset beresp.http.set-cookie;
        }
    }
    
  4. アプリケーションキャッシュとセッション用にRedisを設定する

    <?php
    // app/etc/env.php — Redis cache and session configuration
    
    return [
        'cache' => [
            'frontend' => [
                'default' => [
                    'id_prefix' => 'b0c_',
                    'backend' => 'Magento\\Framework\\Cache\\Backend\\Redis',
                    'backend_options' => [
                        'server'            => '127.0.0.1',
                        'database'          => '0',
                        'port'              => '6379',
                        'password'          => '',
                        'compress_data'     => '1',
                        'compression_lib'   => 'gzip',
                        'persistent'        => 'mgto_cache',
                    ],
                ],
                'page_cache' => [
                    'id_prefix' => 'b0c_',
                    'backend' => 'Magento\\Framework\\Cache\\Backend\\Redis',
                    'backend_options' => [
                        'server'        => '127.0.0.1',
                        'database'      => '1', // Separate DB for FPC
                        'port'          => '6379',
                        'compress_data' => '0', // FPC data is already compressed HTML
                    ],
                ],
            ],
        ],
        'session' => [
            'save'                  => 'redis',
            'redis' => [
                'host'              => '127.0.0.1',
                'port'              => '6379',
                'password'          => '',
                'timeout'           => '2.5',
                'persistent_identifier' => 'mgto_sessions',
                'database'          => '2', // Separate DB for sessions
                'compression_threshold' => '2048',
                'compression_library'   => 'gzip',
                'log_level'             => '1',
                'max_concurrency'       => '6',
                'break_after_frontend'  => '5',
                'max_lifetime'          => '7200',
                'disable_locking'       => '1', // Improves performance but reduces session safety
            ],
        ],
    ];
    
  5. カスタムモジュールにキャッシュタグによる無効化を実装する

    Magentoは、データの変更時にキャッシュ済みページを選択的に無効化するためにキャッシュタグを使用します。カスタムモジュールでは、キャッシュに適切なタグを付け、正しくクリアする必要があります。

    <?php
    // Declare cache tags in your block/model
    namespace MyVendor\CustomModule\Block;
    
    use Magento\Framework\View\Element\Template;
    use Magento\Framework\DataObject\IdentityInterface;
    
    class CustomProductWidget extends Template implements IdentityInterface
    {
        private array $productIds = [];
    
        public function getIdentities(): array
        {
            // Return cache tags so Magento invalidates this block when any of these products change
            $tags = [\Magento\Catalog\Model\Product::CACHE_TAG];
            foreach ($this->productIds as $id) {
                $tags[] = \Magento\Catalog\Model\Product::CACHE_TAG . '_' . $id;
            }
            return $tags;
        }
    }
    
    <?php
    // In your observer or command — flush only relevant pages after product update
    namespace MyVendor\CustomModule\Observer;
    
    use Magento\Framework\Event\ObserverInterface;
    use Magento\Framework\App\Cache\TypeListInterface;
    use Magento\PageCache\Model\Cache\Type as PageCacheType;
    
    class ProductSaveObserver implements ObserverInterface
    {
        public function __construct(
            private readonly TypeListInterface $cacheTypeList,
            private readonly \Magento\Framework\App\Cache\Tag\Resolver $tagResolver
        ) {}
    
        public function execute(\Magento\Framework\Event\Observer $observer): void
        {
            $product = $observer->getEvent()->getProduct();
    
            // Invalidate only pages tagged with this product's cache tag
            // Varnish will purge via PURGE request using X-Magento-Tags-Pattern header
            $this->cacheTypeList->invalidate(PageCacheType::TYPE_IDENTIFIER);
        }
    }
    

例

価格の誤りを引き起こすインデックスの遅延を診断する
# Check if mview changelog has pending rows
bin/magento indexer:show-changelog

# If catalog_product_price has > 0 pending rows, prices are stale
# Run the indexer to catch up
bin/magento indexer:reindex catalog_product_price

# Check cron_schedule table for missed cron jobs (should run indexers every minute)
bin/magento cron:run --group index &
# Or manually via:
mysql -u root -e "SELECT job_code, status, finished_at FROM magento.cron_schedule WHERE job_code LIKE '%index%' ORDER BY finished_at DESC LIMIT 20;"
デプロイ後にFPCをウォームアップする
#!/bin/bash
# scripts/warm-cache.sh — warm the FPC after deploy
set -e

MAGENTO_BASE_URL="https://www.mystore.com"
SITEMAP_URL="$MAGENTO_BASE_URL/sitemap.xml"

echo "Flushing Magento caches..."
bin/magento cache:flush

echo "Warming FPC via sitemap..."
# Download sitemap and curl each URL with a warm-cache header
curl -s "$SITEMAP_URL" | \
  grep -oP '<loc>\K[^<]+' | \
  head -500 | \
  xargs -P 10 -I {} curl -s -o /dev/null -w "%{http_code} {}\n" \
    -H "X-Warm-Cache: 1" {}

echo "Cache warming complete."

ベストプラクティス

  • 本番環境では常にUpdate by Scheduleモードを使用する — Update on Saveでは管理画面での保存中に同期的に再インデックスが行われるため、大規模なカタログではタイムアウトが発生します
  • キャッシュ、FPC、セッションでRedisのデータベースを分ける — すべてにデータベース0を使用するとキーが競合し、1種類だけをフラッシュできなくなります
  • カスタムブロックにIdentityInterfaceでタグを付ける — これにより、データ変更時にVarnishとMagentoのFPCが適切なページを無効化できます
  • インデクサーの変更ログテーブルのサイズを監視する — catalog_product_price_clテーブルに数百万行ある場合、cronが実行されていないことを示します。テーブルサイズが原因で再インデックスがタイムアウトする前にcronを修正してください
  • bin/magento cache:cleanをcache:flushより優先して使用する — cleanは無効なキャッシュエントリーのみを削除します(安全です)。flushは、同じRedisを共有する他のフレームワークのキャッシュも含め、すべてを消去します
  • 環境ごとに異なるid_prefixを設定する — ステージング環境と本番環境でそれぞれ一意のプレフィックスを設定すれば、同じRedisサーバーを共有してもキャッシュ汚染を防げます
  • curl -IとX-CacheヘッダーでVarnishをテストする — HITレスポンスはVarnishがキャッシュから応答していることを示します。MISSはすべてのリクエストでMagentoにアクセスしていることを意味します

よくある問題

問題解決策
インポート後に商品が表示されない、または価格が正しくない一括インポート後に bin/magento indexer:reindex を実行します。ResourceModel\Product::save を直接使用している場合、プログラムから商品を保存してもインデクサーが常に起動するとは限りません
Varnish がログイン済み顧客に古いページを配信するVarnish の VCL ハッシュに X-Magento-Vary Cookie が含まれていることを確認します。ログイン済み顧客には異なる vary 値が割り当てられ、共有キャッシュを迂回します
Redis のメモリが不足するキャッシュデータベースでは redis.conf に maxmemory-policy allkeys-lru を設定します。セッションデータベースでは、セッションが気付かないうちに失われるのを防ぐため、noeviction を使用します
商品の保存後に FPC が無効化されないVarnish の PURGE ACL で Magento サーバーの IP アドレスからのリクエストが許可されていることを確認します。curl -X PURGE http://varnish-ip/ でテストします
全件再インデックスに何時間もかかり、テーブルがロックされるenv.php でインデクサーのバッチサイズを有効にし、--mode realtime を指定して部分的に再インデックスします。オフピーク時間帯に実行するようスケジュールします
Cron のインデクサーが実行されないvar/log/magento.cron.log でエラーを確認します。システムの crontab エントリーで、Web サーバーのユーザーとして bin/magento cron:run が毎分実行されていることを確認します

関連スキル

  • @magento-module-development
  • @magento-graphql
  • @magento-multi-store
  • @caching-strategies
  • @infrastructure-performance

コメント