DevOps:メトリックを送信し、静かに眠ります





突然、夜に電話が鳴り、アプリケーションが機能していないことがわかりました。 彼の蘇生には2時間あります...





はい、 「Elasticsearchへのログの公開-正規表現とlogstashのない生活」という記事のアイデアに触発されて、ログをElasticsearchに定期的に送信しました。 しかし、アプリケーションの「クラッシュ」の真の原因を調査するために、明らかにjmx bins jvm、データベース接続プールのjmx、プロセスによって開かれたファイル記述子の数などのデータが不足しています。 ボルジョミを飲むのが遅れて......



もちろん、nagios、zabbix、collectedまたは独自の監視システムからプロセスデータを取得できますが、Elasticsearchでこれらのデータをすべてすぐに取得する方が便利です。 これにより、 kibanaで視覚化し、ネットワーク内の異なるノードの多くのプロセスからの単一のイベントソースに基づいてアラート受信できます。 Elasticsearchでは、新しい検索エンジンプロセスを追加することで、インデックス作成、全文検索の実行、およびデータウェアハウスの水平スケーリングが可能です。



さて、今回はアプリケーションログをシャベルし、独自の優れたモニタリングでメトリックの履歴を調査します。これに基づいて、アプリケーションクラッシュのより合理的な理由を見つけます。 次回は、より便利な方法でアプリケーションの操作に関する情報を収集し、アプリケーションのメトリックとイベントに基づいて真の理由を見つけようとします。



私はあなたと夜にもっと眠る方法のレシピを共有します:





Elasticsearchとkibanaの調理



メトリックの収集場所から始めましょう。 Elasticsearch(ES)サーバーを起動します。 たとえば、最も単純な構成のElasticsearchでは、すべての新しいインデックスにデフォルトのテンプレートがすぐに設定されるため、完成したLogstashダッシュボードを使用してkibanaを検索できます。 mvn packageとして始まります 。 サーバーノードは、マルチキャストUDPパケットを使用して相互に検出し、clusterNameを一致させることでクラスターをまとめます。 ユニキャストアドレスが存在しないことで開発期間が短縮されることは明らかですが、産業運用ではこのようなクラスターを設定する価値はありません。

この例では、groovyスクリプトを使用してElasticsearchを実行できます...
java -jar groovy-grape-aether-2.4.5.1.jar elasticsearch -server.groovy


スクリプトelasticsearch-server.groovy:

@Grab(group='org.elasticsearch', module='elasticsearch', version='1.1.1') import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.node.Node; import org.elasticsearch.node.NodeBuilder; import java.io.InputStream; import java.net.URL; import java.util.concurrent.TimeUnit; int durationInSeconds = args.length == 0 ? 3600 : Integer.parseInt(this.args[0]); String template; InputStream templateStream = new URL("https://raw.githubusercontent.com/logstash-plugins/logstash-output-elasticsearch/master/lib/logstash/outputs/elasticsearch/elasticsearch-template.json").openStream() try{ template = new String(sun.misc.IOUtils.readFully(templateStream, -1, true)); } finally{ templateStream.close() } Node elasticsearchServer = NodeBuilder.nodeBuilder().settings(ImmutableSettings.settingsBuilder().put("http.cors.enabled","true")).clusterName("elasticsearchServer").data(true).build(); Node node = elasticsearchServer.start(); node.client().admin().indices().preparePutTemplate("logstash").setSource(template).get(); System.out.println("ES STARTED"); Thread.sleep(TimeUnit.SECONDS.toMillis(durationInSeconds));
      
      







メトリック用のストレージがあります。 Kibana Webアプリケーションを使用して接続しますが、まだメトリックを送信していないため、何も表示されません。 elasticsearch-HQを使用して、Elasticsearchクラスターと接続されたクライアントのステータスを表示できますが、管理コンソールには多くのオプションがあり、好みに応じて選択できます。



この例のkibana設定に関するいくつかの言葉。 kibana-3.1.3 / config.jsファイルで、プロパティelasticsearch: " 127.0.0.1:9200 "を置き換える必要があります。 次に、Webインターフェースは、elasticsearch-server.groovyスクリプトまたはmvn packageコマンドを使用して、同じネットワークノードで実行されているelasticsearchサーバーに接続できます。







jvmからElasticsearchにメトリックを送信する



AspectJスクリプトエージェントを使用して、すべての魔法を行います。 エージェントが変更され、AttachAPIを使用してプロセスに簡単に統合できるようになり、エージェントパラメーターを介して構成を受信できるようになりました。 現在、エージェントはアスペクトなしで構成で使用でき、定期的に実行されるタスクを記述することが可能です。



AspectJ-Scriptingを使用すると、アプリケーションを再コンパイルおよび再パッケージせずに、jarファイルをaspectj-scripting-1.3-agent.jarエージェント 、ファイルシステム(またはWebサーバー)の構成ファイル、およびJVMの起動時に追加のパラメーター-javaagentを使用して、メトリックを送信できますElasticsearchのすべてのアプリケーションプロセスから。



