世界は完璧ではない

画像

世界は完璧ではありません。 いつでも、何かがうまくいかないことがあります。 幸いなことに、私たちのほとんどはロケットを宇宙に打ち上げたり、航空機を建造したりしません。



現代人は携帯電話のアプリケーションに依存しており、私たちの仕事は、どんな状況でもいつでもアプリケーションを開いて猫と一緒に写真を見ることができるようにすることです。



人々は完璧ではありません。 私たちは常にミスを犯します。 私たちはタイプミスをします。何かを忘れたり怠lazに屈したりします。 人はうねりを増したり、車の下に乗ることができます。



鉄は完璧ではありません。 ハードドライブが死にかけています。 データセンターはチャネルを失います。 プロセッサが過熱し、電気ネットワークが故障します。



ソフトウェアは完璧ではありません。 メモリが流れています。 接続が破れています。 レプリカが破損し、データが忘却されます。



たわごとが起こる-私たちの海外の友人が言うように。 これらすべてで何ができるでしょうか? そして、答えは単純さに平凡です-何も。 常にテストし、大量の環境を作成し、本番環境をコピーして10万台のバックアップサーバーを保持することはできますが、それでも節約できません。世界は完璧ではありません。



ここでの唯一の正しい決定は、合意することです。 世界をそのまま受け入れ、損失を最小限に抑える必要があります。 新しいサービスを設定するたびに、覚えておく必要があります-それは最も不適切な瞬間に壊れます。



それは間違いなく壊れます。 あなたは間違いを犯します。 鉄は必ず失敗します。 クラスターは確実に崩れます。 そして、この不完全な世界の法則によれば、これはあなたがそれを最も期待しないときに正確に起こります。



私たちのほとんどは、(自分自身を含む)全員を欺くために何をしますか? -アラートを設定します。 トリッキーなメトリックを作成し、ログを収集して、アラート、数千、数十万のアラートを作成します。 メールボックスがいっぱいです。 私たちの電話はSMSと通話で破れています。 私たちは人々のフロア全体を植えてグラフを見ます。 そして、再びサービスにアクセスできなくなると、分析が始まります。何を監視し忘れたのか。



これはすべて、信頼性の外観にすぎません。 アラート、メトリック、モニタリングは役に立ちません。



今日彼らはあなたに電話してサービスを修正しました-何かが壊れていることに誰も気づきませんでした。 そして明日、山に行きました。 そして明後日、彼は腫れた。 人々は完璧ではありません。 幸いなことに、私たちはエンジニアであり、不完全な世界に住んでおり、それを打ち負かすことを学びます。



それでは、なぜコーヒーの代わりに夜または朝に目を覚ます必要があるのか​​、メールを読んでください。 ビジネスが1人とそのパフォーマンスに依存する理由。 なぜだ。 わかりません。



私はあなたがそのように生きることができないことを理解しています、そして私はそのように生きたくありません。 答えは簡単です。これを自動化します(はい、大文字で)。 夜間にアラートや電話をかけるだけでは不十分です。 これらのメッセージへの自動応答が必要です。 システムがそれ自体を修正できることを確認する必要があります。 システムは柔軟性があり、変更できる必要があります。



残念ながら、まだ十分にスマートなAIがありません。 幸いなことに、すべての問題は形式化できます。



特効薬はありませんが、AWSの概念実証はあります。



AWSラムダ



サーバーレス-そもそも、実行されていないものが壊れることはありません。

イベントベース-イベントを受信し、処理し、オフにしました。

JVM対応-これは、Javaの世界のすべての経験を使用できることを意味します(そして、Clojureを使用できることを意味します)。

サードパーティ-AWS Lambdaを監視およびサポートする必要はありません。


パイプラインは次のとおりです。



イベント-> SNSトピック-> AWS Lambda->反応


ところで、SNSトピックには複数のエンドポイントを設定できます。 そのため、メールを追加して、同じ通知を受け取ることができます。 また、ラムダ関数を拡張して、通知をさらに便利にすることができます。たとえば、アラートをチャートとともにすぐに送信したり、SMS送信を追加したりできます。



1つのLambda関数の完全な例は、 github.com / lowl4tency / aws-lambda-exampleにあります。

ラムダ関数は、inServiceではないELBのすべてのノードを釘付けにします。



コード解析



この例では、InService状態にないすべてのノードを強制終了します。 ちなみに、Lambda関数全体は1つのファイルで最大50行のコードを必要とします。つまり、サポートと入力が簡単です。



Clojureのプロジェクトはすべてproject.cljで始まります



公式のJava SDKとこのSDKのラッパーである優れたAmazonicaライブラリを使用しました。 ドラッグしすぎないように、必要のないSDKの部分を除外します



