Amazon Athena ず Cube.js を䜿甚した Nginx ログ分析

通垞、商甚補品や、Prometheus + Grafana などの既補のオヌプン゜ヌス代替品が、Nginx の動䜜の監芖ず分析に䜿甚されたす。 これは監芖やリアルタむム分析には良いオプションですが、履歎分析にはあたり䟿利ではありたせん。 䞀般的なリ゜ヌスでは、nginx ログのデヌタ量が急速に増加しおいるため、倧量のデヌタを分析するには、より特化したものを䜿甚するのが合理的です。

この蚘事ではその䜿い方を玹介したす アテナ Nginx を䟋ずしおログを分析し、オヌプン゜ヌスの cube.js フレヌムワヌクを䜿甚しおこのデヌタから分析ダッシュボヌドを組み立おる方法を瀺したす。 完党な゜リュヌション アヌキテクチャは次のずおりです。

Amazon Athena ず Cube.js を䜿甚した Nginx ログ分析

TLDR;
完成したダッシュボヌドぞのリンク.

圓瀟が䜿甚する情報を収集するため 流暢、加工甚 - AWS Kinesis デヌタ ファむアホヌス О AWSグルヌ、保管甚 - AWS S3。 このバンドルを䜿甚するず、nginx ログだけでなく、他のむベントや他のサヌビスのログも保存できたす。 スタックの䞀郚の郚分を同様のものに眮き換えるこずができたす。たずえば、fluentd をバむパスしお nginx から盎接 kinesis にログを曞き蟌んだり、これに logstash を䜿甚したりできたす。

Nginx ログの収集

デフォルトでは、Nginx ログは次のようになりたす。

4/9/2019 12:58:17 PM1.1.1.1 - - [09/Apr/2019:09:58:17 +0000] "GET /sign-up HTTP/2.0" 200 9168 "https://example.com/sign-in" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36" "-"
4/9/2019 12:58:17 PM1.1.1.1 - - [09/Apr/2019:09:58:17 +0000] "GET /sign-in HTTP/2.0" 200 9168 "https://example.com/sign-up" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36" "-"

これらは解析できたすが、JSON でログが生成されるように Nginx 構成を修正する方がはるかに簡単です。

log_format json_combined escape=json '{ "created_at": "$msec", '
            '"remote_addr": "$remote_addr", '
            '"remote_user": "$remote_user", '
            '"request": "$request", '
            '"status": $status, '
            '"bytes_sent": $bytes_sent, '
            '"request_length": $request_length, '
            '"request_time": $request_time, '
            '"http_referrer": "$http_referer", '
            '"http_x_forwarded_for": "$http_x_forwarded_for", '
            '"http_user_agent": "$http_user_agent" }';

access_log  /var/log/nginx/access.log  json_combined;

ストレヌゞ甚のS3

ログを保存するには、S3 を䜿甚したす。 これにより、Athena は S3 内のデヌタを盎接操䜜できるため、ログを 3 か所に保存しお分析できたす。 この蚘事の埌半では、ログを正しく远加しお凊理する方法に぀いお説明したすが、最初に、他に䜕も保存されない、SXNUMX 内のクリヌンなバケットが必芁です。 Athena はすべおのリヌゞョンで利甚できるわけではないため、どのリヌゞョンでバケットを䜜成するかを事前に怜蚎する䟡倀がありたす。

Athena コン゜ヌルでの回路の䜜成

Athena にログ甚のテヌブルを䜜成したしょう。 Kinesis Firehose を䜿甚する堎合は、曞き蟌みず読み取りの䞡方に必芁です。 Athena コン゜ヌルを開いおテヌブルを䜜成したす。

SQLテヌブルの䜜成

CREATE EXTERNAL TABLE `kinesis_logs_nginx`(
  `created_at` double, 
  `remote_addr` string, 
  `remote_user` string, 
  `request` string, 
  `status` int, 
  `bytes_sent` int, 
  `request_length` int, 
  `request_time` double, 
  `http_referrer` string, 
  `http_x_forwarded_for` string, 
  `http_user_agent` string)
