Amazon Athena рдФрд░ Cube.js рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ Nginx рд▓реЙрдЧ рдПрдирд╛рд▓рд┐рдЯрд┐рдХреНрд╕

рдЖрдорддреМрд░ рдкрд░, рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рдЙрддреНрдкрд╛рдж рдпрд╛ рд░реЗрдбреА-рдореЗрдб рдУрдкрди-рд╕реЛрд░реНрд╕ рд╡рд┐рдХрд▓реНрдк, рдЬреИрд╕реЗ рдкреНрд░реЛрдореЗрдерд┐рдпрд╕ + рдЧреНрд░рд╛рдлрд╛рдирд╛, рдХрд╛ рдЙрдкрдпреЛрдЧ рдиреЗрдЧреНрдиреЗрдХреНрд╕ рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХреА рдирд┐рдЧрд░рд╛рдиреА рдФрд░ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рдирд┐рдЧрд░рд╛рдиреА рдпрд╛ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдордп рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдЪреНрдЫрд╛ рд╡рд┐рдХрд▓реНрдк рд╣реИ, рд▓реЗрдХрд┐рди рдРрддрд┐рд╣рд╛рд╕рд┐рдХ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдирд╣реАрдВ рд╣реИред рдХрд┐рд╕реА рднреА рд▓реЛрдХрдкреНрд░рд┐рдп рд╕рдВрд╕рд╛рдзрди рдкрд░, nginx рд▓реЙрдЧ рд╕реЗ рдбреЗрдЯрд╛ рдХреА рдорд╛рддреНрд░рд╛ рддреЗрдЬреА рд╕реЗ рдмрдврд╝ рд░рд╣реА рд╣реИ, рдФрд░ рдмрдбрд╝реА рдорд╛рддреНрд░рд╛ рдореЗрдВ рдбреЗрдЯрд╛ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдХреБрдЫ рдЕрдзрд┐рдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рддрд░реНрдХрд╕рдВрдЧрдд рд╣реИред

рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдЖрдкрдХреЛ рдмрддрд╛рдКрдВрдЧрд╛ рдХрд┐ рдЖрдк рдХреИрд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдПрдереЗрдирд╛ рд▓реЙрдЧ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, Nginx рдХреЛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрддреЗ рд╣реБрдП, рдФрд░ рдореИрдВ рджрд┐рдЦрд╛рдКрдВрдЧрд╛ рдХрд┐ рдУрдкрди-рд╕реЛрд░реНрд╕ рдХреНрдпреВрдм.рдЬреЗрдПрд╕ рдлреНрд░реЗрдорд╡рд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕ рдбреЗрдЯрд╛ рд╕реЗ рдПрдХ рд╡рд┐рд╢реНрд▓реЗрд╖рдгрд╛рддреНрдордХ рдбреИрд╢рдмреЛрд░реНрдб рдХреИрд╕реЗ рдЗрдХрдЯреНрдард╛ рдХрд┐рдпрд╛ рдЬрд╛рдПред рдпрд╣рд╛рдБ рд╕рдВрдкреВрд░реНрдг рд╕рдорд╛рдзрд╛рди рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рд╣реИ:

Amazon Athena рдФрд░ Cube.js рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ Nginx рд▓реЙрдЧ рдПрдирд╛рд▓рд┐рдЯрд┐рдХреНрд╕

рдЯреАрдПрд▓:рдбреАрдЖрд░;
рддреИрдпрд╛рд░ рдбреИрд╢рдмреЛрд░реНрдб рд╕реЗ рд▓рд┐рдВрдХ рдХрд░реЗрдВ.

