Amazon Athena və Cube.js istifadə edərək Nginx log analitikası

Tipik olaraq, Nginx-in işini izləmək və təhlil etmək üçün Prometheus + Grafana kimi kommersiya məhsulları və ya hazır açıq mənbə alternativləri istifadə olunur. Bu monitorinq və ya real vaxt analitikası üçün yaxşı seçimdir, lakin tarixi təhlil üçün çox əlverişli deyil. İstənilən populyar resursda nginx qeydlərindən alınan məlumatların həcmi sürətlə artır və böyük miqdarda məlumatı təhlil etmək üçün daha ixtisaslaşmış bir şeydən istifadə etmək məntiqlidir.

Bu yazıda sizə necə istifadə edə biləcəyinizi söyləyəcəyəm Athena Nginx-i nümunə götürərək qeydləri təhlil etmək və mən açıq mənbəli cube.js çərçivəsindən istifadə edərək bu məlumatlardan analitik tablosunu necə yığmaq lazım olduğunu göstərəcəyəm. Budur tam həll arxitekturası:

Amazon Athena və Cube.js istifadə edərək Nginx log analitikası

TL: DR;
Bitmiş tablosuna keçid.

İstifadə etdiyimiz məlumat toplamaq üçün səlis, emal üçün - AWS Kinesis Data Firehose и AWS Yapışqan, saxlama üçün - AWS S3. Bu paketdən istifadə etməklə siz təkcə nginx qeydlərini deyil, həm də digər hadisələri, eləcə də digər xidmətlərin qeydlərini saxlaya bilərsiniz. Siz yığınınız üçün bəzi hissələri oxşarları ilə əvəz edə bilərsiniz, məsələn, fluentd-dən yan keçərək, nginx-dən birbaşa kinesisə loglar yaza və ya bunun üçün logstash istifadə edə bilərsiniz.

Nginx qeydlərinin toplanması

Varsayılan olaraq, Nginx qeydləri belə görünür:

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

Onları təhlil etmək olar, lakin Nginx konfiqurasiyasını JSON-da qeydlər yaratması üçün düzəltmək daha asandır:

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;

Saxlama üçün S3

Günlükləri saxlamaq üçün biz S3 istifadə edəcəyik. Bu, qeydləri bir yerdə saxlamağa və təhlil etməyə imkan verir, çünki Athena birbaşa S3-də məlumatlarla işləyə bilər. Daha sonra məqalədə qeydləri necə düzgün əlavə etmək və emal etmək barədə sizə məlumat verəcəyəm, lakin əvvəlcə S3-də başqa heç bir şeyin saxlanmayacağı təmiz bir çömçə lazımdır. Athena bütün bölgələrdə mövcud olmadığı üçün hansı bölgədə vedrənizi yaratacağınızı əvvəlcədən düşünməyə dəyər.

Athena konsolunda bir dövrə yaratmaq

Afinada loglar üçün cədvəl yaradaq. Kinesis Firehose istifadə etməyi planlaşdırırsınızsa, həm yazmaq, həm də oxumaq üçün lazımdır. Athena konsolunu açın və cədvəl yaradın:

SQL cədvəlinin yaradılması

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 yaradılması

Kinesis Firehose seçilmiş formatda Nginx-dən S3-ə qəbul edilmiş məlumatları YYYY/AA/GG/HH formatında qovluqlara bölməklə yazacaq. Bu, məlumatları oxuyarkən faydalı olacaq. Siz əlbəttə ki, fluentd-dən birbaşa S3-ə yaza bilərsiniz, lakin bu halda siz JSON yazmalı olacaqsınız və bu, faylların böyük ölçüsünə görə səmərəsizdir. Bundan əlavə, PrestoDB və ya Athena istifadə edərkən, JSON ən yavaş məlumat formatıdır. Beləliklə, Kinesis Firehose konsolunu açın, "Çatdırılma axını yarat" düyməsini basın, "çatdırılma" sahəsində "birbaşa PUT" seçin:

Amazon Athena və Cube.js istifadə edərək Nginx log analitikası

Növbəti sekmədə "Record format conversion" - "Enabled" seçin və qeyd formatı kimi "Apache ORC" seçin. Bəzi araşdırmalara görə Owen O'Malley, bu PrestoDB və Athena üçün optimal formatdır. Yuxarıda yaratdığımız cədvəldən sxem kimi istifadə edirik. Nəzərə alın ki, siz kinesisdə istənilən S3 yerini təyin edə bilərsiniz, yalnız cədvəldən sxem istifadə olunur. Ancaq fərqli bir S3 yeri göstərsəniz, bu cədvəldən bu qeydləri oxuya bilməyəcəksiniz.

Amazon Athena və Cube.js istifadə edərək Nginx log analitikası

Saxlama üçün S3-ü və əvvəllər yaratdığımız kovanı seçirik. Bir az sonra danışacağım Aws Glue Crawler, S3 vedrəsindəki prefikslərlə işləyə bilməz, ona görə də onu boş qoymaq vacibdir.

Amazon Athena və Cube.js istifadə edərək Nginx log analitikası