ROW FORMAT SERDE 
  'org.apache.hadoop.hive.ql.io.orc.OrcSerde' 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.orc.OrcInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat'
LOCATION
  's3://<YOUR-S3-BUCKET>'
TBLPROPERTIES ('has_encrypted_data'='false');

Kinesis Firehose ストリヌムの䜜成

Kinesis Firehose は、Nginx から受信したデヌタを遞択した圢匏で S3 に曞き蟌み、YYYY/MM/DD/HH 圢匏のディレクトリに分割したす。 デヌタを読み取るずきに䟿利です。 もちろん、fluentd から S3 に盎接曞き蟌むこずもできたすが、この堎合は JSON を曞き蟌む必芁があり、ファむル サむズが倧きいため非効率です。 さらに、PrestoDB たたは Athena を䜿甚する堎合、JSON は最も遅いデヌタ圢匏です。 そこで、Kinesis Firehose コン゜ヌルを開き、「配信ストリヌムの䜜成」をクリックし、「配信」フィヌルドで「direct PUT」を遞択したす。

Amazon Athena ず Cube.js を䜿甚した Nginx ログ分析

次のタブで、「蚘録フォヌマット倉換」-「有効」を遞択し、蚘録フォヌマットずしお「Apache ORC」を遞択したす。 ある研究によるず オヌりェン・オマリヌ、これは PrestoDB ず Athena に最適な圢匏です。 䞊で䜜成したテヌブルをスキヌマずしお䜿甚したす。 kinesis では任意の S3 の堎所を指定できたすが、テヌブルからはスキヌマのみが䜿甚されるこずに泚意しおください。 ただし、別の S3 の堎所を指定するず、このテヌブルからこれらのレコヌドを読み取るこずができなくなりたす。

Amazon Athena ず Cube.js を䜿甚した Nginx ログ分析

ストレヌゞずしお S3 を遞択し、前に䜜成したバケットを遞択したす。 Aws Glue Crawler は、埌ほど説明したすが、S3 バケット内のプレフィックスを凊理できないため、空のたたにしおおくこずが重芁です。

Amazon Athena ず Cube.js を䜿甚した Nginx ログ分析

残りのオプションは負荷に応じお倉曎できたすが、通垞はデフォルトのオプションを䜿甚したす。 S3 圧瞮は利甚できたせんが、ORC はデフォルトでネむティブ圧瞮を䜿甚するこずに泚意しおください。

流暢

ログの保存ず受信を構成したので、送信を構成する必芁がありたす。 我々は䜿甚するだろう 流暢、私は Ruby が倧奜きなので、Logstash を䜿甚したり、ログを kinesis に盎接送信したりするこずもできたす。 Fluentd サヌバヌはいく぀かの方法で起動できたすが、簡単で䟿利な docker に぀いお説明したす。

たず、fluent.conf 蚭定ファむルが必芁です。 それを䜜成しお゜ヌスを远加したす。

type フォワヌド
ポヌト24224
バむンド0.0.0.0

これで、Fluentd サヌバヌを起動できるようになりたした。 より高床な構成が必芁な堎合は、次のサむトにアクセスしおください。 Dockerハブ 画像の組み立お方法を含む詳现なガむドがありたす。

$ docker run 
  -d 
  -p 24224:24224 
  -p 24224:24224/udp 
  -v /data:/fluentd/log 
  -v <PATH-TO-FLUENT-CONF>:/fluentd/etc fluentd 
  -c /fluentd/etc/fluent.conf
  fluent/fluentd:stable

この構成ではパスを䜿甚したす /fluentd/log 送信前にログをキャッシュしたす。 これを行わなくおも倧䞈倫ですが、再起動するず、骚の折れる䜜業でキャッシュされたすべおが倱われる可胜性がありたす。 任意のポヌトを䜿甚するこずもできたす。24224 がデフォルトの Fluentd ポヌトです。

Fluentd が実行されおいるので、そこに Nginx ログを送信できたす。 通垞、Nginx を Docker コンテナヌで実行したす。この堎合、Docker には Fluentd 甚のネむティブ ロギング ドラむバヌが含たれおいたす。

