Facebook にウェブサイトの URL をはっつけるとき参照される HTML メタ情報の仕組みに Open Graph Protocol ってのがある。 Facebook に URL を貼ると bot が URL の内容を読みに行ってページの概要や画像を取得し Facebook 内に埋め込み表示するというもの。 Facebook を見ている人はリンク先の内容をクリックする前に概要を把握できるので、リンクをクリックして見たい情報じゃなかった、ということを避けられる。 Facebook が考案して策定した仕組みだけど、 Facebook に限らずいろんなサイトで OGP タグを出力してるし読み込んでる。 Twitter にも似た仕組みあって Twitter Card という。この辺の対応は結構前にやってた。

アドベントカレンダーに備えて Open Graph protocol に対応

アドベントカレンダーに備えて Open Graph protocol に対応

昨日飲みに行って今朝起きてからふとコード書きたくなって、アドベントカレンダーもあることだし(去年の Adventar で自分のブログだけ og:image がなくて画像が出てなくて残念だった)、このブログを Open Graph protocol に対応させることにした。T...

portalshit.net

ただ自分のサイトが OGP タグを提供するだけではつまんないなと思ったので自分のブログにペロッと URL を貼ったときに相手先に OGP タグがあればそれを出力するようにしてみた。こんな感じ。

OGP Preview

しかしここで困ったことがあって、↑でリンクしてる Circle のサイトは HTTPS で配信されておらず、単純に Circle のサイトで og:image に指定されている画像を SSL 化されているこのブログで読み込むと Mixed Content になってしまう。せっかく HTTP/2 で配信していたのに台なしになってしまう。またそもそも og:image は Facebook でシャアされることを想定されていることがほとんどなので、画像サイズがデカすぎていい感じにスクエアに表示するためには CSS の小技を駆使したりする必要があった。

いい感じに解決する方法ないかなと調べていたら良いのが見つかった。

willnorris/imageproxy

willnorris/imageproxy

imageproxy - A caching, resizing image proxy written in Go

github.com

Go で書かれた Image Proxy Server で、 HTTPS Proxy は当然のこと動的リサイズもできる。使い方は簡単でバイナリを落としてきて動かすだけ。 Go なんで ImageMagick をどうしたりとかを考えなくて良い。 そもそも Docker イメージも提供されているので Docker をインストール済みなら docker run するだけでも動く。 めっちゃお手軽。

こいつのおかげで HTTPS で配信されていないサイトの OGP タグを読み込んでも Mixed Content にならずに済むようになった。また og:image は適切にリサイズできるようになった。画像変換サーバーとかは結構難しいいやつで個人のブログでこんなに簡単に使えるものだとは思ってなかったので正直ビックリした。

AWS の登場で大企業じゃなくても CDN 使ったり仮想サーバーでウェブシステムを構築したりできるようになった。さらには Go や Docker といった技術のおかげで複数の込み入ったソフトウェアを組み合わせて構築していく必要があったシステムが、まるで jQuery を使うような感覚でポン付けで使える時代になってきている。とても素晴らしい。

ちなみに OGP の取得には open_graph_reader という gem を使っている(昔からある opengraph という gem はメンテナンスされておらず最近の Nokogiri で動かない)。 open_graph_reader の作者が結構 Opinionated な人で、以下のような Anti-featurs を掲げている。

open_graph_reader Anti-features

http://ogp.me/ の仕様に準拠していないサイトのことは完全無視というつくり。個人的にはこういう思想は好みだが、現実問題として使い勝手が悪い。例えば hitode909 さんのブログの OGP タグを取得しようとしたところ以下のようなエラーを出して取ってくれなかった。

スクリーンショット 2018-05-26 10.08.47.png

article:published_time は ISO8601 形式の datetime であるべき、とのこと。はてなブログはかなりシェアが大きくリンクする機会が多いので残念。

先日書いた Day One のバックエンドで障害 - portal shit! について、 Day One のヘルプページで詳細を説明する記事が掲載されていました。

May 2018 Day One Outage Postmortem | Day One Help

May 2018 Day One Outage Postmortem | Day One Help

help.dayoneapp.com

ウェブアプリケーションエンジニアの皆さんが読むと参考になるのではないかと思い、翻訳の可否をたずね許可をもらったので翻訳します。


