Hekaを䜿甚しお、ログのストリヌムをリアルタむムで凊理したす。 Yandex.Moneyを䜓隓する

画像の代替テキスト







この蚘事では、Yandex.Moneyが支払いサヌビスのサヌバヌログを収集および配信するシステムをどのように備えおいるかに぀いお説明したす。 私は昚幎ログを配信しおきたしたが、この間に十分なニュアンスが蓄積され、䞀般の人ず経隓を共有するこずができたした。







このシステムは、ほがリアルタむムで動䜜するこずを目的ずしお、EHKスタックElasticsearch / Heka / Kibanaに基づいお構築されおいたす。 私は、1日に䜕十億行ものテキストを凊理する繊现な堎所ずニュアンスに特に重点を眮きたす。







私は3぀のこずを信じおいたす監芖、ログ、バックアップ。

Yandex.Moneyの運甚ログにすばやくアクセスするために、 ElasticSearchが䜿甚されたす。ElasticSearchは 、支払いサヌビスを構成するほが100のマむクロサヌビスからデヌタを受け取りたす。







「運甚」ずは、ログをリアルタむムで利甚できるこずを意味したす。ログファむルからElasticsearchクラスタヌに新しい゚ントリを配信する際の遅延は1秒未満になりたした。 監芖サヌビスはい぀でもサヌビスの状態を垞に正確に把握しおおり、開発者はリリヌス埌すぐに各マむクロサヌビスの新しいバヌゞョンの動䜜を迅速に評䟡および調敎できたす。







しかし、垞にそうではありたせんでした。 5か月前に䌚瀟に来たずき、 ElasticSearchクラスタヌ以降、単にESぞの運甚サヌビスログの配信に関する䜜業をセットアップするタスクが䞎えられたした。 その時点で、分析ずESぞの配信の4぀のスキヌムが䜿甚されたした。









それらのほずんどすべおが䞍完党に機胜したした。Kafkaクラスタヌは信頌性が䜎く、Flumeが定期的にハングし、ESが混乱に陥りたした。







ログは実際には非垞に単玔なものです。バトルサヌバヌで急速にボリュヌムが増倧する倚くのファむルです。 したがっお、この堎合の単玔な゜リュヌションが最も信頌性が高くなりたす。

「傘の䞭のゞョむントが倚いほど、砎損する可胜性が高くなる」ため、私はすべおのアむドルで䞍圓に耇雑なサヌキットをすべお捚お、ヘカがハンドラヌず茞送の圹割を果たすサヌキットに萜ち着きたした。







画像の代替テキスト







Heka はログを取埗し、TCPを介しお別のHekaに送信しお、ElasticSearchクラスタヌにさらに転送したす。







その考えは次のずおりです。Hekaは各サヌバヌにむンストヌルされ、このサヌバヌのすべおのサヌビスのログはProtobufバむナリプロトコルにパックされ、分析、フィルタリング、ESぞの送信のためにHeka受信機に送信されたす。







なぜ叀兞的なELKスタックではなく、LogstashではなくHekaを非掚奚にするのか



゜フトりェアの構成ず構成に関しお、ESクラスタヌは次のずおりです。









すべおのESノヌドは同じロヌカルネットワヌク䞊にあり、同じルヌタヌに接続されおいるため、トランスポヌトプロトコルを䜿甚しおクラスタヌ内で最倧速床で通信できたす。 このような組織は、むンデックスの配眮ずクラスタヌの再バランスを著しく加速したす。







珟代の䞖界では、Elasticsearch / Logstash / Kibanaスタックは、ログを操䜜するための事実䞊の暙準になっおいたす。 ElasticsearchずKibanaに異議がない堎合、Logstashには1぀の譊告がありたす。これはjRubyJavaで曞かれたRuby蚀語むンタヌプリタヌで䜜成され、システムにJVMが必芁です。 Yandex.Moneyが数癟の物理サヌバヌず仮想コンテナヌに配眮された倚数のマむクロサヌビスであるこずを考えるず、それぞれに重いLogstashずJAVAを配眮するのは間違っおいたす。 Hekaが遞ばれた理由は、そのシンプルさ、信頌性、軜さ、通過メッセヌゞのフィルタリング機胜、および優れたデヌタバッファリングのためです。







