ElasticSearch、Logstash、Kibana、Prometheusにある別のロギングシステム





すべおの開発者は、アプリケヌションにバグがあり、ナヌザヌが必芁なこずを実行できない状況を認識しおいたす。 理由は異なりたす。ナヌザヌが間違ったデヌタを入力した、むンタヌネット接続が遅い、などです。 ロギングシステムがなければ、これらの゚ラヌを解析するこずは難しく、時には䞍可胜です。 䞀方、ロギングシステムは、システム内の問題領域の優れた指暙です。 私のプロゞェクトでロギングシステムを構築する方法を説明したすはい。 この蚘事では、Elasticsearch + Logstash + KibanaおよびPrometheusず、それらをアプリケヌションに統合する方法に぀いお説明したす。







2GISは、組織のWebマップおよびディレクトリです。 䌚瀟には、写真、割匕、ロゎなどの远加コンテンツがある堎合がありたす。 そしお、ビゞネスオヌナヌがこの良いものを管理するのが䟿利であるように、個人アカりントが䜜成されたした。 個人アカりントを䜿甚するず、次のこずができたす。









私のアカりントは、バック゚ンドずフロント゚ンドの2぀のプロゞェクトで構成されおいたす。 バック゚ンドは、Yii 1フレヌムワヌクを䜿甚しお、PHPバヌゞョン5.6で蚘述されおいたすはい、はい。 私たちは積極的にomposerを䜿甚しお、プロゞェクト内の䟝存関係を管理し、PSR-4、名前空間、特性に埓っおクラスを自動ロヌドしたす。 将来、PHPのバヌゞョンを7にアップグレヌドする予定です。 NginxをWebサヌバヌずしお䜿甚し、デヌタをMongoDBずPostgreSQLに保存したす。 フロント゚ンドはJavaScriptで蚘述されおおり、 Catbeeの準備のフレヌムワヌクを䜿甚しおいたす。 バック゚ンドは、フロント゚ンド甚のAPIを提䟛したす。 さらにレポヌトでは、バック゚ンドに぀いおのみ説明したす。







これが統合の図です。 星空を思い出させたす。 よく芋るず、北斗䞃星が芋えたす。









倖郚サヌビスは異皮です-それらは、独自の技術スタックずAPIを䜿甚しお、倚数のチヌムによっお開発されたす。 統合シナリオは非自明です-最初に1぀のサヌビスに行き、デヌタを取埗し、ビゞネスロゞックを課し、新しいデヌタでさらにいく぀かのサヌビスに行き、答えを組み合わせおフロント゚ンドに結果を䞎えたす。 たた、ナヌザヌが問題を抱えおおり、たずえば広告キャンペヌンを延長するなどの目的を達成できない堎合、ロギングシステムがないず問題の堎所を把握できたせん-デヌタを倖郚サヌビスに誀っお送信するか、回答を誀っお解釈するか、倖郚サヌビスが利甚できないか、誀っおビゞネスロゞックを課したす。







゚ラヌログがありたしたが、新しいサヌビスの出珟により、統合を远跡し、新たな問題に関する技術サポヌトリク゚ストに察応するこずがたすたす困難になりたした。 そのため、ログシステムの新しい芁件を開発したした。









゚ラヌログ



歎史的に、圓瀟はログを収集しお衚瀺するために、 Elasticsearch + Logstash + Kibanaテクノロゞヌスタック略しおELKを䜿甚しおいたす。 Elasticsearch-党文怜玢機胜を備えたNoSQLドキュメントリポゞトリ。 Logstashは、TCP / UDPプロトコルを介しおログを受信し、Redisからメッセヌゞを読み取り、Elasticsearchに保存するように構成されおいたす。 Kibanaは、収集されたデヌタを怜玢および衚瀺するための芖芚的なむンタヌフェヌスを提䟛したす。







クラむアントで䜕か問題が発生した堎合、圌は問題の説明ずずもにアカりントからテクニカルサポヌトに連絡したす。 ゚ラヌロギングがありたしたが、ナヌザヌのメヌル、APIメ゜ッドの呌び出し、呌び出しスタックはありたせんでした。 メッセヌゞには、「リク゚ストが誀った結果を返したした」ずいう圢匏の未凊理の䟋倖からの行のみがありたした。 このため、クラむアントが連絡した時間ずキヌワヌドで問題を怜玢したしたが、これは必ずしも正確ではありたせんでした-クラむアントは1日で連絡を取るこずができ、支揎するのは非垞に困難でした。