エージェントのJava構成では、 com.github.igor-suhorukov:jvm-metrics:1.2を使用し、このライブラリの内部で動作します





したがって、メトリックを収集して送信するために必要な作業を行うすべてのものは、ファイルlog.metrics.xmlにあります。

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <configuration> <globalContext> <artifacts> <artifact>com.github.igor-suhorukov:jvm-metrics:1.2</artifact> <classRefs> <variable>SigarCollect</variable><className>org.github.suhorukov.SigarCollect</className> </classRefs> <classRefs> <variable>JmxCollect</variable><className>org.github.suhorukov.JmxCollect</className> </classRefs> </artifacts> <artifacts> <artifact>org.elasticsearch:elasticsearch:1.1.1</artifact> <classRefs> <variable>NodeBuilder</variable><className>org.elasticsearch.node.NodeBuilder</className> </classRefs> </artifacts> <init> <expression> SigarCollect sigar = new SigarCollect(); JmxCollect jmxCollect = new JmxCollect(); reportHost = java.net.InetAddress.getLocalHost().getHostName(); pid = java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0]; Thread.currentThread().setContextClassLoader(NodeBuilder.class.getClassLoader()); client = NodeBuilder.nodeBuilder().clusterName("elasticsearchServer").data(false).client(true).build().start().client(); additionalRecords = new java.util.HashMap(); additionalRecords.put("Host", reportHost); additionalRecords.put("Pid", pid); </expression> </init> <timerTasks> <delay>500</delay> <period>2000</period> <jobExpression> import java.text.SimpleDateFormat; import java.util.TimeZone; logstashFormat = new SimpleDateFormat("yyyy.MM.dd"); logstashFormat.setTimeZone(TimeZone.getTimeZone("UTC")); timestamp = new java.util.Date(); index = "logstash-" + logstashFormat.format(timestamp); jmxInfo = jmxCollect.getJsonJmxInfo("java.lang:type=Memory", timestamp, additionalRecords); nativeInfo = sigar.getJsonProcessInfo(additionalRecords); client.index(client.prepareIndex(index, "logs").setSource(jmxInfo).request()).actionGet(); client.index(client.prepareIndex(index, "logs").setSource(nativeInfo).request()).actionGet(); </jobExpression> </timerTasks> </globalContext> </configuration>
      
      







この構成では、SigarCollectクラスとJmxCollectクラスのインスタンスを作成します。これらのクラスは、エージェントの起動時にcom.github.igor-suhorukov:jvm-metrics:1.2ライブラリからロードされます。



SigarCollect-プロセスとオペレーティングシステムに関するデータを収集できます。これらの多くはjxmに含まれておらず、メトリックをjson形式に変換します。 JmxCollect-jmx仮想マシンとアプリケーションにデータを要求し、それらをjsonドキュメントに変換することもできます。 JmxCollectからの情報をフィルター「java.lang:type = Memory」に限定しましたが、jxm Beanからより多くの情報が必要になります。



additionalRecordsに、reportHost-アプリケーションが実行されているホストの名前とプロセスID pidを追加します。



クライアントでは、elasticsearchのクライアントを保存します。これは、クラスター「elasticsearchServer」のElasticsearchという名前のサーバーに参加します。これは、メトリックの送信に使用します。



メトリックを送信するタスクは、2秒ごとに実行され、対応する日付(たとえば、logstash-2015.11.25)でインデックスにメトリックを書き込みます。 このタスクでは、JmxCollectおよびSigarCollectからのメトリックは、kibanaがレンダリングできる形式のjsonオブジェクトとして返されます。 Elasticsearchクライアントを使用するメトリックはクラスターに送信され、インデックスが作成されます。



ご覧のとおり、結果はMVEL言語のjavaに似た構文の構成であり、開発者にはよく知られています。



アプリケーションの起動スクリプトに、-javaagent:/?PATH?/ Aspectj-scripting-1.3-agent.jar = config:file:/?PATH?/ Log.metrics.xmlを追加します

すべてのノードですべてのアプリケーションプロセスを開始し、Elasticsearchクラスターでメトリックがどのように流れるかを確認します







しかし、アプリケーションログはどうでしょうか。



既にElasticsearchにメトリックスを送信していますが、アプリケーションからの十分なその他の情報がありません。 「Elasticsearchでのログの公開-正規表現とLogstashなしでの生活」の記事のアプローチを使用すると、ログファイルの解析は必要ありません。 ロギング形式または新しいメッセージの外観を変更する場合、多数のレギュラーをサポートする必要はありません。 このアプローチでは、ロガーのエラー、警告、情報、デバッグ、トレースメソッドの呼び出しをインターセプトし、データをelasticsearchに直接送信することを提案します。



すでに実行されているjvmプロセスで何をすべきか、groovyはどこですか?