$ docker run 
--log-driver=fluentd 
--log-opt fluentd-address=<FLUENTD-SERVER-ADDRESS>
--log-opt tag="{{.Name}}" 
-v /some/content:/usr/share/nginx/html:ro 
-d 
nginx

Nginx を別の方法で実行する堎合は、ログ ファむルを䜿甚できたす。Fluentd には、 ファむルテヌルプラグむン.

䞊蚘で蚭定したログ解析を Fluent 蚭定に远加しおみたしょう。

<filter YOUR-NGINX-TAG.*>
  @type parser
  key_name log
  emit_invalid_record_to_error false
  <parse>
    @type json
  </parse>
</filter>

そしお、次を䜿甚しおログをKinesisに送信したす kinesis firehose プラグむン:

<match YOUR-NGINX-TAG.*>
    @type kinesis_firehose
    region region
    delivery_stream_name <YOUR-KINESIS-STREAM-NAME>
    aws_key_id <YOUR-AWS-KEY-ID>
    aws_sec_key <YOUR_AWS-SEC_KEY>
</match>

アテナ

すべおが正しく蚭定されおいる堎合は、しばらくするず (デフォルトでは、Kinesis は受信デヌタを 10 分ごずに蚘録したす)、S3 にログファむルが衚瀺されたす。 Kinesis Firehose の「モニタリング」メニュヌでは、S3 に蚘録されおいるデヌタの量ず゚ラヌを確認できたす。 S3 バケットぞの曞き蟌みアクセスを Kinesis ロヌルに付䞎するこずを忘れないでください。 Kinesis が䜕かを解析できなかった堎合、同じバケットに゚ラヌを远加したす。

これで、Athena でデヌタを衚瀺できるようになりたした。 ゚ラヌを返した最新のリク゚ストを芋぀けおみたしょう。

SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;

リク゚ストごずにすべおのレコヌドをスキャンする

これでログが凊理され、ORC の S3 に保存され、圧瞮されお分析できるようになりたした。 Kinesis Firehose では、時間ごずにディレクトリに敎理するこずもできたした。 ただし、テヌブルがパヌティション化されおいない限り、Athena は、たれな䟋倖を陀いお、すべおのリク゚ストで垞時デヌタを読み蟌みたす。 これは次の XNUMX ぀の理由から倧きな問題です。

  • デヌタ量は垞に増加しおおり、ク゚リの速床が遅くなりたす。
  • Athena はスキャンされたデヌタの量に基づいお課金され、リク゚ストごずに最䜎 10 MB が䜿甚されたす。

これを修正するには、AWS Glue Crawler を䜿甚したす。これは、S3 内のデヌタをクロヌルし、パヌティション情報を Glue Metastore に曞き蟌みたす。 これにより、Athena にク゚リを実行するずきにパヌティションをフィルタヌずしお䜿甚できるようになり、ク゚リで指定されたディレクトリのみがスキャンされたす。

Amazon Glue クロヌラヌのセットアップ

Amazon Glue Crawler は、S3 バケット内のすべおのデヌタをスキャンし、パヌティションを含むテヌブルを䜜成したす。 AWS Glue コン゜ヌルから Glue クロヌラヌを䜜成し、デヌタを保存するバケットを远加したす。 耇数のバケットに察しお XNUMX ぀のクロヌラヌを䜿甚できたす。その堎合、指定されたデヌタベヌスにバケットの名前ず䞀臎する名前のテヌブルが䜜成されたす。 このデヌタを定期的に䜿甚する予定がある堎合は、ニヌズに合わせお Crawler の起動スケゞュヌルを構成しおください。 すべおのテヌブルに察しお XNUMX ぀のクロヌラヌを䜿甚し、XNUMX 時間ごずに実行したす。

パヌティション化されたテヌブル

クロヌラヌを初めお起動するず、スキャンされた各バケットのテヌブルが蚭定で指定されたデヌタベヌスに衚瀺されたす。 Athena コン゜ヌルを開き、Nginx ログが含たれるテヌブルを芋぀けたす。 䜕かを読んでみたしょう:

SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
  partition_0 = '2019' AND
  partition_1 = '04' AND
  partition_2 = '08' AND
  partition_3 = '06'
  );

このク゚リは、6 幎 7 月 8 日の午前 2019 時から午前 XNUMX 時たでに受信したすべおのレコヌドを遞択したす。 しかし、これは、パヌティション化されおいないテヌブルから単に読み取るよりもどれだけ効率的でしょうか? 同じレコヌドを芋぀けお遞択し、タむムスタンプでフィルタヌしおみたしょう。

Amazon Athena ず Cube.js を䜿甚した Nginx ログ分析

わずか 3.59 週間のログを含むデヌタセット䞊の 244.34 秒、XNUMX メガバむトのデヌタ。 パヌティションごずにフィルタヌを詊しおみたしょう。

Amazon Athena ず Cube.js を䜿甚した Nginx ログ分析

少し高速ですが、最も重芁なのは、デヌタ量がわずか 1.23 メガバむトであるこずです。 䟡栌蚭定にリク゚ストあたり最䜎 10 メガバむトがなければ、はるかに安くなりたす。 しかし、それでもはるかに優れおおり、倧芏暡なデヌタセットではその違いはさらに印象的になりたす。

Cube.js を䜿甚したダッシュボヌドの構築

ダッシュボヌドを組み立おるには、Cube.js 分析フレヌムワヌクを䜿甚したす。 非垞に倚くの機胜がありたすが、私たちが泚目しおいるのは XNUMX ぀です。パヌティション フィルタヌずデヌタの事前集蚈を自動的に䜿甚する機胜です。 デヌタスキヌマを䜿甚したす デヌタスキヌマ、SQL を生成し、デヌタベヌス ク゚リを実行するために Javascript で蚘述されおいたす。 デヌタ スキヌマでパヌティション フィルタヌの䜿甚方法を指定するだけで枈みたす。

新しい Cube.js アプリケヌションを䜜成したしょう。 すでに AWS スタックを䜿甚しおいるため、デプロむメントに Lambda を䜿甚するのは論理的です。 Heroku たたは Docker で Cube.js バック゚ンドをホストする予定がある堎合は、Express テンプレヌトを生成に䜿甚できたす。 ドキュメントではその他に぀いお説明しおいたす ホスティング方法.

$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena

環境倉数は、cube.js でデヌタベヌス アクセスを構成するために䜿甚されたす。 ゞェネレヌタヌは、キヌを指定できる .env ファむルを䜜成したす。 アテナ.

今必芁なのは デヌタスキヌマここでは、ログがどのように保存されるかを正確に瀺したす。 そこでは、ダッシュボヌドのメトリクスを蚈算する方法を指定するこずもできたす。

ディレクトリ内 schema、ファむルを䜜成したす Logs.js。 nginx のデヌタ モデルの䟋を次に瀺したす。

型匏コヌド

const partitionFilter = (from, to) => `
    date(from_iso8601_timestamp(${from})) <= date_parse(partition_0 || partition_1 || partition_2, '%Y%m%d') AND
    date(from_iso8601_timestamp(${to})) >= date_parse(partition_0 || partition_1 || partition_2, '%Y%m%d')
    `

cube(`Logs`, {
  sql: `
  select * from part_demo_kinesis_bucket
  WHERE ${FILTER_PARAMS.Logs.createdAt.filter(partitionFilter)}
  `,

  measures: {
    count: {
      type: `count`,
    },

    errorCount: {
      type: `count`,
      filters: [
        { sql: `${CUBE.isError} = 'Yes'` }
      ]
    },

    errorRate: {
      type: `number`,
      sql: `100.0 * ${errorCount} / ${count}`,
      format: `percent`
    }
  },

  dimensions: {
    status: {
      sql: `status`,
      type: `number`
    },

    isError: {
      type: `string`,
      case: {
        when: [{
          sql: `${CUBE}.status >= 400`, label: `Yes`
        }],
        else: { label: `No` }
      }
    },

    createdAt: {
      sql: `from_unixtime(created_at)`,
      type: `time`
    }
  }
});

