死活監視ツールGodが暴走するときの対処方法
結論
DelayedJobのような長時間実行するプロセスに対するGod設定にはgrace
を設定しましょう。
God.watch do |w| ... w.grace = 5.seconds ... end
Godとは
Godとはプロセスの死活監視ツールの一つです。プロセスが死ねば再び命を与え、プロセスがコンピューティングリソースを浪費するような悪さをすれば罰を与えるという、まさに『神』の如きツールです。
Rubyで作られたツールであり、設定ファイルもRubyによるDSLを用いて柔軟に構成することができます。 下記は、いろいろなサイトで紹介されているよくある設定です。
RAILS_ROOT = "/path/to/rails_root" RAILS_ENV = "production" 3.times do |num| God.watch do |w| w.name = "DelayedJob-#{num}" w.pid_file = "#{RAILS_ROOT}/tmp/pids/delayed_job.#{num}.pid" w.start = "cd #{RAILS_ROOT} && script/delayed_job --environment=#{RAILS_ENV} --identifier=#{num} start" w.restart = "kill -TERM `cat #{RAILS_ROOT}/tmp/pids/delayed_job.#{num}.pid`" w.stop = "cd #{RAILS_ROOT} && script/delayed_job --environment=#{RAILS_ENV} --identifier=#{num} stop" w.log = File.join(RAILS_ROOT, "log/god_delayed_monitor.#{num}.log") w.behavior(:clean_pid_file) w.start_if do |start| start.condition(:process_running) do |c| c.interval = 5.seconds c.running = false end end w.restart_if do |restart| restart.condition(:memory_usage) do |c| c.above = 500.megabytes c.interval = 10.seconds end end end end
この設定によって以下のような挙動となります。
- DelayedJobプロセスを3つ稼働させる
- 5秒ごとにプロセスの存在をチェックし、存在していなければ起動させる
- 10秒ごとにプロセスの物理メモリ使用量をチェックし500MBを超過したら再起動させる
- 再起動には
kill
を使いプロセスにTERMシグナルを送信する
- 再起動には
こまりごと
前述の設定で死活監視としてはきちんと動作します。しかし、監視対象がDelayedJobの場合に困った事象が発生します。
DelayedJobはTERMシグナルを受け取ったときにジョブ実行中の場合、割り込み処理で内部のフラグを立てたのち元のジョブ処理に戻ります。そしてジョブ実行が完了した後にプロセスを終了するという、gracefulな終了をしてくれます。
一方Godは、監視対象プロセスがメモリ超過したことを検知し、TERMシグナルを送信しますが、DelayedJobプロセスはすぐには死なない。なので再びTERMシグナルを送信します。が、やっぱり死なない... このときのGodの挙動がヒドイ。鬼神の如くこれでもかってくらい殺しにかかる。
2015-09-18T18:40:15+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... 2015-09-18T18:40:15+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... 2015-09-18T18:40:15+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... 2015-09-18T18:40:15+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... 2015-09-18T18:40:15+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... 2015-09-18T18:40:15+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... 2015-09-18T18:40:15+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... 2015-09-18T18:40:15+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... 2015-09-18T18:40:15+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... 2015-09-18T18:40:15+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... 2015-09-18T18:40:15+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... 2015-09-18T18:40:15+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... 2015-09-18T18:40:16+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... 2015-09-18T18:40:16+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... 2015-09-18T18:40:16+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... 2015-09-18T18:40:16+0900: [Worker(delayed_job.1 host:BG.EXAMPLE.COM pid:31039)] Exiting... ...
その数、1秒間に約12回。TERMシグナルを送るためにbashプロセスとkillプロセスがそれぞれ生成されるし、シグナル受け取った側はその度に割り込み処理と復帰処理が発生。ジョブが1時間くらいかかるものだった場合、その間ずっとこれらの処理が繰り返されます。おかげで、サーバーのCPU負荷が上がりまくり。
我々は神の怒りをかってしまった。この世に救いはないのか...
神の怒りを沈める方法
Godのソース(ver. 0.13.6)を眺めていたら下記の記述がありました。
def action(a, c = nil) ... case a when :start call_action(c, :start) sleep(self.start_grace + self.grace) # ← ん? when :restart if self.restart call_action(c, :restart) else action(:stop, c) action(:start, c) end sleep(self.restart_grace + self.grace) # ← んん!? when :stop call_action(c, :stop) sleep(self.stop_grace + self.grace) # ← おおぉぉ!!!? end self end
(ノ゚ρ゚)ノ ォォォ・・ォ・・ォ・・・・ 神は我らに慈悲を与え給うた...
Godのwatch
ブロックにはgrace
およびstart_grace
, restart_grace
, stop_grace
が用意されていました。これを設定すると再起動等のアクションが実行された後、通常の監視状態に戻る前に指定時間だけsleepしてくれます。
God.watch do |w| ... w.grace = 5.seconds ... end
この設定をいれることによって、穏やかに再起動が実行されるようになりました。めでたし。
まとめ
GodでDelayedJobを監視したときに再起動処理が短時間に何度も繰り返される挙動を緩和する方法を紹介しました。
余談ですが、死活監視にGodというメタファーを用い、ウェイト時間にgrace(慈悲、寵愛)という名前を付けるセンスが羨ましい...
UMLでRailsモデリング
ひとりでシステム構築しているなら不要かもしれませんが、チームで活動し、ある程度の規模のシステムを構築/改修する場合は、いきなり実装するのではなくモデリングをしましょう!
モデリングの手段はたくさんありますが、統一記法であるUMLに従うのがいろいろメリットを享受できてよいかと思います。特に下記のメリットが重要です。
- 視覚的な表現によって構造・振る舞いを直感的に把握できる
- 開発に関わるメンバ全員が共通の言語でコミュニケーションできる
本記事ではRailsシステムをUMLでモデリングする際の表現方法を紹介します。想定する読者は、上位者の指示の下Railsシステムの構築/改修をすることができ、今後ステップアップとして実装設計とか構造設計と呼ばれるフェーズを独力で実施できることを望むような人(およびその上位者)です。これによって少しでも多くの人が実装設計できるようになることを願います。
なお、モデリングツールとしては「astah* community」がオススメです。無償で使えて基本的なモデリング作業はほとんどできてしまう。しかも商用利用OK! (ただし、ver. 7.0からは商用利用できなくなってしまいました...) モデリングツールをまだインストールしていない人はぜひ入れておきましょう。
astah* community - 無償UMLモデリングツール | Astah
サンプルシステム
本記事で例示するシステムは下記のユースケースを想定したものとします。
構造設計
モデルの表現
RailsのモデルはO/Rマッピングなので、クラス図と特に相性がよいです。 コードと1対1で完全に一致するような正確性よりも、関係者間で共通の認識を持てることが重要です。そのため部分的に表現を省略することで、読み手に注目してもらいたい箇所が際立つようにします。機能改修テーマであれば、変更のある属性やメソッドだけを記載するといった工夫をすると良いと思います。
属性の表現
クラス図ではクラスの属性とメソッドを表現できます。これを使ってモデルを表現します。
id
やcreated_at
、updated_at
といった属性は大抵のモデルには存在しますが、煩雑になりますのでいちいち記述しないようにします。また、ActiveRecordの機能で属性に対するセッター/ゲッターは自動的に作成されますが、これも煩雑になりますので記述しないようにします。(属性をpublicにすることで表現してもいいのですが、毎度可視性を変更するのは面倒臭いのでやらないほうがいいでしょう。)
マイグレーションファイルにすると以下のようになります。
class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :login t.string :email t.string :hashed_password t.string :password_salt t.datetime :activated_at t.boolean :enabled, null: false, default: true t.timestamps end end end
なお、Datetime
型やText
型などRubyやRailsでは標準で存在するけどモデリングツールにはデフォルトで存在しないようなクラスは、ruby
パッケージを作成してそこに突っ込んでおくとよいです。
スコープの表現
モデルのスコープは静的メソッドにステレオタイプを付けて表現します。
上図のようにクラス図では、静的メソッドは下線付き、ステレオタイプは<< >>
で表現します。
STIの表現
STI(Single Table Inheritance: 単一テーブル継承)はクラスの継承線にステレオタイプを付けて表現します。
type
カラムに具象クラス名を入れておくことで、インスタンスを取り出した時にActiveRecordが自動的にそのクラスのインスタンスに変換してくれます。
もうちょっと細かいSTIの話は下記のサイトを参照ください。 【Rails】ActiveRecord:単一テーブル継承(sti)とポリモーフィック関連を未だにぱっと思い出せないのでまとめ。 - 記すに足らず。
継承線に<<STI>>
というステレオタイプを付けることで表していますので、type
カラムはクラス中に記載しなくてもよいのですが、「typeカラムに具象クラス名が入っているのでここはこのインスタンスになるんです〜」というSTIの説明を何度もすることがあるため、私はいつも記載するようにしています。関係者がSTIをしっかり理解してくれているならtype
カラムは省略してもよいのではないでしょうか。
class CreateImages < ActiveRecord::Migration def change create_table :images do |t| t.string :type t.integer :width t.integer :height t.binary :data t.timestamps end end end class Image < ActiveRecord::Base end class Avator < Image end class Photo < Image end
has_one関連の表現
has_one関連はクラス間の集約を用いて表現します。白抜きひし形が付いている方が所有する側、線の繋がる先が所有される側になります。
上記の例の場合、所有される側のUserAttribute
にuser_id
カラムが必要ですが、関連線があることで自ずと必要なことがわかりますので記載を省略します。
class CreateUserAttributes < ActiveRecord::Migration def change create_table :user_attributes do |t| t.integer :user_id t.string :title t.string :zip_code t.string :address t.string :phone_number t.string :url t.timestamps end end end class User < ActiveRecord::Base has_one :user_attribute end class UserAttribute < ActiveRecord::Base belongs_to :user end
has_many関連の表現
has_many関連はクラス間の集約に多重度を付けて表現します。
has_one関連のときと同様にArticle
側のuser_id
カラムは省略します。
class CreateArticles < ActiveRecord::Migration def change create_table :articles do |t| t.integer :user_id t.string :title t.text :content t.timestamps end end end class User < ActiveRecord::Base has_many :articles end class Article < ActiveRecord::Base belongs_to :user end
polymorphic関連の表現
polymorphic関連は、集約線にロール名をつけることで表現します。
上記の例ではSTIと組み合わせてあるのでちょっと複雑になっていますが、Imageモデルの所有者にowner
というロール名を付けています。Imageモデルにはowner_type
とowner_id
カラムを記載していますが、polymorphic関連であることを関係者が認識してくれるなら記載を省略してもよいでしょう。
polymorphic関連についてもうちょっと細かい話は下記のサイトを参照ください。 【Rails】ActiveRecord:単一テーブル継承(sti)とポリモーフィック関連を未だにぱっと思い出せないのでまとめ。 - 記すに足らず。
class AddOwnerToImages < ActiveRecord::Migration def change add_column :images, :owner_type, :string add_column :images, :owner_id, :integer end end class User < ActiveRecord::Base has_one :avator, as: :owner end class Article < ActiveRecord::Base has_many :photos, as: :owner end class Image < ActiveRecord::Base belongs_to :owner, polymorphic: true end
ネームスペースの表現
ネームスペースはパッケージを使用して表現します。
class Image::Avator < Image end class Image::Photo < Image end
Mix-inの表現
モジュールのMix-inは依存関係を用いて表現します。
Mix-inされるモジュールにはモジュールであることを示すためにステレオタイプで<<module>>
を記載します。そしてMix-inする側からされる側へ、<<include>>
ステレオタイプ付きの依存関係を引いて表現します。
class User < ActiveRecord::Base include User::Exportable end module User::Exportable extend ActiveSupport::Concern module ClassMethods def export ... end end def to_csv ... end end
コントローラの表現
コントローラの構造をクラス図で表現することはできますが、コントローラに複雑な構造を持たせることもあまりないでしょうから、わざわざ図に起こすまでもないかも。ここでは、もし可視化したい要求があった場合の書き方を示します。
アクションの表現
アクションはシンプルにクラスのpubicメソッドとして表現します。
strong parameter用のメソッドなどのアクションから呼ばれるメソッドたちは可視性をprivate(もしくはprotected)にしたメソッドで表現します。
フィルターの表現
コントローラのフィルター機能はステレオタイプ付きprivateメソッドで表現します。
完成図
以上を踏まえて作成したクラス図が下記になります。
(...うーん、配置にセンスがないなぁ。)
振る舞い設計
システムの振る舞いはシーケンス図などを利用して表現します。
アクションの表現
DelayedJobやsidekiqなどを用いた非同期処理を含む場合も上図のようにシーケンス図内に記載することができます。
まとめ
本記事ではRailsシステムをUMLでモデリングする際の表現方法を紹介しました。特に(Rails的な意味の)モデルの構造やモデル間の関係を表現する際に役立つのではないでしょうか。
ソースコードで語り合う前に(UML的な意味の)モデルを使ってチームメンバ間で会話してみましょう。より早く問題点を見つけられるかもしれませんし、その後のコーディングがより速くなると思います。 お試しあれ。
GitHubから人間失格の烙印をもらってしまった
事件発生
別記事を書くために初めてGistを使ってみたのですが、それの影響でGitHub上に下記のような警告が表示されるようになってしまいました。
One of our mostly harmless robots seems to think you are not a human.
オメーは人間じゃねーな!!? (意訳)
いやいやいやいや、めっちゃ人間ですって。あいむ あ ひゅーまんびーいんぐ。
おかげで先の記事に貼り付けたGistが自分では見れているけど、別ユーザーからは404 not found状態で表示されないという状態になってしまいました。
対処
please contact support
とあったのでサポートページからメールを送信しました。
Subject: I'm a human!!! I got a message as : "One of our mostly harmless robots seems to think you are not a human." No! I'm a human. What should I do next?
ちょー簡単な内容ですが、人間っぽさが感じられる内容ならなんでもいいらしいです。
復活
サポートに連絡を入れてから待つこと約5時間。GitHubから返信がありました。
Hello there,
I'm sorry about our misbehaving robots - they do a good job but can be a bit overzealous at times. I've just unflagged your account and made your profile public again, you are all set!
うちのボットが迷惑かけたね、ごめんごめん。彼らはいい仕事するんだけどたまにやり過ぎちゃうんよ。とりま、フラグ外しといたんでこれで勘弁して。 (意訳)
メール受信後にGitHubを確認したら無事に警告が削除されており、Gistも表示されるようになりました。
めでたし。
MySQLのダンプファイルをテーブル毎に分割する
1から学ぶクラウドのセキュリティ勉強会
- 日時: 2014/08/23 13:00〜18:00
- 場所: fabbit (北九州市小倉)
- 参加者: 20名程度
所感
JAWS-UGの勉強会への初めての参加であり、どんな情報が得られるのか全くわからず参加しましたが、行ってみてよかったと思います。 サーバー証明書には3種類あるんですとか、MicrosoftのSHA1排除ポリシーとか、AWSの共有責任モデルという考え方とか、このWebシステム業界としては(特にインフラエンジニアとしては)知っていないといけないことを、今まで知らなかったことに気付かされました。
今回のはちょうど私の関心事に合致したテーマではありましたが、今後も同様の勉強会があれば参加したいと思います。
高まる「認証」の必要性~SSLサーバー証明書の基礎、最近の話題~
講師: サイバートラスト 坂本氏
サーバー証明書の用途:
- 昔は暗号化
- 最近はサイト証明
なぜ? → フィッシング詐欺などが多発
- 2013年上期: 4,500件
- 2013年下期: x,xxx件
- 2014年上期: 18,000件
コンシューマーが危惧すること
- 1位: フィッシング詐欺
- フィッシャーの技術が上がっており、一見しては真偽を見極められない。
- 昔はウチのサイトを真似ることはできないから大丈夫.. という意見もあった。
- 玄人ならカギマークをクリックして証明書を確認するかもしれんけど、エンドユーザーは..?
- フィッシャーの技術が上がっており、一見しては真偽を見極められない。
求められるのはEVサーバー証明書
- EVだけがわかりやすく「安全」をアピール
- EVは規格の名称
- DV: 安い。フィッシャーも簡単に取得できてしまう。
- 「『緑』でなければ警戒して」という活用例は既にはじまっている。
- 各ブラウザがURL入力欄を緑色で表示するように対応し始めている。
証明書3種類
- DV: Domain Validation
- 暗号化: OK, 企業認証: NG
- OV: Organization Validarion
- 暗号化: OK, 企業認証: OK
- 最初に出始めたサーバー証明書はこれ。
- EV: Extended Validation
- 暗号化: OK, 企業認証: OK(厳格な証明)
サイバートラストのメリット
- モバイルの対応が強い
- 発行スピードが速い
- メール、電話、チャット、リモートデスクトップでのサポート完備
- OVなら30分で発行。他社なら3時間とか1日。
- EVなら1日
Microsoft SHA1 Deprecation Policy
- https://www.cybertrust.ne.jp/ssl/sureserver/sha1ms.html
- 「売るな」「使うな」に関する規制
- MS製品上のみで実行される規制
- SSLとコード署名証明書に対してのみ適用
- 2010年問題
- 業界ルールとして1024bitの暗号化はNGに。
- 同じことがハッシュアルゴリズムにもこれから発生する。
- Microsoftの指針
- サイバートラストでは
- SHA1からSHA2へのアップグレードは無償
- 2017/1/1以降も有効な証明書も提供可能。
- 他社ではできないといわれることも。
- MSと関係ないサービスを提供している顧客のために。
- 予算組んでないよという顧客のために。
- ガラケーの多くがSHA-2証明書に非対応
利用者責任範囲におけるセキュリティ実装の方法について~ユースケースから考えてみる~
講師: トレンドマイクロ 南原氏
- 創業者は外国人だけど、日本で起業した国内のベンダー
クラウドのセキュリティ
- 情報漏洩などのセキュリティが心配...
- AWSのセキュリティの考え方 - 共有責任モデル
どうやって利用者責任範囲を守るか
- piyolog
- セキュリティインシデントを毎日まとめてくれているサイト
- http://d.hatena.ne.jp/Kango/archive
- 攻撃タイプ
- 正面から突破系(外部公開Webへのアタック)
- 中から攻め上がってくるタイプ(メールなどでクライアント感染。そこから...)
必要な対策は
- 防ぐというよりは、いかに早く気づくか
- 総合対策を。
トレンドマイクロの商品
- Trend Micro Deep Security
- http://www.trendmicro.co.jp/jp/business/products/tmds/
- インスタンスごとに対応が可能な「ホスト型」
- httpリクエストを監視
- ...
- 5%程度のスループット低下
- クックパッドさんで、500msecのリクエスト応答要求にも、調整次第で対応できた
- エージェント型のシステム要件は512MB以上。
- エージェント型の使用メモリはだいたい200MB。リクエスト数などには変動せずだいたい200MB前後で推移。
- AutoScaling対応。契約台数の2倍までは利用OKなライセンス/料金体系。
- 年間契約タイプ
クラウド環境で利用されるWebアプリケーションファイアウォール
講師: セキュアスカイ・テクノロジー 前平氏
なにを守るか?
- 個人情報。重要情報
- サイトの信頼性
- ユーザーが攻撃者になるかも
- サーバーが攻撃に利用されるかも
- → 情報も持っていなくても、リスクがある。
攻防
- [攻撃者] アカウントリストを元にIDアタック開始
- [管理者] 同一IPからの認証NGが多いため、そのIPを遮断
- [攻撃者] IP遮断されたことを関知して、プロキシを変えて攻撃続行
- [管理者] 認証NGが閾値(30件)を超えたら遮断
- [攻撃者] 閾値を超えないように調整(29件まで)して攻撃を続行
AWSが取得している第三社認証について
講師: サーバーワークス 小室氏
- HIPAA
- USの医療関係情報を扱ってもいいよという規定
- SOC 1/SSAE 16/ISAE 3402
- 委託会社の財務諸表に関するリスクに対して財務諸表監査
- SOC 2
- (委託会社の)可用性、気密性、セキュリティ、プライバシー、完全性をリスクとし、コンプライアンスまたはオペレーションに関する内部統制の報告
- SOC 3
- SOC2をより簡単に一般化・要約したもの
- PCI DSS レベル1
- クレジットカード情報を保管、処理、送信を行える認証
- レベル1: 30万件以上/年
- レベル2: 30万件未満/年
- クレジットカード情報を保管、処理、送信を行える認証
- ISO 270001
- 情報セキュリティに関する標準規格
- 情報の気密性、完全性、可用性の3つを管理、運用する
- FedRAMP (SM)
- 日本にはあんまり関係ない
- US政府がクラウドを使ってもOKと太鼓判おしたもの
- DIACAPおよびFISMA
- 連邦政府が外部委託先に対して決めた、セキュリティ規定
- ITAR
- 日本にはあんまり関係ない
- 武器国際取引に関する規則
- 武器や暗号化方式、飛行機の設計図などを輸出入してもOK
- FIPS 140-2
- 暗号化をどうやって保つか、セキュリティ要件の私用を規定するUSれんぽう標準規定
- CSA
- Cloud Security Alliance
- クラウドプロバイダ内でのセキュリティ業務の透明性を推進し、セキュリティ管理作業を文書化する
- MAPP
- US映画協会
- メティアやコンテンツを安全に保存、処理、配信するための一連のベストプラクティスに準拠しているよ。というもの
AWSに組み込まれてるセキュリティ機能の紹介
講師: ハウインターナショナル 安土氏
セキュリティグループ
- 論理的に分離した仮想ネットワークを構築
- よくある構成
IAM
- AWSサービスにアクセス可能なここのユーザーを作成
- ユーザー個別にセキュリティ認証情報(パスワード、アクセスキー、MFA)を設定
- 各AWSサービスへの権限設定
- ユーザーの集合に対して権限設定できるグループ
- IAM Role for EC2 Instance
- MFAデバイス
- ワンタイムパスワード生成デバイス
S3ストレージの暗号化
Trusted Advisor
- 最近無料化された!
- 特定のポートに対して無制限アクセスを許可していないか?
- ルートアカウントでMFAが無効でないか?
- EC2のEBSが80%を超えていないか?
- ...