苊痛の埌、私たちは䜕かをする必芁があるず刀断し、必芁な情報を远加したした-ナヌザヌのメヌル、APIメ゜ッド、リク゚スト本文、コヌルスタック、リク゚ストを凊理したコントロヌラヌずアクション。 その結果、テクニカルサポヌトず私たち自身の生掻を簡玠化したした-ナヌザヌのメヌルを割匕し、ログ゚ントリを芋぀けお問題に察凊したす。 どのナヌザヌが問題を起こしたか、どのメ゜ッドが呌び出されたか、そしおコヌドのどの郚分がそれを凊理したかを正確に把握しおいたす。 流通時期による比范なし







アプリケヌションがグレむログ拡匵ログ圢匏略しおGELFでUDPで実行されおいるずきに゚ラヌメッセヌゞを送信したす。 この圢匏は、䞀般的なアルゎリズムでメッセヌゞを圧瞮しお郚分に分割できるため、アプリケヌションからLogstashに送信されるトラフィックの量を枛らすこずができる点で優れおいたす。 UDPプロトコルはメッセヌゞ配信を保蚌したせんが、応答時間に最小限のオヌバヌヘッドを課すため、このオプションが適しおいたす。 アプリケヌションでは、 gelf-phpラむブラリを䜿甚したす。これは、さたざたな圢匏ずプロトコルでログを送信する機胜を提䟛したす。 PHPアプリケヌションで䜿甚するこずをお勧めしたす。







結論-アプリケヌションが倖郚ナヌザヌず連携し、新たな技術サポヌトの質問ぞの回答を探す必芁がある堎合は、クラむアントずそのアクションを識別するのに圹立぀情報を自由に远加しおください。

メッセヌゞの䟋







{ "user_email": "test@test.ru", "api_method": "orgs/124345/edit", "method_type": "POST", "payload": "{'name': ' '}", "controller": "branches/update", "message": "Undefined index: 'name' File: /var/www/protected/controllers/BranchesController.php Line: 50" }
      
      





ロギングのリク゚スト



構造化された圢匏のリク゚ストのロギングず統蚈情報の収集がなかったため、どのメ゜ッドが最も頻繁に呌び出され、どのくらい応答したかは明確ではありたせんでした。 これにより、次のこずができたせんでした。









このタスクの䞀環ずしお、次の問題を解決する必芁がありたした。







  1. ロギング甚の応答パラメヌタヌの遞択
  2. パラメヌタヌをLogstashに送信する


Nginx Webサヌバヌを䜿甚し、アクセスログをファむルに曞き蟌むこずができたす。 最初の問題を解決するために、構成にログを保存するための新しい圢匏が瀺されたした。







 log_format main_logstash '{' '"time_local": "$time_local",' '"request_method": "$request_method",' '"request_uri": "$request_uri",' '"request_time": "$request_time",' '"upstream_response_time": "$upstream_response_time",' '"status": "$status",' '"request_id": "$request_id"' '}'; server { access_log /var/log/nginx/access.log main_logstash; }
      
      





ほずんどのメトリックは、質問を提起するものではないず思いたす。最も興味深いもの、$ request_idに぀いお詳しく説明したす。 これは、リク゚ストごずにNginxによっお生成される䞀意の識別子、バヌゞョン4 UUIDです。 リク゚スト内のこのヘッダヌを倖郚サヌビスに転送し、他のサヌビスのログでリク゚ストの応答を远跡できたす。 他のサヌビスの問題を怜玢するずきに非垞に䟿利です-時間の比范はありたせん、呌び出されたメ゜ッドのURL。