рдЬрд╛рдирдХрд╛рд░реА рдПрдХрддреНрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдо рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рдзрд╛рд░рд╛рдкреНрд░рд╡рд╛рд╣, рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд▓рд┐рдП - рдПрдбрдмреНрд▓реНрдпреВрдПрд╕ рдХрд┐рдиреЗрд╕рд┐рд╕ рдбреЗрдЯрд╛ рдлрд╝рд╛рдпрд░рд╣реЛрдЬрд╝ ╨╕ рдПрдбрдмреНрд▓реНрдпреВрдПрд╕ рдЧреЛрдВрдж, рднрдВрдбрд╛рд░рдг рдХреЗ рд▓рд┐рдП - рдПрдбрдмреНрд▓реНрдпреВрдПрд╕ рдПрд╕ 3. рдЗрд╕ рдмрдВрдбрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдЖрдк рди рдХреЗрд╡рд▓ nginx рд▓реЙрдЧ, рдмрд▓реНрдХрд┐ рдЕрдиреНрдп рдИрд╡реЗрдВрдЯ, рд╕рд╛рде рд╣реА рдЕрдиреНрдп рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рд▓реЙрдЧ рднреА рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЖрдк рдЕрдкрдиреЗ рд╕реНрдЯреИрдХ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рд╣рд┐рд╕реНрд╕реЛрдВ рдХреЛ рд╕рдорд╛рди рднрд╛рдЧреЛрдВ рд╕реЗ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЖрдк рдлреНрд▓реБрдПрдВрдЯ рдХреЛ рджрд░рдХрд┐рдирд╛рд░ рдХрд░рддреЗ рд╣реБрдП рд╕реАрдзреЗ nginx рд╕реЗ рдХрд╛рдЗрдиреЗрд╕рд┐рд╕ рдореЗрдВ рд▓реЙрдЧ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╛ рдЗрд╕рдХреЗ рд▓рд┐рдП рд▓реЙрдЧрд╕реНрдЯреИрд╢ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

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 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдпрд╣ рдЖрдкрдХреЛ рд▓реЙрдЧ рдХреЛ рдПрдХ рд╣реА рд╕реНрдерд╛рди рдкрд░ рд╕рдВрдЧреНрд░рд╣реАрдд рдФрд░ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдПрдереЗрдирд╛ рд╕реАрдзреЗ S3 рдореЗрдВ рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдмрд╛рдж рдореЗрдВ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдЖрдкрдХреЛ рдмрддрд╛рдКрдВрдЧрд╛ рдХрд┐ рд▓реЙрдЧ рдХреЛ рд╕рд╣реА рддрд░реАрдХреЗ рд╕реЗ рдХреИрд╕реЗ рдЬреЛрдбрд╝рд╛ рдФрд░ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдП, рд▓реЗрдХрд┐рди рдкрд╣рд▓реЗ рд╣рдореЗрдВ S3 рдореЗрдВ рдПрдХ рд╕рд╛рдл рдмрд╛рд▓реНрдЯреА рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рдЬрд┐рд╕рдореЗрдВ рдФрд░ рдХреБрдЫ рднреА рд╕рдВрдЧреНрд░рд╣реАрдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рд╡рд┐рдЪрд╛рд░ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ рдЖрдк рдХрд┐рд╕ рдХреНрд╖реЗрддреНрд░ рдореЗрдВ рдЕрдкрдирд╛ рдмрдХреЗрдЯ рдмрдирд╛рдПрдВрдЧреЗ, рдХреНрдпреЛрдВрдХрд┐ рдПрдереЗрдирд╛ рд╕рднреА рдХреНрд╖реЗрддреНрд░реЛрдВ рдореЗрдВ рдЙрдкрд▓рдмреНрдз рдирд╣реАрдВ рд╣реИред

рдПрдереЗрдирд╛ рдХрдВрд╕реЛрд▓ рдореЗрдВ рдПрдХ рд╕рд░реНрдХрд┐рдЯ рдмрдирд╛рдирд╛

рдЖрдЗрдП рд▓реЙрдЧ рдХреЗ рд▓рд┐рдП рдПрдереЗрдирд╛ рдореЗрдВ рдПрдХ рддрд╛рд▓рд┐рдХрд╛ рдмрдирд╛рдПрдВред рдпрджрд┐ рдЖрдк рдХрд╛рдЗрдиреЗрд╕рд┐рд╕ рдлрд╝рд╛рдпрд░рд╣реЛрдЬрд╝ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдпреЛрдЬрдирд╛ рдмрдирд╛ рд░рд╣реЗ рд╣реИрдВ рддреЛ рдпрд╣ рд▓рд┐рдЦрдиреЗ рдФрд░ рдкрдврд╝рдиреЗ рджреЛрдиреЛрдВ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИред рдПрдереЗрдирд╛ рдХрдВрд╕реЛрд▓ рдЦреЛрд▓реЗрдВ рдФрд░ рдПрдХ рддрд╛рд▓рд┐рдХрд╛ рдмрдирд╛рдПрдВ:

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');