Groovyスクリプトを使用すると、プロセス識別子と構成パスのみを指定して、jvmで既に実行されているアプリケーションにもエージェントを実装できます。 また、AttachAPIを使用して実行中のプロセスにエージェントを注入するために、jvmのtools.jarも必要ありません。 これは、JMockit / OpenJDKのクラスに基づいたライブラリcom.github.igor-suhorukov:attach-vm:1.0のおかげで可能になりました。



このスクリプトを実行するには、特別に準備された溝groovy-grape-aether-2.4.5.1.jarが必要です。 私が最近話した能力。

java -jar groovy-grape-aether-2.4.5.1.jar attachjvm.groovy JVM_PID config:file :?PATH? / log.metrics.xml


attachjvm.groovyスクリプトは、aspectj-scripting:jar:エージェントをmavenリポジトリからダウンロードし、 AttachAPIを使用してJVM_PIDプロセス番号でjvmに接続し、構成log.metrics.xmlでエージェントをこのjvm aspectj-scriptingにロードします

 @Grab(group='com.github.igor-suhorukov', module='attach-vm', version='1.0') import com.github.igorsuhorukov.jvmattachapi.VirtualMachineUtils; import com.sun.tools.attach.VirtualMachine; import com.github.igorsuhorukov.smreed.dropship.MavenClassLoader; def aspectJScriptingFile = MavenClassLoader.forMavenCoordinates("com.github.igor-suhorukov:aspectj-scripting:jar:agent:1.3").getURLs().getAt(0).getFile() println aspectJScriptingFile def processId = this.args.getAt(0) //CliBuilder def configPath = this.args.getAt(1) VirtualMachine virtualMachine = VirtualMachineUtils.connectToVirtualMachine(processId) try { virtualMachine.loadAgent(aspectJScriptingFile, configPath) } finally { virtualMachine.detach() }
      
      





システムを診断するか、ロギングのレベルを変更する必要がある場合は、Javaアプリケーションにクロスプラットフォームsshサーバー埋め込みます 。 すでに実行中のJavaプロセスに埋め込むことができます:

java -jar groovy-grape-aether-2.4.5.1.jar attachjvm.groovy JVM_PID config:file :?PATH? / CRaSHub_ssh.xml


CRaSHub_ssh.xmlの次の構成では...
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <configuration> <globalContext> <artifacts> <artifact>org.crashub:crash.connectors.ssh:1.3.1</artifact> <classRefs> <variable>Bootstrap</variable> <className>org.crsh.standalone.Bootstrap</className> </classRefs> <classRefs> <variable>Builder</variable> <className>org.crsh.vfs.FS$Builder</className> </classRefs> <classRefs> <variable>ClassPathMountFactory</variable> <className>org.crsh.vfs.spi.url.ClassPathMountFactory</className> </classRefs> <classRefs> <variable>FileMountFactory</variable> <className>org.crsh.vfs.spi.file.FileMountFactory</className> </classRefs> </artifacts> <init> <expression> import java.util.concurrent.TimeUnit; otherCmd = new FileMountFactory(new java.io.File(System.getProperty("user.dir"))); classLoader = otherCmd.getClass().getClassLoader(); classpathDriver = new ClassPathMountFactory(classLoader); cmdFS = new Builder().register("classpath", classpathDriver).register("file", otherCmd).mount("classpath:/crash/commands/").build(); confFS = new Builder().register("classpath", classpathDriver).mount("classpath:/crash/").build(); bootstrap = new Bootstrap(classLoader, confFS, cmdFS); config = new java.util.Properties(); config.put("crash.ssh.port", "2000"); config.put("crash.ssh.auth_timeout", "300000"); config.put("crash.ssh.idle_timeout", "300000"); config.put("crash.auth", "simple"); config.put("crash.auth.simple.username", "admin"); config.put("crash.auth.simple.password", "admin"); bootstrap.setConfig(config); bootstrap.bootstrap(); Thread.sleep(TimeUnit.MINUTES.toMillis(30)); bootstrap.shutdown(); </expression> </init> </globalContext> </configuration>
      
      











結論



安らかに眠るには、アプリケーションの操作に関連するタスクに注意を払う必要があります。



これで、機能するElasticsearchクラスターができました。インデックスからのデータは、kibanaで分析できます。 Elasticsearchは、JMX Bean、jvmプロセスメトリック、およびオペレーティングシステムのメトリックを持つアプリケーションから情報を受け取ります。 ここで、アプリケーションログの書き方は既にわかっます。 通知を設定し、通知の場合は、アプリケーションの問題の原因をすばやく見つけ、問題をすばやく修正します。 さらに、 クロスプラットフォームのsshサーバーをJavaアプリケーション組み込み 、実行中のアプリケーションでも再起動せずに診断できます。 CRaSHを使用したスイッチログレベルを含みます。



アプリケーションが安定して動作することを望みますが、それでも問題の原因が発生した場合はすぐに見つけられます!



All Articles