„Nginx“ registruoja analizę naudodami „Amazon Athena“ ir „Cube.js“.

Paprastai Nginx veikimui stebėti ir analizuoti naudojami komerciniai produktai arba paruoštos atvirojo kodo alternatyvos, tokios kaip Prometheus + Grafana. Tai geras pasirinkimas stebėjimui ar realiojo laiko analizei, bet nelabai patogus istorinei analizei. Bet kuriame populiariame šaltinyje duomenų iš nginx žurnalų kiekis sparčiai auga, o norint išanalizuoti didelį duomenų kiekį, logiška naudoti ką nors labiau specializuotą.

Šiame straipsnyje aš jums pasakysiu, kaip galite naudoti Atėnė analizuoti žurnalus, kaip pavyzdį paimdamas Nginx, ir parodysiu, kaip iš šių duomenų surinkti analitinę informacijos suvestinę naudojant atvirojo kodo cube.js sistemą. Štai visa sprendimo architektūra:

„Nginx“ registruoja analizę naudodami „Amazon Athena“ ir „Cube.js“.

TL:DR;
Nuoroda į baigtą prietaisų skydelį.

Norėdami rinkti informaciją, kurią naudojame sklandžiai, perdirbimui - AWS Kinesis Data Firehose и AWS klijai, saugojimui - AWS S3. Naudodamiesi šiuo paketu galite saugoti ne tik nginx žurnalus, bet ir kitus įvykius, taip pat kitų paslaugų žurnalus. Kai kurias dalis galite pakeisti panašiomis savo kamino dalimis, pavyzdžiui, galite rašyti žurnalus į kinesis tiesiai iš nginx, apeinant fluentd arba tam naudoti logstash.

Nginx žurnalų rinkimas

Pagal numatytuosius nustatymus „Nginx“ žurnalai atrodo maždaug taip:

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

Juos galima išanalizuoti, tačiau daug lengviau ištaisyti Nginx konfigūraciją, kad ji sukurtų žurnalus 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 saugojimui

Žurnalams saugoti naudosime S3. Tai leidžia saugoti ir analizuoti žurnalus vienoje vietoje, nes Athena gali tiesiogiai dirbti su S3 duomenimis. Vėliau straipsnyje aš jums pasakysiu, kaip teisingai pridėti ir apdoroti žurnalus, tačiau pirmiausia mums reikia švaraus S3 kibiro, kuriame nieko daugiau nebus saugoma. Verta iš anksto pagalvoti, kuriame regione kursite kibirą, nes „Athena“ pasiekiama ne visuose regionuose.

Grandinės sukūrimas konsolėje Athena

Sukurkime „Athena“ lentelę rąstams. Jis reikalingas tiek rašant, tiek skaitant, jei planuojate naudoti Kinesis Firehose. Atidarykite „Athena“ konsolę ir sukurkite lentelę:

SQL lentelės kūrimas

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 kūrimas

Kinesis Firehose iš Nginx gautus duomenis įrašys į S3 pasirinktu formatu, suskirstydamas juos į katalogus formatu YYYY/MM/DD/HH. Tai bus naudinga skaitant duomenis. Žinoma, galite rašyti tiesiai į S3 iš fluentd, tačiau tokiu atveju turėsite rašyti JSON, o tai neefektyvu dėl didelio failų dydžio. Be to, naudojant PrestoDB arba Athena, JSON yra lėčiausias duomenų formatas. Taigi atidarykite Kinesis Firehose pultą, spustelėkite „Sukurti pristatymo srautą“, lauke „pristatymas“ pasirinkite „tiesioginis PUT“:

„Nginx“ registruoja analizę naudodami „Amazon Athena“ ir „Cube.js“.

Kitame skirtuke pasirinkite „Įrašymo formato konvertavimas“ - „Įjungta“ ir kaip įrašymo formatą pasirinkite „Apache ORC“. Kai kurių tyrimų duomenimis Owenas O'Malley, tai yra optimalus „PrestoDB“ ir „Athena“ formatas. Mes naudojame aukščiau sukurtą lentelę kaip schemą. Atkreipkite dėmesį, kad kineze galite nurodyti bet kurią S3 vietą; naudojama tik lentelės schema. Bet jei nurodysite kitą S3 vietą, negalėsite perskaityti šių įrašų iš šios lentelės.

„Nginx“ registruoja analizę naudodami „Amazon Athena“ ir „Cube.js“.

Saugymui pasirenkame S3 ir anksčiau sukurtą kibirą. Aws Glue Crawler, apie kurį pakalbėsiu šiek tiek vėliau, negali dirbti su priešdėliais S3 kibirėlyje, todėl svarbu jį palikti tuščią.

„Nginx“ registruoja analizę naudodami „Amazon Athena“ ir „Cube.js“.