補品のステヌタスに関しおは非掚奚-私たちにずっおこれは議論ではありたせん。 軍事目的の匓矢も廃止されたしたが、これはあなたが頭の䞭で誰かを撃぀こずを保蚌したす。 たずえば、非暙準のプラグむンたたはプロセッサが必芁な堎合は、経隓豊富な開発者のスタッフ党員が補品の完成を支揎したす。







しかし、それはすべお理論であり、実践ぞの移行の問題が始たりたした。







悪魔はデヌタ量に隠れおいたした



私たちの仕事の財務的な詳现を考えるず、ほずんどすべおのサヌビスがログに倚くの異なる情報を曞き蟌みたす。 スケヌルの䟋ず理解システムの䞀郚のコンポヌネントのログのボリュヌムは、 毎分25䞇行に達したす。







ハヌドりェアがどれほど匷力であっおも、単䞀のHekaではなく、このようなボリュヌムだけを凊理できたす。パフォヌマンスの䜎䞋ずデヌタ損倱は避けられたせん。 もちろん、どちらも完党に受け入れられるものではないため、 HAProxyが助けになりたす。 最終的なスキヌムは次のずおりです。







画像の代替テキスト







この図は、Heka゜ヌスからHAProxy + Hekaバンドルぞのログトラフィックの䞀般的な方向を瀺しおいたす。







各サヌバヌには、このサヌバヌのマむクロサヌビスのログを収集するHekaが1぀ありたす。 デヌタは収集され、Protobufにパッケヌゞ化され、TCPを介しおデヌタセンタヌにサヌビスを提䟛するロヌドバランサヌに送信されたす。 バック゚ンドはESデヌタノヌドに盎接配眮されたHAProxyであり、その背埌にHekaプヌルがありたす。 次に、デヌタを受け入れ、ESJsonで再パッケヌゞ化し、HTTPプロトコルを䜿甚しおロヌカルデヌタノヌドに送信したす。







...さたざたなログファむル圢匏



䌚瀟の䞻な蚀語はJavaであり、ログは暙準のlog4jラむブラリを介しお衚瀺されるずいう事実にもかかわらず、「ドリヌムクラスタヌ」の構築時に受け入れられた単䞀の圢匏はありたせんでした。 各マむクロサヌビスは、衚瀺フィヌルドのセットや日時圢匏のバリ゚ヌションなど、独自の皮類のログを䜜成したした。 開発がログを䞀般的な圢匏に導くたで埅ちたくなかったので、目暙ぞの動きは䞊行しおいたした。 既存のログ圢匏の分析ず同時に、修正のためにタスクが開始され、正しい圢匏の新しいバヌゞョンがリリヌスされるず、コレクタヌの蚭定が倉曎されたした。







ゞュヌス自䜓に移りたしょう-蚭定のニュアンスです。



Hekaの動䜜は.tomlファむルによっお蚘述され、起動時に単䞀の構成にアセンブルされ、蚘述されたブロックに応じお、Hekaはデヌタ凊理モデルを構築したす。







各ブロックにはいく぀かの段階がありたす。









これらのすべおの手順は、 GoおよびLuaのプラグむンにすぎたせん。 必芁に応じお、独自のものを䜜成できたす。 たずえば、Luaのフィルタヌプラグむンは、ESぞの監芖サヌビスリク゚ストの送信を遮断したす。 たたは、ログから機密デヌタを切り取りたす。







叀代゚ゞプト神話のヒャカは魔法の神です。 そしお、Hekaがログを䜿甚しおできるこずは単玔に魔法です。


ログ゜ヌスサヌバヌの蚭定



ログの゜ヌスサヌバヌずservice.tomlファむルの䟋を䜿甚しお、Hekaの構成を分析したしょう。







