丼砲で落ちないブログを建てる

このエントリはmstdn.maud .io Advent Calendar 2018 (A:don:vent Calendar) の11日目です。きのうはえいわすの末代にいない末代はどこへいったのかでした。

@hina@mstdn.maud.io  です。当初はOSCでもらったラズパイの話でも書こうかと思ってたのですが忘れてたし某氏のブログが死にまくっていたのでこのネタでも書いておこうかと思います。

丼砲、あるいはMastoDDoS

:don: を含む最近のバージョンの Mastodon では投稿本文にURLが貼られると、そのURLの先のOGPタグを探しに行き投稿にそのページのタイトルや概要を埋め込むためのHTTPリクエストを発生させます。

TwitterやFacebook、あるいはLINEやSlackなどでも同様のことは行われていますが、これらのような単一サービスで完結するSNSや各種コミュニケーションツールでのリクエストは何度も飛んでくることはない[^1]ので、まあ問題になることはないでしょう。

[^1]: ちなみに私がTwitterでURLを張るとそのページには色んな所から10以上のアクセスが飛んでくるようです。少なくともUserStreamが死ぬ前時点では。

しかしMastodonは連合SNSです。同じ投稿を受け取った複数(数百、場合によっては数千?)のサーバーから一斉にこのリクエストが飛んでくることになります。この結果、同時、あるいは短時間にそれだけのリクエストが当該のURLに飛ぶ訳となるので、サーバーの構成が貧弱だったり欠陥的なプログラムを利用しているサーバーは過度な負荷に耐えられずにダウンしてしまう(503や502を返したり、ずっと真っ白なままぐるぐるしたりetc)ことがあります。このような事象を俗に(DDoSになぞえて)MastoDDoS丼DDoSMastodon砲などと呼んでいます。(まあ丼砲程度で死ぬサイトは噂のWBS砲やYahoo!ニュース砲には耐えられない気がするのですが)

以前から課題とされているものの今の所根本的な解決には至っていないと言えるのが現状のようです。一応v2.5.0以降はOGPの取得に60秒以内のランダムなディレイを入れて同時リクエストの集中を緩和しているのですがあくまでも少し緩和される程度。

とりあえずしばらく解決しそうにはないので耐えられるサイトが大事。あ、もちろんこのことの悪用は厳禁。

落ちないように対策しよう

Mastodonのインスタンスを管理していたり常駐していたりするのに自分のブログをTootしたら落ちてしまうなんて笑えないし絶対に避けたいですよね。そもそも誰も得しない。

……とりあえずこういった自体を未然に防ぐためにも丼砲を受けても絶対に死なない(死なないとは言っていない)、なおかつコストはかけないで済むブログの構成を考えてみましょう。

SSG

殆どの場合においてアクセス集中でサイトがダウンするのはバックエンドで動作するCMSなどのアプリケーションが耐えられなくなる(DBやI/Oが詰まったり単純に順番待ちになったり謎の無限リクエストを生み出したり(???)などなど)のが原因です。言い換えればそれをなくしてしまえばよっぽどサーバーが弱くない限り落ちることはないでしょう。

ということでそぎぎ……じゃなくてスタティックサイトジェネレーター等で性的静的なHTMLを吐き出してそれをサーバーに配置しておけばこれで多分落ちないブログの完成ですね。

例えばマツダイアリー茜の鯖缶日誌で使われているHexoなんかがその一例。ほかにもGatsbyだとかJekyllだとかNetlify CMSだとかHugoだとか新旧いろいろ存在します。みんなだいすき(みんな好きとは言っていない) WordPress でもSSGとして使えるStaticPressがあります(メンテされてないのでちゃんと使えるかは知らない)。変態的な仕様でブラウザだけで GitHub 上にブログを生成してくれるHubPressだってSSGの一種ですし、Vue使いならVuePressなんてものも……まあまだブログとして使うには不十分っぽいですが。

静的サイトとして吐き出してしまえば別にわざわざそれを設置するサーバーを自前で用意しなくても Netlify や GitHub Pages のような無料で使用可能なホスティングに置いておくだけでいいのでコストもかからないわけで、末代もよく使ってる(要出典)のも納得です。

もちろん上に上げた以外にもSSGや静的サイトを出力するCMSは無数に存在しますね……

CDN

ブログのコンテンツなんて短時間に何度も修正することはあっても長い期間で見ればほとんど変化しませんし、わざわざ毎回リクエストをCMSで処理する必要があるようなものは普通ほとんどありません。アクセス解析やカウンター(死語)は外部サービスや別API等でやれってわけですし。(リファラ一覧を記録するtDiary?そんなものは知らない)

