Nginx log analytics bl-użu ta 'Amazon Athena u Cube.js

Tipikament, prodotti kummerċjali jew alternattivi open-source lesti, bħal Prometheus + Grafana, jintużaw biex jimmonitorjaw u janalizzaw l-operat ta 'Nginx. Din hija għażla tajba għall-monitoraġġ jew l-analiżi f'ħin reali, iżda mhux konvenjenti ħafna għall-analiżi storika. Fuq kwalunkwe riżors popolari, il-volum ta 'dejta minn zkuk nginx qed jikber malajr, u biex tanalizza ammont kbir ta' dejta, huwa loġiku li tuża xi ħaġa aktar speċjalizzata.

F'dan l-artikolu ser ngħidlek kif tista 'tuża Athena biex tanalizza zkuk, billi tieħu Nginx bħala eżempju, u ser nuri kif tiġbor dashboard analitiku minn din id-dejta billi tuża l-qafas open-source cube.js. Hawnhekk hawn l-arkitettura sħiħa tas-soluzzjoni:

Nginx log analytics bl-użu ta 'Amazon Athena u Cube.js

TL:DR;
Link għad-dashboard lest.

Biex niġbru informazzjoni li nużaw fluentd, għall-ipproċessar - AWS Kinesis Data Firehose и Kolla AWS, għall-ħażna - AWS S3. Billi tuża dan il-pakkett, tista 'taħżen mhux biss zkuk nginx, iżda wkoll avvenimenti oħra, kif ukoll zkuk ta' servizzi oħra. Tista 'tissostitwixxi xi partijiet ma' oħrajn simili għall-munzell tiegħek, pereżempju, tista 'tikteb zkuk għal kinesis direttament minn nginx, billi tevita fluentd, jew tuża logstash għal dan.

Ġbir ta 'zkuk Nginx

B'mod awtomatiku, zkuk Nginx jidhru xi ħaġa bħal din:

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" "-"

Jistgħu jiġu analizzati, iżda huwa ħafna aktar faċli li tikkoreġi l-konfigurazzjoni Nginx sabiex tipproduċi zkuk f'JSON:

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 għall-ħażna

Biex naħżnu zkuk, se nużaw S3. Dan jippermettilek taħżen u tanalizza zkuk f'post wieħed, peress li Athena tista 'taħdem bid-dejta f'S3 direttament. Aktar tard fl-artikolu ser ngħidlek kif iżżid u tipproċessa zkuk b'mod korrett, iżda l-ewwel neħtieġu barmil nadif f'S3, li fih ma jinħażen xejn aktar. Ta' min tikkunsidra minn qabel f'liema reġjun se tkun qed toħloq il-barmil tiegħek, għaliex Athena mhix disponibbli fir-reġjuni kollha.

Ħolqien ta 'ċirkwit fil-console Athena

Ejja noħolqu tabella f'Athena għal zkuk. Huwa meħtieġ kemm għall-kitba kif ukoll għall-qari jekk qed tippjana li tuża Kinesis Firehose. Iftaħ il-console Athena u oħloq tabella:

Ħolqien ta' tabella 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');

Ħolqien Kinesis Firehose Stream

Kinesis Firehose se jikteb id-dejta riċevuta minn Nginx għal S3 fil-format magħżul, u jaqsamha f'direttorji fil-format YYYY/MM/DD/HH. Dan se jkun utli meta taqra d-dejta. Tista', ovvjament, tikteb direttament lil S3 minn fluentd, iżda f'dan il-każ ikollok tikteb JSON, u dan huwa ineffiċjenti minħabba d-daqs kbir tal-fajls. Barra minn hekk, meta tuża PrestoDB jew Athena, JSON huwa l-aktar format tad-dejta bil-mod. Allura tiftaħ il-console Kinesis Firehose, ikklikkja "Oħloq fluss ta 'kunsinna", agħżel "PUT dirett" fil-qasam "kunsinna":

Nginx log analytics bl-użu ta 'Amazon Athena u Cube.js

Fit-tab li jmiss, agħżel "Record format conversion" - "Enabled" u agħżel "Apache ORC" bħala l-format tar-reġistrazzjoni. Skond xi riċerka Owen O'Malley, dan huwa l-aħjar format għal PrestoDB u Athena. Aħna nużaw it-tabella li ħloqna hawn fuq bħala skema. Jekk jogħġbok innota li tista 'tispeċifika kwalunkwe post S3 f'kinesis biss l-iskema hija użata mit-tabella. Imma jekk tispeċifika post S3 differenti, allura ma tkunx tista' taqra dawn ir-rekords minn din it-tabella.

Nginx log analytics bl-użu ta 'Amazon Athena u Cube.js

Aħna nagħżlu S3 għall-ħażna u l-barmil li ħloqna qabel. Aws Glue Crawler, li se nitkellem dwaru ftit aktar tard, ma jistax jaħdem bi prefissi f'barmil S3, għalhekk huwa importanti li tħallih vojt.

Nginx log analytics bl-użu ta 'Amazon Athena u Cube.js