[amazonica "0.3.52" :exclusions [com.amazonaws/aws-java-sdk]] [com.amazonaws/aws-java-sdk-core "1.10.62"] [com.amazonaws/aws-lambda-java-core "1.1.0"] [com.amazonaws/aws-java-sdk-elasticloadbalancing "1.11.26" :exclusions [joda-time]] [com.amazonaws/aws-java-sdk-ec2 "1.10.62" :exclusions [joda-time]] [com.amazonaws/aws-lambda-java-events "1.1.0" :exclusions [com.amazonaws/aws-java-sdk-dynamodb com.amazonaws/aws-java-sdk-kinesis com.amazonaws/aws-java-sdk-cognitoidentity com.amazonaws/aws-java-sdk-sns com.amazonaws/aws-java-sdk-s3]]]
      
      





各Lambda関数の柔軟性を高めるために、最も一般的なednを持つ構成ファイルを使用します。 イベントを処理できるようにするには、関数宣言をわずかに変更する必要があります



 (ns aws-lambda-example.core (:gen-class :implements [com.amazonaws.services.lambda.runtime.RequestStreamHandler])
      
      





エントリーポイント。 入力イベントを読み取り、handle-eventを使用してこのイベントを処理し、結果としてJSONストリームに書き込みます。



 (defn -handleRequest [this is os context] "Parser of input and genarator of JSON output" (let [w (io/writer os)] (-> (io/reader is) json/read (-> (io/reader is) json/read walk/keywordize-keys handle-event (json/write w)) (.flush w))))
      
      





主力:



 (defn handle-event [event] (let [instances (get-elb-instances-status (:load-balancer-name (edn/read-string (slurp (io/resource "config.edn"))))) unhealthy (unhealthy-elb-instances instances)] (when (seq unhealthy) (pprint "The next instances are unhealthy: ") (pprint unhealthy) (ec2/terminate-instances :instance-ids unhealthy)) {:message (get-in event [:Records 0 :Sns :Message]) :elb-instance-ids (mapv :instance-id instances)}))
      
      







ELBでノードのリストを取得し、ステータスでフィルターします。 InService状態にあるすべてのノードがリストから削除されます。 残りはシロアリです。



pprintを介して印刷したものはすべてCloudWatchログに記録されます。 これはデバッグに役立ちます。 常に実行されるラムダがなく、REPLに接続する方法がないため、これは非常に便利です。



  {:message (get-in event [:Records 0 :Sns :Message]) :instance-ids (mapv :instance-id instances)}))
      
      





この時点で、この関数から生成して返す構造全体がJSONで記述され、Lambda Webインターフェースの実行結果が表示されます。



unhealthy-elb-instances関数では 、リストフィルタリングし、ELBが動作不能であると見なしたノードについてのみinstance-idを取得します。 インスタンスのリストを取得し、タグでフィルタリングします。



 (defn unhealthy-elb-instances [instances-status] (->> instances-status (remove #(= (:state %) "InService")) (map :instance-id)))
      
      





get-elb-instances-status関数では 、APIメソッド呼び出して、特定の1つのELBのステータスを持つすべてのノードのリストを取得します



 (defn get-elb-instances-status [elb-name] (->> (elb/describe-instance-health :load-balancer-name elb-name) :instance-states (map get-health-status )))
      
      





便宜上、不要なものを削除し、興味のある情報のみを含むリストを生成します。 これは、各インスタンスのインスタンスIDとステータスです。



 (defn get-health-status [instance] {:instance-id (:instance-id instance) :state (:state instance)})
      
      





そして、リストをフィルタリングし、InService状態にあるノードを削除します。



 (defn unhealthy-elb-instances [instances-status] (->> instances-status (remove #(= (:state %) "InService")) (map :instance-id)))
      
      





そしてそれだけです。夜に目を覚まして、静かに山に行かないようにする50行。



展開



展開を容易にするために、単純なbashスクリプトを使用します



 #!/bin/bash # Loader AWS Lambda aws lambda create-function --debug \ --function-name example \ --handler aws-lambda-example.core \ --runtime java8 \ --memory 256 \ --timeout 59 \ --role arn:aws:iam::611066707117:role/lambda_exec_role \ --zip-file fileb://./target/aws-lambda-example-0.1.0-SNAPSHOT-standalone.jar
      
      





アラートを設定し、SNSトピックに固定します。 SNSトピックをエンドポイントとしてラムダに固定します。 私たちは静かに山に行くか、車の下に落ちます。



ところで、柔軟性のために、システムだけでなくビジネス指標によっても、システムのあらゆる動作をプログラムすることが可能です。



ありがとう



All Articles