ΠΠ΄ΡΠ°Π²ΠΎ Π½Π° ΡΠΈΡΠ΅. ΠΠΎ ΡΠΏΠΎΠ΄Π΅Π»ΡΠ²Π°ΠΌΠ΅ ΠΏΡΠ΅Π²ΠΎΠ΄ΠΎΡ Π½Π° ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΠΎΡ Π΄Π΅Π» ΠΎΠ΄ ΡΡΠ°ΡΠΈΡΠ°ΡΠ°, ΠΏΠΎΠ΄Π³ΠΎΡΠ²Π΅Π½ ΡΠΏΠ΅ΡΠΈΡΠ°Π»Π½ΠΎ Π·Π° ΡΡΡΠ΄Π΅Π½ΡΠΈΡΠ΅ Π½Π° ΠΊΡΡΡΠΎΡ.
Apache Beam ΠΈ Data Flow Π·Π° ΡΠ΅Π²ΠΊΠΎΠ²ΠΎΠ΄ΠΈ Π²ΠΎ ΡΠ΅Π°Π»Π½ΠΎ Π²ΡΠ΅ΠΌΠ΅
ΠΠΎΡΡΠ°Π²ΡΠ²Π°ΡΠ΅ Π½Π° Google Cloud
ΠΠ°Π±Π΅Π»Π΅ΡΠΊΠ°: ΠΠΎ ΠΊΠΎΡΠΈΡΡΠ΅Π² Google Cloud Shell Π·Π° ΠΈΠ·Π²ΡΡΡΠ²Π°ΡΠ΅ Π½Π° Π½Π°ΡΡΠΎΠ²ΠΎΠ΄ΠΎΡ ΠΈ ΠΎΠ±ΡΠ°Π²ΡΠ²Π°ΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π·Π° ΠΏΡΠΈΡΠΏΠΎΡΠΎΠ±Π΅Π½ΠΈ Π΄Π½Π΅Π²Π½ΠΈΡΠΈ Π±ΠΈΠ΄Π΅ΡΡΠΈ ΠΈΠΌΠ°Π² ΠΏΡΠΎΠ±Π»Π΅ΠΌΠΈ ΡΠΎ ΠΈΠ·Π²ΡΡΡΠ²Π°ΡΠ΅ΡΠΎ Π½Π° Π³Π°ΡΠΎΠ²ΠΎΠ΄ΠΎΡ Π²ΠΎ Python 3. Google Cloud Shell ΠΊΠΎΡΠΈΡΡΠΈ Python 2, ΡΡΠΎ Π΅ ΠΏΠΎΠΊΠΎΠ½Π·ΠΈΡΡΠ΅Π½ΡΠ½ΠΎ ΡΠΎ Apache Beam.
ΠΠ° Π΄Π° Π³ΠΎ Π·Π°ΠΏΠΎΡΠ½Π΅ΠΌΠ΅ Π³Π°ΡΠΎΠ²ΠΎΠ΄ΠΎΡ, ΡΡΠ΅Π±Π° ΠΌΠ°Π»ΠΊΡ Π΄Π° ΠΊΠΎΠΏΠ°ΠΌΠ΅ Π²ΠΎ ΠΏΠΎΡΡΠ°Π²ΠΊΠΈΡΠ΅. ΠΠ° ΠΎΠ½ΠΈΠ΅ ΠΎΠ΄ Π²Π°Ρ ΠΊΠΎΠΈ ΠΏΡΠ΅ΡΡ
ΠΎΠ΄Π½ΠΎ Π½Π΅ ΠΊΠΎΡΠΈΡΡΠ΅Π»Π΅ GCP, ΡΠ΅ ΡΡΠ΅Π±Π° Π΄Π° Π³ΠΈ ΡΠ»Π΅Π΄ΠΈΡΠ΅ ΡΠ»Π΅Π΄Π½ΠΈΡΠ΅ 6 ΡΠ΅ΠΊΠΎΡΠΈ Π½Π°Π²Π΅Π΄Π΅Π½ΠΈ Π²ΠΎ ΠΎΠ²Π°
ΠΠΎΡΠ»Π΅ ΠΎΠ²Π°, ΡΠ΅ ΡΡΠ΅Π±Π° Π΄Π° Π³ΠΈ ΠΏΠΎΡΡΠ°Π²ΠΈΠΌΠ΅ Π½Π°ΡΠΈΡΠ΅ ΡΠΊΡΠΈΠΏΡΠΈ Π½Π° Google Cloud Storage ΠΈ Π΄Π° Π³ΠΈ ΠΊΠΎΠΏΠΈΡΠ°ΠΌΠ΅ Π²ΠΎ Π½Π°ΡΠΈΠΎΡ Google Cloud Shel. ΠΠΎΡΡΠ°Π²ΡΠ²Π°ΡΠ΅ΡΠΎ Π²ΠΎ ΡΠΊΠ»Π°Π΄ΠΈΡΠ°ΡΠ΅ ΠΎΠ±Π»Π°ΠΊ Π΅ ΠΏΡΠΈΠ»ΠΈΡΠ½ΠΎ ΡΡΠΈΠ²ΠΈΡΠ°Π»Π½ΠΎ (ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ Π½Π°ΡΠ΄Π΅ ΠΎΠΏΠΈΡ
Π‘Π»ΠΈΠΊΠ° 2
ΠΠΎΠΌΠ°Π½Π΄ΠΈΡΠ΅ ΡΡΠΎ Π½ΠΈ ΡΠ΅ ΠΏΠΎΡΡΠ΅Π±Π½ΠΈ Π·Π° Π΄Π° Π³ΠΈ ΠΊΠΎΠΏΠΈΡΠ°ΠΌΠ΅ Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈΡΠ΅ ΠΈ Π΄Π° Π³ΠΈ ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°ΠΌΠ΅ ΠΏΠΎΡΡΠ΅Π±Π½ΠΈΡΠ΅ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ ΡΠ΅ Π½Π°Π²Π΅Π΄Π΅Π½ΠΈ ΠΏΠΎΠ΄ΠΎΠ»Ρ.
# Copy file from cloud storage
gsutil cp gs://<YOUR-BUCKET>/ * .
sudo pip install apache-beam[gcp] oauth2client==3.0.0
sudo pip install -U pip
sudo pip install Faker==1.0.2
# Environment variables
BUCKET=<YOUR-BUCKET>
PROJECT=<YOUR-PROJECT>
ΠΡΠ΅ΠΈΡΠ°ΡΠ΅ Π½Π° Π½Π°ΡΠ°ΡΠ° Π±Π°Π·Π° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΠΈ ΡΠ°Π±Π΅Π»Π°
ΠΡΠΊΠ°ΠΊΠΎ ΡΠ΅ Π³ΠΈ Π·Π°Π²ΡΡΠΈΠΌΠ΅ ΡΠΈΡΠ΅ ΡΠ΅ΠΊΠΎΡΠΈ ΠΏΠΎΠ²ΡΠ·Π°Π½ΠΈ ΡΠΎ ΠΏΠΎΡΡΠ°Π²ΡΠ²Π°ΡΠ΅ΡΠΎ, ΡΠ»Π΅Π΄Π½ΠΎΡΠΎ Π½Π΅ΡΡΠΎ ΡΡΠΎ ΡΡΠ΅Π±Π° Π΄Π° Π½Π°ΠΏΡΠ°Π²ΠΈΠΌΠ΅ Π΅ Π΄Π° ΡΠΎΠ·Π΄Π°Π΄Π΅ΠΌΠ΅ Π±Π°Π·Π° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΠΈ ΡΠ°Π±Π΅Π»Π° Π²ΠΎ BigQuery. ΠΠΎΡΡΠΎΡΠ°Ρ Π½Π΅ΠΊΠΎΠ»ΠΊΡ Π½Π°ΡΠΈΠ½ΠΈ Π΄Π° Π³ΠΎ Π½Π°ΠΏΡΠ°Π²ΠΈΡΠ΅ ΠΎΠ²Π°, Π½ΠΎ Π½Π°ΡΠ΅Π΄Π½ΠΎΡΡΠ°Π²Π½ΠΈΠΎΡ Π΅ Π΄Π° ΡΠ° ΠΊΠΎΡΠΈΡΡΠΈΡΠ΅ ΠΊΠΎΠ½Π·ΠΎΠ»Π°ΡΠ° Π½Π° Google Cloud ΡΠΎ ΠΏΡΠ²ΠΎ ΡΠΎΠ·Π΄Π°Π²Π°ΡΠ΅ Π½Π° Π±Π°Π·Π° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ. ΠΠΎΠΆΠ΅ΡΠ΅ Π΄Π° Π³ΠΈ ΡΠ»Π΅Π΄ΠΈΡΠ΅ ΡΠ΅ΠΊΠΎΡΠΈΡΠ΅ ΠΏΠΎΠ΄ΠΎΠ»Ρ
Π‘Π»ΠΈΠΊΠ° 3. Π Π°ΡΠΏΠΎΡΠ΅Π΄ Π½Π° ΡΠ°Π±Π΅Π»Π°
ΠΠ±ΡΠ°Π²ΡΠ²Π°ΡΠ΅ Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΠΎΠ΄ Π΄Π½Π΅Π²Π½ΠΈΠΊΠΎΡ Π½Π° ΠΊΠΎΡΠΈΡΠ½ΠΈΠΊΠΎΡ
Pub/Sub Π΅ ΠΊΡΠΈΡΠΈΡΠ½Π° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ° Π½Π° Π½Π°ΡΠΈΠΎΡ Π³Π°ΡΠΎΠ²ΠΎΠ΄ Π±ΠΈΠ΄Π΅ΡΡΠΈ Π΄ΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° ΠΏΠΎΠ²Π΅ΡΠ΅ Π½Π΅Π·Π°Π²ΠΈΡΠ½ΠΈ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΠΈ Π΄Π° ΠΊΠΎΠΌΡΠ½ΠΈΡΠΈΡΠ°Π°Ρ Π΅Π΄Π½ΠΈ ΡΠΎ Π΄ΡΡΠ³ΠΈ. ΠΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΎ, ΡΠ°Π±ΠΎΡΠΈ ΠΊΠ°ΠΊΠΎ ΠΏΠΎΡΡΠ΅Π΄Π½ΠΈΠΊ ΠΊΠΎΡ Π½ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡΠ²Π° Π΄Π° ΠΈΡΠΏΡΠ°ΡΠ°ΠΌΠ΅ ΠΈ ΠΏΡΠΈΠΌΠ°ΠΌΠ΅ ΠΏΠΎΡΠ°ΠΊΠΈ ΠΏΠΎΠΌΠ΅ΡΡ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΠΈΡΠ΅. ΠΡΠ²ΠΎΡΠΎ Π½Π΅ΡΡΠΎ ΡΡΠΎ ΡΡΠ΅Π±Π° Π΄Π° Π½Π°ΠΏΡΠ°Π²ΠΈΠΌΠ΅ Π΅ Π΄Π° ΡΠΎΠ·Π΄Π°Π΄Π΅ΠΌΠ΅ ΡΠ΅ΠΌΠ°. ΠΠ΄Π½ΠΎΡΡΠ°Π²Π½ΠΎ ΠΎΠ΄Π΅ΡΠ΅ Π²ΠΎ Pub/Sub Π²ΠΎ ΠΊΠΎΠ½Π·ΠΎΠ»Π°ΡΠ° ΠΈ ΠΊΠ»ΠΈΠΊΠ½Π΅ΡΠ΅ CREATE TOPIC.
ΠΠΎΠ΄ΠΎΡ ΠΏΠΎΠ΄ΠΎΠ»Ρ ΡΠ° ΠΏΠΎΠ²ΠΈΠΊΡΠ²Π° Π½Π°ΡΠ°ΡΠ° ΡΠΊΡΠΈΠΏΡΠ° Π΄Π° Π³ΠΈ Π³Π΅Π½Π΅ΡΠΈΡΠ° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈΡΠ΅ ΠΎΠ΄ Π΄Π½Π΅Π²Π½ΠΈΠΊΠΎΡ Π΄Π΅ΡΠΈΠ½ΠΈΡΠ°Π½ΠΈ ΠΏΠΎΠ³ΠΎΡΠ΅, Π° ΠΏΠΎΡΠΎΠ° Π³ΠΈ ΠΏΠΎΠ²ΡΠ·ΡΠ²Π° ΠΈ ΠΈΡΠΏΡΠ°ΡΠ° Π΄Π½Π΅Π²Π½ΠΈΡΠΈΡΠ΅ Π΄ΠΎ Pub/Sub. ΠΠ΄ΠΈΠ½ΡΡΠ²Π΅Π½ΠΎΡΠΎ Π½Π΅ΡΡΠΎ ΡΡΠΎ ΡΡΠ΅Π±Π° Π΄Π° Π½Π°ΠΏΡΠ°Π²ΠΈΠΌΠ΅ Π΅ Π΄Π° ΡΠΎΠ·Π΄Π°Π΄Π΅ΠΌΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡ PublisherClient, Π½Π°Π²Π΅Π΄Π΅ΡΠ΅ ΡΠ° ΠΏΠ°ΡΠ΅ΠΊΠ°ΡΠ° Π΄ΠΎ ΡΠ΅ΠΌΠ°ΡΠ° ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ Π³ΠΎ ΠΌΠ΅ΡΠΎΠ΄ΠΎΡ topic_path
ΠΈ ΠΏΠΎΠ²ΠΈΠΊΠ°ΡΡΠ΅ ΡΠ° ΡΡΠ½ΠΊΡΠΈΡΠ°ΡΠ° publish
Ρ topic_path
ΠΈ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ. ΠΠ΅ ΠΌΠΎΠ»ΠΈΠΌΠ΅ ΠΈΠΌΠ°ΡΡΠ΅ ΠΏΡΠ΅Π΄Π²ΠΈΠ΄ Π΄Π΅ΠΊΠ° Π½ΠΈΠ΅ ΡΠ²Π΅Π·ΡΠ²Π°ΠΌΠ΅ generate_log_line
ΠΎΠ΄ Π½Π°ΡΠ΅ΡΠΎ ΡΡΠ΅Π½Π°ΡΠΈΠΎ stream_logs
, Π·Π°ΡΠΎΠ° ΠΏΡΠΎΠ²Π΅ΡΠ΅ΡΠ΅ Π΄Π°Π»ΠΈ ΠΎΠ²ΠΈΠ΅ Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈ ΡΠ΅ Π²ΠΎ ΠΈΡΡΠ°ΡΠ° ΠΏΠ°ΠΏΠΊΠ°, ΠΈΠ½Π°ΠΊΡ ΡΠ΅ Π΄ΠΎΠ±ΠΈΠ΅ΡΠ΅ Π³ΡΠ΅ΡΠΊΠ° ΠΏΡΠΈ ΡΠ²ΠΎΠ·. ΠΠΎΡΠΎΠ° ΠΌΠΎΠΆΠ΅ΠΌΠ΅ Π΄Π° Π³ΠΎ ΠΈΠ·Π²ΡΡΠΈΠΌΠ΅ ΠΎΠ²Π° ΠΏΡΠ΅ΠΊΡ Π½Π°ΡΠ°ΡΠ° ΠΊΠΎΠ½Π·ΠΎΠ»Π° Π½Π° Google ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ:
python publish.py
from stream_logs import generate_log_line
import logging
from google.cloud import pubsub_v1
import random
import time
PROJECT_ID="user-logs-237110"
TOPIC = "userlogs"
publisher = pubsub_v1.PublisherClient()
topic_path = publisher.topic_path(PROJECT_ID, TOPIC)
def publish(publisher, topic, message):
data = message.encode('utf-8')
return publisher.publish(topic_path, data = data)
def callback(message_future):
# When timeout is unspecified, the exception method waits indefinitely.
if message_future.exception(timeout=30):
print('Publishing message on {} threw an Exception {}.'.format(
topic_name, message_future.exception()))
else:
print(message_future.result())
if __name__ == '__main__':
while True:
line = generate_log_line()
print(line)
message_future = publish(publisher, topic_path, line)
message_future.add_done_callback(callback)
sleep_time = random.choice(range(1, 3, 1))
time.sleep(sleep_time)
Π¨ΡΠΎΠΌ Π΄Π°ΡΠΎΡΠ΅ΠΊΠ°ΡΠ° ΡΠ΅ ΡΠ΅ ΠΈΠ·Π²ΡΡΠΈ, ΡΠ΅ ΠΌΠΎΠΆΠ΅ΠΌΠ΅ Π΄Π° Π³ΠΎ Π²ΠΈΠ΄ΠΈΠΌΠ΅ ΠΈΠ·Π»Π΅Π·ΠΎΡ ΠΎΠ΄ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈΡΠ΅ ΠΎΠ΄ Π΄Π½Π΅Π²Π½ΠΈΠΊΠΎΡ Π²ΠΎ ΠΊΠΎΠ½Π·ΠΎΠ»Π°ΡΠ°, ΠΊΠ°ΠΊΠΎ ΡΡΠΎ Π΅ ΠΏΡΠΈΠΊΠ°ΠΆΠ°Π½ΠΎ Π½Π° ΡΠ»ΠΈΠΊΠ°ΡΠ° ΠΏΠΎΠ΄ΠΎΠ»Ρ. ΠΠ²Π°Π° ΡΠΊΡΠΈΠΏΡΠ° ΡΠ΅ ΡΠ°Π±ΠΎΡΠΈ ΡΠ΅ Π΄ΠΎΠ΄Π΅ΠΊΠ° Π½Π΅ ΡΠ° ΠΊΠΎΡΠΈΡΡΠΈΠΌΠ΅ CTRL + CΠ΄Π° Π³ΠΎ Π΄ΠΎΠ²ΡΡΠΈΡ.
Π‘Π»ΠΈΠΊΠ° 4. ΠΠ·Π»Π΅Π· publish_logs.py
ΠΠΈΡΡΠ²Π°ΡΠ΅ Π½Π° Π½Π°ΡΠΈΠΎΡ ΠΊΠΎΠ΄ Π·Π° Π³Π°ΡΠΎΠ²ΠΎΠ΄ΠΎΡ
Π‘Π΅Π³Π° ΠΊΠΎΠ³Π° ΠΈΠΌΠ°ΠΌΠ΅ ΡΓ¨ ΠΏΠΎΠ΄Π³ΠΎΡΠ²Π΅Π½ΠΎ, ΠΌΠΎΠΆΠ΅ΠΌΠ΅ Π΄Π° Π³ΠΎ Π·Π°ΠΏΠΎΡΠ½Π΅ΠΌΠ΅ Π·Π°Π±Π°Π²Π½ΠΈΠΎΡ Π΄Π΅Π» - ΠΊΠΎΠ΄ΠΈΡΠ°ΡΠ΅ Π½Π° Π½Π°ΡΠΈΠΎΡ Π³Π°ΡΠΎΠ²ΠΎΠ΄ ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ Beam ΠΈ Python. ΠΠ° Π΄Π° ΡΠΎΠ·Π΄Π°Π΄Π΅ΠΌΠ΅ Beam pipeline, ΡΡΠ΅Π±Π° Π΄Π° ΡΠΎΠ·Π΄Π°Π΄Π΅ΠΌΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡ Π½Π° ΡΠ΅Π²ΠΊΠΎΠ²ΠΎΠ΄ (p). ΠΡΠΊΠ°ΠΊΠΎ ΡΠ΅ ΡΠΎΠ·Π΄Π°Π΄Π΅ΠΌΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡ Π½Π° ΡΠ΅Π²ΠΊΠΎΠ²ΠΎΠ΄, ΠΌΠΎΠΆΠ΅ΠΌΠ΅ Π΄Π° ΠΏΡΠΈΠΌΠ΅Π½ΠΈΠΌΠ΅ ΠΏΠΎΠ²Π΅ΡΠ΅ ΡΡΠ½ΠΊΡΠΈΠΈ Π΅Π΄Π½Π° ΠΏΠΎ Π΄ΡΡΠ³Π° ΡΠΎ ΠΏΠΎΠΌΠΎΡ Π½Π° ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠΎΡ pipe (|)
. ΠΠΎ ΠΏΡΠΈΠ½ΡΠΈΠΏ, ΡΠ°Π±ΠΎΡΠ½ΠΈΠΎΡ ΡΠ΅ΠΊ ΠΈΠ·Π³Π»Π΅Π΄Π° ΠΊΠ°ΠΊΠΎ ΡΠ»ΠΈΠΊΠ°ΡΠ° ΠΏΠΎΠ΄ΠΎΠ»Ρ.
[Final Output PCollection] = ([Initial Input PCollection] | [First Transform]
| [Second Transform]
| [Third Transform])
ΠΠΎ Π½Π°ΡΠΈΠΎΡ ΠΊΠΎΠ΄, ΡΠ΅ ΡΠΎΠ·Π΄Π°Π΄Π΅ΠΌΠ΅ Π΄Π²Π΅ ΡΠΎΠΏΡΡΠ²Π΅Π½ΠΈ ΡΡΠ½ΠΊΡΠΈΠΈ. Π€ΡΠ½ΠΊΡΠΈΡΠ° regex_clean
, ΠΊΠΎΡ Π³ΠΈ ΡΠΊΠ΅Π½ΠΈΡΠ° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈΡΠ΅ ΠΈ Π³ΠΎ Π²ΡΠ°ΡΠ° ΡΠΎΠΎΠ΄Π²Π΅ΡΠ½ΠΈΠΎΡ ΡΠ΅Π΄ Π²ΡΠ· ΠΎΡΠ½ΠΎΠ²Π° Π½Π° ΡΠΏΠΈΡΠΎΠΊΠΎΡ PATTERNS ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ ΡΠ° ΡΡΠ½ΠΊΡΠΈΡΠ°ΡΠ° re.search
. Π€ΡΠ½ΠΊΡΠΈΡΠ°ΡΠ° Π²ΡΠ°ΡΠ° Π½ΠΈΠ·Π° ΠΎΠ΄Π²ΠΎΠ΅Π½Π° ΡΠΎ Π·Π°ΠΏΠΈΡΠΊΠ°. ΠΠΊΠΎ Π½Π΅ ΡΡΠ΅ Π΅ΠΊΡΠΏΠ΅ΡΡ Π·Π° ΡΠ΅Π΄ΠΎΠ²Π½ΠΎ ΠΈΠ·ΡΠ°Π·ΡΠ²Π°ΡΠ΅, ΠΏΡΠ΅ΠΏΠΎΡΠ°ΡΡΠ²Π°ΠΌ Π΄Π° Π³ΠΎ ΠΏΡΠΎΠ²Π΅ΡΠΈΡΠ΅ ΠΎΠ²Π° datetime
Π²Π½Π°ΡΡΠ΅ Π²ΠΎ ΡΡΠ½ΠΊΡΠΈΡΠ° Π·Π° Π΄Π° ΡΡΠ½ΠΊΡΠΈΠΎΠ½ΠΈΡΠ°. ΠΠΎΠ±ΠΈΠ² Π³ΡΠ΅ΡΠΊΠ° ΠΏΡΠΈ ΡΠ²ΠΎΠ· Π½Π° ΠΏΠΎΡΠ΅ΡΠΎΠΊΠΎΡ Π½Π° Π΄Π°ΡΠΎΡΠ΅ΠΊΠ°ΡΠ°, ΡΡΠΎ Π±Π΅ΡΠ΅ ΡΡΠ΄Π½ΠΎ. ΠΠ²Π°Π° Π»ΠΈΡΡΠ° ΠΏΠΎΡΠΎΠ° ΡΠ΅ ΠΏΡΠ΅Π½Π΅ΡΡΠ²Π° Π½Π° ΡΡΠ½ΠΊΡΠΈΡΠ°ΡΠ° WriteToBigQuery, ΡΡΠΎ Π΅Π΄Π½ΠΎΡΡΠ°Π²Π½ΠΎ Π³ΠΈ Π΄ΠΎΠ΄Π°Π²Π° Π½Π°ΡΠΈΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π½Π° ΡΠ°Π±Π΅Π»Π°ΡΠ°. ΠΠΎΠ΄ΠΎΡ Π·Π° Batch DataFlow Job ΠΈ Streaming DataFlow Job Π΅ Π΄Π°Π΄Π΅Π½ ΠΏΠΎΠ΄ΠΎΠ»Ρ. ΠΠ΄ΠΈΠ½ΡΡΠ²Π΅Π½Π°ΡΠ° ΡΠ°Π·Π»ΠΈΠΊΠ° ΠΏΠΎΠΌΠ΅ΡΡ ΡΠ΅ΡΠΈΡΠΊΠΈΠΎΡ ΠΈ ΡΡΡΠΈΠΌΠΈΠ½Π³ ΠΊΠΎΠ΄ΠΎΡ Π΅ ΡΠΎΠ° ΡΡΠΎ Π²ΠΎ ΡΠ΅ΡΠΈΡΠ° Π³ΠΎ ΡΠΈΡΠ°ΠΌΠ΅ CSV ΠΎΠ΄ src_path
ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ ΡΠ° ΡΡΠ½ΠΊΡΠΈΡΠ°ΡΠ° ReadFromText
ΠΎΠ΄ ΠΡΠ°ΠΊ.
Π Π°Π±ΠΎΡΠ° Π·Π° ΡΠ΅ΡΠΈΡΠΊΠΈ ΠΏΡΠΎΡΠΎΠΊ Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ (ΡΠ΅ΡΠΈΡΠΊΠ° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ°)
import apache_beam as beam
from apache_beam.options.pipeline_options import PipelineOptions
from google.cloud import bigquery
import re
import logging
import sys
PROJECT='user-logs-237110'
schema = 'remote_addr:STRING, timelocal:STRING, request_type:STRING, status:STRING, body_bytes_sent:STRING, http_referer:STRING, http_user_agent:STRING'
src_path = "user_log_fileC.txt"
def regex_clean(data):
PATTERNS = [r'(^S+.[S+.]+S+)s',r'(?<=[).+?(?=])',
r'"(S+)s(S+)s*(S*)"',r's(d+)s',r"(?<=[).d+(?=])",
r'"[A-Z][a-z]+', r'"(http|https)://[a-z]+.[a-z]+.[a-z]+']
result = []
for match in PATTERNS:
try:
reg_match = re.search(match, data).group()
if reg_match:
result.append(reg_match)
else:
result.append(" ")
except:
print("There was an error with the regex search")
result = [x.strip() for x in result]
result = [x.replace('"', "") for x in result]
res = ','.join(result)
return res
class Split(beam.DoFn):
def process(self, element):
from datetime import datetime
element = element.split(",")
d = datetime.strptime(element[1], "%d/%b/%Y:%H:%M:%S")
date_string = d.strftime("%Y-%m-%d %H:%M:%S")
return [{
'remote_addr': element[0],
'timelocal': date_string,
'request_type': element[2],
'status': element[3],
'body_bytes_sent': element[4],
'http_referer': element[5],
'http_user_agent': element[6]
}]
def main():
p = beam.Pipeline(options=PipelineOptions())
(p
| 'ReadData' >> beam.io.textio.ReadFromText(src_path)
| "clean address" >> beam.Map(regex_clean)
| 'ParseCSV' >> beam.ParDo(Split())
| 'WriteToBigQuery' >> beam.io.WriteToBigQuery('{0}:userlogs.logdata'.format(PROJECT), schema=schema,
write_disposition=beam.io.BigQueryDisposition.WRITE_APPEND)
)
p.run()
if __name__ == '__main__':
logger = logging.getLogger().setLevel(logging.INFO)
main()
Π Π°Π±ΠΎΡΠ° Π·Π° ΠΏΡΠ΅Π½ΠΎΡ Π½Π° ΠΏΡΠΎΡΠΎΠΊ Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ (ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π½Π° ΠΏΡΠ΅Π½ΠΎΡ)
from apache_beam.options.pipeline_options import PipelineOptions
from google.cloud import pubsub_v1
from google.cloud import bigquery
import apache_beam as beam
import logging
import argparse
import sys
import re
PROJECT="user-logs-237110"
schema = 'remote_addr:STRING, timelocal:STRING, request_type:STRING, status:STRING, body_bytes_sent:STRING, http_referer:STRING, http_user_agent:STRING'
TOPIC = "projects/user-logs-237110/topics/userlogs"
def regex_clean(data):
PATTERNS = [r'(^S+.[S+.]+S+)s',r'(?<=[).+?(?=])',
r'"(S+)s(S+)s*(S*)"',r's(d+)s',r"(?<=[).d+(?=])",
r'"[A-Z][a-z]+', r'"(http|https)://[a-z]+.[a-z]+.[a-z]+']
result = []
for match in PATTERNS:
try:
reg_match = re.search(match, data).group()
if reg_match:
result.append(reg_match)
else:
result.append(" ")
except:
print("There was an error with the regex search")
result = [x.strip() for x in result]
result = [x.replace('"', "") for x in result]
res = ','.join(result)
return res
class Split(beam.DoFn):
def process(self, element):
from datetime import datetime
element = element.split(",")
d = datetime.strptime(element[1], "%d/%b/%Y:%H:%M:%S")
date_string = d.strftime("%Y-%m-%d %H:%M:%S")
return [{
'remote_addr': element[0],
'timelocal': date_string,
'request_type': element[2],
'body_bytes_sent': element[3],
'status': element[4],
'http_referer': element[5],
'http_user_agent': element[6]
}]
def main(argv=None):
parser = argparse.ArgumentParser()
parser.add_argument("--input_topic")
parser.add_argument("--output")
known_args = parser.parse_known_args(argv)
p = beam.Pipeline(options=PipelineOptions())
(p
| 'ReadData' >> beam.io.ReadFromPubSub(topic=TOPIC).with_output_types(bytes)
| "Decode" >> beam.Map(lambda x: x.decode('utf-8'))
| "Clean Data" >> beam.Map(regex_clean)
| 'ParseCSV' >> beam.ParDo(Split())
| 'WriteToBigQuery' >> beam.io.WriteToBigQuery('{0}:userlogs.logdata'.format(PROJECT), schema=schema,
write_disposition=beam.io.BigQueryDisposition.WRITE_APPEND)
)
result = p.run()
result.wait_until_finish()
if __name__ == '__main__':
logger = logging.getLogger().setLevel(logging.INFO)
main()
Π‘ΡΠ°ΡΡΡΠ²Π°ΡΠ΅ Π½Π° ΡΡΠ°Π½ΡΠΏΠΎΡΡΠ΅ΡΠΎΡ
ΠΠΎΠΆΠ΅ΠΌΠ΅ Π΄Π° Π³ΠΎ Π²ΠΎΠ΄ΠΈΠΌΠ΅ Π³Π°ΡΠΎΠ²ΠΎΠ΄ΠΎΡ Π½Π° Π½Π΅ΠΊΠΎΠ»ΠΊΡ ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ Π½Π°ΡΠΈΠ½ΠΈ. ΠΠΊΠΎ ΡΠ°ΠΊΠ°ΠΌΠ΅, ΠΌΠΎΠΆΠ΅ΠΌΠ΅ ΡΠ°ΠΌΠΎ Π΄Π° Π³ΠΎ ΠΈΠ·Π²ΡΡΠΈΠΌΠ΅ Π»ΠΎΠΊΠ°Π»Π½ΠΎ ΠΎΠ΄ ΡΠ΅ΡΠΌΠΈΠ½Π°Π» Π΄ΠΎΠ΄Π΅ΠΊΠ° ΡΠ΅ Π½Π°ΡΠ°Π²ΡΠ²Π°ΠΌΠ΅ Π½Π° GCP ΠΎΠ΄ Π΄Π°Π»Π΅ΡΠΈΠ½Π°.
python -m main_pipeline_stream.py
--input_topic "projects/user-logs-237110/topics/userlogs"
--streaming
Π‘Π΅ΠΏΠ°ΠΊ, Π½ΠΈΠ΅ ΡΠ΅ Π³ΠΎ ΠΈΠ·Π²ΡΡΠΈΠΌΠ΅ ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ DataFlow. ΠΠΎΠΆΠ΅ΠΌΠ΅ Π΄Π° Π³ΠΎ Π½Π°ΠΏΡΠ°Π²ΠΈΠΌΠ΅ ΡΠΎΠ° ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ ΡΠ° ΠΊΠΎΠΌΠ°Π½Π΄Π°ΡΠ° ΠΏΠΎΠ΄ΠΎΠ»Ρ ΡΠΎ ΠΏΠΎΡΡΠ°Π²ΡΠ²Π°ΡΠ΅ Π½Π° ΡΠ»Π΅Π΄Π½ΠΈΡΠ΅ ΠΏΠΎΡΡΠ΅Π±Π½ΠΈ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΈ.
project
β ID Π½Π° Π²Π°ΡΠΈΠΎΡ GCP ΠΏΡΠΎΠ΅ΠΊΡ.runner
Π΅ ΡΠ΅Π²ΠΊΠΎΠ²ΠΎΠ΄ ΡΡΠΎ ΡΠ΅ ΡΠ° Π°Π½Π°Π»ΠΈΠ·ΠΈΡΠ° Π²Π°ΡΠ°ΡΠ° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ° ΠΈ ΡΠ΅ Π³ΠΎ ΠΊΠΎΠ½ΡΡΡΡΠΈΡΠ° Π²Π°ΡΠΈΠΎΡ Π³Π°ΡΠΎΠ²ΠΎΠ΄. ΠΠ° Π΄Π° ΡΠ°Π±ΠΎΡΠΈ Π²ΠΎ ΠΎΠ±Π»Π°ΠΊΠΎΡ, ΠΌΠΎΡΠ° Π΄Π° Π½Π°Π²Π΅Π΄Π΅ΡΠ΅ DataflowRunner.staging_location
β ΠΏΠ°ΡΠ΅ΠΊΠ°ΡΠ° Π΄ΠΎ ΠΎΠ±Π»Π°ΠΊΠΎΡ Π·Π° ΡΠΊΠ»Π°Π΄ΠΈΡΠ°ΡΠ΅ Π½Π° Cloud Dataflow Π·Π° ΠΈΠ½Π΄Π΅ΠΊΡΠΈΡΠ°ΡΠ΅ Π½Π° ΠΏΠ°ΠΊΠ΅ΡΠΈ ΡΠΎ ΠΊΠΎΠ΄ΠΎΠ²ΠΈ ΠΏΠΎΡΡΠ΅Π±Π½ΠΈ Π½Π° ΠΏΡΠΎΡΠ΅ΡΠΎΡΠΈΡΠ΅ ΡΡΠΎ ΡΠ° Π²ΡΡΠ°Ρ ΡΠ°Π±ΠΎΡΠ°ΡΠ°.temp_location
β ΠΏΠ°ΡΠ΅ΠΊΠ° Π΄ΠΎ ΡΠΊΠ»Π°Π΄ΠΈΡΡΠ΅ΡΠΎ Π²ΠΎ ΠΎΠ±Π»Π°ΠΊ Π½Π° Cloud Dataflow Π·Π° ΡΠΊΠ»Π°Π΄ΠΈΡΠ°ΡΠ΅ Π½Π° ΠΏΡΠΈΠ²ΡΠ΅ΠΌΠ΅Π½ΠΈ Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈ Π·Π° ΡΠ°Π±ΠΎΡΠ½ΠΈ Π·Π°Π΄Π°ΡΠΈ ΡΠΎΠ·Π΄Π°Π΄Π΅Π½ΠΈ Π΄ΠΎΠ΄Π΅ΠΊΠ° ΡΠ°Π±ΠΎΡΠΈ Π½Π°ΡΡΠΎΠ²ΠΎΠ΄ΠΎΡ.streaming
python main_pipeline_stream.py
--runner DataFlow
--project $PROJECT
--temp_location $BUCKET/tmp
--staging_location $BUCKET/staging
--streaming
ΠΠΎΠ΄Π΅ΠΊΠ° ΠΎΠ²Π°Π° ΠΊΠΎΠΌΠ°Π½Π΄Π° ΡΠ°Π±ΠΎΡΠΈ, ΠΌΠΎΠΆΠ΅ΠΌΠ΅ Π΄Π° ΠΎΠ΄ΠΈΠΌΠ΅ Π²ΠΎ ΡΠ°Π±ΡΠ»Π°ΡΠΎΡΠΎΡ DataFlow Π²ΠΎ ΠΊΠΎΠ½Π·ΠΎΠ»Π°ΡΠ° Π½Π° Google ΠΈ Π΄Π° ΡΠ° Π²ΠΈΠ΄ΠΈΠΌΠ΅ Π½Π°ΡΠ°ΡΠ° Π»ΠΈΠ½ΠΈΡΠ°. ΠΠΎΠ³Π° ΠΊΠ»ΠΈΠΊΠ½ΡΠ²Π°ΠΌΠ΅ Π½Π° ΡΠ΅Π²ΠΊΠΎΠ²ΠΎΠ΄ΠΎΡ, ΡΡΠ΅Π±Π° Π΄Π° Π²ΠΈΠ΄ΠΈΠΌΠ΅ Π½Π΅ΡΡΠΎ ΡΠ»ΠΈΡΠ½ΠΎ Π½Π° Π‘Π»ΠΈΠΊΠ° 4. ΠΠ° ΡΠ΅Π»ΠΈΡΠ΅ Π½Π° Π΄Π΅Π±Π°Π³ΠΈΡΠ°ΡΠ΅, ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΠΈΠ΄Π΅ ΠΌΠ½ΠΎΠ³Ρ ΠΊΠΎΡΠΈΡΠ½ΠΎ Π΄Π° ΠΎΡΠΈΠ΄Π΅ΡΠ΅ Π²ΠΎ Logs, Π° ΠΏΠΎΡΠΎΠ° Π²ΠΎ Stackdriver Π·Π° Π΄Π° Π³ΠΈ Π²ΠΈΠ΄ΠΈΡΠ΅ Π΄Π΅ΡΠ°Π»Π½ΠΈΡΠ΅ Π΄Π½Π΅Π²Π½ΠΈΡΠΈ. ΠΠ²Π° ΠΌΠΈ ΠΏΠΎΠΌΠΎΠ³Π½Π° Π΄Π° Π³ΠΈ ΡΠ΅ΡΠ°ΠΌ ΠΏΡΠΎΠ±Π»Π΅ΠΌΠΈΡΠ΅ ΡΠΎ Π³Π°ΡΠΎΠ²ΠΎΠ΄ΠΎΡ Π²ΠΎ Π³ΠΎΠ»Π΅ΠΌ Π±ΡΠΎΡ ΡΠ»ΡΡΠ°ΠΈ.
Π‘Π»ΠΈΠΊΠ° 4: Π’ΡΠ°Π½ΡΠΏΠΎΡΡΠ΅Ρ ΡΠΎ Π·ΡΠ°ΠΊ
ΠΡΠΈΡΡΠ°ΠΏΠ΅ΡΠ΅ Π΄ΠΎ Π½Π°ΡΠΈΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π²ΠΎ BigQuery
ΠΠ½Π°ΡΠΈ, Π²Π΅ΡΠ΅ ΡΡΠ΅Π±Π° Π΄Π° ΠΈΠΌΠ°ΠΌΠ΅ ΡΠ΅Π²ΠΊΠΎΠ²ΠΎΠ΄ ΡΡΠΎ ΡΠ°Π±ΠΎΡΠΈ ΡΠΎ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΡΡΠΎ ΡΠ΅ Π²Π»Π΅Π²Π°Π°Ρ Π²ΠΎ Π½Π°ΡΠ°ΡΠ° ΡΠ°Π±Π΅Π»Π°. ΠΠ° Π΄Π° Π³ΠΎ ΡΠ΅ΡΡΠΈΡΠ°ΠΌΠ΅ ΠΎΠ²Π°, ΠΌΠΎΠΆΠ΅ΠΌΠ΅ Π΄Π° ΠΎΠ΄ΠΈΠΌΠ΅ Π½Π° BigQuery ΠΈ Π΄Π° Π³ΠΈ ΠΏΠΎΠ³Π»Π΅Π΄Π½Π΅ΠΌΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈΡΠ΅. ΠΡΠΊΠ°ΠΊΠΎ ΡΠ΅ ΡΠ° ΠΊΠΎΡΠΈΡΡΠΈΡΠ΅ ΠΊΠΎΠΌΠ°Π½Π΄Π°ΡΠ° ΠΏΠΎΠ΄ΠΎΠ»Ρ, ΡΡΠ΅Π±Π° Π΄Π° Π³ΠΈ Π²ΠΈΠ΄ΠΈΡΠ΅ ΠΏΡΠ²ΠΈΡΠ΅ Π½Π΅ΠΊΠΎΠ»ΠΊΡ ΡΠ΅Π΄ΠΎΠ²ΠΈ ΠΎΠ΄ ΡΠ΅ΡΠΎΡ. Π‘Π΅Π³Π° ΠΊΠΎΠ³Π° Π³ΠΈ ΠΈΠΌΠ°ΠΌΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈΡΠ΅ Π·Π°ΡΡΠ²Π°Π½ΠΈ Π²ΠΎ BigQuery, ΠΌΠΎΠΆΠ΅ΠΌΠ΅ Π΄Π° ΡΠΏΡΠΎΠ²Π΅Π΄Π΅ΠΌΠ΅ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»Π½Π° Π°Π½Π°Π»ΠΈΠ·Π°, ΠΊΠ°ΠΊΠΎ ΠΈ Π΄Π° Π³ΠΈ ΡΠΏΠΎΠ΄Π΅Π»ΠΈΠΌΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈΡΠ΅ ΡΠΎ ΠΊΠΎΠ»Π΅Π³ΠΈΡΠ΅ ΠΈ Π΄Π° ΠΏΠΎΡΠ½Π΅ΠΌΠ΅ Π΄Π° ΠΎΠ΄Π³ΠΎΠ²Π°ΡΠ°ΠΌΠ΅ Π½Π° Π΄Π΅Π»ΠΎΠ²Π½ΠΈ ΠΏΡΠ°ΡΠ°ΡΠ°.
SELECT * FROM `user-logs-237110.userlogs.logdata` LIMIT 10;
Π‘Π»ΠΈΠΊΠ° 5: BigQuery
ΠΠ°ΠΊΠ»ΡΡΠΎΠΊ
Π‘Π΅ Π½Π°Π΄Π΅Π²Π°ΠΌΠ΅ Π΄Π΅ΠΊΠ° ΠΎΠ²Π°Π° ΠΎΠ±ΡΠ°Π²Π° ΡΠ΅ ΠΏΠΎΡΠ»ΡΠΆΠΈ ΠΊΠ°ΠΊΠΎ ΠΊΠΎΡΠΈΡΠ΅Π½ ΠΏΡΠΈΠΌΠ΅Ρ Π·Π° ΡΠΎΠ·Π΄Π°Π²Π°ΡΠ΅ Π½Π° ΠΏΡΠΎΡΠΎΠΊ Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π·Π° ΡΡΡΠΈΠΌΠΈΠ½Π³, ΠΊΠ°ΠΊΠΎ ΠΈ Π·Π° ΠΈΠ·Π½Π°ΠΎΡΠ°ΡΠ΅ Π½Π°ΡΠΈΠ½ΠΈ Π΄Π° Π³ΠΈ Π½Π°ΠΏΡΠ°Π²ΠΈΠΌΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈΡΠ΅ ΠΏΠΎΠ΄ΠΎΡΡΠ°ΠΏΠ½ΠΈ. Π‘ΠΊΠ»Π°Π΄ΠΈΡΠ°ΡΠ΅ΡΠΎ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π²ΠΎ ΠΎΠ²ΠΎΡ ΡΠΎΡΠΌΠ°Ρ Π½ΠΈ Π΄Π°Π²Π° ΠΌΠ½ΠΎΠ³Ρ ΠΏΡΠ΅Π΄Π½ΠΎΡΡΠΈ. Π‘Π΅Π³Π° ΠΌΠΎΠΆΠ΅ΠΌΠ΅ Π΄Π° ΠΏΠΎΡΠ½Π΅ΠΌΠ΅ Π΄Π° ΠΎΠ΄Π³ΠΎΠ²Π°ΡΠ°ΠΌΠ΅ Π½Π° Π²Π°ΠΆΠ½ΠΈ ΠΏΡΠ°ΡΠ°ΡΠ° ΠΊΠ°ΠΊΠΎ Π½Π° ΠΏΡΠΈΠΌΠ΅Ρ ΠΊΠΎΠ»ΠΊΡ Π»ΡΡΠ΅ Π³ΠΎ ΠΊΠΎΡΠΈΡΡΠ°Ρ Π½Π°ΡΠΈΠΎΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄? ΠΠ°Π»ΠΈ Π²Π°ΡΠ°ΡΠ° ΠΊΠΎΡΠΈΡΠ½ΠΈΡΠΊΠ° Π±Π°Π·Π° ΡΠ°ΡΡΠ΅ ΡΠΎ ΡΠ΅ΠΊΠΎΡ Π½Π° Π²ΡΠ΅ΠΌΠ΅ΡΠΎ? Π‘ΠΎ ΠΊΠΎΠΈ Π°ΡΠΏΠ΅ΠΊΡΠΈ Π½Π° ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΎΡ Π»ΡΡΠ΅ΡΠΎ Π½Π°ΡΠΌΠ½ΠΎΠ³Ρ ΠΊΠΎΠΌΡΠ½ΠΈΡΠΈΡΠ°Π°Ρ? Π Π΄Π°Π»ΠΈ ΠΈΠΌΠ° Π³ΡΠ΅ΡΠΊΠΈ ΡΠ°ΠΌΡ ΠΊΠ°Π΄Π΅ ΡΡΠΎ Π½Π΅ ΡΡΠ΅Π±Π° Π΄Π° ΠΈΠΌΠ°? ΠΠ²Π° ΡΠ΅ ΠΏΡΠ°ΡΠ°ΡΠ°ΡΠ° ΠΊΠΎΠΈ ΡΠ΅ Π±ΠΈΠ΄Π°Ρ ΠΎΠ΄ ΠΈΠ½ΡΠ΅ΡΠ΅Ρ Π·Π° ΠΎΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΈΡΠ°ΡΠ°. ΠΡΠ· ΠΎΡΠ½ΠΎΠ²Π° Π½Π° ΡΠ²ΠΈΠ΄ΠΈΡΠ΅ ΡΡΠΎ ΠΏΡΠΎΠΈΠ·Π»Π΅Π³ΡΠ²Π°Π°Ρ ΠΎΠ΄ ΠΎΠ΄Π³ΠΎΠ²ΠΎΡΠΈΡΠ΅ Π½Π° ΠΎΠ²ΠΈΠ΅ ΠΏΡΠ°ΡΠ°ΡΠ°, ΠΌΠΎΠΆΠ΅ΠΌΠ΅ Π΄Π° Π³ΠΎ ΠΏΠΎΠ΄ΠΎΠ±ΡΠΈΠΌΠ΅ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΎΡ ΠΈ Π΄Π° Π³ΠΎ Π·Π³ΠΎΠ»Π΅ΠΌΠΈΠΌΠ΅ Π°Π½Π³Π°ΠΆΠΌΠ°Π½ΠΎΡ Π½Π° ΠΊΠΎΡΠΈΡΠ½ΠΈΡΠΈΡΠ΅.
Beam Π΅ Π½Π°Π²ΠΈΡΡΠΈΠ½Π° ΠΊΠΎΡΠΈΡΠ΅Π½ Π·Π° ΠΎΠ²ΠΎΡ ΡΠΈΠΏ Π½Π° Π²Π΅ΠΆΠ±Π°ΡΠ΅, Π° ΠΈΠΌΠ° ΠΈ Π³ΠΎΠ»Π΅ΠΌ Π±ΡΠΎΡ Π΄ΡΡΠ³ΠΈ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ½ΠΈ ΡΠ»ΡΡΠ°ΠΈ Π½Π° ΡΠΏΠΎΡΡΠ΅Π±Π°. ΠΠ° ΠΏΡΠΈΠΌΠ΅Ρ, ΠΌΠΎΠΆΠ΅Π±ΠΈ ΡΠ΅ ΡΠ°ΠΊΠ°ΡΠ΅ Π΄Π° Π³ΠΈ Π°Π½Π°Π»ΠΈΠ·ΠΈΡΠ°ΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈΡΠ΅ ΠΎΠ΄ ΠΊΡΠ»Π΅ΠΆΠΈΡΠ΅ Π·Π° Π°ΠΊΡΠΈΠΈ Π²ΠΎ ΡΠ΅Π°Π»Π½ΠΎ Π²ΡΠ΅ΠΌΠ΅ ΠΈ Π΄Π° ΠΏΡΠ°Π²ΠΈΡΠ΅ ΡΡΠ³ΡΠ²Π°ΡΠ΅ Π²ΡΠ· ΠΎΡΠ½ΠΎΠ²Π° Π½Π° Π°Π½Π°Π»ΠΈΠ·Π°ΡΠ°, ΠΌΠΎΠΆΠ΅Π±ΠΈ ΠΈΠΌΠ°ΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΠΎΠ΄ ΡΠ΅Π½Π·ΠΎΡΠΈΡΠ΅ ΠΊΠΎΠΈ Π΄ΠΎΠ°ΡΠ°Π°Ρ ΠΎΠ΄ Π²ΠΎΠ·ΠΈΠ»Π°ΡΠ° ΠΈ ΡΠ°ΠΊΠ°ΡΠ΅ Π΄Π° Π³ΠΈ ΠΏΡΠ΅ΡΠΌΠ΅ΡΠ°ΡΠ΅ ΠΏΡΠ΅ΡΠΌΠ΅ΡΠΊΠΈΡΠ΅ Π½Π° Π½ΠΈΠ²ΠΎΡΠΎ Π½Π° ΡΠΎΠΎΠ±ΡΠ°ΡΠ°Ρ. ΠΠΎΠΆΠ΅ΡΠ΅ ΠΈΡΡΠΎ ΡΠ°ΠΊΠ°, Π½Π° ΠΏΡΠΈΠΌΠ΅Ρ, Π΄Π° Π±ΠΈΠ΄Π΅ΡΠ΅ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΡΠ° Π·Π° ΠΈΠ³ΡΠΈ ΡΡΠΎ ΡΠΎΠ±ΠΈΡΠ° ΠΊΠΎΡΠΈΡΠ½ΠΈΡΠΊΠΈ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΠΈ Π³ΠΈ ΠΊΠΎΡΠΈΡΡΠΈ Π·Π° ΡΠΎΠ·Π΄Π°Π²Π°ΡΠ΅ ΠΊΠΎΠ½ΡΡΠΎΠ»Π½ΠΈ ΡΠ°Π±Π»ΠΈ Π·Π° ΡΠ»Π΅Π΄Π΅ΡΠ΅ Π½Π° ΠΊΠ»ΡΡΠ½ΠΈΡΠ΅ ΠΌΠ΅ΡΡΠΈΠΊΠΈ. ΠΠΎΠ±ΡΠΎ, Π³ΠΎΡΠΏΠΎΠ΄Π°, ΠΎΠ²Π° Π΅ ΡΠ΅ΠΌΠ° Π·Π° ΡΡΡΠ΅ Π΅Π΄Π΅Π½ ΠΏΠΎΡΡ, Π±Π»Π°Π³ΠΎΠ΄Π°ΡΠ°ΠΌ ΡΡΠΎ ΠΏΡΠΎΡΠΈΡΠ°Π²ΡΠ΅, Π° Π·Π° ΠΎΠ½ΠΈΠ΅ ΠΊΠΎΠΈ ΡΠ°ΠΊΠ°Π°Ρ Π΄Π° Π³ΠΎ Π²ΠΈΠ΄Π°Ρ ΡΠ΅Π»ΠΎΡΠ½ΠΈΠΎΡ ΠΊΠΎΠ΄, ΠΏΠΎΠ΄ΠΎΠ»Ρ Π΅ Π»ΠΈΠ½ΠΊΠΎΡ Π΄ΠΎ ΠΌΠΎΡΠΎΡ GitHub.
Π’ΠΎΠ° Π΅ ΡΓ¨.
ΠΠ·Π²ΠΎΡ: www.habr.com