Qalan seçimlər yükünüzdən asılı olaraq dəyişdirilə bilər; Mən adətən standart olanlardan istifadə edirəm. Qeyd edək ki, S3 sıxılma mövcud deyil, lakin ORC standart olaraq yerli sıxılmadan istifadə edir.

səlis

İndi qeydlərin saxlanmasını və qəbulunu konfiqurasiya etdikdən sonra göndərməni konfiqurasiya etməliyik. istifadə edəcəyik səlis, çünki mən Ruby-ni sevirəm, lakin siz Logstash-dan istifadə edə və ya logları birbaşa kinesisə göndərə bilərsiniz. Fluentd serveri bir neçə yolla işə salına bilər, mən sizə docker haqqında danışacağam, çünki o, sadə və rahatdır.

Əvvəlcə fluent.conf konfiqurasiya faylına ehtiyacımız var. Yaradın və mənbə əlavə edin:

növü irəli
port 24224
bağlama 0.0.0.0

İndi siz Fluentd serverinə başlaya bilərsiniz. Daha təkmil konfiqurasiyaya ehtiyacınız varsa, keçin Docker mərkəzi Şəkilinizi necə yığmaq da daxil olmaqla ətraflı təlimat var.

$ 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

Bu konfiqurasiya yoldan istifadə edir /fluentd/log göndərməzdən əvvəl qeydləri keş etmək. Bunu etmədən də edə bilərsiniz, lakin sonra yenidən başlatdığınız zaman, geri çəkilən əməklə keşlənmiş hər şeyi itirə bilərsiniz. Siz həmçinin istənilən portdan istifadə edə bilərsiniz; 24224 standart Fluentd portudur.

İndi bizdə Fluentd işləyir, biz oraya Nginx qeydlərini göndərə bilərik. Biz adətən Nginx-i Docker konteynerində işlədirik, bu halda Docker-in Fluentd üçün yerli giriş sürücüsü var:

$ 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-i fərqli şəkildə işlədirsinizsə, Fluentd-də log fayllarından istifadə edə bilərsiniz fayl quyruğu plagini.

Yuxarıda konfiqurasiya edilmiş log təhlilini Fluent konfiqurasiyasına əlavə edək:

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

Və istifadə edərək, Kinesis-ə logların göndərilməsi kinesis firehose plagini:

<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

Hər şeyi düzgün konfiqurasiya etmisinizsə, bir müddət sonra (standart olaraq, Kinesis alınan məlumatları hər 10 dəqiqədə bir dəfə qeyd edir) S3-də log fayllarını görməlisiniz. Kinesis Firehose-un "monitorinq" menyusunda S3-də nə qədər məlumatın qeydə alındığını, həmçinin səhvləri görə bilərsiniz. Kinesis roluna S3 vedrəsinə yazma imkanı verməyi unutmayın. Kinesis bir şeyi təhlil edə bilmədisə, səhvləri eyni vedrə əlavə edəcək.

İndi məlumatlara Athena-da baxa bilərsiniz. Səhvləri qaytardığımız ən son sorğuları tapaq:

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

Hər sorğu üçün bütün qeydlərin skan edilməsi

İndi jurnallarımız işlənmiş və S3-də ORC-də saxlanılmış, sıxılmış və təhlil üçün hazırdır. Kinesis Firehose hətta onları hər saat üçün kataloqlar şəklində təşkil etdi. Bununla belə, cədvəl bölünmədiyi müddətcə, Athena nadir istisnalar istisna olmaqla, hər sorğu üzrə bütün zaman məlumatlarını yükləyəcək. Bu iki səbəbə görə böyük problemdir:

  • Məlumatların həcmi daim artır, sorğuları yavaşlatır;
  • Athena, hər sorğu üçün minimum 10 MB olmaqla, skan edilmiş məlumatların həcminə əsasən hesablanır.

Bunu düzəltmək üçün biz S3-də məlumatları tarayacaq və bölmə məlumatlarını Glue Metastore-a yazacaq AWS Glue Crawler-dən istifadə edirik. Bu, Athena sorğusu zamanı arakəsmələrdən filtr kimi istifadə etməyə imkan verəcək və o, yalnız sorğuda göstərilən qovluqları skan edəcək.

Amazon Glue Crawler-ın qurulması

Amazon Glue Crawler S3 kovasındakı bütün məlumatları skan edir və arakəsmələrlə cədvəllər yaradır. AWS Glue konsolundan Glue Crawler yaradın və məlumatları saxladığınız yerə bir vedrə əlavə edin. Bir neçə vedrə üçün bir sürünəndən istifadə edə bilərsiniz, bu halda o, müəyyən edilmiş verilənlər bazasında vedrələrin adlarına uyğun adlarla cədvəllər yaradacaqdır. Bu məlumatları müntəzəm olaraq istifadə etməyi planlaşdırırsınızsa, Crawler-in işə salınma cədvəlini ehtiyaclarınıza uyğun olaraq konfiqurasiya etdiyinizə əmin olun. Biz hər saat işləyən bütün cədvəllər üçün bir Crawler istifadə edirik.

Bölünmüş masalar