рдХрд╛рдЗрдиреЗрд╕рд┐рд╕ рдлрд╝рд╛рдпрд░рд╣реЛрдЬрд╝ рд╕реНрдЯреНрд░реАрдо рдмрдирд╛рдирд╛

рдХрд╛рдЗрдиреЗрд╕рд┐рд╕ рдлрд╝рд╛рдпрд░рд╣реЛрдЬрд╝ Nginx рд╕реЗ S3 рдореЗрдВ рдкреНрд░рд╛рдкреНрдд рдбреЗрдЯрд╛ рдХреЛ рдЪрдпрдирд┐рдд рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рд▓рд┐рдЦреЗрдЧрд╛, рдЗрд╕реЗ YYYY/MM/DD/HH рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛рдУрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдЧрд╛ред рдбреЗрдЯрд╛ рдкрдврд╝рддреЗ рд╕рдордп рдпрд╣ рдХрд╛рдо рдЖрдПрдЧрд╛ред рдмреЗрд╢рдХ, рдЖрдк fluentd рд╕реЗ рд╕реАрдзреЗ S3 рдкрд░ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдЖрдкрдХреЛ JSON рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛, рдФрд░ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рдмрдбрд╝реЗ рдЖрдХрд╛рд░ рдХреЗ рдХрд╛рд░рдг рдпрд╣ рдЕрдХреНрд╖рдо рд╣реИред рдЗрд╕рдХреЗ рдЕрддрд┐рд░рд┐рдХреНрдд, PrestoDB рдпрд╛ рдПрдереЗрдирд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп, JSON рд╕рдмрд╕реЗ рдзреАрдорд╛ рдбреЗрдЯрд╛ рдкреНрд░рд╛рд░реВрдк рд╣реИред рддреЛ рдХрд╛рдЗрдиреЗрд╕рд┐рд╕ рдлрд╝рд╛рдпрд░рд╣реЛрдЬрд╝ рдХрдВрд╕реЛрд▓ рдЦреЛрд▓реЗрдВ, "рдбрд┐рд▓реАрд╡рд░реА рд╕реНрдЯреНрд░реАрдо рдмрдирд╛рдПрдВ" рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░реЗрдВ, "рдбрд┐рд▓реАрд╡рд░реА" рдлрд╝реАрд▓реНрдб рдореЗрдВ "рдбрд╛рдпрд░реЗрдХреНрдЯ рдкреБрдЯ" рдЪреБрдиреЗрдВ:

Amazon Athena рдФрд░ Cube.js рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ Nginx рд▓реЙрдЧ рдПрдирд╛рд▓рд┐рдЯрд┐рдХреНрд╕

рдЕрдЧрд▓реЗ рдЯреИрдм рдореЗрдВ, "рд░рд┐рдХреЙрд░реНрдб рдкреНрд░рд╛рд░реВрдк рд░реВрдкрд╛рдВрддрд░рдг" - "рд╕рдХреНрд╖рдо" рдЪреБрдиреЗрдВ рдФрд░ рд░рд┐рдХреЙрд░реНрдбрд┐рдВрдЧ рдкреНрд░рд╛рд░реВрдк рдХреЗ рд░реВрдк рдореЗрдВ "рдЕрдкрд╛рдЪреЗ рдУрдЖрд░рд╕реА" рдЪреБрдиреЗрдВред рдХреБрдЫ рд╢реЛрдз рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдУрд╡реЗрди рдУ'рдореИрд▓реА, рдпрд╣ PrestoDB рдФрд░ рдПрдереЗрдирд╛ рдХреЗ рд▓рд┐рдП рдЗрд╖реНрдЯрддрдо рдкреНрд░рд╛рд░реВрдк рд╣реИред рд╣рдо рдКрдкрд░ рдмрдирд╛рдИ рдЧрдИ рддрд╛рд▓рд┐рдХрд╛ рдХреЛ рдПрдХ рд╕реНрдХреАрдорд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЖрдк рдХрд╛рдЗрдиреЗрд╕рд┐рд╕ рдореЗрдВ рдХреЛрдИ рднреА S3 рд╕реНрдерд╛рди рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ; рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рдХреЗрд╡рд▓ рд╕реНрдХреАрдорд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдпрджрд┐ рдЖрдк рдХреЛрдИ рднрд┐рдиреНрди S3 рд╕реНрдерд╛рди рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдЗрд╕ рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рдЗрди рд░рд┐рдХреЙрд░реНрдбреНрд╕ рдХреЛ рдирд╣реАрдВ рдкрдврд╝ рдкрд╛рдПрдВрдЧреЗред

