Nginx žurnāla analītika, izmantojot Amazon Athena un Cube.js

Parasti Nginx darbības uzraudzībai un analīzei tiek izmantoti komerciāli produkti vai gatavas atvērtā pirmkoda alternatīvas, piemēram, Prometheus + Grafana. Šī ir laba iespēja uzraudzībai vai reāllaika analīzei, taču ne pārāk ērta vēsturiskai analīzei. Jebkurā populārajā resursā nginx žurnālu datu apjoms strauji pieaug, un, lai analizētu lielu datu apjomu, ir loģiski izmantot kaut ko specializētāku.

Å ajā rakstā es jums pastāstÄ«Å”u, kā jÅ«s varat izmantot Athena lai analizētu žurnālus, kā piemēru ņemot Nginx, un es parādÄ«Å”u, kā no Å”iem datiem izveidot analÄ«tisko informācijas paneli, izmantojot atvērtā koda cube.js ietvaru. Å eit ir visa risinājuma arhitektÅ«ra:

Nginx žurnāla analītika, izmantojot Amazon Athena un Cube.js

TL:DR;
Saite uz gatavo informācijas paneli.

Lai apkopotu informāciju, ko mēs izmantojam tekoÅ”i, apstrādei - AWS Kinesis Data Firehose Šø AWS lÄ«me, uzglabāŔanai - AWS S3. Izmantojot Å”o komplektu, varat saglabāt ne tikai nginx žurnālus, bet arÄ« citus notikumus, kā arÄ« citu pakalpojumu žurnālus. Dažas daļas varat aizstāt ar lÄ«dzÄ«gām jÅ«su steka daļām, piemēram, varat rakstÄ«t žurnālus kinesis tieÅ”i no nginx, apejot fluentd, vai Å”im nolÅ«kam izmantot logstash.

Nginx žurnālu vākŔana

Pēc noklusējuma Nginx žurnāli izskatās Ŕādi:

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

Tos var parsēt, taču ir daudz vieglāk labot Nginx konfigurāciju, lai tā izveidotu žurnālus 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 uzglabāŔanai

Lai saglabātu žurnālus, mēs izmantosim S3. Tas ļauj glabāt un analizēt žurnālus vienuviet, jo Athena var tieÅ”i strādāt ar datiem S3. Vēlāk rakstā es jums pastāstÄ«Å”u, kā pareizi pievienot un apstrādāt žurnālus, taču vispirms mums ir nepiecieÅ”ams tÄ«rs S3 spainis, kurā nekas cits netiks saglabāts. Ir vērts iepriekÅ” apsvērt, kurā reÄ£ionā veidosit savu spaini, jo Athena nav pieejams visos reÄ£ionos.

Ķēdes izveide Athena konsolē

Atēnās izveidosim tabulu žurnāliem. Tas ir nepiecieÅ”ams gan rakstÄ«Å”anai, gan lasÄ«Å”anai, ja plānojat izmantot Kinesis Firehose. Atveriet Athena konsoli un izveidojiet tabulu:

SQL tabulas izveide

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 Stream izveide

Kinesis Firehose no Nginx saņemtos datus ierakstÄ«s uz S3 izvēlētajā formātā, sadalot tos direktorijās GGGG/MM/DD/HH formātā. Tas noderēs, lasot datus. JÅ«s, protams, varat rakstÄ«t tieÅ”i uz S3 no fluentd, taču Å”ajā gadÄ«jumā jums bÅ«s jāraksta JSON, un tas ir neefektÄ«vi failu lielā izmēra dēļ. Turklāt, izmantojot PrestoDB vai Athena, JSON ir lēnākais datu formāts. Tātad atveriet Kinesis Firehose konsoli, noklikŔķiniet uz "Izveidot piegādes straumi", laukā "piegāde" atlasiet "tieÅ”ais PUT":

Nginx žurnāla analītika, izmantojot Amazon Athena un Cube.js