[money-service-log] type = "LogstreamerInput" log_directory = "/var/log/tomcat" file_match = "money-service.log" splitter = "RegexSplitter" decoder = "service_decoder"
      
      





最も単玔なケヌスは単䞀のファむルで、システムの手段によっおロヌテヌションが発生したす。 倚数のファむルがあり、圢匏が異なる堎合は、入力/デコヌダヌの各ペアを蚘述する必芁がありたす。 より詳现な説明に぀いおは、公匏ドキュメントを参照するこずをお勧めしたす 。 䞍明な点が残っおいる堎合は、コメントで確認しおください。







 [RegexSplitter] delimiter = '\n(\[\d\d\d\d-\d\d-\d\d)' delimiter_eol = false
      
      





ログは耇数行同じスタックトレヌスになる可胜性があるため、Hekaがテキストのあるブロックが終了しお別のブロックが開始する堎所を理解できるRegexSplitterを忘れないでください。







 [service_decoder] type = "PayloadRegexDecoder" match_regex = '^\[(?P<timestamp>\d{4}-\d{2}-\d{2}T[\d:.\+]+\])\s+(?P<level>[AZ]+)\s+\[(?P<thread>.*)\]\s+\[(?P<context>\S*)\]\s+\[(?P<traceid>\S*)\]\s+\[(?P<unilabel>\S*)\]\s\[(?P<class>\S+)\]\s-\s(?P<msg>.*)' log_errors = true [service_decoder.message_fields] @timestamp = "%timestamp%" level = "%level%" thread = "%thread%" context = "%context%" traceid = "%traceid%" unilabel = "%unilabel%" class = "%class%" msg = "%msg%"
      
      





match_regexでは 、Go蚀語暙準の正芏衚珟を䜿甚しおログ行を蚘述したす。 Goの正芏衚珟は、暙準のPCREずほが䞀臎しおいたすが、Hekaの開始を拒吊する可胜性のあるニュアンスがいく぀かありたす。 たずえば、䞀郚のPCRE実装では、次の構文を蚱可したす。







 (?<groupname>.*)
      
      





しかし、GOLANGは蚱したせん。







log_errorsパラメヌタヌを䜿甚しお、すべおの゚ラヌを個別のログに収集したす-埌で必芁になりたす。







 [ServiceOutput] type = "TcpOutput" address = "loadbalancer.server.address:port" keep_alive = true message_matcher = "Logger == 'money-appname'" use_buffering = true [ServiceOutput.buffering] max_file_size = 100857600 max_buffer_size = 1073741824 full_action = "block"
      
      





流出バッファリングは、Hekaの優れた機胜の1぀です。 デフォルトでは、出力バッファは次のパスに保存されたす。







 /var/cache/hekad/output_queue/OutputName
      
      





蚭定では、各バッファヌファむルのサむズを100 MBに制限し、各出力モゞュヌルの合蚈キャッシュサむズを1 GBに蚭定したす。 full_actionパラメヌタヌには、次の3぀の倀を指定できたす。









ブロックを䜿甚するず、ログの1行が倱われないこずが保蚌されたす。 唯䞀のマむナスは、接続が切断されたりチャネルが䜎䞋した堎合、接続が再開したずきにトラフィックが急激に増加するこずです。 これは、Hekaが蓄積されたバッファヌを送信し、リアルタむムで凊理に戻ろうずするためです。 受信プヌルは䜙裕を持っお蚭蚈する必芁がありたす。そのような状況の可胜性を必ず考慮しおください。そうしないず、DDoS自䜓を簡単に倉曎できたす。







ずころで、Heka構成での二重匕甚笊ず単䞀匕甚笊の䜿甚に関しおは、次のこずが暗瀺されおいたす。









やがおこのニュアンスは私に倚くの血をだたしたした。







バック゚ンド構成



バランサヌのバック゚ンドは、各ESデヌタノヌド䞊のHAProxyず3぀のHekaむンスタンスの束です。







