非可逆圧縮の画像フォーマットとして有名です。圧縮するとどう劣化するのか、そしてそのメカニズムを紹介します。圧縮率をあげると以下のような現象が見られます。モスキートノイズ元画像(png)q=100q=80q=40q=20クオリティ1を下げると文字やその周りに汚れのようなノイズが発生しています。これはモスキートノイズやリンギングと呼ばれます。大きく色が異なる箇所付近に目立って発生します。ブロックノイズ元画像(png)q=100q=60q=40q=20なだらかだったグラデーションが、クオリティを下げると四角い形での歪みが見られるようになります。これはブロックノイズやブロック歪みと呼ばれています。元画像(png)q=20q=10q=5q=3さらにクオリティを下げると、グラデーションが荒くなり、色数が減っていきます。ブロック2に分割してそれぞれに対して圧縮処理を行います。そのため、圧縮による劣化はブロック単位で変わる事になり、ブロックの境界で劣化が目立つ事になります。これがブロックノイズとなって現れます。上の例でいうと、細かい劣化の目立つブロック(薄い赤い部分)と目立たないブロック(青い部分)の境界(赤い部分)で劣化が目立ちます。各ブロックに離散コサイン変換という変換を施した形式で保存しています。種類のパターンの組み合わせに分解されて表現されるようになります。例として「A」という文字の32x32(つまり4x4ブロック)の画像を離散コサイン変換します。変換後の64パターン左上からブレンドするとこうなるポイントとしては、以下のようになります。変換すると64種類のパターンに分解される64種類のパターンをブレンド3するとちゃんと元の画像になる左上のパターンは低周波成分と呼ばれ、ブロック全体の色を決めるのに使用します。一方で、右下のパターンは高周波成分と呼ばれ、ブロック内のより細かい色の変化を表現するのに使用します。ところで、離散コサイン変換を行うだけでは画像の劣化は起きません4。各パラメーターの値を近似値に丸めるため、それによって品質が劣化します。これを「量子化」と呼びます。指定する品質を設定した経験があるかもしれません。場合はほぼ正確な値を残すと思われますが、数値を下げると思い切った近似をするようになります。実はこの数字によってどのような近似を行うかはソフトウェア毎に異なります5。同じ品質の数値でもソフトウェアによっては劣化の仕方が変わります。パターン(周波数)毎に近似の強さを変える事ができます。上の図で言う左上の低周波成分を強く近似すると、ブロックの色がまんべんなく変わります。右や下のストライプや、右下のチェックのような高周波成分を近似すると、縞模様やチェックが浮き上がって来る事になります。これがモスキートノイズの原因になります。高周波のパターンが人間には判別しづらい事がわかっているので、多くのソフトウェアでは左上よりも右下を優先的に近似をします。いう色の表現方法を採用している事も関係しています。モスキートノイズ先ほどのモスキートノイズの画像を拡大してみます。画像は白と赤しか使ってないにもかかわらず、うっすらと青いノイズが見えるのではないでしょうか。表現している事から発生するものです。色を輝度(Y)と二軸の色差で表現します。それぞれの成分に対してブロック分割し、圧縮を行います。そのため、圧縮に伴う歪みは「輝度の歪み」と「色差の歪み」という形で発生します。輝度成分に対してモスキートノイズが発生すると、縞模様やチェック状の「輝度の歪み」が発生します。一方で色差成分に対してモスキートノイズが発生すると、縞模様やチェック状の「色差の歪み」が発生します。先ほどの画像で青いノイズが発生したのは、色差成分のモスキートノイズが原因です。上で説明した量子化による情報の切り落としの他に、色差の情報を落とす事があります。以下は品質を100の状態でPNGからJPEGに変換したものです。元画像(png)q=100最高品質にしたのにもかかわらず、緑と紫のチェックがグレー6になってしまいました。ストライプの部分もぼんやりと色がついているもののほぼグレーです。この劣化はクロマサブサンプリングと呼ばれる操作が行われているのが原因です。色差成分を縮小する事でデータ量を減らす方法で、人間が色の変化よりも明度の変化に敏感であることを活用しています。(横方向だけ間引く)などがあります。形式でサブサンプリングを行っています7。4:4:4(間引かない)4:2:04:2:2クロマサブサンプリングとブロックノイズJPEGのブロック化や離散コサイン変換の処理は、クロマサブサンプリングされたものに対して行われます。そのため、色差成分に関してはより広い範囲(4:2:2だと16x8、4:2:0だと16x16)でブロックノイズが発生します。以外のサイズに指定する事も可能です。↩︎グレーより明るい色でブレンドするとより明るくなり、暗い色でブレンドするとより暗くなる、といったブレンドになっています。実際には丸め誤差で小さな劣化が発生します。製品はこれとは別の独自の量子化ロジックを使っているようです。↩︎なおこの画像は色差の平均をとるとグレーになるように調整しています。エンコーダー(ImageMagickが使っているlibjpegだと思われます)が平均値をとってサブサンプリングを行っているため、このようになっています。写真の場合はこのように極端な色差の劣化が発生する事は少ないと思われます。↩︎この記事を書いた人:鷲田ルームクリップのアプリケーションエンジニア。:みなさんこんにちわ。ルームクリップ株式会社CTOの平山です。残暑が厳しい日々ですね。昨日の9日、表題の通り日本テレビ「今夜くらべてみました」でルームクリップが紹介されました。大きな衆目を集めるシーンでの言及となると、ちょっぴり特別な興奮がありますね。これが「エンジニアとして」、となるとなおさらです。なんてったって巨大トラフィックが襲撃してくるかも知れないわけです。この手の興奮は上手にコントロールして、常に冷静に対処し、万全の対策で迎え撃たなければなりません。ご多分に漏れず今回も我々は相応の準備をもって立ち向かいました。結果として、今回はもっと興奮しておくべきでした。私の想像のはるか上空を飛び、ずいぶん時間がたちこのブログを書いている今ですら、おおきな影響を及ぼし続けております。これから同じ轍を踏むかもしれないすべてのエンジニアに向けての転ばぬ先の杖を記していこうと思います。中には「え、こんなの当たり前でしょ、むしろなんでやってなかったの?」ってものもあるかと思います。不安にならずとも皆様の手厳しいご意見は、これ以上ないくらい私の脳幹をえぐっています。時には包み隠さないことも大事です。わたしは後ろ暗さを抱えて危険なシステムを運用しているすべてのエンジニアの味方です。「正しい運用しようぜ」の流れを全力で社内に引き込むための道具として、ぜひ本ブログをお使いください。その前に...改めまして、今回突発的に発生しましたアクセスに対応しきれず、長きに渡ってサービスに障害を起こしてしまいましたことをこの場を借りて謝罪いたします。期待をもってアクセスしていただいたすべてのユーザの皆様、また、すべての関係各位の皆様に対し大変にご迷惑をおかけいたしました。以下、専門的な話になりますが公開できる限りにおいて、障害の経緯を共有させていただきます。簡単に言ってしまうと下記のようなことが起きました。TV局から連絡を受けて流入トラフィックを推計した余裕で外れた単一障害点はスケールアップで大丈夫だろうと高をくくった余裕で外れてそいつのせいで全部落ちた分散しまくればなんだって耐えうるだろうと甘く構えたネットワークリソースについて忘れてて分散できず落ちた対策範囲なんてアプリケーションサーバとDBくらいだろ、って思ったバックエンド色々マイクロ化したため対策ポイントが増えててんやわんやになって気分が落ちた一つでも「あ、これは対岸の火事じゃないぞ」と思ったエンジニアは今すぐ点検しましょう。単一障害点は本当に危険です。当たり前ですが大事なことです。「当たり前のことができていない」というケースは「当たり前に多い」と思ってます。心当たりあるエンジニアは、今日だけは責めないので、そっと確認しましょう。それでは、一つ一つ見ていきましょう。その後に「サービス言及中に見ている人の割合」とか「その時間帯に検索する人の割合」とかを適当に見積もって積算して当たりをつけるものだと思います。大事になるのは瞬間最大風速req/secなので、秒単位で平坦にならすのではなく、適当にピーク分布を積算して出すのがまぁ妥当かと思われます。今回わたしが見誤ったのは、「その時間帯に検索する人の割合」でした。番組の性質上、検索やサービス起動を促す作りになっていて(これは本当にすばらしい!)、思った以上のリクエストが発生しました。数値でいうと2倍程度見誤りました。皆様、「危険だな」と思ったら妥当な計算のあと、「2倍」しましょう。ちなみに私は、放送直前に「チュートリアル徳井さんがサービス名を発話するかも」という情報を追加で得ました。(このあたりの連絡網を強化することも必須ですね!)この時点で実はかなり迷いました。今の対策が不十分である可能性がよぎっていたのです。・・・皆さん、虫の知らせがやってきたら迷わず「最大値の2倍」にしましょう。単一障害点への対策これが本当に悔やまれるポイントです。どの本にだって書いてあることです、こういうボトルネックは障害時にも影響を波及させないように対策しておけと。それができないなら、どんなアクセスにも耐えられるような設計にしておけと。ところで、RoomClipはiOS、Android、ブラウザ向けにサービスを展開しており、そのバックエンドとして概ね下記のようなクラウドサービスを利用しています。Cloud共有リソースに対するAPIアクセス、が多発するような状態と言えるでしょう。ルームクリップにおいて負荷障害発生時の犯人の9割はDBでした。よって我々はDBに対してどんな奇行種も入ってこれない防壁で守っておりました。実際今回のアクセスに対しても唯一と言っていいくらい割と大丈夫だったのはDBです。皆さんもそこは大丈夫だと思います。問題は、かねてよりバックエンドで進めていたマイクロ化にあります。検索サーバ・画像配信サーバ、このあたりはサービスの隅々で使われている重要な機能なので特別に本体設計から切り離し、大事に保守メンテしていました。それはそれでいいことだと思います。そのAPIの呼び出し部分が悪かった。一部のページにおいて、APIのレスポンスをタイムアウトせず待つ、帰ってこなければExceptionを投げエラー終了する、というコードになっていました。運命共同体コードです。本当に反省しています。本来であればサービスメッシュやenvoyレイヤのように、API接地面の安全な設計は暗黙的に処理する予定でした。そのレイヤについてちゃんと決めきることを少し後回しにて、とりあえず(後からどうとでもなるような形で)切り離すということを優先していました。これはこれで限られたリソースや検証という意味ではメリットのあることだと思います。外部環境は待ってくれません。TV番組の話は突然来ますよ。これは悪くない選択肢です。「リスクを受容した」ということはもっと強烈に認識すべきでした。皆さん、モノリシックなシステムをDDD的思想でもって妥当な範囲でバラしたく気持ちはわかります。いつでも想定しておいてください。来週、あなたのサービスについてチュートリアル徳井さんが言及するかも知れないことを。想定外のネットワークリソース枯渇さて、異常を察知して直ちにリソースの水平スケールをアップした我々ですが、そこで地団駄を踏むことになります。インスタンス・コンテナが全く増えません。ルームクリップのAPIサーバ、Webサーバは基本的にECS(一部EC2)という状況だったので、オートスケーリンググループをいじれば続々と援軍追加されるはずでした。たってもエラーで立ち上がりません。AWSリソース制限かとも思ったのですが、つい最近あげたばかりです。調査してわかったことは、サブネットのPrivateIP枯渇でした。事情あってサブネットの許可IPのCIDRを厳しくチューンしていたため、ここの上限にぶつかってインスタンスの立ち上げができなくなっていました。サブネットの設定なんてそうそう変更しないので、すっかり忘れておりました。皆さんもそらで言えますか?あなたのサブネットは第何オクテットまでマスクしていますか?あ、ごめんなさい、そらで言える必要は全くありません。確認しに行けばいいだけです。ネットワークに限らず「リソース枯渇」系の話は結構緊急時に人をイラつかせるものです。nlimit、inode、エフェメラルポート、帯域制限、もちろんHDD容量。今回忘れてならないIP。これは激痛で、リカバリの速度がだいぶ遅れた原因の一つとなってしまいます。先に触れたマイクロ化の流れもそうですが、BFFなども積極的に導入した結果、スケール対象となるインスタンスの塊は結構増えておりました。端的にALBの数が多いんですね。これは本質的にはそこまで問題ではないことなのですが、少ない人数でこれらのスケールアップを管理するというのは中々ストレスがたまります。事前準備はまぁいいんですが、障害中「やべぇ!」となったときのあっちゃこっちゃいじる千手観音っぷりは悲惨です。いろいろな対策がありえますが、Lambdaなりでサーバレスに切り替えていくのは非常に良い選択かもしれません。ウォームアップなんていらない!というのは大正義です。まとめ非常に長くなってしまいましたが、簡単にまとめますと、今回の障害の大きな原因はやはり単一障害点の対策不備になります。RDB周りは特に手厚く対策されると思いますが、(当たり前ですが)転置インデックスを扱うサーバや、DynamoやRedisといった領域についても、「手厚くするか、緊急時に被害を軽微にするような設計にする」など、最低でも波及を抑える設計にすべきでした。外部APIを使うときの接地面の設計(リトライ制御やブレーカーなどを含む、一般にenvoyレイヤなどで処理される諸問題)も非常に繊細になされるべきだということを改めて実感しました。これ以外にも気づけなかった問題は多々ありますが、本ブログではひとまず猛省しつつ「速報」という形での共有とさせていただきたいと思います。これからバックエンドをマイクロ化していくプレーヤーは多数存在していると思いますが、ぜひ改めて「管理すべきドメイン」が増えていくことにより、それぞれの障害点への対策やスケーラビリティの保証などが手薄にならないよう、気をつけていただけるとよいかと思います。課題はたくさんありますが、日々精進し、これからも皆様の日常にある「創造性」を応援して参ります。末永くルームクリップをよろしくお願い申し上げます。改めまして、この度の大規模な障害、大変申し訳ありませんでした。「しかたない、、わたしがなんとかしてあげよう」と思うエンジニアの方、ぜひ遊びに来てください!フロントもサーバサイドも!生産性の高いサービス開発基盤を作りませんか?この記事を書いた人:平山知宏ルームクリップ株式会社のCTO。インフラからサーバサイド全般担当。インダストリアル系の家に住みたいと思うけど、子供もできちゃったし危ないから工具とかほっぽっとくのやめようと思っている1985年生まれ。