Nākamajā cilnē atlasiet ā€œIeraksta formāta konvertÄ“Å”anaā€ - ā€œIespējotsā€ un kā ierakstÄ«Å”anas formātu atlasiet ā€œApache ORCā€. Saskaņā ar dažiem pētÄ«jumiem Ouens O'Malijs, tas ir optimālais formāts PrestoDB un Athena. Mēs izmantojam iepriekÅ” izveidoto tabulu kā shēmu. LÅ«dzu, ņemiet vērā, ka kinēzē varat norādÄ«t jebkuru S3 atraÅ”anās vietu; no tabulas tiek izmantota tikai shēma. Bet, ja norādāt citu S3 atraÅ”anās vietu, jÅ«s nevarēsit nolasÄ«t Å”os ierakstus no Ŕīs tabulas.

Nginx žurnāla analītika, izmantojot Amazon Athena un Cube.js

Mēs izvēlamies S3 glabāŔanai un iepriekÅ” izveidoto spaini. Aws Glue Crawler, par kuru es runāŔu nedaudz vēlāk, nevar strādāt ar prefiksiem S3 spainÄ«, tāpēc ir svarÄ«gi atstāt to tukÅ”u.

Nginx žurnāla analītika, izmantojot Amazon Athena un Cube.js

Pārējās opcijas var mainÄ«t atkarÄ«bā no slodzes; es parasti izmantoju noklusējuma opcijas. Ņemiet vērā, ka S3 saspieÅ”ana nav pieejama, bet ORC pēc noklusējuma izmanto sākotnējo saspieÅ”anu.

tekoŔi

Tagad, kad esam konfigurējuÅ”i žurnālu glabāŔanu un saņemÅ”anu, mums ir jākonfigurē sÅ«tÄ«Å”ana. Mēs izmantosim tekoÅ”i, jo es mÄ«lu Ruby, bet jÅ«s varat izmantot Logstash vai nosÅ«tÄ«t žurnālus tieÅ”i uz kinesis. Fluentd serveri var palaist vairākos veidos, es jums pastāstÄ«Å”u par docker, jo tas ir vienkārÅ”i un ērti.

Pirmkārt, mums ir nepiecieŔams konfigurācijas fails fluent.conf. Izveidojiet to un pievienojiet avotu:

tips uz priekŔu
port 24224
saistīt 0.0.0.0

Tagad varat palaist Fluentd serveri. Ja jums nepiecieÅ”ama papildu konfigurācija, dodieties uz Dokera centrmezgls Ir detalizēts ceļvedis, tostarp, kā salikt attēlu.

$ 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

Å ajā konfigurācijā tiek izmantots ceļŔ /fluentd/log keÅ”atmiņā saglabāt žurnālus pirms nosÅ«tÄ«Å”anas. JÅ«s varat iztikt bez Ŕī, taču, restartējot, varat zaudēt visu, kas ir saglabāts keÅ”atmiņā, ko izraisa aizkavējoÅ”s darbs. Varat arÄ« izmantot jebkuru portu; 24224 ir noklusējuma Fluentd ports.

Tagad, kad darbojas Fluentd, mēs varam tur nosÅ«tÄ«t Nginx žurnālus. Mēs parasti palaižam Nginx Docker konteinerā, un tādā gadÄ«jumā Docker ir vietējais Fluentd reÄ£istrÄ“Å”anas draiveris:

$ 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

Ja palaižat Nginx citādi, varat izmantot žurnālfailus, ko piedāvā Fluentd faila astes spraudnis.

Pievienosim iepriekÅ” konfigurēto žurnāla parsÄ“Å”anu Fluent konfigurācijai:

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

Un žurnālu nosūtīŔana uz Kinesis, izmantojot kinesis firehose spraudnis:

<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