2018 年 5 月の Day One 障害報告

執筆者: Paul Mayne (訳注:Day One の創業者)
今週更新(訳注:障害復旧日の午後に公開されました)

2018 年の 5 月 7 日から 10 日にかけて、 Day One は重大な Sync サービスの停止に陥りました。ユーザーの皆さんから堅牢な Sync サービスを期待されていることはわかっていますし、この出来事は我々の基準を満たすものでもありません。何が起こったのか、そして将来にわたってどのようにこの問題を回避していくかをユーザーの皆さんにお伝えしたいと思います。

簡単なまとめ

5 月 7 日にハードウェア障害が発生し、最初の Sync サービスの停止が発生しました。バックアップデータが不完全だったことが原因で、 5 月 8 日の Sync サービスの復旧処理中、一部のユーザーのアカウント ID が既存のユーザーのものと重複してしまいました。結果、一部の新規登録ユーザーは他人の記事を見ることができる状態となっていました。問題に気がついてすぐに Sync サービスを再び停止させました。対象のユーザーは 106 人で、これは我々のユーザー全体の 0.01% よりも少ない値です。

現在、 Sync サービスは正常に復旧しており、記事が他人に見られることはありません。近日中(訳註:すでにリリース済みです)に意図せず共有されてしまった記事を削除するアップデートを提供します。

End-to-end の暗号化を施していた記事は今回の事故の対象外です。

いかなる偶発的な個人情報の漏出も信用を毀損するものであると我々は認識しています。この不幸な状況にあって我々は、正直に状況を説明することが最善だと思っていますし、また信頼を回復するために全力を尽くしています。今回、個人情報の流出被害にあった 106 人のユーザーには終身の Premium メンバーシップを無償提供し、それぞれ個別に連絡を取っています。自分たちにできるあらゆることを行ってみなさんの信頼を回復していきたいと思っています。

障害の詳細

5 月 7 日月曜日、 Day One の社員が DB サーバーでハードウェア障害が発生していることに気がつきました。問題のあるサーバーをデータベースクラスターから取り除く作業とデータを残りのサーバーに分散する作業を始めました。

データの分散処理に失敗します。これが最初の障害です。すぐに Sync サービスを復旧させたかったため、新しいデータベースクラスターを作成して最新のバックアップデータを読み込むことにしました。新しいクラスターがセットアップされ、バックアップが読み込まれました。

5 月 8 日火曜日の早い時間に復旧処理が完了し、 Sync サービスを再開しました。当初は順調に動いているように見えました。しかし数時間で「自分の記事ではない記事が見える」という問い合わせが何人かのユーザーからありました。これは由々しき事態であり、我々はすぐに Sync サービスを再停止し、これ以上被害が拡大しないようにしました。

この時点で、問題と対応方法の調査を行う間、 Day One Sync を無期限に停止する旨をソーシャルメディアに投稿しました。何が原因なのか、何が起こっているのか、そしてもう問題が起こらないと確信できるまで Sync サービスは再開できませんした。

5 月 9 日水曜日の午前、問題の根本原因を突き止めました。復旧処理に用いたバックアップデータが不完全だったのです。記事データは完全なものでしたが、ユーザーアカウントデータに欠落がありました。具体的には、 3 月 22 日よりも後に作られたユーザーアカウントデータが含まれていなかったのです。その結果これらのユーザーはログインすることができていませんでしたし、特定の記事データが意図せず他人から見えてしまうという問題につながりました。

それぞれの記事データベースは “accountID” というフィールドを持ち、どのアカウントがその記事の所有者であるかを判断しています。全ての記事データは正しく復旧されましたが、ユーザーアカウントデータはそうではなかったため、データベースに所有者が存在しない記事ができてしまいました(例えば “My Travel Journal” という記事は 123456 というアカウントのものだったとしましょう。しかしそのアカウントが存在しなくなってしまったということです)。新しいユーザーアカウントの ID は連番で作られます。復旧されたデータは最新のユーザー情報を含んでいなかったため、 5 月 8 日に新規登録したユーザーは本来よりも小さな値の ID で登録され、既存のユーザーアカウントと重複することになったのです。その結果、これらの新規ユーザーはすでに存在する他人が書いた記事を読めるようになってしまったのです。