Amazon Athena рдФрд░ Cube.js рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ Nginx рд▓реЙрдЧ рдПрдирд╛рд▓рд┐рдЯрд┐рдХреНрд╕

рд╣рдо рд╕реНрдЯреЛрд░реЗрдЬ рдФрд░ рдЙрд╕ рдмрдХреЗрдЯ рдХреЗ рд▓рд┐рдП S3 рдХрд╛ рдЪрдпрди рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рд╕реЗ рд╣рдордиреЗ рдкрд╣рд▓реЗ рдмрдирд╛рдпрд╛ рдерд╛ред рдПрдбрдмреНрд▓реНрдпреВрдПрд╕ рдЧреНрд▓реВ рдХреНрд░реЙрд▓рд░, рдЬрд┐рд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдореИрдВ рдереЛрдбрд╝реА рджреЗрд░ рдмрд╛рдж рдмрд╛рдд рдХрд░реВрдВрдЧрд╛, рдПрд╕3 рдмрд╛рд▓реНрдЯреА рдореЗрдВ рдЙрдкрд╕рд░реНрдЧреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛, рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рдЦрд╛рд▓реА рдЫреЛрдбрд╝рдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред

Amazon Athena рдФрд░ Cube.js рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ Nginx рд▓реЙрдЧ рдПрдирд╛рд▓рд┐рдЯрд┐рдХреНрд╕

рд╢реЗрд╖ рд╡рд┐рдХрд▓реНрдк рдЖрдкрдХреЗ рд▓реЛрдб рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдмрджрд▓реЗ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ; рдореИрдВ рдЖрдорддреМрд░ рдкрд░ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╡рд╛рд▓реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ S3 рд╕рдВрдкреАрдбрд╝рди рдЙрдкрд▓рдмреНрдз рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди ORC рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдореВрд▓ рд╕рдВрдкреАрдбрд╝рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред

рдзрд╛рд░рд╛рдкреНрд░рд╡рд╛рд╣

рдЕрдм рдЬрдм рд╣рдордиреЗ рд▓реЙрдЧ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдФрд░ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░ рд▓рд┐рдпрд╛ рд╣реИ, рддреЛ рд╣рдореЗрдВ рднреЗрдЬрдиреЗ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╣рдо рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд░реЗрдВрдЧреЗ рдзрд╛рд░рд╛рдкреНрд░рд╡рд╛рд╣, рдХреНрдпреЛрдВрдХрд┐ рдореБрдЭреЗ рд░реВрдмреА рдкрд╕рдВрдж рд╣реИ, рд▓реЗрдХрд┐рди рдЖрдк рд▓реЙрдЧрд╕реНрдЯреИрд╢ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрд╛ рд╕реАрдзреЗ рдХрд┐рдиреЗрд╕рд┐рд╕ рдкрд░ рд▓реЙрдЧ рднреЗрдЬ рд╕рдХрддреЗ рд╣реИрдВред рдлреНрд▓реБрдПрдВрдЯ рд╕рд░реНрд╡рд░ рдХреЛ рдХрдИ рддрд░реАрдХреЛрдВ рд╕реЗ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдореИрдВ рдЖрдкрдХреЛ рдбреЙрдХрд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрддрд╛рдКрдВрдЧрд╛ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╕рд░рд▓ рдФрд░ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИред

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдореЗрдВ fluent.conf рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЗрд╕реЗ рдмрдирд╛рдПрдВ рдФрд░ рд╕реНрд░реЛрдд рдЬреЛрдбрд╝реЗрдВ:

рдЯрд╛рдЗрдк рдЖрдЧреЗ
рдкреЛрд░реНрдЯ 24224
рдмрд╛рдБрдз 0.0.0.0

