Amazon Athena және Cube.js көмегімен Nginx журналының талдауы

Әдетте, Nginx жұмысын бақылау және талдау үшін Prometheus + Grafana сияқты коммерциялық өнімдер немесе дайын ашық бастапқы баламалар пайдаланылады. Бұл мониторинг немесе нақты уақыттағы талдау үшін жақсы нұсқа, бірақ тарихи талдау үшін өте ыңғайлы емес. Кез келген танымал ресурста nginx журналдарынан алынған деректер көлемі тез өсуде және деректердің үлкен көлемін талдау үшін мамандандырылған нәрсені пайдалану қисынды.

Бұл мақалада мен сізге қалай қолдануға болатынын айтамын Афина журналдарды талдау үшін, мысал ретінде Nginx алып, мен ашық бастапқы cube.js жақтауын пайдаланып осы деректерден аналитикалық бақылау тақтасын қалай жинау керектігін көрсетемін. Міне, шешімнің толық архитектурасы:

Amazon Athena және Cube.js көмегімен Nginx журналының талдауы

TL: DR;
Аяқталған бақылау тақтасына сілтеме.

Ақпаратты жинау үшін біз пайдаланамыз Еркін, өңдеу үшін - AWS Kinesis Data Firehose и AWS желімі, сақтау үшін - AWS S3. Бұл топтаманы пайдалану арқылы сіз тек nginx журналдарын ғана емес, сонымен қатар басқа оқиғаларды, сондай-ақ басқа қызметтердің журналдарын сақтай аласыз. Стек үшін кейбір бөліктерді ұқсас бөліктерімен ауыстыруға болады, мысалы, nginx жүйесінен тікелей кинесиске журналдарды жазуға, fluentd-ді айналып өтуге немесе бұл үшін 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" "-"

Оларды талдауға болады, бірақ Nginx конфигурациясын 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 сақтау үшін

Журналдарды сақтау үшін біз S3 пайдаланамыз. Бұл журналдарды бір жерде сақтауға және талдауға мүмкіндік береді, өйткені Athena S3 жүйесіндегі деректермен тікелей жұмыс істей алады. Кейінірек мақалада журналдарды қалай дұрыс қосу және өңдеу керектігін айтамын, бірақ алдымен бізге S3 ішінде таза шелек қажет, онда басқа ештеңе сақталмайды. Шелекті қай аймақта жасайтыныңызды алдын ала қарастырған жөн, өйткені 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 Stream жасау

Kinesis Firehose Nginx-тен S3-ке алынған деректерді таңдалған пішімде жазады, оны ЖЖЖЖ/АА/КК/СС пішіміндегі каталогтарға бөледі. Бұл деректерді оқу кезінде пайдалы болады. Сіз, әрине, Fluentd-тен S3-ге тікелей жаза аласыз, бірақ бұл жағдайда JSON жазуға тура келеді және бұл файлдардың үлкен көлеміне байланысты тиімсіз. Сонымен қатар, PrestoDB немесе Athena пайдалану кезінде JSON ең баяу деректер пішімі болып табылады. Сондықтан Kinesis Firehose консолін ашыңыз, «Жеткізу ағынын жасау» түймесін басыңыз, «жеткізу» өрісінде «тікелей PUT» таңдаңыз:

Amazon Athena және Cube.js көмегімен Nginx журналының талдауы

Келесі қойындыда «Жазба пішімін түрлендіру» - «Қосулы» таңдаңыз және жазу пішімі ретінде «Apache ORC» таңдаңыз. Кейбір зерттеулерге сәйкес Оуэн О'Мэлли, бұл PrestoDB және Athena үшін оңтайлы пішім. Жоғарыда жасаған кестені схема ретінде қолданамыз. Кинезисте кез келген S3 орнын көрсетуге болатынын ескеріңіз, кестеде тек схема қолданылады. Бірақ егер сіз басқа S3 орнын көрсетсеңіз, осы кестеден бұл жазбаларды оқи алмайсыз.

Amazon Athena және Cube.js көмегімен Nginx журналының талдауы

Сақтау және бұрын жасаған шелек үшін S3 таңдаймыз. Мен сәл кейінірек айтатын Aws Glue Crawler S3 шелегіндегі префикстермен жұмыс істей алмайды, сондықтан оны бос қалдыру маңызды.

Amazon Athena және Cube.js көмегімен Nginx журналының талдауы

Қалған опцияларды жүктемеге байланысты өзгертуге болады; Мен әдетте әдепкі опцияларды қолданамын. S3 қысу қол жетімді емес екенін ескеріңіз, бірақ ORC әдепкі бойынша жергілікті қысуды пайдаланады.

Еркін

Енді біз журналдарды сақтау және қабылдауды конфигурациялағандықтан, жіберуді конфигурациялауымыз керек. пайдаланамыз Еркін, өйткені мен Ruby-ді жақсы көремін, бірақ сіз Logstash-ты пайдалана аласыз немесе журналдарды кинезиске тікелей жібере аласыз. Fluentd серверін бірнеше жолмен іске қосуға болады, мен сізге докер туралы айтып беремін, себебі ол қарапайым және ыңғайлы.

