Аналитика Π»ΠΎΠ³ΠΎΠ² Nginx с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Amazon Athena ΠΈ Cube.js

ΠžΠ±Ρ‹Ρ‡Π½ΠΎ для ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³Π° ΠΈ Π°Π½Π°Π»ΠΈΠ·Π° Ρ€Π°Π±ΠΎΡ‚Ρ‹ Nginx ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ коммСрчСскиС ΠΏΡ€ΠΎΠ΄ΡƒΠΊΡ‚Ρ‹ ΠΈΠ»ΠΈ Π³ΠΎΡ‚ΠΎΠ²Ρ‹Π΅ open-source Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Ρ‹, Ρ‚Π°ΠΊΠΈΠ΅ ΠΊΠ°ΠΊ Prometheus + Grafana. Π­Ρ‚ΠΎ Ρ…ΠΎΡ€ΠΎΡˆΠΈΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ для ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³Π° ΠΈΠ»ΠΈ real-time Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ, Π½ΠΎ Π½Π΅ слишком ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ для историчСского Π°Π½Π°Π»ΠΈΠ·Π°. На любом популярном рСсурсС объСм Π΄Π°Π½Π½Ρ‹Ρ… ΠΈΠ· Π»ΠΎΠ³ΠΎΠ² nginx быстро растСт, ΠΈ для Π°Π½Π°Π»ΠΈΠ·Π° большого объСма Π΄Π°Π½Π½Ρ‹Ρ… Π»ΠΎΠ³ΠΈΡ‡Π½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π±ΠΎΠ»Π΅Π΅ спСциализированноС.

Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ я расскаТу, ΠΊΠ°ΠΊ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Athena для Π°Π½Π°Π»ΠΈΠ·Π° Π»ΠΎΠ³ΠΎΠ², взяв для ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° Nginx, ΠΈ ΠΏΠΎΠΊΠ°ΠΆΡƒ, ΠΊΠ°ΠΊ ΠΈΠ· этих Π΄Π°Π½Π½Ρ‹Ρ… ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ аналитичСский Π΄ΡΡˆΠ±ΠΎΡ€Π΄, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ open-source Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊ cube.js. Π’ΠΎΡ‚ полная Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π° Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ:

Аналитика Π»ΠΎΠ³ΠΎΠ² Nginx с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Amazon Athena ΠΈ Cube.js

TL:DR;
Бсылка Π½Π° Π³ΠΎΡ‚ΠΎΠ²Ρ‹ΠΉ Π΄ΡΡˆΠ±ΠΎΡ€Π΄.

Для сбора ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Fluentd, для процСссинга β€” AWS Kinesis Data Firehose ΠΈ AWS Glue, для хранСния β€” AWS S3. Π‘ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ этой связки ΠΌΠΎΠΆΠ½ΠΎ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π»ΠΎΠ³ΠΈ nginx, Π½ΠΎ ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ эвСнты, Π° Ρ‚Π°ΠΊΠΆΠ΅ Π»ΠΎΠ³ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΡ… сСрвисов. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ части Π½Π° Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½Ρ‹Π΅ для вашСго стэка, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΈΡΠ°Ρ‚ΡŒ Π»ΠΎΠ³ΠΈ Π² kinesis напрямик ΠΈΠ· 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

Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ Π² 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 Π² Π²Ρ‹Π±Ρ€Π°Π½Π½ΠΎΠΌ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅, Ρ€Π°Π·Π±ΠΈΠ² ΠΏΠΎ дирСкториям Π² Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅ Π“Π“Π“Π“/ММ/Π”Π”/Π§Π§. Π­Ρ‚ΠΎ пригодится ΠΏΡ€ΠΈ Ρ‡Ρ‚Π΅Π½ΠΈΠΈ Π΄Π°Π½Π½Ρ‹Ρ…. МоТно, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, ΠΏΠΈΡΠ°Ρ‚ΡŒ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ Π² S3 ΠΈΠ· fluentd, Π½ΠΎ Π² этом случаС придСтся ΠΏΠΈΡΠ°Ρ‚ΡŒ JSON, Π° это нСэффСктивно ΠΈΠ·-Π·Π° большого Ρ€Π°Π·ΠΌΠ΅Ρ€Π° Ρ„Π°ΠΉΠ»ΠΎΠ². К Ρ‚ΠΎΠΌΡƒ ΠΆΠ΅, ΠΏΡ€ΠΈ использовании PrestoDB ΠΈΠ»ΠΈ Athena, JSON β€” самый ΠΌΠ΅Π΄Π»Π΅Π½Π½Ρ‹ΠΉ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ Π΄Π°Π½Π½Ρ‹Ρ…. Π’Π°ΠΊ Ρ‡Ρ‚ΠΎ ΠΎΡ‚ΠΊΡ€Ρ‹Π²Π°Π΅ΠΌ консоль Kinesis Firehose, Π½Π°ΠΆΠΈΠΌΠ°Π΅ΠΌ «Create delivery stream», Π²Ρ‹Π±ΠΈΡ€Π°Π΅ΠΌ «direct PUT» Π² ΠΏΠΎΠ»Π΅ «delivery»:

Аналитика Π»ΠΎΠ³ΠΎΠ² Nginx с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Amazon Athena ΠΈ Cube.js

Π’ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ Π²ΠΊΠ»Π°Π΄ΠΊΠ΅ Π²Ρ‹Π±ΠΈΡ€Π°Π΅ΠΌ «Record format conversion» β€” «Enabled» ΠΈ Π²Ρ‹Π±ΠΈΡ€Π°Π΅ΠΌ «Apache ORC» ΠΊΠ°ΠΊ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ для записи. Богласно исслСдованиям Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Owen O’Malley, это ΠΎΠΏΡ‚ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ для PrestoDB ΠΈ Athena. Π’ качСствС схСмы ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΠΌΡ‹ создали Π²Ρ‹ΡˆΠ΅. ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Ρ‚ΠΎ S3 location Π² kinesis ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ любой, ΠΈΠ· Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ схСма. Но Ссли Π²Ρ‹ ΡƒΠΊΠ°ΠΆΠ΅Ρ‚Π΅ Π΄Ρ€ΡƒΠ³ΠΎΠΉ S3 location, Ρ‚ΠΎ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΈΠ· этой Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ эти записи Π½Π΅ получится.

Аналитика Π»ΠΎΠ³ΠΎΠ² Nginx с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Amazon Athena ΠΈ Cube.js

Π’Ρ‹Π±ΠΈΡ€Π°Π΅ΠΌ S3 для хранСния ΠΈ Π±Π°ΠΊΠ΅Ρ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ создали Ρ€Π°Π½ΡŒΡˆΠ΅. Aws Glue Crawler, ΠΏΡ€ΠΎ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ я расскаТу Ρ‡ΡƒΡ‚ΡŒ ΠΏΠΎΠ·ΠΆΠ΅, Π½Π΅ ΡƒΠΌΠ΅Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с прСфиксами Π² S3 Π±Π°ΠΊΠ΅Ρ‚Π΅, Ρ‚Π°ΠΊ Ρ‡Ρ‚ΠΎ Π΅Π³ΠΎ Π²Π°ΠΆΠ½ΠΎ ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ пустым.

Аналитика Π»ΠΎΠ³ΠΎΠ² Nginx с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Amazon Athena ΠΈ Cube.js

ΠžΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ ΠΎΠΏΡ†ΠΈΠΈ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒ Π² зависимости ΠΎΡ‚ вашСй Π½Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ, я ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽ Π΄Π΅Ρ„ΠΎΠ»Ρ‚Π½Ρ‹Π΅. ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Ρ‚ΠΎ сТатиС S3 нСдоступно, Π½ΠΎ ORC ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ собствСнноС сТатиС ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ.

Fluentd

Π’Π΅ΠΏΠ΅Ρ€ΡŒ, ΠΊΠΎΠ³Π΄Π° Ρƒ нас настроСно Ρ…Ρ€Π°Π½Π΅Π½ΠΈΠ΅ ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ Π»ΠΎΠ³ΠΎΠ², Π½Π°Π΄ΠΎ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΡƒ. ΠœΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Fluentd, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ я люблю Ruby, Π½ΠΎ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Logstash ΠΈΠ»ΠΈ ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ Π»ΠΎΠ³ΠΈ Π² kinesis Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ. Fluentd сСрвСр ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ нСсколькими способами, я расскаТу ΠΏΡ€ΠΎ docker, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ это просто ΠΈ ΡƒΠ΄ΠΎΠ±Π½ΠΎ.