Ja esat visu pareizi konfigurējis, tad pēc kāda laika (pēc noklusējuma Kinesis reÄ£istrē saņemtos datus reizi 10 minÅ«tēs) jums vajadzētu redzēt žurnāla failus S3. Kinesis Firehose izvēlnē ā€œUzraudzÄ«baā€ varat redzēt, cik daudz datu ir ierakstÄ«ts S3, kā arÄ« kļūdas. Neaizmirstiet pieŔķirt Kinesis lomai rakstÄ«Å”anas piekļuvi S3 spainim. Ja Kinesis nevarēja kaut ko parsēt, tas pievienos kļūdas tam paÅ”am segmentam.

Tagad jūs varat skatīt datus pakalpojumā Atēna. Atradīsim jaunākos pieprasījumus, par kuriem atgriezām kļūdas:

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

Skenē visus ierakstus katram pieprasījumam

Tagad mūsu žurnāli ir apstrādāti un saglabāti S3 ORC, saspiesti un gatavi analīzei. Kinesis Firehose pat organizēja tos direktorijos katrai stundai. Tomēr, kamēr tabula nav sadalīta, Athena ielādēs visu laiku datus par katru pieprasījumu, ar retiem izņēmumiem. Tā ir liela problēma divu iemeslu dēļ:

  • Datu apjoms nepārtraukti pieaug, palēninot vaicājumus;
  • Maksa par Athena tiek iekasēta, pamatojoties uz skenēto datu apjomu, vismaz 10 MB vienam pieprasÄ«jumam.

Lai to novērstu, mēs izmantojam AWS Glue Crawler, kas pārmeklēs datus S3 un ierakstīs nodalījuma informāciju Glue metastore. Tas ļaus mums izmantot nodalījumus kā filtru, veicot vaicājumu Athena, un tas skenēs tikai vaicājumā norādītos direktorijus.

Amazon Glue Crawler iestatīŔana

Amazon Glue Crawler skenē visus S3 spainÄ« esoÅ”os datus un izveido tabulas ar nodalÄ«jumiem. Izveidojiet Glue Crawler no AWS Glue konsoles un pievienojiet spaini, kurā glabājat datus. Varat izmantot vienu rāpuļprogrammu vairākiem segmentiem, un tādā gadÄ«jumā tas izveidos tabulas norādÄ«tajā datu bāzē ar nosaukumiem, kas atbilst segmentu nosaukumiem. Ja plānojat regulāri izmantot Å”os datus, noteikti konfigurējiet rāpuļprogrammas palaiÅ”anas grafiku atbilstoÅ”i savām vajadzÄ«bām. Mēs izmantojam vienu rāpuļprogrammu visiem galdiem, kas darbojas katru stundu.

Sadalītas tabulas

Pēc pirmās rāpuļprogrammas palaiÅ”anas iestatÄ«jumos norādÄ«tajā datu bāzē jāparādās katra skenētā segmenta tabulām. Atveriet Athena konsoli un atrodiet tabulu ar Nginx žurnāliem. Mēģināsim kaut ko izlasÄ«t:

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

Å ajā vaicājumā tiks atlasÄ«ti visi ieraksti, kas saņemti no 6. gada 7. aprīļa plkst. 8:2019 lÄ«dz plkst. XNUMX:XNUMX. Bet cik daudz efektÄ«vāk tas ir nekā tikai lasÄ«Å”ana no nesadalÄ«tas tabulas? Noskaidrosim un atlasÄ«sim tos paÅ”us ierakstus, filtrējot tos pēc laikspiedola:

Nginx žurnāla analītika, izmantojot Amazon Athena un Cube.js

3.59 sekundes un 244.34 megabaiti datu datu kopā ar tikai nedēļas žurnāliem. Izmēģināsim filtru pēc nodalÄ«juma:

Nginx žurnāla analītika, izmantojot Amazon Athena un Cube.js

Nedaudz ātrāk, bet pats galvenais ā€“ tikai 1.23 megabaiti datu! Tas bÅ«tu daudz lētāk, ja ne minimālie 10 megabaiti vienam pieprasÄ«jumam cenā. Bet tas joprojām ir daudz labāks, un lielās datu kopās atŔķirÄ«ba bÅ«s daudz iespaidÄ«gāka.

