Nginx log greiningar með Amazon Athena og Cube.js

Venjulega eru auglýsingavörur eða tilbúnir opinn uppspretta valkostir, eins og Prometheus + Grafana, notaðar til að fylgjast með og greina rekstur Nginx. Þetta er góður kostur fyrir eftirlit eða rauntíma greiningu, en ekki mjög þægilegt fyrir sögulega greiningu. Á hvaða vinsælu auðlind sem er, eykst magn gagna úr nginx logs hratt og til að greina mikið magn af gögnum er rökrétt að nota eitthvað sérhæfðara.

Í þessari grein mun ég segja þér hvernig þú getur notað Athena til að greina annála, taka Nginx sem dæmi, og ég mun sýna hvernig á að setja saman greiningarmælaborð úr þessum gögnum með því að nota opinn uppspretta cube.js ramma. Hér er heildarlausnararkitektúrinn:

Nginx log greiningar með Amazon Athena og Cube.js

TL:DR;
Tengill á fullunnið mælaborð.

Til að safna upplýsingum sem við notum reiprennandi, til vinnslu - AWS Kinesis Data Firehose и AWS lím, til geymslu - AWS S3. Með því að nota þennan búnt geturðu geymt ekki aðeins nginx annála, heldur einnig aðra viðburði, sem og skrá yfir aðra þjónustu. Þú getur skipt út sumum hlutum fyrir svipaða fyrir stafla þinn, til dæmis geturðu skrifað logs í kinesis beint frá nginx, framhjá fluentd, eða notað logstash fyrir þetta.

Að safna Nginx annálum

Sjálfgefið er að Nginx logs líta eitthvað svona út:

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

Hægt er að flokka þær, en það er miklu auðveldara að leiðrétta Nginx stillinguna þannig að hún framleiði logs í 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 fyrir geymslu

Til að geyma logs munum við nota S3. Þetta gerir þér kleift að geyma og greina annála á einum stað, þar sem Athena getur unnið með gögn í S3 beint. Síðar í greininni mun ég segja þér hvernig á að bæta við og vinna úr annálum rétt, en fyrst þurfum við hreina fötu í S3, þar sem ekkert annað verður geymt. Það er þess virði að íhuga fyrirfram á hvaða svæði þú ætlar að búa til fötuna þína, því Athena er ekki í boði á öllum svæðum.

Að búa til hringrás í Athena stjórnborðinu

Búum til töflu í Aþenu fyrir annála. Það er nauðsynlegt bæði til að skrifa og lesa ef þú ætlar að nota Kinesis Firehose. Opnaðu Athena stjórnborðið og búðu til töflu:

SQL töflugerð

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');

Að búa til Kinesis Firehose Stream

Kinesis Firehose mun skrifa gögnin sem berast frá Nginx til S3 á völdu sniði og skipta þeim í möppur á YYYY/MM/DD/HH sniðinu. Þetta mun koma sér vel þegar gögn eru lesin. Þú getur auðvitað skrifað beint á S3 frá fluentd, en í þessu tilfelli þarftu að skrifa JSON og það er óhagkvæmt vegna þess hve skrárnar eru stórar. Að auki, þegar þú notar PrestoDB eða Athena, er JSON hægasta gagnasniðið. Svo opnaðu Kinesis Firehose stjórnborðið, smelltu á „Create delivery stream“, veldu „direct PUT“ í „afhending“ reitnum:

Nginx log greiningar með Amazon Athena og Cube.js

Í næsta flipa, veldu „Record format conversion“ - „Enabled“ og veldu „Apache ORC“ sem upptökusnið. Samkvæmt sumum rannsóknum Owen O'Malley, þetta er besta sniðið fyrir PrestoDB og Athena. Við notum töfluna sem við bjuggum til hér að ofan sem skema. Vinsamlegast athugaðu að þú getur tilgreint hvaða S3 staðsetningu sem er í kinesis; aðeins skemað er notað úr töflunni. En ef þú tilgreinir aðra S3 staðsetningu, þá muntu ekki geta lesið þessar færslur úr þessari töflu.

Nginx log greiningar með Amazon Athena og Cube.js

Við veljum S3 fyrir geymslu og fötuna sem við bjuggum til áðan. Aws Glue Crawler, sem ég mun tala um aðeins síðar, getur ekki virkað með forskeytum í S3 fötu, svo það er mikilvægt að hafa það tómt.

Nginx log greiningar með Amazon Athena og Cube.js