L-għażliet li jifdal jistgħu jinbidlu skont it-tagħbija tiegħek normalment nuża dawk default. Innota li l-kompressjoni S3 mhix disponibbli, iżda ORC juża kompressjoni nattiva b'mod awtomatiku.

fluentd

Issa li kkonfigurajna l-ħażna u r-riċeviment ta' zkuk, irridu nikkonfiguraw li tibgħat. Aħna se nużaw fluentd, għax inħobb Ruby, imma tista' tuża Logstash jew tibgħat zkuk lil kinesis direttament. Is-server Fluentd jista 'jiġi mniedi b'diversi modi, jien ngħidlek dwar docker għax huwa sempliċi u konvenjenti.

L-ewwel, għandna bżonn il-fajl tal-konfigurazzjoni fluent.conf. Oħloqha u żid is-sors:

tip quddiem
port 24224
jorbot 0.0.0.0

Issa tista 'tibda s-server Fluentd. Jekk għandek bżonn konfigurazzjoni aktar avvanzata, mur fuq Ċentru tad-Docker Hemm gwida dettaljata, inkluż kif tiġbor l-immaġni tiegħek.

$ 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

Din il-konfigurazzjoni tuża l-mogħdija /fluentd/log għall-cache zkuk qabel ma tibgħat. Tista 'tagħmel mingħajr dan, iżda mbagħad meta terġa' tibda, tista 'titlef kollox fil-cache b'xogħol li jkisser id-dahar. Tista 'wkoll tuża kwalunkwe port 24224 huwa l-port Fluentd default.

Issa li għandna Fluentd qed jaħdem, nistgħu nibagħtu zkuk Nginx hemmhekk. Normalment inħaddmu Nginx f'kontenitur Docker, f'liema każ Docker għandu sewwieq ta 'logging indiġeni għal 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

Jekk tmexxi Nginx b'mod differenti, tista 'tuża log files, Fluentd għandu plugin tad-denb tal-fajl.

Ejja nżidu l-parsing tal-log konfigurat hawn fuq mal-konfigurazzjoni Fluwenti:

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

U tibgħat zkuk lil Kinesis bl-użu plugin 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>

Athena

Jekk ikkonfigurajt kollox b'mod korrett, imbagħad wara xi żmien (b'mod awtomatiku, Kinesis jirrekordja d-dejta riċevuta darba kull 10 minuti) għandek tara fajls tal-ġurnal f'S3. Fil-menu ta '"monitoraġġ" ta' Kinesis Firehose tista 'tara kemm hija rreġistrata dejta f'S3, kif ukoll żbalji. Tinsiex li tagħti aċċess għall-kitba għall-barmil S3 għar-rwol Kinesis. Jekk Kinesis ma setgħetx parse xi ħaġa, se żżid l-iżbalji fl-istess barmil.

Issa tista 'tara d-dejta f'Athena. Ejja nsibu l-aħħar talbiet li għalihom irritornajna żbalji:

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

Skannjar tar-rekords kollha għal kull talba

Issa zkuk tagħna ġew ipproċessati u maħżuna f'S3 f'ORC, ikkompressati u lesti għall-analiżi. Kinesis Firehose saħansitra organizzahom f'direttorji għal kull siegħa. Madankollu, sakemm it-tabella ma tkunx maqsuma, Athena se tgħabbi d-dejta ta 'kull żmien fuq kull talba, b'eċċezzjonijiet rari. Din hija problema kbira għal żewġ raġunijiet:

  • Il-volum tad-dejta qed jikber kontinwament, u jnaqqas il-mistoqsijiet;
  • Athena tiġi ffatturata abbażi tal-volum ta' dejta skanjata, b'minimu ta' 10 MB għal kull talba.

Biex nirranġaw dan, nużaw AWS Glue Crawler, li se jitkaxkru d-dejta f'S3 u jikteb l-informazzjoni tal-partizzjoni fil-Glue Metastore. Dan se jippermettilna nużaw diviżorji bħala filtru meta nistaqsu lil Athena, u se tiskennja biss id-direttorji speċifikati fil-mistoqsija.

Twaqqif ta' Amazon Glue Crawler

Amazon Glue Crawler tiskennja d-dejta kollha fil-barmil S3 u toħloq tabelli b'diviżorji. Oħloq Glue Crawler mill-console AWS Glue u żid barmil fejn taħżen id-dejta. Tista 'tuża crawler wieħed għal diversi bramel, f'liema każ se toħloq tabelli fid-database speċifikata b'ismijiet li jaqblu mal-ismijiet tal-bramel. Jekk qed tippjana li tuża din id-dejta regolarment, kun żgur li tikkonfigura l-iskeda tat-tnedija ta' Crawler biex taqbel mal-bżonnijiet tiegħek. Aħna nużaw Crawler wieħed għat-tabelli kollha, li jimxi kull siegħa.

Imwejjed maqsuma

Wara l-ewwel tnedija tat-tkaxkir, it-tabelli għal kull barmil skennjat għandhom jidhru fid-database speċifikata fis-settings. Iftaħ il-console Athena u sib it-tabella bi zkuk Nginx. Ejja nippruvaw naqraw xi ħaġa:

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