Informācijas paneļa izveide, izmantojot Cube.js

Lai saliktu informācijas paneli, mēs izmantojam Cube.js analÄ«tisko sistēmu. Tam ir diezgan daudz funkciju, taču mÅ«s interesē divas: iespēja automātiski izmantot nodalÄ«jumu filtrus un datu iepriekŔēja apkopoÅ”ana. Tas izmanto datu shēmu datu shēma, kas rakstÄ«ts Javascript, lai Ä£enerētu SQL un izpildÄ«tu datu bāzes vaicājumu. Mums tikai jānorāda, kā datu shēmā izmantot nodalÄ«juma filtru.

Izveidosim jaunu Cube.js lietojumprogrammu. Tā kā mēs jau izmantojam AWS steku, ir loÄ£iski izmantot Lambda izvietoÅ”anai. Varat izmantot ātrās veidnes Ä£enerÄ“Å”anai, ja plānojat mitināt Cube.js aizmugursistēmu Heroku vai Docker. Dokumentācijā ir aprakstÄ«ti citi hostinga metodes.

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

Vides mainīgie tiek izmantoti, lai konfigurētu piekļuvi datubāzei failā cube.js. Ģenerators izveidos .env failu, kurā varēsiet norādīt savas atslēgas Athena.

Tagad mums vajag datu shēma, kurā mēs precīzi norādīsim, kā tiek glabāti mūsu žurnāli. Tur varat arī norādīt, kā aprēķināt metriku informācijas paneļiem.

Direktorijā schema, izveidojiet failu Logs.js. Šeit ir nginx datu modeļa piemērs:

Modeļa kods

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

Šeit mēs izmantojam mainīgo FILTER_PARAMSlai ģenerētu SQL vaicājumu ar nodalījuma filtru.

Mēs arÄ« iestatām metriku un parametrus, ko vēlamies parādÄ«t informācijas panelÄ«, un norādām iepriekŔēju apkopojumu. Cube.js izveidos papildu tabulas ar iepriekÅ” apkopotiem datiem un automātiski atjauninās datus, tiklÄ«dz tie tiks saņemti. Tas ne tikai paātrina vaicājumu izpildi, bet arÄ« samazina Athena lietoÅ”anas izmaksas.

Pievienosim Å”o informāciju datu shēmas failam:

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

Å ajā modelÄ« mēs norādām, ka ir nepiecieÅ”ams iepriekÅ” apkopot datus par visiem izmantotajiem rādÄ«tājiem un izmantot sadalÄ«jumu pa mēneÅ”iem. SadalÄ«Å”ana pirms apkopoÅ”anas var ievērojami paātrināt datu vākÅ”anu un atjaunināŔanu.

Tagad mēs varam salikt informācijas paneli!

Cube.js aizmugure nodroÅ”ina REST API un klientu bibliotēku kopa populārām priekÅ”gala ietvariem. Lai izveidotu informācijas paneli, mēs izmantosim klienta React versiju. Cube.js nodroÅ”ina tikai datus, tāpēc mums bÅ«s nepiecieÅ”ama vizualizācijas bibliotēka ā€” man tā patÄ«k atkārtotas diagrammas, bet jÅ«s varat izmantot jebkuru.

Cube.js serveris pieņem pieprasÄ«jumu JSON formātā, kas norāda nepiecieÅ”amos rādÄ«tājus. Piemēram, lai aprēķinātu, cik kļūdu Nginx sniedza dienā, jums jānosÅ«ta Ŕāds pieprasÄ«jums:

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

Instalēsim Cube.js klientu un React komponentu bibliotēku, izmantojot NPM:

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

Mēs importējam komponentus cubejs Šø QueryRendererlai lejupielādētu datus un apkopotu informācijas paneli:

Informācijas paneļa kods

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

Informācijas paneļa avoti ir pieejami vietnē koda smilÅ”kaste.

Avots: www.habr.com

Pievieno komentāru