Для Π½Π°Ρ‡Π°Π»Π°, Π½Π°ΠΌ Π½ΡƒΠΆΠ΅Π½ Ρ„Π°ΠΉΠ» ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ fluent.conf. Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ Π΅Π³ΠΎ ΠΈ Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ source:

type forward
port 24224
bind 0.0.0.0

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ Fluentd сСрвСр. Если Π²Π°ΠΌ Π½ΡƒΠΆΠ½Π° Π±ΠΎΠ»Π΅Π΅ продвинутая конфигурация, Π½Π° Docker Hub Π΅ΡΡ‚ΡŒ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Ρ‹ΠΉ Π³Π°ΠΉΠ΄, Π² Ρ‚ΠΎΠΌ числС ΠΈ ΠΎ Ρ‚ΠΎΠΌ, ΠΊΠ°ΠΊ ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ свой ΠΎΠ±Ρ€Π°Π·.

$ 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 Π΅ΡΡ‚ΡŒ file tail plugin.

Π”ΠΎΠ±Π°Π²ΠΈΠΌ Π² ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ Fluent парсинг Π»ΠΎΠ³ΠΎΠ², настроСнный Π²Ρ‹ΡˆΠ΅:

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

И ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΡƒ Π»ΠΎΠ³ΠΎΠ² Π² Kinesis, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ kinesis firehose plugin:

<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

Если Π²Ρ‹ всС ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ настроили, Ρ‚ΠΎ Ρ‡Π΅Ρ€Π΅Π· Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ врСмя (ΠΏΠΎ-ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Kinesis записываСт ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ Ρ€Π°Π· Π² 10 ΠΌΠΈΠ½ΡƒΡ‚) Π²Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»Ρ‹ Π»ΠΎΠ³ΠΎΠ² Π² S3. Π’ мСню «monitoring» Kinesis Firehose ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ, сколько Π΄Π°Π½Π½Ρ‹Ρ… записано Π² S3, Π° Ρ‚Π°ΠΊ ΠΆΠ΅ ошибки. НС Π·Π°Π±ΡƒΠ΄ΡŒΡ‚Π΅ Π΄Π°Ρ‚ΡŒ доступ Π½Π° запись Π² Π±Π°ΠΊΠ΅Ρ‚ S3 для Ρ€ΠΎΠ»ΠΈ Kinesis. Если Kinesis Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π½Π΅ смог Ρ€Π°ΡΠΏΠ°Ρ€ΡΠΈΡ‚ΡŒ, ΠΎΠ½ слоТит ошибки Π² Ρ‚ΠΎΠΌ ΠΆΠ΅ Π±Π°ΠΊΠ΅Ρ‚Π΅.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ Π² Athena. Π”Π°Π²Π°ΠΉΡ‚Π΅ Π½Π°ΠΉΠ΄Π΅ΠΌ свСТиС запросы, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ ΠΎΡ‚Π΄Π°Π»ΠΈ ошибки:

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

Π‘ΠΊΠ°Π½ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ всСх записСй Π½Π° ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ запрос

Π’Π΅ΠΏΠ΅Ρ€ΡŒ наши Π»ΠΎΠ³ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π½Ρ‹ ΠΈ слоТСны Π² S3 Π² ORC, сТаты ΠΈ Π³ΠΎΡ‚ΠΎΠ²Ρ‹ ΠΊ Π°Π½Π°Π»ΠΈΠ·Ρƒ. Kinesis Firehose Π΄Π°ΠΆΠ΅ Ρ€Π°Π·Π»ΠΎΠΆΠΈΠ» ΠΈΡ… ΠΏΠΎ дирСкториям Π½Π° ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ час. Однако, ΠΏΠΎΠΊΠ° Ρ‚Π°Π±Π»ΠΈΡ†Π° Π½Π΅ ΠΏΠ°Ρ€Ρ‚ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Π½Π°, Athena Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ Π·Π° всС врСмя Π½Π° ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ запрос, Π·Π° Ρ€Π΅Π΄ΠΊΠΈΠΌ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ΠΌ. Π­Ρ‚ΠΎ большая ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° ΠΏΠΎ Π΄Π²ΡƒΠΌ ΠΏΡ€ΠΈΡ‡ΠΈΠ½Π°ΠΌ:

  • ОбъСм Π΄Π°Π½Π½Ρ‹Ρ… постоянно растСт, замСдляя запросы;
  • Π‘Ρ‡Π΅Ρ‚ Π·Π° Athena выставляСтся Π² зависимости ΠΎΡ‚ объСма просканированных Π΄Π°Π½Π½Ρ‹Ρ…, с ΠΌΠΈΠ½ΠΈΠΌΡƒΠΌΠΎΠΌ 10 ΠœΠ‘ Π·Π° ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ запрос.

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΈΡΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ это, ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ AWS Glue Crawler, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ просканируСт Π΄Π°Π½Π½Ρ‹Π΅ Π² S3 ΠΈ Π·Π°ΠΏΠΈΡˆΠ΅Ρ‚ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ ΠΎ партициях Π² Glue Metastore. Π­Ρ‚ΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ‚ Π½Π°ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠ°Ρ€Ρ‚ΠΈΡ†ΠΈΠΈ ΠΊΠ°ΠΊ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ ΠΏΡ€ΠΈ запросах Π² Athena, ΠΈ ΠΎΠ½Π° Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΊΠ°Π½ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ, ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹Π΅ Π² запросС.

