kariaの日記 @ Alice::Diary

ノリツッコミの鳩子がはてなブログ書いちゃうよ

メンテナンス作業の手順書をつくるときの考え方

最近システムメンテナンスの手順書の作り方的な記事をちょこちょこ見かけるなーと思って、以前書きかけのものがあったので、ちょっと便乗してみようかなと。

papix.hatenablog.com

blog.tkuchiki.net

といっても自分流の「作り方」を書き出すと途方も無い長文記事になってしまうので、メンテナンス作業をやっていくぞ!手順書作るぞ!となったときに根底にある考え方を書き出してみます。

監視の通知を止めるか止めないか

大抵の商用のシステムには何らかの形で監視が入っているかと思います。メンテナンス作業の間はサービスが通常と異なる状態となるため(例えば通常はHTTPステータスコード200が返ってくるところ503が返ってくるとかね)、大抵はアラートが発生します。作業してもアラートなんて出ないよという場合は、その監視は見直した方が良いかと思います。

作業影響アラートをどう扱うかには2つの選択肢があります。

  • 抑止する:あらかじめアラートが出ない(もしくはアラートを検知しても通知しない)ように抑止しておく
  • 無視する:メンテナンスの間はアラートが出てもスルーする

どちらを採用するかはケースバイケース、システムや組織やアラート対応の枠組み*1により異なりますが、基本的には抑止する方向に倒すのではないかと思います。

わかりやすくMackerelを例に取って挙げると「ミュート」という機能がありますね。ミュートをONにしておけば、Mackerel上ではアラート発生扱いにはなるものの、Slackやメールなどの通知はされません。また、PagerDutyやTwillioもしくは人力でアラートが電話通知される枠組みになっている場合、メンテナンス期間中のアラートを抑止しておかないと業務に支障が出るレベルで電話が鳴ってしまう恐れもあります。

ただ、アラート抑止で最も恐ろしいのは「抑止の解除をし忘れる」ことです。メンテナンスが終わったあとに抑止の解除をし忘れると、本当に障害が発生したとき必要な通知が来なくなってしまいます。こんなに恐ろしいことはありませんね。ええ、恐ろしい……。

解除漏れを防ぐために考えられる方法は以下の3つ。一つ一つ見ていきましょう。

アラートの抑止をしない(静観する)

「そもそも抑止をしなければいいんだ!」という考え方。アラートの通知がメールやSlackで流れてくるだけなのであれば、メンテナンス期間中のアラートは無視すればよい、というのも一つの考え方でしょう。

これを「静観」という言い方をします。人力での監視が絡む場合は「●●時からメンテナンスのため、アラートの静観をお願いします」という依頼を出すこともあります。

抑止を時間指定にする

メンテナンス作業は通常は予定時間が決まっていますから、監視の抑止をする際にあらかじめ「●●時から××時まで抑止する」「今から90分間は抑止する」という時限設定を入れておけばアラート抑止の解除漏れがなくなります。Mackerelにも時間指定ミュート機能ありますよね(今年2月に実装されて超助かってます)。

mackerel.io

人間忘れっぽい生き物ですから、監視システムにできることは監視システムにやってもらいましょう。

手順書を上下対称で書く

どうしてもアラート通知を抑止したいけど、Mackerelは使ってないし時間指定ミュートを入れることは出来ない、でもメンテナンスはもう明日……そんなとき、初めて手順書の書き方が肝になってきます。

手順書を書く時は「上下対称になっているかどうか」を意識しながら書きます。上下対称とは?と思われるかと思いますが、例えば

  • 「メンテナンスモードにする」という手順があるなら、終了時に「メンテナンスモードを解除する」という手順が必要
  • 「監視を抑止する」という手順があるなら、終了時に「抑止を解除する」という手順が必要

といった風に上下対称にすることを意識して書くと、手順書の漏れを少なくすることが出来ます。

これって、監視の話に限らず手順書に書かれるであろう作業全てに言えることだと思うんです。たとえば、データベースのダンプを取るのであればリストアできるかどうかを考える*2ロードバランサーから切り離すのであれば、元通りに組み込めるのかどうかを考える。対称にならない作業って無いはずなんですよね。対称に作業するかどうかは別として、対称に出来る作業なのかどうかを考えるのが、漏れや事故を無くす一つのコツなのではないかと思います。

予定時間と実績時間を書く

個人的にはあんまりGitHub Issueに手順書作るのって馴染みなくて、スプレッドシートに書くことが多いです。何故かというと、作業項目ごとに時間を入れる欄が欲しいんですよね。それも「開始」「終了」と「予定」「実績」で合わせて4つ。

何故かというと、現在の進捗が知りたいわけです。オンスケで進んでるのかどうかが知りたい。たとえば、

開始時刻(予定) 終了時刻(予定) 開始時刻(実績) 終了時刻(実績)
00:00 00:30 00:00 00:20
00:30 01:00 00:20

となっていたら、30分で見積もっていた作業が20分で終わったことがわかります。素晴らしいですね。