рдЕрдм рдЖрдк рдлрд╝реНрд▓реБрдПрдВрдЯ рд╕рд░реНрд╡рд░ рдкреНрд░рд╛рд░рдВрдн рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ. рдпрджрд┐ рдЖрдкрдХреЛ рдЕрдзрд┐рдХ рдЙрдиреНрдирдд рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рдпрд╣рд╛рдВ рдЬрд╛рдПрдВ рдбреЙрдХрд░ рд╣рдм рдЗрд╕рдореЗрдВ рдПрдХ рд╡рд┐рд╕реНрддреГрдд рдорд╛рд░реНрдЧрджрд░реНрд╢рд┐рдХрд╛ рджреА рдЧрдИ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдЖрдкрдХреА рдЫрд╡рд┐ рдХреЛ рдХреИрд╕реЗ рд╕рдВрдпреЛрдЬрд┐рдд рдХрд░рдирд╛ рд╢рд╛рдорд┐рд▓ рд╣реИред

$ 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 рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдлрд╝реНрд▓реБрдПрдВрдЯрдбреА рдкреЛрд░реНрдЯ рд╣реИред

рдЕрдм рдЬрдмрдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдлрд╝реНрд▓реБрдПрдВрдЯ рдЪрд▓ рд░рд╣рд╛ рд╣реИ, рд╣рдо рд╡рд╣рд╛рдВ 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 рдХреЛ рдЕрд▓рдЧ рддрд░реАрдХреЗ рд╕реЗ рдЪрд▓рд╛рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рд▓реЙрдЧ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдлрд╝реНрд▓реБрдПрдВрдЯрдбреА рдХреЗ рдкрд╛рд╕ рд╣реИ рдлрд╝рд╛рдЗрд▓ рдЯреЗрд▓ рдкреНрд▓рдЧрдЗрди.

рдЖрдЗрдП рдКрдкрд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХреА рдЧрдИ рд▓реЙрдЧ рдкрд╛рд░реНрд╕рд┐рдВрдЧ рдХреЛ рдлрд╝реНрд▓реБрдПрдВрдЯ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ:

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

рдФрд░ рдХрд╛рдЗрдиреЗрд╕рд┐рд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓реЙрдЧ рднреЗрдЬ рд░рд╣реЗ рд╣реИрдВ рдХрд╛рдЗрдиреЗрд╕рд┐рд╕ рдлрд╝рд╛рдпрд░рд╣реЛрдЬрд╝ рдкреНрд▓рдЧрдЗрди:

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

рдПрдереЗрдирд╛

рдпрджрд┐ рдЖрдкрдиреЗ рд╕рдм рдХреБрдЫ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдпрд╛ рд╣реИ, рддреЛ рдереЛрдбрд╝реА рджреЗрд░ рдХреЗ рдмрд╛рдж (рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, рдХрд╛рдЗрдиреЗрд╕рд┐рд╕ рд░рд┐рдХреЙрд░реНрдб рд╣рд░ 10 рдорд┐рдирдЯ рдореЗрдВ рдПрдХ рдмрд╛рд░ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ) рдЖрдкрдХреЛ S3 рдореЗрдВ рд▓реЙрдЧ рдлрд╝рд╛рдЗрд▓реЗрдВ рджреЗрдЦрдиреА рдЪрд╛рд╣рд┐рдПред рдХрд╛рдЗрдиреЗрд╕рд┐рд╕ рдлрд╝рд╛рдпрд░рд╣реЛрдЬрд╝ рдХреЗ "рдореЙрдирд┐рдЯрд░рд┐рдВрдЧ" рдореЗрдиреВ рдореЗрдВ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ S3 рдореЗрдВ рдХрд┐рддрдирд╛ рдбреЗрдЯрд╛ рд░рд┐рдХреЙрд░реНрдб рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд╕рд╛рде рд╣реА рддреНрд░реБрдЯрд┐рдпрд╛рдБ рднреАред рдХрд╛рдЗрдиреЗрд╕рд┐рд╕ рднреВрдорд┐рдХрд╛ рдХреЗ рд▓рд┐рдП S3 рдмрдХреЗрдЯ рддрдХ рд▓реЗрдЦрди рдкрд╣реБрдВрдЪ рджреЗрдирд╛ рди рднреВрд▓реЗрдВред рдпрджрд┐ рдХрд╛рдЗрдиреЗрд╕рд┐рд╕ рдХреБрдЫ рдкрд╛рд░реНрд╕ рдирд╣реАрдВ рдХрд░ рд╕рдХрд╛, рддреЛ рдпрд╣ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдЙрд╕реА рдмрдХреЗрдЯ рдореЗрдВ рдЬреЛрдбрд╝ рджреЗрдЧрд╛ред