Din il-mistoqsija se tagħżel ir-rekords kollha riċevuti bejn is-6 a.m. u s-7 a.m. fit-8 ta’ April, 2019. Imma kemm huwa aktar effiċjenti dan milli sempliċiment qari minn tabella mhux diviżorja? Ejja nsiru nafu u agħżel l-istess rekords, billi niffiltrawhom skont it-timbru tal-ħin:

Nginx log analytics bl-użu ta 'Amazon Athena u Cube.js

3.59 sekondi u 244.34 megabytes ta' data fuq dataset b'ġimgħa biss ta' zkuk. Ejja nippruvaw filtru skond il-partizzjoni:

Nginx log analytics bl-użu ta 'Amazon Athena u Cube.js

Ftit aktar mgħaġġla, iżda l-aktar importanti - 1.23 megabytes biss ta 'dejta! Ikun ferm irħas jekk mhux għall-minimu ta '10 megabytes għal kull talba fl-ipprezzar. Iżda xorta huwa ferm aħjar, u fuq settijiet ta 'dejta kbar id-differenza se tkun ħafna aktar impressjonanti.

Bini ta' dashboard bl-użu ta' Cube.js

Biex tgħaqqad id-dashboard, nużaw il-qafas analitiku Cube.js. Għandu ħafna funzjonijiet, iżda aħna interessati f'żewġ: il-kapaċità li nużaw awtomatikament filtri tal-partizzjoni u pre-aggregazzjoni tad-dejta. Hija tuża data schema skema tad-data, miktuba bil-Javascript biex tiġġenera SQL u tesegwixxi mistoqsija tad-database. Għandna bżonn biss li nindikaw kif tuża l-filtru tal-partizzjoni fl-iskema tad-dejta.

Ejja noħolqu applikazzjoni Cube.js ġdida. Peress li diġà qed nużaw il-munzell AWS, huwa loġiku li nużaw Lambda għall-iskjerament. Tista 'tuża l-mudell espress għall-ġenerazzjoni jekk qed tippjana li tospita l-backend ta' Cube.js f'Heroku jew Docker. Id-dokumentazzjoni tiddeskrivi oħrajn metodi ta' akkoljenza.

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

Il-varjabbli tal-ambjent jintużaw biex jiġi kkonfigurat l-aċċess tad-database f'cube.js. Il-ġeneratur se joħloq fajl .env li fih tista 'tispeċifika ċ-ċwievet tiegħek għal Athena.

Issa għandna bżonn skema tad-data, li fiha se nindikaw eżattament kif inħażnu z-zkuk tagħna. Hemmhekk tista' wkoll tispeċifika kif tikkalkula l-metriċi għad-dashboards.

Fid-direttorju schema, oħloq fajl Logs.js. Hawn hu eżempju ta’ mudell ta’ data għal nginx:

Kodiċi tal-mudell

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`
    }
  }
});

Hawnhekk qed nużaw il-varjabbli FILTER_PARAMSbiex tiġġenera mistoqsija SQL b'filtru ta' partizzjoni.

Aħna nissettjaw ukoll il-metriċi u l-parametri li rridu nuru fuq id-dashboard u nispeċifikaw pre-aggregazzjonijiet. Cube.js se joħloq tabelli addizzjonali b'dejta aggregata minn qabel u awtomatikament jaġġorna d-dejta hekk kif tasal. Dan mhux biss iħaffef il-mistoqsijiet, iżda jnaqqas ukoll l-ispiża tal-użu ta 'Athena.

Ejja nżidu din l-informazzjoni mal-fajl tal-iskema tad-dejta:

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`
      )
    }
  }
}

Aħna nispeċifikaw f'dan il-mudell li huwa meħtieġ li d-dejta tiġi aggregata minn qabel għall-metriċi kollha użati, u nużaw il-qsim skond ix-xahar. Tqassim ta' qabel l-aggregazzjoni jista' jħaffef b'mod sinifikanti l-ġbir u l-aġġornament tad-dejta.

Issa nistgħu niġbru d-dashboard!

Backend Cube.js jipprovdi SERĦAN API u sett ta 'libreriji tal-klijenti għal oqfsa front-end popolari. Aħna se nużaw il-verżjoni React tal-klijent biex nibnu d-dashboard. Cube.js jipprovdi biss data, għalhekk ikollna bżonn librerija ta' viżwalizzazzjoni - jogħġobni recharts, imma tista' tuża kwalunkwe.

Is-server Cube.js jaċċetta t-talba fil Format JSON, li jispeċifika l-metriċi meħtieġa. Pereżempju, biex tikkalkula kemm Nginx ta żbalji kuljum, trid tibgħat it-talba li ġejja:

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

Ejja ninstallaw il-klijent Cube.js u l-librerija tal-komponenti React permezz tal-NPM:

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

Aħna importazzjoni komponenti cubejs и QueryRendererbiex tniżżel id-dejta, u tiġbor id-dashboard:

Kodiċi tad-dashboard

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>
        );
      }}
    />
  )
}

Is-sorsi tad-dashboard huma disponibbli fuq kodiċi sandbox.

Sors: www.habr.com

Żid kumment