5 月 8 日の問題が発生していた期間のうちに、 326 アカウントが正しくない account ID で作成されました。その 326 個の ID のうち、 106 個が別人によって書かれた既存の記事データに結びついていました。 2018 年の 3 月 22 日から 23 日に作成されたアカウントは他人から記事が見られる状態になっていたということです。それらは account ID 1104506 から 1104831 の人たちでした。

現在のところそれらの記事のうちどれくらいが end-to-end の暗号化処理をされていたかはわかっていませんが、 end-to-end の暗号化をしていた記事は今回の問題でも他人に見られることはありませんした。

水曜日の調査の後、元のデータベースでデータの分散処理に失敗する問題を解決することが最善の選択肢だと判断しました。いくつか設定ミスがあり、データベースの負荷が高まる原因になっていることがわかりました。この負荷が原因でデータの分散処理が失敗していました。

水曜日の午後、この問題を修正し、元のデータベースクラスターで分散処理が正しく完了することを確認しました。しかしエンジニアチームとサポートスタッフが万全の態勢で臨めるよう、 Sync サービスの再開を木曜の朝まで遅らせることにしました。山岳時間で 5 月 10 日木曜の午前 8 時、 Sync サービスは再度有効化されました。

同期サーバーには大量の待機処理があったため、それらの処理が終わるまでは少しパフォーマンスに問題があるかもしれませんが、なるべく遅延が発生しないように対処しています。

今後どうするのか?

意図せず共有されてしまった記事を削除する機能が入った Day One.app のアップデート(バージョン 2.6.4 )をすぐにリリースします(訳注:すでにリリース済みです)。このアップデートをインストールすると、未ログイン状態のユーザーの端末からは非公開の記事はすべて削除されます。対象ユーザーはアップデートのインストール後 30 日以内に Day One アカウントにログインすることが必要で、このログインをもって Day One.app はログインユーザーを記事の所有者であると認定し、記事を復元します。 Day One.app は影響を受けるユーザーに対してこの変更内容を通知します。

今後、同様の問題が起こらないように、近々以下の改修を同期サーバーに対して施します。

  1. account ID の新規作成時、すでにその ID で記事が作成されていないかをチェックします
  2. 新規の account ID に対しては、連番の数字に加えてランダム生成された二桁の数字を末尾に付加することにします。将来、同じような問題が発生して連番 ID が若返ってしまったとしても ID の衝突が起こる可能性は非常に小さくなります。
  3. いくらかのユーザーアカウントがバックアップ対象から除外されてしまう問題を修正します。

他人に記事を見られてしまった 106 人のユーザーに対しては真摯に謝罪します。対象のユーザーには終身 Premium メンバーシップを提供するとともに、その他懸念点がないか個別に連絡をとっています。今回、大規模な情報流出は起こっていません。第三者がデータベースに侵入したということもありませんし、すべてのデータは我々のサーバーで安全に保管されています。しかしながら 106 人のユーザーの我々に対する信頼は失われてしまいました。信頼は獲得するものであり、与えられるものではないということを承知していますし、再び皆さんからの信頼を取り戻せる機会を得たいと思っています。ユーザーの皆さんには 2017 年 6 月にリリースした end-to-end の暗号化機能を利用することを推奨します。この機能は今回のような事故やその他の問題があったときにもあなたの個人情報を保護します。

今回の障害で Sync サービスを利用できなかった間、辛抱して下さったユーザーの皆さんに感謝します。皆さんが Day One を使って大事な思い出を記録していることを理解しています。今後、よりよくしていくことをお約束します。信頼を回復するため、全力を尽くします。

— Paul

Day One という日記書きソフト、愛用しているのだけど今週頭に障害が発生して日本時間で 2018/05/11 の明け方まで同期ができない状態になってた。

Sync Status | Day One Help

ユーザーとして不便だったけど復旧にかなり時間がかかったのがソフトウェア開発者の一人として興味深かった。何が原因で復旧が遅れたのか推測した。

Day One のバックエンドは AWS に構築してあるようで、負荷でサーバーがダウンしたのなら EC2 インスタンスを追加してサーバー再起動すれば良いはずなのですぐ復旧できるはずと思ったが、一向に復旧しない。復旧作業の状況報告ページにしきりに “server rebalance” というフレーズが出てきており、アプリケーションサーバーで “rebalance” なんてことはやらないから、どうもデータベースがクラッシュしたようだった。