Hægt er að breyta þeim valmöguleikum sem eftir eru eftir álagi þínu; ég nota venjulega sjálfgefna. Athugaðu að S3 þjöppun er ekki tiltæk, en ORC notar sjálfgefið innbyggða þjöppun.

reiprennandi

Nú þegar við höfum stillt geymslu og móttöku annála þurfum við að stilla sendingu. Við munum nota reiprennandi, vegna þess að ég elska Ruby, en þú getur notað Logstash eða sent logs til kinesis beint. Fluent netþjóninn er hægt að ræsa á nokkra vegu, ég skal segja þér frá docker því hann er einfaldur og þægilegur.

Fyrst þurfum við fluent.conf stillingarskrána. Búðu til það og bættu við uppruna:

tegund áfram
höfn 24224
binda 0.0.0.0

Nú geturðu ræst Fluent netþjóninn. Ef þú þarft ítarlegri uppsetningu skaltu fara á Docker miðstöð Það er ítarleg leiðarvísir, þar á meðal hvernig á að setja saman myndina þína.

$ 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

Þessi uppsetning notar slóðina /fluentd/log til að vista annála fyrir sendingu. Þú getur verið án þessa, en svo þegar þú endurræsir geturðu tapað öllu sem er í skyndiminni með erfiðri vinnu. Þú getur líka notað hvaða höfn sem er; 24224 er sjálfgefið Fluentd tengi.

Nú þegar Fluent er í gangi getum við sent Nginx logs þangað. Við keyrum venjulega Nginx í Docker gámi, en í því tilviki er Docker með innfæddan skógarhöggsrekla fyrir 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

Ef þú keyrir Nginx öðruvísi geturðu notað log skrár, Fluentd hefur skráarhala viðbót.

Bætum loggreiningunni sem stillt er hér að ofan við Fluent stillinguna:

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

Og senda logs til Kinesis með því að nota kinesis firehose viðbót:

<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

Ef þú hefur stillt allt rétt, þá eftir smá stund (sjálfgefið, Kinesis skráir móttekin gögn einu sinni á 10 mínútna fresti) ættir þú að sjá annálsskrár í S3. Í „eftirlit“ valmyndinni á Kinesis Firehose geturðu séð hversu mikið af gögnum er skráð í S3, auk villna. Ekki gleyma að veita Kinesis hlutverkinu skrifaðgang að S3 fötunni. Ef Kinesis gæti ekki þáttað eitthvað mun það bæta villunum í sömu fötu.

Nú er hægt að skoða gögnin í Athena. Við skulum finna nýjustu beiðnirnar sem við skiluðum villum fyrir:

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

Skanna allar færslur fyrir hverja beiðni

Nú hafa annálar okkar verið unnar og geymdar í S3 í ORC, þjappaðar og tilbúnar til greiningar. Kinesis Firehose skipulagði þær jafnvel í möppur fyrir hverja klukkustund. Hins vegar, svo framarlega sem borðið er ekki skipt í skipting, mun Athena hlaða gögnum allra tíma á hverja beiðni, með sjaldgæfum undantekningum. Þetta er stórt vandamál af tveimur ástæðum:

  • Gagnamagn eykst stöðugt og hægir á fyrirspurnum;
  • Innheimt er fyrir Athena miðað við magn skannaðra gagna, að lágmarki 10 MB á beiðni.

Til að laga þetta notum við AWS Glue Crawler, sem mun skríða gögnin í S3 og skrifa skiptingarupplýsingarnar í Glue Metastore. Þetta gerir okkur kleift að nota skipting sem síu þegar spurt er um Athena, og það mun aðeins skanna möppurnar sem tilgreindar eru í fyrirspurninni.

Setja upp Amazon Glue Crawler

Amazon Glue Crawler skannar öll gögnin í S3 fötunni og býr til töflur með skiptingum. Búðu til Glue Crawler úr AWS Glue stjórnborðinu og bættu við fötu þar sem þú geymir gögnin. Þú getur notað einn skrið fyrir nokkrar fötur, í því tilviki mun hann búa til töflur í tilgreindum gagnagrunni með nöfnum sem passa við nöfnin á fötunum. Ef þú ætlar að nota þessi gögn reglulega, vertu viss um að stilla ræsingaráætlun Crawler til að henta þínum þörfum. Við notum einn Crawler fyrir öll borð, sem keyrir á klukkutíma fresti.

Skipt töflur

Eftir fyrstu ræsingu skriðans ættu töflur fyrir hverja skannaða fötu að birtast í gagnagrunninum sem tilgreindur er í stillingunum. Opnaðu Athena stjórnborðið og finndu borðið með Nginx logs. Við skulum reyna að lesa eitthvað:

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