開始時刻(予定) 終了時刻(予定) 開始時刻(実績) 終了時刻(実績)
00:00 00:30 00:00 00:50
00:30 01:00 00:50

となっていたら、20分遅れで進んでいることがわかります。何があったんでしょうね。

このように、実績を入れる欄を作ることで単純に作業の進み具合がわかるわけです。予定よりも早く進む分には、後半の作業のバッファが生まれるし、メンテナンスを予定より早く終わらせられるかもしれない。予定より遅れているなら、後半のバッファで吸収できるのかどうか、作業を中止するかどうかも検討しなくてはらない。時間を意識せずにメンテナンス作業を進めること無いですよね?ってことです。

実績を書くことによるもう一つの利点は、次回の作業に活用できることです。次回また同じ作業をするかどうかわからない時こそ実績を書いておくのは大事で、実際のところ同じメンテナンス作業をするのは数ヶ月単位だったり年単位だったりすることはあるわけです。繰り返しますが人間は忘れっぽい生き物なので、数ヶ月前のことなんて覚えてません。そんなときに、過去の作業で記録しておいた実績値を見れば「この作業だったら●●時間程度で終わる」とパッと分かるわけです。

でも別にスプレッドシートにコダワリがあるわけではないのでMarkdownでその辺うまく表現できるならそれでもいいかなー。

本当にこのメンテナンス必要?

ここまで長ったらしく書いてきましたが、全部ひっくり返す事を言うと「メンテナンスによるサービス停止なんて無い方がいい」に決まってるわけです。皆さんも、一般の利用者として使っているサービスがメンテナンスしているところに遭遇したら困りますよね。なので、手順書を作りながらも「本当にこの作業必要?」「もっと停止時間短くできない?」という自分との対話が続くことになります。

たとえば2つの作業を同時に進めることで、合計3時間かかる作業が1.5時間になるとか、単純に並列化するだけで時間を短縮できませんか?「プロセスを停止する」という作業のところにkillコマンドそのものを載せておけば、文字通り秒殺できるのではないですか?メンテナンスモードに入る前に済ませておける作業はありませんか?いろんな時間短縮の工夫を考えましょう。

もっとも、その短縮の工夫が裏目に出てしまうことがないとも限りません。確実に予定したメンテナンス枠内で終わらせられるように工夫した方が、何度もメンテナンスをやり直さずに済む結果につながるケースもあるでしょうね。

結局長くなってしまった。とりとめもなくおしまい。

入門 監視 ―モダンなモニタリングのためのデザインパターン

入門 監視 ―モダンなモニタリングのためのデザインパターン

*1:例えばアラート毎に自動でチケットが起票されるような場合は、アラートが大量に出るとチケットも大量に作られて業務に支障が出るので、作業影響アラートが大量チケット起票につながらないようにうまく調整する必要がありますよね。

*2:単にバックアップとしてダンプを取る場合、その作業内ではそのダンプをリストアする事は無いかもしれません。でも、バックアップということは万一の事態が起きたらリストアしますよね、作業する前にちゃんとそのやり方抑えてますか?というお話です。

個人的によく使う主要チェーン店における2018年12月の電子マネー・コード払い・ポイントの還元率まとめ

最近流行りのコード払いで期間限定キャンペーンが増えすぎてわけわかんなくなってるので、支払方法の選択肢が多くて個人的に使いそうなチェーン店での還元率をざっとまとめ。

この記事に記載されている内容については誤りがあっても筆者は責任を負いません。またキャンペーンの内容や還元率は変更される場合があります。 ご自身でよくお確かめになってからご利用ください。

※2018/12/14追記:PayPayの「100億円あげちゃうキャンペーン」は既に終了しています。ご注意ください。

比較条件

比較時の条件は以下の通り。

  • 期間
    • 2018年12月4日9:00~2019年1月6日23:59まで
  • 各コード払いにおける残高とクレジットカードの扱い
    • LINE Payコード払い
      • 残高・ポイントでの支払のみ(LINEサービス以外で直接クレジットカードを利用することが出来ない)
    • d払い(街のお店)
      • 直接的には残高という概念が無く、電話料金合算か登録クレジットカードのどちらかを事前に選択する
      • dポイント・ドコモ口座残高は、コード表示画面で使用するかどうかを選択できる(dポイントとドコモ口座のどちらか片方のみ、併用できない模様)
    • PayPay
      • PayPay残高が不足したらYahoo!マネー残高を併用、どちらも足りなければ全額登録クレジットカードから支払い、の順序で自動適用
  • 各キャンペーンについて
    • dポイントの「×20倍」表記は、「魔法のスーパーチャンス!」エントリー済かつ買い回り15倍を達成済みの場合。通常の付与ポイント含む。ポイントで支払った分には適用されない。2019年1月6日まで。
    • PayPay 100億円あげちゃうキャンペーンは2019年3月31日まで。100億円に達した場合、終了する可能性がある。どの支払方法でも適用(PayPayボーナスでの支払分にも適用)されるように読める。
    • LINE Payコード払い促進プログラムは2019年7月31日まで。文面を読む限りはおそらくポイントで支払った分には適用されない。