Tarayıcının ilk işə salınmasından sonra, parametrlərdə göstərilən verilənlər bazasında hər bir skan edilmiş vedrə üçün cədvəllər görünməlidir. Athena konsolunu açın və Nginx qeydləri olan cədvəli tapın. Gəlin bir şey oxumağa çalışaq:

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

Bu sorğu 6 aprel 7-cu il tarixində səhər saat 8-dan səhər 2019-dək qəbul edilmiş bütün qeydləri seçəcək. Bəs bu, bölünməmiş cədvəldən oxumaqdan nə qədər səmərəlidir? Gəlin eyni qeydləri tapıb seçək, onları vaxt damğasına görə süzək:

Amazon Athena və Cube.js istifadə edərək Nginx log analitikası

3.59 saniyə və 244.34 meqabayt məlumat toplusunda cəmi bir həftəlik qeydlər. Gəlin bölmə üzrə filtri sınayaq:

Amazon Athena və Cube.js istifadə edərək Nginx log analitikası

Bir az daha sürətli, lakin ən əsası - yalnız 1.23 meqabayt məlumat! Qiymətləndirmədə hər sorğu üçün minimum 10 meqabayt olmasaydı, daha ucuz olardı. Ancaq yenə də daha yaxşıdır və böyük məlumat dəstlərində fərq daha təsir edici olacaq.

Cube.js istifadə edərək tablosunun qurulması

İdarə panelini yığmaq üçün biz Cube.js analitik çərçivəsindən istifadə edirik. Onun kifayət qədər çox funksiyası var, lakin bizi iki maraqlandırır: bölmə filtrlərindən avtomatik istifadə etmək və məlumatların əvvəlcədən yığılması. Məlumat sxemindən istifadə edir məlumat sxemi, SQL yaratmaq və verilənlər bazası sorğusunu yerinə yetirmək üçün Javascript-də yazılmışdır. Biz yalnız məlumat sxemində bölmə filtrindən necə istifadə edəcəyimizi göstərməliyik.

Gəlin yeni Cube.js tətbiqi yaradaq. Artıq AWS yığınından istifadə etdiyimiz üçün yerləşdirmə üçün Lambda-dan istifadə etmək məntiqlidir. Cube.js backendini Heroku və ya Docker-də yerləşdirməyi planlaşdırırsınızsa, nəsil üçün ekspress şablondan istifadə edə bilərsiniz. Sənədlər başqalarını təsvir edir hostinq üsulları.

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

Ətraf dəyişənləri cube.js-də verilənlər bazasına girişi konfiqurasiya etmək üçün istifadə olunur. Generator açarlarınızı təyin edə biləcəyiniz .env faylı yaradacaq Athena.

İndi ehtiyacımız var məlumat sxemi, burada qeydlərimizin necə saxlandığını dəqiq göstərəcəyik. Orada həmçinin tablosuna ölçüləri necə hesablamaq lazım olduğunu təyin edə bilərsiniz.

Kataloqda schema, fayl yaradın Logs.js. Nginx üçün nümunə məlumat modeli:

Model kodu

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

Burada dəyişəndən istifadə edirik FILTER_PARAMSbölmə filtri ilə SQL sorğusu yaratmaq.

Biz həmçinin tablosunda göstərmək istədiyimiz ölçüləri və parametrləri təyin edirik və əvvəlcədən birləşmələri təyin edirik. Cube.js əvvəlcədən yığılmış data ilə əlavə cədvəllər yaradacaq və məlumat gələn kimi avtomatik yenilənəcək. Bu, sorğuları sürətləndirməklə yanaşı, Athena-dan istifadə xərclərini də azaldır.

Gəlin bu məlumatı verilənlər sxemi faylına əlavə edək:

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

Biz bu modeldə qeyd edirik ki, istifadə olunan bütün ölçülər üçün məlumatları əvvəlcədən toplamaq və aylar üzrə bölmədən istifadə etmək lazımdır. Əvvəlcədən toplama bölməsi məlumatların toplanması və yenilənməsini əhəmiyyətli dərəcədə sürətləndirə bilər.

İndi tablosunu yığa bilərik!

Cube.js backend təmin edir REST API və populyar cəbhə çərçivələri üçün müştəri kitabxanaları dəsti. Biz tablosunu yaratmaq üçün müştərinin React versiyasından istifadə edəcəyik. Cube.js yalnız data təmin edir, ona görə də bizə vizuallaşdırma kitabxanası lazımdır - mənim xoşuma gəlir yenidən qrafiklər, lakin istənilən istifadə edə bilərsiniz.

Cube.js serveri sorğunu qəbul edir JSON formatı, tələb olunan ölçüləri müəyyən edir. Məsələn, Nginx-in gündə neçə səhv verdiyini hesablamaq üçün aşağıdakı sorğunu göndərməlisiniz:

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

NPM vasitəsilə Cube.js müştərisini və React komponent kitabxanasını quraşdıraq:

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

Biz komponentləri idxal edirik cubejs и QueryRendererməlumatları yükləmək və tablosunu toplamaq üçün:

İdarə paneli kodu

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

Dashboard mənbələri burada mövcuddur kod sandbox.

Mənbə: www.habr.com

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