рдЕрдм рдЖрдк рдПрдереЗрдирд╛ рдореЗрдВ рдбреЗрдЯрд╛ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ. рдЖрдЗрдП рдирд╡реАрдирддрдо рдЕрдиреБрд░реЛрдз рдЦреЛрдЬреЗрдВ рдЬрд┐рдирдХреЗ рд▓рд┐рдП рд╣рдордиреЗ рддреНрд░реБрдЯрд┐рдпрд╛рдБ рд▓реМрдЯрд╛рдИрдВ:

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

рдкреНрд░рддреНрдпреЗрдХ рдЕрдиреБрд░реЛрдз рдХреЗ рд▓рд┐рдП рд╕рднреА рд░рд┐рдХреЙрд░реНрдб рд╕реНрдХреИрди рдХрд░рдирд╛

рдЕрдм рд╣рдорд╛рд░реЗ рд▓реЙрдЧ рд╕рдВрд╕рд╛рдзрд┐рдд рд╣реЛ рдЧрдП рд╣реИрдВ рдФрд░ ORC рдореЗрдВ S3 рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд, рд╕рдВрдкреАрдбрд╝рд┐рдд рдФрд░ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВред рдХрд╛рдЗрдиреЗрд╕рд┐рд╕ рдлрд╝рд╛рдпрд░рд╣реЛрдЬрд╝ рдиреЗ рдЙрдиреНрд╣реЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдШрдВрдЯреЗ рдХреЗ рд▓рд┐рдП рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛рдУрдВ рдореЗрдВ рднреА рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд┐рдпрд╛ред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдЬрдм рддрдХ рддрд╛рд▓рд┐рдХрд╛ рдХреЛ рд╡рд┐рднрд╛рдЬрд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдПрдереЗрдирд╛ рджреБрд░реНрд▓рдн рдЕрдкрд╡рд╛рджреЛрдВ рдХреЗ рд╕рд╛рде, рд╣рд░ рдЕрдиреБрд░реЛрдз рдкрд░ рд╕рднреА рд╕рдордп рдХрд╛ рдбреЗрдЯрд╛ рд▓реЛрдб рдХрд░реЗрдЧрд╛ред рдпрд╣ рджреЛ рдХрд╛рд░рдгреЛрдВ рд╕реЗ рдПрдХ рдмрдбрд╝реА рд╕рдорд╕реНрдпрд╛ рд╣реИ:

  • рдбреЗрдЯрд╛ рдХреА рдорд╛рддреНрд░рд╛ рд▓рдЧрд╛рддрд╛рд░ рдмрдврд╝ рд░рд╣реА рд╣реИ, рдЬрд┐рд╕рд╕реЗ рдХреНрд╡реЗрд░реАрдЬрд╝ рдзреАрдореА рд╣реЛ рд░рд╣реА рд╣реИрдВ;
  • рдПрдереЗрдирд╛ рдХреЛ рд╕реНрдХреИрди рдХрд┐рдП рдЧрдП рдбреЗрдЯрд╛ рдХреА рдорд╛рддреНрд░рд╛ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдмрд┐рд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдкреНрд░рддрд┐ рдЕрдиреБрд░реЛрдз рдиреНрдпреВрдирддрдо 10 рдПрдордмреА рд╣реЛрддрд╛ рд╣реИред

рдЗрд╕реЗ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо AWS рдЧреНрд▓реВ рдХреНрд░реЙрд▓рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдЬреЛ S3 рдореЗрдВ рдбреЗрдЯрд╛ рдХреЛ рдХреНрд░реЙрд▓ рдХрд░реЗрдЧрд╛ рдФрд░ рд╡рд┐рднрд╛рдЬрди рдХреА рдЬрд╛рдирдХрд╛рд░реА рдЧреНрд▓реВ рдореЗрдЯрд╛рд╕реНрдЯреЛрд░ рдореЗрдВ рд▓рд┐рдЦреЗрдЧрд╛ред рдпрд╣ рд╣рдореЗрдВ рдПрдереЗрдирд╛ рд╕реЗ рдкреВрдЫрддрд╛рдЫ рдХрд░рддреЗ рд╕рдордп рд╡рд┐рднрд╛рдЬрди рдХреЛ рдлрд╝рд┐рд▓реНрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛, рдФрд░ рдпрд╣ рдХреЗрд╡рд▓ рдХреНрд╡реЗрд░реА рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛рдУрдВ рдХреЛ рд╕реНрдХреИрди рдХрд░реЗрдЧрд╛ред