Day One のバックエンドエンジニアの採用情報見たら技術スタックが書いてあって、開発言語は Scala で DB は Couchbase を使ってるとのことだった。で、 Couchbase では Shared Cluster の rebalance という作業が必要らしい。

Couchbase は CAP 定理のうち一貫性と分断耐性を保証していて、その代わりに可用性が犠牲になっている(Couchbase Server - Wikipedia)。 Day One では複数のクライアントからほぼ同時に同一ドキュメントに対して更新が走ることが多いし、 iOS からは不安定なモバイル回線経由で接続される。かつては Dropbox や iCloud も同期のバックエンドとしてサポートしていたが、コンフリクトしたり意図せぬデータ欠落などがあったと思われ、自前のバックエンドシステムに移行したのだろう。一貫性と分断耐性に特化した Couchbase はユースケースとして最適に思えるが、障害が起こるとリバランスに手間取り復旧の難易度が上がるようだった。

自分は大規模分散データベースみたいなやつは受託の会社に勤めてた下っ端の頃にしか使ったことがなく、自分でがっつり運用・構築したことがないので大規模データベースに対する知識が足りていないと思う。大した考察は出来ていないが、今後もバックエンド API おじさんとして余生を過ごしていく上で参考になる出来事だった。そのうち詳細な post-mortem が Day One のエンジニアによって公開されるようなのでこちらもあとで読んでおきたい。

あまりに復旧が遅かったのでこのままサービス終了するのではないかと心配になったが、何とか復旧出来たようである。 Day One のバックエンドの皆さんおつさまでした 🍵

🤩人気記事を表示するようにした - portal shit! で人気の記事を表示するようにしたけど、人気のエントリー(直近一ヶ月間でアクセス数が多い記事)に加えて、ホットエントリー(はてなブックマークでブックマーク数が多い記事)も表示するようにしてみた1ところ興味深い結果になった。

スクリーンショット 2018-02-08 10.09.53.png

短期的に膨大なアクセスを集める記事と長期的に安定したアクセスを集める記事は全く異なる。はてブのようなサービスで見つけられるのは前者で、後者のような記事を見つける場所が意外にネットにはないのではないかと思う。前者を動的な人気記事だとすれば、後者は静かな人気記事だと言えるだろう。こういう静かな人気記事だけを紹介するウェブサービスがあっても面白いのかもしれない。ちなみに人気のエントリーのリンク元は Google を除くとだいたいヤフー知恵袋か 2ch の過去ログが多い。


  1. このサイトの はてブの RSS を利用しています 

ツイッター歴10年を超え、どういうウプダテスをしたらファボをもらえるかはだいたい予想がつくようになってきたけど、それよりも前からやってるブログに関してはどうやったらバズるかがわからない。 mizch さんがブログを書く前にどのくらいブックマークが付くか想像できると言ってた気がする1けどそういうのすごいと思う。「もうちょい反応あるんじゃないかな」と思った記事が全然伸びなかったり、逆に完全に自己満足のために書いた記事がバズったこともある。ツイッターもブログも商売と同じで読み手に価値を提供することができたら良い反応があるものだと思う。ツイッターに関しては面白ツイートで読み手に価値を提供できている(自分が面白いと思うものが読み手にとっても面白いと評価されている)のだろうけど、ブログでは価値を提供できていない(少なくとも狙ってはやれていない)のだろう。

短文で面白おじさんを演じるのは簡単だけど、長文だととても難しくなる。自分で自分が書いた過去の記事を読んでも「滑ってるなぁ」という感じしかしない一方で、たとえば寿司について書いた記事はいま自分で読んでも「攻めてるなぁ」と感じる。また仕事で社内ブログに記事を投稿してもそこそこ反響得られてるので文章を書く能力が著しく低いわけではないのだと思う。

つまるところ自分はブログで記事を書くときに、自分の興味関心とオーディエンスの興味関心を一致させられていないのだろう。ツイッターや社内ブログでは読み手が誰であるかを把握するのが簡単なので事前にコンテキストを共有した上で記事を書ける。コンテキストが共有されているのでどんな内容が受けるかを想像しやすいのだ。しかしブログの場合は誰が読むかは見当がつかない。パソコン関係の記事が受けるのか、日記的な雑文が受けるのか、蓄財についての記事が受けるのか、あるいはそれ以外か、全く見当がつかない。