НастраиваСм Amazon Glue Crawler

Amazon Glue Crawler сканируСт всС Π΄Π°Π½Π½Ρ‹Π΅ Π² S3 Π±Π°ΠΊΠ΅Ρ‚Π΅ ΠΈ создаСт Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ с партициями. Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ Glue Crawler ΠΈΠ· консоли AWS Glue ΠΈ Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ Π±Π°ΠΊΠ΅Ρ‚, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π²Ρ‹ Ρ…Ρ€Π°Π½ΠΈΡ‚Π΅ Π΄Π°Π½Π½Ρ‹Π΅. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ΄ΠΈΠ½ ΠΊΡ€Π°ΡƒΠ»Π΅Ρ€ для Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… Π±Π°ΠΊΠ΅Ρ‚ΠΎΠ², Π² этом случаС ΠΎΠ½ создаст Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π² ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΉ Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ… с названиями, ΡΠΎΠ²ΠΏΠ°Π΄Π°ΡŽΡ‰ΠΈΠΌΠΈ с названиями Π±Π°ΠΊΠ΅Ρ‚ΠΎΠ². Если Π²Ρ‹ ΠΏΠ»Π°Π½ΠΈΡ€ΡƒΠ΅Ρ‚Π΅ постоянно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ эти Π΄Π°Π½Π½Ρ‹Π΅, Π½Π΅ Π·Π°Π±ΡƒΠ΄ΡŒΡ‚Π΅ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ расписаниС запуска 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 Π³ΠΎΠ΄Π°. Но насколько это эффСктивнСС, Ρ‡Π΅ΠΌ просто Ρ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΈΠ· Π½Π΅-ΠΏΠ°Ρ€Ρ‚ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹? Π”Π°Π²Π°ΠΉΡ‚Π΅ ΡƒΠ·Π½Π°Π΅ΠΌ ΠΈ Π²Ρ‹Π±Π΅Ρ€Π΅ΠΌ Ρ‚Π΅ ΠΆΠ΅ записи, ΠΎΡ‚Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠ²Π°Π² ΠΈΡ… ΠΏΠΎ таймстСмпу:

Аналитика Π»ΠΎΠ³ΠΎΠ² Nginx с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Amazon Athena ΠΈ Cube.js

3.59 сСкунды ΠΈ 244.34 ΠΌΠ΅Π³Π°Π±Π°ΠΉΡ‚ Π΄Π°Π½Π½Ρ‹Ρ… Π½Π° датасСтС, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ всСго нСдСля Π»ΠΎΠ³ΠΎΠ². ΠŸΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ ΠΏΠΎ партициям:

Аналитика Π»ΠΎΠ³ΠΎΠ² Nginx с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Amazon Athena ΠΈ Cube.js

Π§ΡƒΡ‚ΡŒ быстрСС, Π½ΠΎ самоС Π²Π°ΠΆΠ½ΠΎΠ΅ β€” всСго 1.23 ΠΌΠ΅Π³Π°Π±Π°ΠΉΡ‚Π° Π΄Π°Π½Π½Ρ‹Ρ…! Π­Ρ‚ΠΎ Π±Ρ‹Π»ΠΎ Π±Ρ‹ Π³ΠΎΡ€Π°Π·Π΄ΠΎ дСшСвлС, Ссли Π±Ρ‹ Π½Π΅ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹Π΅ 10 ΠΌΠ΅Π³Π°Π±Π°ΠΉΡ‚ Π·Π° запрос Π² прайсингС. Но всС Ρ€Π°Π²Π½ΠΎ Π³ΠΎΡ€Π°Π·Π΄ΠΎ Π»ΡƒΡ‡ΡˆΠ΅, Π° Π½Π° Π±ΠΎΠ»ΡŒΡˆΠΈΡ… датасСтах Ρ€Π°Π·Π½ΠΈΡ†Π° Π±ΡƒΠ΄Π΅Ρ‚ ΠΊΡƒΠ΄Π° Π±ΠΎΠ»Π΅Π΅ Π²ΠΏΠ΅Ρ‡Π°Ρ‚Π»ΡΡŽΡ‰Π΅ΠΉ.