рдЕрдореЗрдЬрд╝реЕрди рдЧреНрд▓реВ рдХреНрд░реЙрд▓рд░ рдХреА рд╕реНрдерд╛рдкрдирд╛

рдЕрдореЗрдЬрд╝реЕрди рдЧреНрд▓реВ рдХреНрд░реЙрд▓рд░ S3 рдмрдХреЗрдЯ рдореЗрдВ рд╕рднреА рдбреЗрдЯрд╛ рдХреЛ рд╕реНрдХреИрди рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╡рд┐рднрд╛рдЬрди рдХреЗ рд╕рд╛рде рддрд╛рд▓рд┐рдХрд╛рдПрдБ рдмрдирд╛рддрд╛ рд╣реИред AWS рдЧреНрд▓реВ рдХрдВрд╕реЛрд▓ рд╕реЗ рдПрдХ рдЧреНрд▓реВ рдХреНрд░реЙрд▓рд░ рдмрдирд╛рдПрдВ рдФрд░ рдПрдХ рдмрдХреЗрдЯ рдЬреЛрдбрд╝реЗрдВ рдЬрд╣рд╛рдВ рдЖрдк рдбреЗрдЯрд╛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддреЗ рд╣реИрдВред рдЖрдк рдПрдХ рдХреНрд░реЙрд▓рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрдИ рдмрдХреЗрдЯ рдХреЗ рд▓рд┐рдП рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдРрд╕реА рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдпрд╣ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдЙрди рдирд╛рдореЛрдВ рдХреЗ рд╕рд╛рде рддрд╛рд▓рд┐рдХрд╛рдПрдБ рдмрдирд╛рдПрдЧрд╛ рдЬреЛ рдмрдХреЗрдЯ рдХреЗ рдирд╛рдореЛрдВ рд╕реЗ рдореЗрд▓ рдЦрд╛рддреЗ рд╣реИрдВред рдпрджрд┐ рдЖрдк рдЗрд╕ рдбреЗрдЯрд╛ рдХрд╛ рдирд┐рдпрдорд┐рдд рд░реВрдк рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдпреЛрдЬрдирд╛ рдмрдирд╛ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рдЕрдкрдиреА рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЗ рдЕрдиреБрд░реВрдк рдХреНрд░реЙрд▓рд░ рдХреЗ рд▓реЙрдиреНрдЪ рд╢реЗрдбреНрдпреВрд▓ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдирд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВред рд╣рдо рд╕рднреА рдЯреЗрдмрд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдХреНрд░реЙрд▓рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдЬреЛ рд╣рд░ рдШрдВрдЯреЗ рдЪрд▓рддрд╛ рд╣реИред

рд╡рд┐рднрд╛рдЬрд┐рдд рдЯреЗрдмрд▓

рдХреНрд░реЙрд▓рд░ рдХреЗ рдкрд╣рд▓реЗ рд▓реЙрдиреНрдЪ рдХреЗ рдмрд╛рдж, рдкреНрд░рддреНрдпреЗрдХ рд╕реНрдХреИрди рдХреА рдЧрдИ рдмрдХреЗрдЯ рдХреЗ рд▓рд┐рдП рддрд╛рд▓рд┐рдХрд╛рдПрдБ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рджрд┐рдЦрд╛рдИ рджреЗрдиреА рдЪрд╛рд╣рд┐рдПред рдПрдереЗрдирд╛ рдХрдВрд╕реЛрд▓ рдЦреЛрд▓реЗрдВ рдФрд░ 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 рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдФрд░ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреНрд╡реЗрд░реА рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрдВ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИред рд╣рдореЗрдВ рдХреЗрд╡рд▓ рдпрд╣ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рдбреЗрдЯрд╛ рд╕реНрдХреАрдорд╛ рдореЗрдВ рд╡рд┐рднрд╛рдЬрди рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░реЗрдВред