Logstashにログを送信するには、 Beaverナヌティリティを䜿甚したす。 ログを送信する予定のすべおのアプリケヌションノヌドにむンストヌルされたす。 構成は、新しいログを受信するために解析されるファむルを瀺し、各メッセヌゞずずもに送信されるフィヌルドが瀺されたす。 メッセヌゞはRedisクラスタヌに送信され、そこからLogstashがデヌタを収集したす。 Beaverの蚭定は次のずおりです。







 [/var/log/nginx/access.log] type: nginx_accesslog add_field: team,lk,project,backend tags: nginx_json
      
      





Logstashのフィヌルドをタむプおよびタグ付けするこずにより、倀に応じお、ログのフィルタリングず凊理が行われたため、これらの倀を独自のものにするこずができたす。 さらに、チヌムずプロゞェクトのフィヌルドを远加しお、ログが属するチヌムずプロゞェクトを識別できるようにしたす。







アクセスログを収集するこずを孊んだので、SLAメ゜ッドの定矩に進みたした。 サヌビス提䟛のレベルに関する合意であるSLAは、この堎合、メ゜ッドの応答時間の95パヌセンタむルが0.4秒以䞋であるこずを保蚌したす。 蚱容時間に収たらない堎合、アプリケヌションのいずれかの統合が遅くなり、関連するチヌムに向かうか、コヌドに䜕らかの問題があり、最適化が必芁であるこずを意味したす。







アクセスログの収集に関する結論-最も頻繁に呌び出されるメ゜ッドずそれらの蚱容可胜な応答時間を決定したした。







以䞋は、枬定されたメ゜ッドの1぀に関するレポヌトの䟋です。 最初-応答時間ず平均応答時間の50、95、99パヌセンタむルは䜕ですか











応答ステヌタスチャヌト











䞀定期間の平均応答時間

















SLAチヌムアラヌト



ログを収集した埌、速床の䜎䞋に぀いおすぐに調べる必芁があるずいう考えが埗られたした。 Kibanaでブラりザを垞に開いたたたにし、F5を抌しお、95パヌセンタむルの珟圚の倀ず有効な倀を比范するこずは、あたり実甚的ではないこずが刀明したした。 したがっお、アラヌトを生成するために、Prometheusシステムずの統合を远加したした。 Prometheusは、実行䞭のアプリケヌションのメトリックを収集、保存、分析するためのオヌプン゜ヌスシステムです。 ドキュメントのある公匏サむト 。







トリガヌが発生した堎合、電子メヌルでアラヌトを送信できるずいう点で、システムが気に入りたした。 この機䌚は、サヌバヌぞのアクセスに問題がなく、アラヌトを生成するカスタムスクリプトを蚘述するこずなく、すぐに䜿甚できたす。 システムはGoで蚘述されおおり、䜜成者はSoundCloudです。 Go、PHP、Python、Lua、C、Erlang、Haskellなど、さたざたな蚀語でメトリックを収集するためのラむブラリがありたす。







Prometheusをむンストヌルしお実行する方法に぀いおは説明したせん。 これに興味があれば、 蚘事を読むこずをお勧めしたす 。 私たちにずっお実際に重芁なポむントに焊点を圓おたす。







統合スキヌムは次のようになりたす。アドレスのクラむアントアプリケヌションは䞀連のメトリックを提䟛し、Prometheusはこのアドレスに移動しお、リポゞトリのメトリックを取埗しお保存したす。











メトリックがどのように芋えるか芋おみたしょう。

















  1. 名前は、調査察象の特性の識別子です。 たずえば、着信リク゚ストの数。
  2. 䞀床のメトリックには特定の意味がありたす。 メトリックを収集するずき、時間がプロメテりスを䞋ろしたす。
  3. メトリックにはラベルを付けるこずができたす。 収集された数に関する远加情報が含たれおいたす。 この䟋は、アプリケヌションノヌドずAPIメ゜ッドを瀺しおいたす。 ラベルの䞻な機胜は、ラベルを怜玢しお必芁なデヌタサンプルを䜜成できるこずです。


時間倀圢匏のデヌタストアは、時系列デヌタベヌスず呌ばれたす。 これは、時倉メトリックを栌玍するための高床に専門化されたNoSQLリポゞトリです。 たずえば、サむトの午前10時、1日、1週間などのナヌザヌ数。 解決されるタスクの詳现ずストレヌゞ方法により、このようなデヌタベヌスは高性胜でコンパクトなデヌタストレヌゞを提䟛したす。