Likusios parinktys gali būti keičiamos atsižvelgiant į jūsų apkrovą; dažniausiai naudoju numatytąsias. Atminkite, kad S3 glaudinimas nepasiekiamas, tačiau pagal numatytuosius nustatymus ORC naudoja savąjį glaudinimą.

sklandžiai

Dabar, kai sukonfigūravome žurnalų saugojimą ir gavimą, turime sukonfigūruoti siuntimą. Mes naudosime sklandžiai, nes aš myliu Ruby, bet jūs galite naudoti Logstash arba siųsti žurnalus tiesiai į kinesis. „Fluentd“ serverį galima paleisti keliais būdais, aš jums pasakysiu apie „docker“, nes tai paprasta ir patogu.

Pirmiausia mums reikia fluent.conf konfigūracijos failo. Sukurkite jį ir pridėkite šaltinį:

tipas pirmyn
uostas 24224
surišti 0.0.0.0

Dabar galite paleisti „Fluentd“ serverį. Jei jums reikia sudėtingesnės konfigūracijos, eikite į „Docker Hub“ Yra išsamus vadovas, įskaitant tai, kaip surinkti vaizdą.

$ 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

Ši konfigūracija naudoja kelią /fluentd/log į talpyklą išsaugoti žurnalus prieš siunčiant. Galite apsieiti ir be šito, bet tada, kai paleisite iš naujo, galite prarasti viską, kas saugoma talpykloje dėl laužymo darbų. Taip pat galite naudoti bet kurį prievadą; 24224 yra numatytasis Fluentd prievadas.

Dabar, kai veikia „Fluentd“, galime ten siųsti „Nginx“ žurnalus. Paprastai „Nginx“ paleidžiame „Docker“ konteineryje, tokiu atveju „Docker“ turi savąją „Fluentd“ registravimo tvarkyklę:

$ 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

Jei naudojate „Nginx“ kitaip, galite naudoti žurnalo failus, „Fluentd“. failo uodegos įskiepis.

Pridėkime anksčiau sukonfigūruotą žurnalo analizę prie „Fluent“ konfigūracijos:

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

Ir žurnalų siuntimas į Kinesis naudojant kinesis firehose įskiepis:

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

Atėnė

Jei viską sukonfigūravote teisingai, po kurio laiko (pagal numatytuosius nustatymus Kinesis gautus duomenis įrašo kartą per 10 minučių) turėtumėte matyti žurnalo failus S3. Kinesis Firehose "stebėjimo" meniu galite pamatyti, kiek duomenų įrašyta S3, taip pat klaidas. Nepamirškite suteikti „Kinesis“ vaidmens rašymo prieigos prie S3 segmento. Jei Kinesis nepavyko ko nors išanalizuoti, jis įtrauks klaidas į tą patį segmentą.

Dabar galite peržiūrėti duomenis „Athena“. Suraskime paskutines užklausas, kuriose pateikėme klaidų:

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

Nuskaitomi visi įrašai pagal kiekvieną užklausą

Dabar mūsų žurnalai buvo apdoroti ir saugomi S3 ORC, suspausti ir paruošti analizei. Kinesis Firehose netgi suskirstė juos į katalogus kiekvienai valandai. Tačiau tol, kol lentelė nėra skaidoma, „Athena“ įkels visų laikų duomenis pagal kiekvieną užklausą, išskyrus retas išimtis. Tai didelė problema dėl dviejų priežasčių:

  • Duomenų apimtis nuolat auga, stabdo užklausas;
  • „Athena“ apmokestinama atsižvelgiant į nuskaitytų duomenų kiekį, mažiausiai 10 MB už užklausą.

Norėdami tai išspręsti, naudojame „AWS Glue Crawler“, kuri nuskaitys duomenis S3 ir įrašys skaidinio informaciją į „Glue Metastore“. Tai leis mums naudoti skaidinius kaip filtrą užklausant Athena ir nuskaitys tik užklausoje nurodytus katalogus.

„Amazon Glue Crawler“ nustatymas

„Amazon Glue Crawler“ nuskaito visus S3 kibiro duomenis ir sukuria lenteles su skaidiniais. Sukurkite klijų skaitytuvą naudodami AWS klijų konsolę ir pridėkite kibirą, kuriame saugosite duomenis. Galite naudoti vieną skaitytuvą keliems segmentams, tokiu atveju jis sukurs lenteles nurodytoje duomenų bazėje su pavadinimais, atitinkančiais segmentų pavadinimus. Jei planuojate reguliariai naudoti šiuos duomenis, būtinai sukonfigūruokite tikrinimo programos paleidimo tvarkaraštį, kad jis atitiktų jūsų poreikius. Visiems stalams naudojame vieną skaitytuvą, kuris veikia kas valandą.