Þessi fyrirspurn mun velja allar færslur sem berast á milli klukkan 6:7 og 8:2019 þann XNUMX. apríl XNUMX. En hversu miklu skilvirkara er þetta en bara að lesa úr óskiptu borði? Við skulum finna út og velja sömu færslurnar og sía þær eftir tímastimpli:

Nginx log greiningar með Amazon Athena og Cube.js

3.59 sekúndur og 244.34 megabæti af gögnum á gagnasafni með aðeins viku af annálum. Við skulum reyna að sía eftir skipting:

Nginx log greiningar með Amazon Athena og Cube.js

Aðeins hraðar, en síðast en ekki síst - aðeins 1.23 megabæti af gögnum! Það væri miklu ódýrara ef ekki væri fyrir lágmark 10 megabæti á beiðni í verðlagningunni. En það er samt miklu betra og á stórum gagnasöfnum verður munurinn miklu áhrifameiri.

Byggja mælaborð með Cube.js

Til að setja saman mælaborðið notum við Cube.js greiningarrammann. Það hefur töluvert af aðgerðum, en við höfum áhuga á tvennu: getu til að nota skiptingarsíur sjálfkrafa og gagnaforsöfnun. Það notar gagnaskema gagnaskema, skrifað í Javascript til að búa til SQL og framkvæma gagnagrunnsfyrirspurn. Við þurfum aðeins að gefa til kynna hvernig eigi að nota skiptingarsíuna í gagnaskemanu.

Búum til nýtt Cube.js forrit. Þar sem við erum nú þegar að nota AWS stafla er rökrétt að nota Lambda til dreifingar. Þú getur notað hraðsniðmátið fyrir kynslóð ef þú ætlar að hýsa Cube.js bakendann í Heroku eða Docker. Skjölin lýsa öðrum hýsingaraðferðir.

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

Umhverfisbreytur eru notaðar til að stilla aðgang að gagnagrunni í cube.js. Rafallinn mun búa til .env skrá þar sem þú getur tilgreint lyklana þína fyrir Athena.

Nú þurfum við gagnaskema, þar sem við munum tilgreina nákvæmlega hvernig annálarnir okkar eru geymdir. Þar geturðu líka tilgreint hvernig á að reikna út mælikvarða fyrir mælaborð.

Í möppu schema, búa til skrá Logs.js. Hér er dæmi um gagnalíkan fyrir nginx:

Fyrirmyndarkóði

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

Hér erum við að nota breytuna FILTER_PARAMStil að búa til SQL fyrirspurn með skiptingarsíu.

Við stillum einnig mæligildi og færibreytur sem við viljum birta á mælaborðinu og tilgreinum forsamsetningar. Cube.js mun búa til viðbótartöflur með fyrirfram samanlögðum gögnum og mun sjálfkrafa uppfæra gögnin þegar þau berast. Þetta flýtir ekki aðeins fyrir fyrirspurnum heldur dregur einnig úr kostnaði við notkun Athena.

Við skulum bæta þessum upplýsingum við gagnaskemaskrána:

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

Við tilgreinum í þessu líkani að nauðsynlegt sé að safna saman gögnum fyrir alla mælikvarða sem notuð eru og nota skiptingu eftir mánuðum. Forsöfnun skipting getur flýtt verulega fyrir gagnasöfnun og uppfærslu.

Nú getum við sett saman mælaborðið!

Cube.js bakendi veitir REST API og safn viðskiptavinabókasafna fyrir vinsæla framenda ramma. Við munum nota React útgáfuna af viðskiptavininum til að byggja upp mælaborðið. Cube.js veitir aðeins gögn, svo við þurfum sjónrænt bókasafn - mér líkar það endurupptökur, en þú getur notað hvaða sem er.

Cube.js þjónninn samþykkir beiðnina inn JSON sniði, sem tilgreinir nauðsynlegar mæligildi. Til dæmis, til að reikna út hversu margar villur Nginx gaf eftir dag, þarftu að senda eftirfarandi beiðni:

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

Við skulum setja upp Cube.js biðlarann ​​og React íhlutasafnið í gegnum NPM:

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

Við flytjum inn íhluti cubejs и QueryRenderertil að hlaða niður gögnunum og safna mælaborðinu:

Kóði mælaborðs

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

Heimildir mælaborðs eru fáanlegar á KóðiSandbox.

Heimild: www.habr.com

Bæta við athugasemd