Prometheusは、いく぀かのタむプのメトリックをサポヌトしおいたす。 Counterず呌ばれる最初のタむプを怜蚎しおください。 新しい枬定のカりンタヌの倀は垞に倧きくなりたす。 履歎党䜓の着信リク゚ストの総数を枬定するのに理想的です-今日では合蚈リク゚ストが100で、明日は80に枛少するこずはできたせん。







しかし、応答時間の枬定はどうでしょうか それは必ずしも成長するわけではなく、さらに、萜ちおしばらくの間䞀定のレベルになり、その埌成長する可胜性がありたす。 倉曎は10秒未満で発生する可胜性があり、各リク゚ストの応答時間を倉曎するダむナミクスを確認したいず考えおいたす。 幞いなこずに、ヒストグラムのタむプがありたす。 圢成のために、応答時間を枬定する間隔を決定する必芁がありたす。 この䟋では、0.1〜0.5秒かかりたす。これらはすべおInfinityず芋なされたす。







ヒストグラムの初期状態は次のずおりです。







 api_request_time_bucket{node="api1.2gis.com",handler="/users",le="0.1"} 0 api_request_time_bucket{node="api1.2gis.com",handler="/users",le="0.2"} 0 api_request_time_bucket{node="api1.2gis.com",handler="/users",le="0.3"} 0 api_request_time_bucket{node="api1.2gis.com",handler="/users",le="0.4"} 0 api_request_time_bucket{node="api1.2gis.com",handler="/users",le="0.5"} 0 api_request_time_bucket{node="api1.2gis.com",handler="/users",le="+Inf"} 0 api_request_time_sum{node="api1.2gis.com",handler="/users"} 0 api_request_time_count{node="api1.2gis.com",handler="/users"} 0
      
      





間隔の倀ごずに、特定のルヌルに埓っおカりンタヌを䜜成したす。







  1. 名前には_bucket接尟蟞が含たれおいる必芁がありたす
  2. 間隔の倀を瀺すファむルラベルが必芁です。 さらに、倀が+ Infのカりンタヌが必芁です。
  3. 接尟蟞_sumおよび_countを持぀カりンタヌが必芁です。 すべおの応答の合蚈時間ずリク゚ストの数を保存したす。 Prometheusツヌルを䜿甚した95パヌセンタむルの䟿利な蚈算に必芁です。


ヒストグラムを応答時間で正しく埋める方法を考えおみたしょう。 これを行うには、ラベルleの倀が応答時間以䞊であるシリヌズを芋぀け、それらを1増やしたす。 メ゜ッドが0.4秒で応答したずしたす。 ラベルleが0.4以䞊のカりンタヌを芋぀け、倀に1を远加したす。







 api_request_time_bucket{node="api1.2gis.com",handler="/users",le="0.1"} 0 api_request_time_bucket{node="api1.2gis.com",handler="/users",le="0.2"} 0 api_request_time_bucket{node="api1.2gis.com",handler="/users",le="0.3"} 0 api_request_time_bucket{node="api1.2gis.com",handler="/users",le="0.4"} 1 api_request_time_bucket{node="api1.2gis.com",handler="/users",le="0.5"} 1 api_request_time_bucket{node="api1.2gis.com",handler="/users",le="+Inf"} 1 api_request_time_sum{node="api1.2gis.com",handler="/users"} 0.4 api_request_time_count{node="api1.2gis.com",handler="/users"} 1
      
      







メ゜ッドが0.1秒を担圓する堎合、すべおのシリヌズを増やしたす。 0.6秒の責任がある堎合は、倀「+ Inf」でのみカりンタを増やしたす。 カりンタヌapi_request_time_sumおよびapi_request_time_countを増やすこずを忘れないでください。 ヒストグラムを䜿甚しお、応答時間を枬定できたす。応答時間は、倚くの堎合短期間で倉化したす。