Біріншіден, бізге fluent.conf конфигурация файлы қажет. Оны жасаңыз және дереккөзді қосыңыз:

түрі алға
24224 порты
байлау 0.0.0.0

Енді Fluentd серверін іске қосуға болады. Жетілдірілген конфигурация қажет болса, өтіңіз Докер хабы Егжей-тегжейлі нұсқаулық бар, оның ішінде кескінді қалай жинау керек.

$ 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 жүйесінде қанша деректер жазылғанын, сондай-ақ қателерді көре аласыз. Kinesis рөліне S3 шелекіне жазу рұқсатын беруді ұмытпаңыз. Егер Kinesis бір нәрсені талдай алмаса, ол қателерді бірдей шелекке қосады.

Енді сіз Athena-да деректерді көре аласыз. Қателерді қайтарған соңғы сұрауларды табайық:

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

Әрбір сұрау үшін барлық жазбаларды сканерлеу

Енді біздің журналдар өңделді және ORC жүйесінде S3 форматында сақталды, қысылды және талдауға дайын. Kinesis Firehose тіпті оларды әр сағат үшін каталогтарға ұйымдастырды. Дегенмен, кесте бөлінбегенше, Athena сирек жағдайларды қоспағанда, әрбір сұрау бойынша барлық уақыттағы деректерді жүктейді. Бұл екі себеп бойынша үлкен мәселе:

  • Деректер көлемі үнемі өсуде, сұрауларды баяулатады;
  • Athena үшін шот сканерленген деректер көлеміне негізделген, әрбір сұрау үшін кемінде 10 МБ.

Мұны түзету үшін біз S3 ішіндегі деректерді тексеріп шығып, Glue Metastore бөліміне ақпарат жазатын AWS Glue Crawler қолданамыз. Бұл бізге Athena сұрауы кезінде бөлімдерді сүзгі ретінде пайдалануға мүмкіндік береді және ол тек сұрауда көрсетілген каталогтарды сканерлейді.

Amazon Glue Crawler орнату

Amazon Glue Crawler S3 шелекіндегі барлық деректерді сканерлейді және бөлімдері бар кестелерді жасайды. AWS Glue консолінен Glue Crawler жасаңыз және деректерді сақтайтын шелек қосыңыз. Бірнеше шелек үшін бір тексеріп шығу құралын пайдалануға болады, бұл жағдайда ол көрсетілген дерекқорда шелектердің атауларына сәйкес атаулары бар кестелерді жасайды. Бұл деректерді үнемі пайдалануды жоспарласаңыз, Crawler іске қосу кестесін қажеттіліктеріңізге сәйкес конфигурациялауды ұмытпаңыз. Біз сағат сайын жұмыс істейтін барлық кестелер үшін бір Crawler пайдаланамыз.

Бөлінген кестелер

Тексеру құралын бірінші іске қосқаннан кейін әрбір сканерленген шелекке арналған кестелер параметрлерде көрсетілген дерекқорда пайда болуы керек. 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-ге дейін алынған барлық жазбаларды таңдайды. Бірақ бұл бөлінбеген кестеден оқудан гөрі қаншалықты тиімді? Сол жазбаларды уақыт белгісі бойынша сүзіп, анықтап, таңдап алайық:

Amazon Athena және Cube.js көмегімен Nginx журналының талдауы

3.59 секунд және 244.34 мегабайт деректер жинағында тек бір апталық журналдар бар. Бөлім бойынша сүзгіні қолданып көрейік:

Amazon Athena және Cube.js көмегімен Nginx журналының талдауы

Біраз жылдамырақ, бірақ ең бастысы - тек 1.23 мегабайт деректер! Баға белгілеуінде сұраныс үшін кем дегенде 10 мегабайт болмаса, бұл әлдеқайда арзанырақ болар еді. Бірақ бұл әлдеқайда жақсы және үлкен деректер жиынтығында айырмашылық әлдеқайда әсерлі болады.

Cube.js арқылы бақылау тақтасын құру

Бақылау тақтасын жинау үшін Cube.js аналитикалық құрылымын қолданамыз. Оның көптеген функциялары бар, бірақ бізді екі қызықтырады: бөлім сүзгілерін автоматты түрде пайдалану және деректерді алдын ала біріктіру. Ол деректер схемасын пайдаланады деректер схемасы, SQL құру және дерекқор сұрауын орындау үшін Javascript тілінде жазылған. Бізге деректер схемасында бөлім сүзгісін қалай пайдалану керектігін ғана көрсету керек.

Жаңа Cube.js қолданбасын жасайық. Біз AWS стекін пайдаланып жатқандықтан, орналастыру үшін Lambda пайдалану қисынды. Cube.js серверін Heroku немесе Docker ішінде орналастыруды жоспарласаңыз, генерация үшін экспресс үлгісін пайдалана аласыз. Құжаттама басқаларды сипаттайды хостинг әдістері.

$ 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 бір күнде қанша қате жібергенін есептеу үшін келесі сұрауды жіберу керек:

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

Бақылау тақтасының көздері мына жерден қолжетімді кодты құмсалғыш.

Ақпарат көзі: www.habr.com

пікір қалдыру