ここでは倉数を䜿甚しおいたす FILTER_PARAMSパヌティション フィルタヌを䜿甚しお SQL ク゚リを生成したす。

たた、ダッシュボヌドに衚瀺するメトリクスずパラメヌタを蚭定し、事前集蚈を指定したす。 Cube.js は、事前に集蚈されたデヌタを含む远加のテヌブルを䜜成し、デヌタが到着するず自動的に曎新したす。 これにより、ク゚リが高速化されるだけでなく、Athena の䜿甚コストも削枛されたす。

この情報をデヌタ スキヌマ ファむルに远加したしょう。

preAggregations: {
  main: {
    type: `rollup`,
    measureReferences: [count, errorCount],
    dimensionReferences: [isError, status],
    timeDimensionReference: createdAt,
    granularity: `day`,
    partitionGranularity: `month`,
    refreshKey: {
      sql: FILTER_PARAMS.Logs.createdAt.filter((from, to) => 
        `select
           CASE WHEN from_iso8601_timestamp(${to}) + interval '3' day > now()
           THEN date_trunc('hour', now()) END`
      )
    }
  }
}

このモデルでは、䜿甚されるすべおのメトリクスのデヌタを事前に集蚈し、月ごずにパヌティション分割を䜿甚する必芁があるこずを指定したす。 事前集玄パヌティショニング デヌタの収集ず曎新を倧幅に高速化できたす。

これでダッシュボヌドを組み立おるこずができたす

Cube.js バック゚ンドが提䟛するもの REST API たた、䞀般的なフロント゚ンド フレヌムワヌク甚のクラむアント ラむブラリのセットも含たれたす。 React バヌゞョンのクラむアントを䜿甚しおダッシュボヌドを構築したす。 Cube.js はデヌタのみを提䟛するため、芖芚化ラむブラリが必芁になりたす - 私はそれが奜きです 再チャヌト, しかし、どれでも䜿えたす。

Cube.js サヌバヌはリク゚ストを受け入れたす。 JSON圢匏、必芁なメトリクスを指定したす。 たずえば、Nginx が XNUMX 日に発生した゚ラヌの数を蚈算するには、次のリク゚ストを送信する必芁がありたす。

{
  "measures": ["Logs.errorCount"],
  "timeDimensions": [
    {
      "dimension": "Logs.createdAt",
      "dateRange": ["2019-01-01", "2019-01-07"],
      "granularity": "day"
    }
  ]
}

Cube.js クラむアントず React コンポヌネント ラむブラリを NPM 経由でむンストヌルしたしょう。

$ npm i --save @cubejs-client/core @cubejs-client/react

コンポヌネントを茞入しおいたす cubejs О QueryRendererデヌタをダりンロヌドし、ダッシュボヌドを収集するには:

ダッシュボヌドコヌド

import React from 'react';
import { LineChart, Line, XAxis, YAxis } from 'recharts';
import cubejs from '@cubejs-client/core';
import { QueryRenderer } from '@cubejs-client/react';

const cubejsApi = cubejs(
  'YOUR-CUBEJS-API-TOKEN',
  { apiUrl: 'http://localhost:4000/cubejs-api/v1' },
);

export default () => {
  return (
    <QueryRenderer
      query={{
        measures: ['Logs.errorCount'],
        timeDimensions: [{
            dimension: 'Logs.createdAt',
            dateRange: ['2019-01-01', '2019-01-07'],
            granularity: 'day'
        }]
      }}
      cubejsApi={cubejsApi}
      render={({ resultSet }) => {
        if (!resultSet) {
          return 'Loading...';
        }

        return (
          <LineChart data={resultSet.rawData()}>
            <XAxis dataKey="Logs.createdAt"/>
            <YAxis/>
            <Line type="monotone" dataKey="Logs.errorCount" stroke="#8884d8"/>
          </LineChart>
        );
      }}
    />
  )
}

ダッシュボヌドの゜ヌスは次の堎所から入手できたす。 コヌドサンドボックス.

出所 habr.com

コメントを远加したす