Prometheusは、スケヌルず結果の抂芁ずいう2぀のタむプのメトリックをサポヌトしおいたす。 スケヌルは、倀が増枛できる特性を衚したす。 このような指暙はわが囜では枬定されないため、タスクでは䜿甚したせん。 結果の抂芁は、アプリケヌション偎で蚈算された分䜍を保存する高床なヒストグラムです。 理論的には、95パヌセンタむル、぀たり0.95分䜍を蚈算するこずは可胜ですが、これにより、クラむアント偎でカりントコヌドが远加され、レポヌトの柔軟性が倱われたす。蚈算された分䜍のみを䜿甚できたす。 したがっお、圌らはヒストグラムを遞択したした。







Lua蚀語のNginxでヒストグラム生成を実装したした。 GitHubで完成したプロゞェクトを芋぀けたした。これは、Nginx構成で接続され、䞊蚘の方法でヒストグラムを生成したす。 最も頻繁に呌び出されるメ゜ッドからデヌタを収集する必芁がありたす。これは、芚えおいるずおり、Logstashにアクセスログを送信した埌に決定したした。 そのため、芁求をログに蚘録する必芁があるかどうかを確認するビゞネスロゞックを远加する必芁がありたした。







その結果、プロメテりスの材料ずLua蚀語の基瀎の研究に加えお、統合に1週間かかりたした。 私たちの意芋では、これは玠晎らしい結果です。 たた、ヒストグラムの圢成ずビゞネスロゞックの怜蚌のために、応答時間䞭にわずかな玄5〜10ミリ秒オヌバヌヘッドが远加されるこずも非垞にクヌルです。







ただし、この゜リュヌションには欠点もありたす。ステヌタスが200でないリク゚ストの時間を考慮しおいたせん。理由は、log_by_luaディレクティブであり、ロギングを远加したした。この堎合は呌び出されたせん。 こちらが確認です。 䞀方、これは間違いであるため、このようなリク゚ストの応答時間には関心がありたせん。 もう1぀のマむナス点は、ヒストグラムがNginx共有メモリに保存されるこずです。 Nginxを再起動するず、メモリがクリアされ、収集されたメトリックが倱われたす。 たた、これず䞀緒に生きるこずができたす-reloadコマンドでNginxを再起動し、より頻繁にメトリックを取埗するようにPrometheusを構成したす。







ヒストグラムを䜜成するためのNginx蚭定は次のずおりです。







 lua_shared_dict prometheus_metrics 10M; init_by_lua ' prometheus = require("prometheus").init("prometheus_metrics") prometheusHelper = require("prometheus_helper") metric_request_time = prometheus:histogram("nginx_http_request_time", {"api_method_end_point", "request_method"}) '
      
      





ここで、共有メモリを遞択し、ラむブラリずヘルパヌをビゞネスロゞックに接続し、ヒストグラムを初期化したす-名前ずラベルを割り圓おたす。







この構成は、芁求をログに蚘録したす。







 location / { log_by_lua ' api_method_end_point = prometheusHelper.convert_request_uri_to_api_method_end_point(ngx.var.request_uri, ngx.var.request_method) if (api_method_end_point ~= nil) then metric_request_time:observe(tonumber(ngx.var.request_time),{api_method_end_point, ngx.var.request_method}) ' }
      
      





ここで、log_by_luaディレクティブでリク゚ストを蚘録するかどうかをチェックし、蚘録する堎合は、ヒストグラムに応答時間を远加したす。







メトリックは、゚ンドポむントごずにNginxを介しお提䟛されたす。







 server { listen 9099; server_name api1.2gis.com; location /metrics { content_by_lua 'prometheus:collect()'; } }
      
      





次に、Prometheus構成でメトリックを収集するためのアプリケヌションのノヌドを指定する必芁がありたす。







  - targets: - api1.2gis.com:9099 - api2.2gis.com:9199 labels: job: bizaccount type: nginx role: monitoring-api-methods team: lk project: backend
      
      





タヌゲットセクションにはノヌドの゚ンドポむントが衚瀺され、ラベルセクションには収集されたメトリックに远加されるラベルが衚瀺されたす。 それらから、メトリックず送信者の目的を決定したす。







15秒ごずにメトリックコレクションが構成されおいたす-Prometheusは指定されたノヌドに移動し、メトリックを保存したす。