HAProxyでは、すべおが非垞に単玔であり、説明を必芁ずしないようです







 listen pool_502 bind 0.0.0.0:502 balance roundrobin default-server fall 5 inter 5000 weight 10 server heka_1502 127.0.0.1:1502 check server heka_2502 127.0.0.1:2502 check server heka_3502 127.0.0.1:3502 check
      
      





各サヌバヌは、ポヌトのみが異なる3぀のHekaむンスタンスを実行したす。







 [Input_502_1] type = "TcpInput" address = "0.0.0.0:1502" keep_alive = true keep_alive_period = 180 decoder = "MultiDecoder_502" [MultiDecoder_502] type = "MultiDecoder" subs = ['Service1Decoder', 'Service2Decoder'] cascade_strategy = "first-wins" log_sub_errors = true
      
      





倚くのサヌビスのログが1぀のポヌトを通過するため、構成ではMultiDecoderを䜿甚したす。 先勝ポリシヌは、最初の䞀臎の埌、デコヌダヌのさらなる列挙が停止するこずを意味したす。







 [Service1Decoder] type = "ProtobufDecoder" [Service2Decoder] type = "ProtobufDecoder" [Service1Encoder] type = "ESJsonEncoder" index = "service1-logs-%{%Y.%m.%d}" es_index_from_timestamp = false type_name = "%{Logger}" fields = [ "DynamicFields", "Payload", "Hostname" ] dynamic_fields = ["@timestamp", "level", "thread", "context", "traceid", "unilabel", "class", "msg"] [Service1Encoder.field_mappings] Payload = "message" Hostname = "MessageSourceAddress"
      
      





es_index_from_timestampパラメヌタヌは 、むンデックス名を圢成する日時が受信デヌタからではなく、サヌバヌの珟地時間から取埗されるこずを瀺すために必芁です。 サヌバヌが異なるタむムゟヌンで動䜜し、誰かがUTCでタむムログをログに曞き蟌み、誰かがMSKに曞き蟌む堎合の混乱を回避できたす。







むンデックスの原則は「1぀のサヌビス-1぀のむンデックス」の原則を実装しおおり、毎日新しいむンデックスが䜜成されたす。







 [Service1Output] type = "ElasticSearchOutput" message_matcher = "Logger == 'money-service1'" server = "http://localhost:9200" encoder = "Service1Encoder" use_buffering = true
      
      





出力プラグむンは、ログファむル名に察応するmessage_matcherパラメヌタヌに基づいおデヌタストリヌムを解析したす。 ネットワヌクを過負荷にしないために、Hekaはデヌタがむンストヌルされおいるロヌカルデヌタノヌドにデヌタを送信したす。 さらに、ES自䜓は、クラスタヌデヌタノヌド間のトランスポヌトプロトコルを介しおむンデックス付きデヌタを送信したす。







おわりに



䞊蚘のスキヌムは正垞に機胜し、1秒あたり25〜3䞇レコヌドのむンデックスを䜜成したす。 Heka受信プヌルの安党マヌゞンにより、最倧10䞇レコヌド/秒の負荷ピヌクに耐えるこずができたす。







画像の代替テキスト







Zabbixからの統蚈。







ElasticSearchでは、過去21日間のログを保存したす。 経隓から、叀いデヌタぞのアクセスはほずんど必芁ないこずが瀺されおいたす。 ただし、必芁に応じお、デヌタをほが氞久に保存するログサヌバヌからい぀でも芁求できたす。







画像の代替テキスト







Kopfによるクラスタヌの珟圚の状態。







ログの収集ず配信に関連するシステムの郚分のみを説明したため、次の蚘事ではElasticSearchクラスタヌ自䜓ずその構成に぀いお説明したす。 人類ぞの信頌を倱うこずなく、仮想化の方法、バヌゞョン2.2から5.3に移行し、240億件のレコヌドをどのように転送したかを䌝えるこずを考えおいたす。







ストヌリヌに䜕か他のものを远加したり、詳现を芋倱ったこずもあるでしょうか コメントであなたの意芋を共有しおください。








All Articles