はじめに
WordPress のウェブサイトのトップページ ( https://www.example.com/
) にアクセスした。 その結果「検索結果が見つかりませんでした」という内容のページが表示されてしまった。
アプリケーションのバグかと思ってサーバーを確かめると、サーバー内で localhost
向けに curl
を実行する分には正常にレスポンスが表示されており、上記のような問題は発生していない。
何か間違えたかと思って、改めてトップページにアクセスすると、今度は正常にページが表示された。
この問題について調査したのだが、複合的な要因が噛み合うことで問題が起こっていた。 そのため、その現象を説明する。
個別の事象
WordPress のデフォルト検索機能
WordPress ではデフォルトでクエリ s
を付与することでサイト内検索を行うことができる。 例えば https://www.example.com/?s=検索
としてアクセスすればよい。
個人的には色々と思うところがあるが、事実としてデフォルトではこのような機能がある。
外部サイトからのリンクに独自のクエリパラメータが追加されることと CDN の設定
例えば Facebook からの流入であれば fbcid=...
といったクエリが付与された状態でページが呼び出される。 例としては https://www.example.com/?fbcid=xxxxxxxx
など。
その他、アクセス解析などの理由でこのような独自のクエリを付与して外部ウェブサイトを呼び出す仕組みはかなり多い。
しかし、ウェブページ全体を見ると、クエリを表示制御に利用しないページの方が多い。 例えばウェブサイトのトップページはそうである。
https://www.example.com/?fbcid=xxxxxxxx
であっても https://www.example.com/?token=yyyyyy
であっても、内容の変わらない同じトップページが表示されてほしい。
同じページが表示されてほしいというのであれば、CDN や nginx によるウェブサイトキャッシュを利用している場合、それらのキャッシュを共用して、キャッシュヒット率を上げたい、という考えが出てくるのは自然である。
クエリを無視してキャッシュを作るのであれば、例えどんなクエリを付与する外部システムからのリンクであっても、共用のキャッシュを利用できる。 言い換えると、個別のクエリを見てキャッシュを生成・利用する場合、先の2つのアクセスを別物ととらえてしまうため、外部から付与されるクエリ毎にサーバーに問い合わせが行われるため、サーバー側の負荷が上がってしまう。
そのため、多くの CDN ではクエリパラメータとキャッシュをどのように関連付けるか、と言った設定を提供している。 クエリをすべて無視するのであれば、/
と /?q=aaa
と /?q=bbb
と /?s=aaa
はすべて同じキャッシュを利用する設定になるし、クエリすべてを利用するのであれば先の4つは異なるキャッシュを利用する設定になる。 もちろん、特定のクエリのみ利用 / 特定のクエリのみ除外、という機能も併せて提供されていることが多い。
WordPress 側はデフォルトだとおそらく Cache-Control: no-cache
を返すが、CDN を利用するためにこのヘッダを変更しているか、あるいは CDN 側で Cache-Control を無視して強制キャッシュを行うといった方法を取ることもできる。
任意のクエリを付与した検索汚染
例えば、以下のページにまとめられているが、要は「クエリを付与した有効な URL を配置したウェブページを準備し、そのウェブページを検索エンジンのクローラーにアクセスされることで、それらの URL を 検索結果に表示させる」ことが行われている。 その結果、それらの URL も Google などの検索結果として表示されてしまうという現象が生じている。
現在の多くのウェブサイトは WordPress で構築されていることもあり、この汚染には当然 s
パラメータを利用した URL は多く用いられている。
何が起こったか
先に挙げた内容から「ウェブサイトの特定ページに任意のクエリを付与してアクセスすること」自体はごく当たり前に行われることである。
しかしそうなると WordPress のデフォルト検索機能が問題になってくる。
https://www.example.com
ではウェブサイトのトップページを表示したいにも関わらず、https://www.example.com/?s=検索
では検索結果を表示してしまうのである。
通常のウェブサイトであればこれで問題は起こらないのだが、CDN でクエリを無視している 場合は話が別になる。 クエリを無視しているということは、ウェブサイトのトップページと検索結果を同じキャッシュを利用して表示する ということに他ならない。
まとめると、最初に説明した事象は以下の仕組みで発生した。
- 外部利用者が
https://www.example.com/?s=.....
として検索結果が0件となるリクエストを行い、CDN がこの結果をキャッシュした - この状態で
https://www.example.com/
にアクセスするとCDNがクエリを無視する設定になっていたため 1 で作成したキャッシュを利用者に返した - そのため、トップページにアクセスしているにも関わらず、検索結果が0件ですというメッセージが表示された
- キャッシュの有効期限が切れた状態でトップページにアクセスすることで、正常なトップページが表示された
対応策として、クエリを無視する設定をやめ、クエリ毎に異なるキャッシュを利用するような CDN の設定とすることで、この問題を回避した。 負荷の上昇は許容範囲であったため、そのような対処を取った。
まとめ
そもそもの問題の発生頻度が低く、また、正常に利用している限りは起こりえない問題のため原因の特定には苦労したが、理屈を並べてみると腑に落ちた。
サイトの構成要素全体が俯瞰できないとなぜこのような問題が起こるかが分からないため、システム全体の理解のためのケーススタディとして有用ではないかと思い、ここで紹介した。