15年前にブログが流行ったとき、ブログはテーマを絞った方がいいというアドバイスをよく目にした。思えばそれは読者の種類を絞り、読み手とコンテキストを共有することで記事を書きやすくするためだったんだろうなぁと思う。

自分はなんでもブログに書くスタンスでやってきたので今更書く内容を絞ったりはしたくないんだけど、今年は読み手とのコンテキストの共有を意識してインターネットしていきたい。


  1. ブログを書き続けること - mizchi's blog読まれるテキストは読者へのおもてなしの構造を持っている - mizchi's blog あたりで書いてたような気がするけどそんなことなかった。ツイッターでの発言かもしれない。 これだった ブログで何を書くべきか - mizchi's blog 

connpass で募集されていた勉強会に参加したところ、イベント終了後にイベント管理者から一方的にメールマガジン的なものが送られてくるようになった。勉強会直前の確認メッセージや次回の勉強会の告知ならよく他のイベントからも届くが、そうではなく主催者の私信的な内容だったのでこのようなメールは不要だった。大抵の一斉送信メールにはフッターなどに購読解除ページへのリンクなどがあるが、 connpass から届くメールにはそのような文言はなかった。

スクリーンショット 2018-01-11 21.50.31.png

最初なぜこのような私信メールが届き続けるのかわからなかったが、自分が管理者になっているイベントで確認してみたところ、管理画面からイベント参加者に任意のメッセージを一斉送信することができるようだった。 connpass はイベントに参加登録すると自動的にイベントのグループに追加されるので、グループの管理者はグループメンバーにメッセージを一斉送信する仕組みがあるようだ。勉強会に参加しただけで一方的にグループのメンバーにされてしまうのは違和感がある。

とりあえず今回はメールマガジンは受信したくないと思ったので該当のイベントページから主催者に「勉強会に参加したときにこのようなメールを送り続けるという説明はなかった、メールマガジンを受信したくない」旨の問い合わせを行い、あわせて connpass にも「勉強会参加後に定期的にメールが届くようになった、同意なしにこのようなメールを送り続けるのを規約上容認しているのか」を問い合わせた。イベント主催者の方からは即座に返信があり、今後メールが届かないようにしてもらえた。 connpass の方(運営元のビープラウド社)からは一週間後に返信があり、自分でイベント主催者とやりとりしろという旨の文章と利用規約ページへのリンクが貼ってあるのみで、自分が尋ねた規約上容認しているかどうかへの回答は書かれてなかった。

そもそも自分が情弱だったのだが、勉強会参加後に自動的に登録されるグループから退会すれば主催者からの一斉送信メールは届かなくなるようだ。自分の場合には当該グループから退会すればよかったのにイベント主催者に苦情めいた問い合わせを行ってしまい申し訳なかった。ただ退会ボタンはぱっと見 disabled されており、到底クリックできるようには見えないし、そもそも退会することでメールが届かなくなるかどうかはわからない(ヘルプページをよく読まない限り退会することで何が起こるのかわからない)。

スクリーンショット 2018-01-11 8.36.11.png

そもそもメールのみの受信設定を行えるような画面があってもよいと思うのだが、調べてみたところ新しいイベントが公開されたときや資料がアップロードされたときの通知設定は行えるが、イベント主催者からのメッセージを受け取らないようにする設定項目は存在しなかった。

スクリーンショット 2018-01-11 8.36.31.png

connpass 内全体の各グループで適用される受信設定も同様で、イベント主催者からの恣意的なメッセージを受け取るかどうかの設定項目はなかった。

スクリーンショット 2018-01-11 8.36.40.png

いらないものを拒否する手順への説明が記されておらず、自分の意図に反して送られてき続けるメールは全て迷惑メールだと思うが、運営元に問い合わせる限りはこれらは規約違反でもなくイベント管理者は自由に行えるようなので、 IT 勉強会を主催している各社の採用担当の皆さんは一度でも勉強会に参加したことがあるカモの皆さんに求人メールを定期的に送り続けてやれば良いのではないでしょうか。