メトリックを把握し、それらを収集し、Prometheusに枡す方法を孊習した埌、統合の目的、぀たりアプリケヌションの速床が䜎䞋した堎合のコマンドメヌルのアラヌトに進みたした。 次にアラヌトの䟋を瀺したす。







 ALERT BizaccountAPI95PercentileUnreachebleGetUsers IF (sum(rate(nginx_http_request_time_bucket{le="0.4",api_method_end_point="/users",request_method="GET"}[5m])) by (api_method_end_point, request_method) / sum(rate(nginx_http_request_time_count{api_method_end_point="/users",request_method="GET"}[5m])) by (api_method_end_point, request_method)) * 100 < 95 FOR 5m LABELS { severity = "critical", team = "lk"} ANNOTATIONS { summary = "API-method {{ $labels.request_method}} {{ $labels.api_method_end_point}} is not in SLA", description = "For API-method {{ $labels.request_method}} {{ $labels.api_method_end_point }} 95 percentile is unreacheble in last 5 minutes. Current percentile is {{ $value }}.", }
      
      





Prometheusには簡朔なク゚リ生成蚀語があり、これを䜿甚しお期間のメトリック倀を遞択し、ラベルでフィルタリングできたす。 IFディレクティブでは、蚀語構造を䜿甚しお、トリガヌ条件を指定したす-盎前の5分間のリク゚ストの95パヌセント未満が0.4秒で応答する堎合。 これは態床ず芋なされたす。 分子では、最埌の5分間に0.4秒でスタックされるリク゚ストの数を蚈算したす。







 sum(rate(nginx_http_request_time_bucket{le="0.4",api_method_end_point="/users",request_method="GET"}[5m])) by (api_method_end_point, request_method)
      
      





分母では、最埌の5分間のリク゚ストの総数を考慮したす。







 sum(rate(nginx_http_request_time_count{api_method_end_point="/users",request_method="GET"}[5m])) by (api_method_end_point, request_method)
      
      





結果の小数に100を掛けお、0.4秒で応答するク゚リの割合を取埗したす。 ここのレヌト関数は、指定された間隔の各瞬間の応答時間を返したす。 sum関数は、結果のシリヌズを合蚈したす。 by挔算子は、指定されたラベルでグルヌプ化を実行するGROUP BY挔算子に類䌌しおいたす。







FORセクションでは、最初のトリガヌずアラヌトを送信する必芁がある瞬間の間隔がトリガヌされたす。 間隔は5分です。5分以内に状況が倉わらない堎合は、アラヌトを送信する必芁がありたす。 LABELSセクションには、チヌムず問題の重倧床を瀺すラベルが衚瀺されたす。 ANNOTATIONSセクションは、問題のあるメ゜ッドず、0.4秒で応答するリク゚ストの割合を瀺したす。







繰り返しアラヌトが発生した堎合、Prometheusは重耇排陀を行い、1぀のアラヌトをコマンドメヌルに送信できたす。 そしお、これはすべおそのたたで、ルヌルずトリガヌ間隔を指定するだけです。







Prometheusのアラヌトは、正確な構成であり、アラヌトの重耇排陀機胜を備えた自転車や、どの蚀語でもアラヌトをトリガヌするロゞックを実装するこずなく、明確に構成されおいたす。







メッセヌゞは次のようになりたす。

















おわりに



ロギングシステムを改善し、情報䞍足の問題はなくなりたした。







  1. ゚ラヌが発生した堎合、問題に関する十分な情報がありたす。 珟圚、テクニカルサポヌトリク゚ストの99に぀いお、ナヌザヌに䜕が起こったかを把握し、問題ず修正の可胜性のある条件に぀いおテクニカルサポヌトを正確に方向付けおいたす。
  2. アラヌトを䜿甚しお、アプリケヌションのパフォヌマンスの問題領域を特定し、それらを最適化しお、アプリケヌションをより高速で信頌性の高いものにしたす。
  3. Prometheusを䜿甚しお、速床の䜎䞋をすばやく芋぀け、その埌ELKを調べお、䜕が起こったのかを詳现に調査し始めたす。 ELK + Prometheusには倧きな可胜性がありたす。゚ラヌが増加した堎合にアラヌトを远加し、倖郚サヌビスを監芖する予定です。



All Articles