もうここまでで頭痛くなってきた……。とりあえず3店舗だけ。

店舗別

ファミリーマート

  • PayPay:20.5%+α
  • d払い:10.5%+α
    • Tポイントカード0.5%+dポイント(d払い時に付与)0.5%×20倍(+支払方法に登録したクレジットカードのポイント)
  • LINE Payコード払い:4~5.5%
    • Tポイントカード0.5%+LINE Payマイカラー基本ポイント0.5%~2%+LINE Payコード払い促進プログラム3%

いきなり厄介すぎる例。現状の予定ではスーパーチャンス→PayPay→LINE Payコード払いの順にキャンペーンが終わるはずなので、この還元率だとPayPayのキャンペーンが終わったら次はLINE Payコード払いかな。相当高還元率のカードを使わない限りd払いの出番なさそう。あと、Tポイントと他の施策が本当に両方付与されるのかどうかは始まってみないとわからない(この記事を書いているのは2018年12月3日です)。

service.smt.docomo.ne.jp

さらに事態をややこしくしているのは12/10 23:59までd払いでスーパーチャンスとは別キャンペーンが行われること。とはいえそれでもPayPayより還元率低いというね。本当に厄介。

ローソン

dカード決済(iD利用時含む、但しdポイントカードの提示が別途必要) or dポイントカード提示+LINE Payコード払い時の2択。

ここで登場するのが「d払い」ではなく「dカード決済」であることに注意(別物です)。d払いの支払方法をdカードにしてもdカード決済扱いにはならないんじゃなかろうか。誰か聞いてみて。

基本的には恒久的に行われているdカード決済3% CBが大きいのでそれに頼れば良いのですが、LINE Payコード払い促進プログラムが行われている期間中は(特にマイカラーが高ランクなのであれば)LINE Payでも良いのではないでしょうか。dカード持ってるとは限らないし。

くすりの福太郎ツルハドラッググループ)

ここが厄介なのはポイントサービスデーがあって、日によって10%になるんですよね。しかも楽天ポイントとの重複付与、dポイント非対応だけどd払い対応。よく対応できるよねコレ。

  • d払い:11.5~20.5%+α
    • 福太郎ポイントカード1~10%+楽天ポイントカード0.5%+dポイント(d払い時に付与)0.5%×20倍(+支払方法に登録したクレジットカードのポイント)
  • LINE Payコード払い:5%~15.5%+α
    • 福太郎ポイントカード1~10%+楽天ポイントカード0.5%+LINE Payマイカラー基本ポイント0.5%~2%+LINE Payコード払い促進プログラム3%

※お酒など「ポイントサービスデー」対象外の品目が存在することに注意

ポイントサービスデー10%の日を狙ってd払いすればトータルで20%越えが可能。

まとめ

まとまらないので各自好きなように払って。

Faradayを使うときの「デフォルトの」タイムアウト値

RubyのFaraday gem使ってるときにタイムアウト値を明示的に指定しなかった場合にどうなるかというお話。

これ、すごい頻繁にハマってる気がするのでメモする。なぜハマるかというと「タイムアウト値を指定した場合にどういう挙動になるのか?」という考えになかなか辿り着かないからですね。発想力が貧困である。

さっそく該当部分を見てみましょう。

github.com

なるほどAdapterに渡してるだけ。じゃあデフォルトのAdapterであるところのNet::HTTPのデフォルト値はどうなのか(AdapterがNet::HTTPでない場合は各自で調べてください)。

docs.ruby-lang.org

docs.ruby-lang.org

open_timeout、read_timeoutともに(Ruby2.5の時点では)デフォルト60秒とのこと。ということは極端な話、接続が確立するまでに59秒かかって更にreadに59秒かかったのでトータルで120秒近くかかっちゃいました、みたいなケースも一応あり得る。どんなケースだよと書いてて思いましたが、なくはない。ダイヤルアップか何かですかね。

Faradayのoptionに timeout: 5 だけを指定するとどうなるかというと、Net::HTTPに渡すopen_timeoutとread_timeoutが(後述するように指定できる場合はwrite_timeoutも)それぞれ5秒に設定される。リクエスト全体のタイムアウト値が5秒に設定できるかのように早とちりしそうだけどそんなものは存在しないので(そもそもリクエスト全体とはどこからどこまで?という話だ)、ある程度一括で揃えることが出来るだけと理解したほうがよさそうだ。

ここでFaradayのPull Requestを見て初めて知ったけど、Ruby2.6でNet::HTTPにwrite_timeoutが追加されるのね。

techracho.bpsinc.jp

確かに「bodyがむちゃくちゃデカくて全然送信し終わらないんで止めさせてくれ」みたいなケースはあり得るか。あとは、逆に「Ruby2.6に上げたら外部へのPOSTリクエストがxx秒で落ちちゃうんですが何コレ」なんてこともありそう。平成も終わるしRuby2.5も終わらせるか、などとお考えの未来の皆さんはがんばってください。

※タイトル修正しました(11/27)