рдЖрдЗрдП рдПрдХ рдирдпрд╛ Cube.js рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдПрдВред рдЪреВрдБрдХрд┐ рд╣рдо рдкрд╣рд▓реЗ рд╕реЗ рд╣реА AWS рд╕реНрдЯреИрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рддреИрдирд╛рддреА рдХреЗ рд▓рд┐рдП рд▓реИрдореНрдмреНрдбрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рддрд░реНрдХрд╕рдВрдЧрдд рд╣реИред рдпрджрд┐ рдЖрдк рд╣реЗрд░реЛрдХреВ рдпрд╛ рдбреЙрдХрд░ рдореЗрдВ рдХреНрдпреВрдм.рдЬреЗрдПрд╕ рдмреИрдХрдПрдВрдб рдХреЛ рд╣реЛрд╕реНрдЯ рдХрд░рдиреЗ рдХреА рдпреЛрдЬрдирд╛ рдмрдирд╛ рд░рд╣реЗ рд╣реИрдВ рддреЛ рдЖрдк рдкреАрдврд╝реА рдХреЗ рд▓рд┐рдП рдПрдХреНрд╕рдкреНрд░реЗрд╕ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рджреВрд╕рд░реЛрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддрд╛ рд╣реИ рд╣реЛрд╕реНрдЯрд┐рдВрдЧ рдХреЗ рддрд░реАрдХреЗ.

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

рдХреНрдпреВрдм.рдЬреЗрдПрд╕ рдореЗрдВ рдбреЗрдЯрд╛рдмреЗрд╕ рдПрдХреНрд╕реЗрд╕ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЬрдирд░реЗрдЯрд░ рдПрдХ .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 рдкреВрд░реНрд╡-рдПрдХрддреНрд░рд┐рдд рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдЕрддрд┐рд░рд┐рдХреНрдд рддрд╛рд▓рд┐рдХрд╛рдПрдБ рдмрдирд╛рдПрдЧрд╛ рдФрд░ рдбреЗрдЯрд╛ рдЖрддреЗ рд╣реА рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЕрдкрдбреЗрдЯ рд╣реЛ рдЬрд╛рдПрдЧрд╛ред рдЗрд╕рд╕реЗ рди рдХреЗрд╡рд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреА рдЧрддрд┐ рддреЗрдЬ рд╣реЛ рдЬрд╛рддреА рд╣реИ, рдмрд▓реНрдХрд┐ рдПрдереЗрдирд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рд▓рд╛рдЧрдд рднреА рдХрдо рд╣реЛ рдЬрд╛рддреА рд╣реИред

рдЖрдЗрдП рдЗрд╕ рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рдбреЗрдЯрд╛ рд╕реНрдХреАрдорд╛ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ:

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 рдмреИрдХрдПрдВрдб рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ рдмрд╛рдХреА рдПрдкреАрдЖрдИ рдФрд░ рд▓реЛрдХрдкреНрд░рд┐рдп рдлреНрд░рдВрдЯ-рдПрдВрдб рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЗ рд▓рд┐рдП рдХреНрд▓рд╛рдЗрдВрдЯ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдПрдХ рд╕реЗрдЯред рдбреИрд╢рдмреЛрд░реНрдб рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдо рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗ рд░рд┐рдПрдХреНрдЯ рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред Cube.js рдХреЗрд╡рд▓ рдбреЗрдЯрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рд╡рд┐рдЬрд╝реБрдЕрд▓рд╛рдЗрдЬрд╝реЗрд╢рди рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА - рдореБрдЭреЗ рдпрд╣ рдкрд╕рдВрдж рд╣реИ рд░рд┐рдЪрд╛рд░реНрдЬ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЖрдк рдХреЛрдИ рднреА рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

Cube.js рд╕рд░реНрд╡рд░ рдЕрдиреБрд░реЛрдз рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ JSON рдкреНрд░рд╛рд░реВрдк, рдЬреЛ рдЖрд╡рд╢реНрдпрдХ рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣ рдЧрдгрдирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ Nginx рдиреЗ рджрд┐рди рдореЗрдВ рдХрд┐рддрдиреА рддреНрд░реБрдЯрд┐рдпрд╛рдБ рджреАрдВ, рдЖрдкрдХреЛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЕрдиреБрд░реЛрдз рднреЗрдЬрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

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

рдЖрдЗрдП NPM рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ Cube.js рдХреНрд▓рд╛рдЗрдВрдЯ рдФрд░ рд░рд┐рдПрдХреНрдЯ рдШрдЯрдХ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ:

$ 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

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдЬреЛрдбрд╝реЗрдВ