Π‘ΠΎΠ±ΠΈΡ€Π°Π΅ΠΌ Π΄ΡΡˆΠ±ΠΎΡ€Π΄ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Cube.js

Π§Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ Π΄ΡΡˆΠ±ΠΎΡ€Π΄, ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ аналитичСский Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊ Cube.js. Π£ Π½Π΅Π³ΠΎ довольно ΠΌΠ½ΠΎΠ³ΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, Π½ΠΎ нас ΠΈΠ½Ρ‚Π΅Ρ€Π΅ΡΡƒΡŽΡ‚ Π΄Π²Π΅: Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ автоматичСски ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Ρ‹ ΠΏΠΎ партициям ΠΈ ΠΏΡ€Π΅-Π°Π³Ρ€Π΅Π³Π°Ρ†ΠΈΠΈ Π΄Π°Π½Π½Ρ‹Ρ…. Он ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ схСму Π΄Π°Π½Π½Ρ‹Ρ… data schema, Π½Π°ΠΏΠΈΡΠ°Π½Π½ΡƒΡŽ Π½Π° Javascript, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠ³Π΅Π½Π΅Π½Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ SQL ΠΈ ΠΈΡΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ запрос ΠΊ Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ…. ΠžΡ‚ нас трСбуСтся лишь ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ ΠΏΠΎ партициям Π² схСмС Π΄Π°Π½Π½Ρ‹Ρ….

Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Cube.js. Π’Π°ΠΊ ΠΊΠ°ΠΊ ΠΌΡ‹ ΡƒΠΆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ AWS-стэк, Π»ΠΎΠ³ΠΈΡ‡Π½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Lambda для дСплоя. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ express-шаблон для Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ, Ссли ΠΏΠ»Π°Π½ΠΈΡ€ΡƒΠ΅Ρ‚Π΅ Ρ…ΠΎΡΡ‚ΠΈΡ‚ΡŒ Cube.js бэкСнд Π² Heroku ΠΈΠ»ΠΈ Docker. Π’ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ описаны Π΄Ρ€ΡƒΠ³ΠΈΠ΅ способы хостинга.

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

Для настройки доступа ΠΊ Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ… Π² cube.js ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ окруТСния. Π“Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ создаст Ρ„Π°ΠΉΠ» .env, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ ваши ΠΊΠ»ΡŽΡ‡ΠΈ для Athena.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π½Π°ΠΌ потрСбуСтся схСма Π΄Π°Π½Π½Ρ‹Ρ…, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΌΡ‹ ΡƒΠΊΠ°ΠΆΠ΅ΠΌ, ΠΊΠ°ΠΊ ΠΈΠΌΠ΅Π½Π½ΠΎ хранятся наши Π»ΠΎΠ³ΠΈ. Π’Π°ΠΌ ΠΆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ ΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊΠΈ для Π΄ΡΡˆΠ±ΠΎΡ€Π΄ΠΎΠ².

Π’ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ 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 прСдоставляСт лишь Π΄Π°Π½Π½Ρ‹Π΅, Ρ‚Π°ΠΊ Ρ‡Ρ‚ΠΎ Π½Π°ΠΌ потрСбуСтся Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° для Π²ΠΈΠ·ΡƒΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΉ β€” ΠΌΠ½Π΅ нравится recharts, Π½ΠΎ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π»ΡŽΠ±ΡƒΡŽ.

Π‘Π΅Ρ€Π²Π΅Ρ€ 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>
        );
      }}
    />
  )
}

Π˜ΡΡ…ΠΎΠ΄Π½ΠΈΠΊΠΈ Π΄ΡΡˆΠ±ΠΎΡ€Π΄Π° доступны Π½Π° CodeSandbox.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com