つまり一般的なブログではCDNを前段に置き、そのレイヤーでキャッシュしたものをすべての閲覧者に返してしまえば問題ないはず。例えばWPならログイン中のユーザーならキャッシュを使わずにアクセスさせそれ以外ならキャッシュしたものを返すというのが定石です。

CDNを前に噛ませておけば地理的に閲覧者に近いところからキャッシュが返せて高速化もできたり(国内だと離れる場合も多そうだけど)、貧弱なサーバーでもほとんどリクエストを処理する必要がなくなったりして一石二鳥です。

CloudFrontやCloudflare、Fastly……なんかいろいろあったりそれぞれクセがあったりすることもあるので詳しくはググってください。設定をミスってしまうと某所の個人情報流出事案のようになってしまう可能性もないわけではないものの……まあそうそうないはずですが注意が必要です。

ちなみに私は一部のWPサイトでCloudfront+C3 Cloudfront Cache Controllerの運用をしています。WordPress の前段に CloudFront を配置する | dogmap.jpとかの内容がベース。

リバプロキャッシュ

もしお使いのブログでnginxをリバプロに使っていたり新しくVPS上にWPを建てようとかいうならnginxのレイヤーでCDN同様にコンテンツをキャッシュして返すようにすることでやはりバックエンドの負荷を大幅に抑えられ、キャッシュhit時はレスポンスも向上します。

前段でキャッシュする場合コンテンツ更新時にはキャッシュのクリア(無効化)が必要になり、一部のCDNではラグが発生するものもありますがこのレイヤーで自分でキャッシュしておく分には自分の管理域にそれが存在するわけなのですぐにクリアすることができます。(といってもキャッシュってRAM上にも乗るし正しく確実に消す方法とは)

proxy_cachefastcgi_cacheを使用するのですが、詳しい設定方法は面倒になったのと時間がなかったので割愛します。ググって。

設定が面倒であればWPなら AmimotoKUSANAGI ならデフォルトで有効だったり1コマンドで有効化できるように構成されていたりするので便利。AmimotoのChefのテンプレはオープンソースで実際にAmimotoで使われているキャッシュ設定が見れるので(読めるのであれば)参考に。

最近はいわゆるレンタルサーバーのような共有Webホスティングでも前段にnginx等を置いてキャッシュを返せるようにしてるところも増えてきましたね。ロリポのWPキャッシュとかエックスサーバーのXアクセラレータConoHa Wingのコンテンツキャッシュなど。

プログラムやその中でのキャッシュ

環境的に前段でキャッシュできなかったりキャッシュが存在していなかった場合でもアプリケーション自体のボトルネックを抑えれば総合的な負荷を抑えてアクセス集中しても耐えられるかもしれない、そういう話です。(もちろん上記とも組み合わせるべき)

DBやI/Oのキャッシュ

RDBやファイルのI/Oを細かく繰り返していたりすると重くなったりしやすいのでよく使うものとかはそれが得意なものに任せようみたいな話。Mastodonで言えばしばらくLTLが流れずに無限にFTLだけが流れたインスタンスのLTLの読み込みは激重になりやすい(わたしの個人インスタンス)みたいなのです(雑すぎて意味がわからない)。

具体的にはMemcachedやRedisのようなNoSQL DB/オンメモリKVSなんかでキャッシュする実装がCMSやそのプラグイン、FW等でオプションとして用意されてたりするので使えるなら使うといいかも。たとえばWordPressではObject cacheとして様々な対応プラグインが存在します。

コード自体のキャッシュ

PHPのようなインタプリタ言語はC言語のようなプレコンパイルされた言語と比べて構文解析とかに時間がかかると言われます。

PHPではOPcacheが実行時に吐かれたオペコードをキャッシュして次回以降に利用したり、それを前もってコンパイルしておいたりすることができます。なお最近のPHPではデフォルトで有効になっていますが、もし無効化されていれば opcache.enableで有効化。

他の言語は知らん。

その他諸々

レポート提出期限に間に合わない学生みたいな書き方をしてしまったせいでクソ雑なエントリになってしまいましたが、要はできるだけアプリケーションサーバーの仕事を減らさせることでブログごとき落ちることはなくなります。

そういや以前似たようなネタ(WPのいろんなキャッシュ)で登壇したことがあったので貼っておきます。

まとめ

とりあえずCDN挟んでおけ。

あと面倒なのがいやならSSGを使うか無難にレンサバ使うと楽。

まあこのブログの主なところはNginxのキャッシュくらいですが丼砲とかで落ちたり重くなったことはまずないです。

ちなみに例の件の原因はプロフィールの更新でBIOのURLにアクセスが世界中から(?)飛んできたからだったっぽいです、まじか。

あしたは8号さんです。

コメントを残す