Skirstytos lentelės

Pirmą kartą paleidus tikrintuvą, nustatymuose nurodytoje duomenų bazėje turėtų atsirasti kiekvieno nuskaityto segmento lentelės. Atidarykite „Athena“ konsolę ir raskite lentelę su „Nginx“ žurnalais. Pabandykime ką nors perskaityti:

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

Ši užklausa atrinks visus įrašus, gautus nuo 6 iki 7 val. 8 m. balandžio 2019 d. Tačiau kiek tai yra efektyviau nei tiesiog skaitymas iš neskirstytos lentelės? Išsiaiškinkime ir pasirinkite tuos pačius įrašus, filtruodami juos pagal laiko žymą:

„Nginx“ registruoja analizę naudodami „Amazon Athena“ ir „Cube.js“.

3.59 sekundės ir 244.34 megabaitų duomenų duomenų rinkinyje, kuriame yra tik savaitės žurnalų. Išbandykime filtrą pagal skaidinį:

„Nginx“ registruoja analizę naudodami „Amazon Athena“ ir „Cube.js“.

Šiek tiek greičiau, bet svarbiausia – tik 1.23 megabaitų duomenų! Būtų daug pigiau, jei ne minimalūs 10 megabaitų užklausai kainodaroje. Tačiau tai vis tiek daug geriau, o dideliuose duomenų rinkiniuose skirtumas bus daug įspūdingesnis.

Informacijos suvestinės kūrimas naudojant Cube.js

Norėdami surinkti prietaisų skydelį, naudojame Cube.js analitinę sistemą. Jis turi gana daug funkcijų, tačiau mus domina dvi: galimybė automatiškai naudoti skaidinių filtrus ir išankstinis duomenų agregavimas. Jis naudoja duomenų schemą duomenų schema, parašyta Javascript, kad sugeneruotų SQL ir vykdytų duomenų bazės užklausą. Mums reikia tik nurodyti, kaip duomenų schemoje naudoti skaidinio filtrą.

Sukurkime naują Cube.js programą. Kadangi jau naudojame AWS steką, logiška diegti naudoti Lambda. Galite naudoti greitąjį šabloną generavimui, jei planuojate priglobti Cube.js pagrindinę programą Heroku arba Docker. Dokumentuose aprašomi kiti prieglobos metodai.

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

Aplinkos kintamieji naudojami duomenų bazės prieigai cube.js konfigūruoti. Generatorius sukurs .env failą, kuriame galėsite nurodyti savo raktus Atėnė.

Dabar mums reikia duomenų schema, kuriame tiksliai nurodysime, kaip saugomi mūsų žurnalai. Čia taip pat galite nurodyti, kaip apskaičiuoti prietaisų skydelių metriką.

Kataloge schema, sukurkite failą Logs.js. Štai nginx duomenų modelio pavyzdys:

Modelio kodas

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

Čia mes naudojame kintamąjį FILTER_PARAMSsugeneruoti SQL užklausą su skaidinio filtru.

Taip pat nustatome metriką ir parametrus, kuriuos norime rodyti prietaisų skydelyje, ir nurodome išankstinius sujungimus. Cube.js sukurs papildomas lenteles su iš anksto sukauptais duomenimis ir automatiškai atnaujins gautus duomenis. Tai ne tik pagreitina užklausas, bet ir sumažina Athena naudojimo išlaidas.

Pridėkime šią informaciją į duomenų schemos failą:

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

Šiame modelyje nurodome, kad būtina iš anksto sukaupti visų naudojamų metrikų duomenis ir naudoti skirstymą pagal mėnesius. Išankstinis sujungimas skaidymas gali žymiai pagreitinti duomenų rinkimą ir atnaujinimą.

Dabar galime surinkti prietaisų skydelį!

Cube.js backend suteikia POILSIO API ir klientų bibliotekų rinkinys populiarioms priekinėms sistemoms. Kurdami prietaisų skydelį naudosime kliento „React“ versiją. Cube.js pateikia tik duomenis, todėl mums reikės vizualizacijos bibliotekos – man tai patinka kartojasi, bet galite naudoti bet kurį.

Cube.js serveris priima užklausą JSON formatu, kuriame nurodoma reikalinga metrika. Pavyzdžiui, norėdami apskaičiuoti, kiek klaidų Nginx pateikė per dieną, turite išsiųsti šią užklausą:

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

Įdiegkime Cube.js klientą ir React komponentų biblioteką per NPM:

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

Importuojame komponentus cubejs и QueryRendererNorėdami atsisiųsti duomenis ir rinkti prietaisų skydelį:

Prietaisų skydelio kodas

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

Informacijos suvestinės šaltiniai pasiekiami adresu „CodeSandbox“.

Šaltinis: www.habr.com

Добавить комментарий