์๋
ํ์ธ์ ์ฌ๋ฌ๋ถ. ์ฐ๋ฆฌ๋ ์ด ๊ณผ์ ์ ํ์๋ค์ ์ํด ํน๋ณํ ์ค๋น๋ ๊ธฐ์ฌ์ ๋ง์ง๋ง ๋ถ๋ถ์ ๋ฒ์ญ์ ๊ณต์ ํ๊ณ ์์ต๋๋ค.
์ค์๊ฐ ํ์ดํ๋ผ์ธ์ ์ํ Apache Beam ๋ฐ DataFlow
Google ํด๋ผ์ฐ๋ ์ค์
์ฐธ๊ณ : Python 3์์ ํ์ดํ๋ผ์ธ์ ์คํํ๋ ๋ฐ ๋ฌธ์ ๊ฐ ์์๊ธฐ ๋๋ฌธ์ Google Cloud Shell์ ์ฌ์ฉํ์ฌ ํ์ดํ๋ผ์ธ์ ์คํํ๊ณ ์ปค์คํ ๋ก๊ทธ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํ์ต๋๋ค. Google Cloud Shell์ Apache Beam๊ณผ ๋ ์ผ๊ด๋ Python 2๋ฅผ ์ฌ์ฉํฉ๋๋ค.
ํ์ดํ๋ผ์ธ์ ์์ํ๋ ค๋ฉด ์ค์ ์ ์ข ๋ ์์ธํ ์ดํด๋ด์ผ ํฉ๋๋ค. ์ด์ ์ 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๋ก ์ด๋ํ์ฌ ์ฃผ์ ๋ง๋ค๊ธฐ๋ฅผ ํด๋ฆญํ๋ฉด ๋ฉ๋๋ค.
์๋ ์ฝ๋๋ ์คํฌ๋ฆฝํธ๋ฅผ ํธ์ถํ์ฌ ์์ ์ ์๋ ๋ก๊ทธ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ ํ ๋ก๊ทธ๋ฅผ Pub/Sub์ ์ฐ๊ฒฐํ๊ณ ์ ์กํฉ๋๋ค. ์ฐ๋ฆฌ๊ฐ ํด์ผ ํ ์ ์ผํ ์ผ์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๊ฒ์
๋๋ค. ๊ฒ์์ํด๋ผ์ด์ธํธ, ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ์ฃผ์ ์ ๋ํ ๊ฒฝ๋ก๋ฅผ ์ง์ ํ์ญ์์ค. 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 ํ์ดํ๋ผ์ธ์ ์์ฑํ๋ ค๋ฉด ํ์ดํ๋ผ์ธ ๊ฐ์ฒด(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
๋น์์.
์ผ๊ด DataFlow ์์ (์ผ๊ด ์ฒ๋ฆฌ)
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()
์คํธ๋ฆฌ๋ฐ DataFlow ์์ (์คํธ๋ฆผ ์ฒ๋ฆฌ)
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
โ GCP ํ๋ก์ ํธ์ ID์ ๋๋ค.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
์ด ๋ช ๋ น์ด ์คํ๋๋ ๋์ Google ์ฝ์์ DataFlow ํญ์ผ๋ก ์ด๋ํ์ฌ ํ์ดํ๋ผ์ธ์ ๋ณผ ์ ์์ต๋๋ค. ํ์ดํ๋ผ์ธ์ ํด๋ฆญํ๋ฉด ๊ทธ๋ฆผ 4์ ๋น์ทํ ๋ด์ฉ์ด ํ์๋ฉ๋๋ค. ๋๋ฒ๊น ๋ชฉ์ ์ผ๋ก ๋ก๊ทธ๋ก ์ด๋ํ ๋ค์ Stackdriver๋ก ์ด๋ํ์ฌ ์์ธํ ๋ก๊ทธ๋ฅผ ๋ณด๋ ๊ฒ์ด ๋งค์ฐ ์ ์ฉํ ์ ์์ต๋๋ค. ์ด๋ ์ฌ๋ฌ ๊ฒฝ์ฐ์ ํ์ดํ๋ผ์ธ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐ ๋์์ด ๋์์ต๋๋ค.
๊ทธ๋ฆผ 4: ๋น ์ปจ๋ฒ ์ด์ด
BigQuery์์ ๋ฐ์ดํฐ์ ์ก์ธ์ค
๋ฐ๋ผ์ ํ ์ด๋ธ๋ก ๋ฐ์ดํฐ๊ฐ ํ๋ฅด๋ ํ์ดํ๋ผ์ธ์ด ์ด๋ฏธ ์คํ๋๊ณ ์์ด์ผ ํฉ๋๋ค. ์ด๋ฅผ ํ ์คํธํ๋ ค๋ฉด BigQuery๋ก ์ด๋ํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์ดํด๋ณด์ธ์. ์๋ ๋ช ๋ น์ ์ฌ์ฉํ๋ฉด ๋ฐ์ดํฐ ์ธํธ์ ์ฒ์ ๋ช ํ์ด ํ์๋ฉ๋๋ค. ์ด์ BigQuery์ ๋ฐ์ดํฐ๊ฐ ์ ์ฅ๋์์ผ๋ฏ๋ก ์ถ๊ฐ ๋ถ์์ ์ํํ ์ ์์ ๋ฟ๋ง ์๋๋ผ ๋๋ฃ์ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ๊ณ ๋น์ฆ๋์ค ์ง๋ฌธ์ ๋ํ ๋ต๋ณ์ ์์ํ ์ ์์ต๋๋ค.
SELECT * FROM `user-logs-237110.userlogs.logdata` LIMIT 10;
๊ทธ๋ฆผ 5: BigQuery
๊ฒฐ๋ก
์ด ๊ฒ์๋ฌผ์ด ์คํธ๋ฆฌ๋ฐ ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ์ ์์ฑํ๊ณ ๋ฐ์ดํฐ์ ๋ ์ฝ๊ฒ ์ ๊ทผํ ์ ์๋ ๋ฐฉ๋ฒ์ ์ฐพ๋ ์ ์ฉํ ์๊ฐ ๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. ์ด ํ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ฉด ๋ง์ ์ด์ ์ ์ป์ ์ ์์ต๋๋ค. ์ด์ ์ผ๋ง๋ ๋ง์ ์ฌ๋๋ค์ด ์ฐ๋ฆฌ ์ ํ์ ์ฌ์ฉํ๊ณ ์๋์ง์ ๊ฐ์ ์ค์ํ ์ง๋ฌธ์ ๋ตํ ์ ์์ต๋๋ค. ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ์ฌ์ฉ์ ๊ธฐ๋ฐ์ด ์ฆ๊ฐํ๊ณ ์์ต๋๊น? ์ฌ๋๋ค์ด ์ ํ์ ์ด๋ค ์ธก๋ฉด๊ณผ ๊ฐ์ฅ ๋ง์ด ์ํธ ์์ฉํฉ๋๊น? ๊ทธ๋ฆฌ๊ณ ์์ด์๋ ์ ๋๋ ๊ณณ์ ์ค๋ฅ๊ฐ ์๋์? ์ด๋ ์กฐ์ง์ด ๊ด์ฌ์ ๊ฐ์ง ์ง๋ฌธ์ ๋๋ค. ์ด๋ฌํ ์ง๋ฌธ์ ๋ํ ๋ต๋ณ์์ ์ป์ ํต์ฐฐ๋ ฅ์ ๋ฐํ์ผ๋ก ์ ํ์ ๊ฐ์ ํ๊ณ ์ฌ์ฉ์ ์ฐธ์ฌ๋ฅผ ๋์ผ ์ ์์ต๋๋ค.
Beam์ ์ด๋ฌํ ์ ํ์ ์ด๋์ ์ ๋ง ์ ์ฉํ๋ฉฐ ๋ค๋ฅธ ํฅ๋ฏธ๋ก์ด ์ฌ์ฉ ์ฌ๋ก๋ ๋ง์ด ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์ฃผ์ ํฑ ๋ฐ์ดํฐ๋ฅผ ์ค์๊ฐ์ผ๋ก ๋ถ์ํ๊ณ ๋ถ์์ ๊ธฐ๋ฐ์ผ๋ก ๊ฑฐ๋๋ฅผ ํ๊ณ ์ถ์ ์๋ ์๊ณ , ์ฐจ๋์์ ์ค๋ ์ผ์ ๋ฐ์ดํฐ๊ฐ ์๊ณ ๊ตํต ์์ค ๊ณ์ฐ์ ๊ณ์ฐํ๋ ค๊ณ ํ ์๋ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ์์งํ๊ณ ์ด๋ฅผ ์ฌ์ฉํ์ฌ ์ฃผ์ ์งํ๋ฅผ ์ถ์ ํ๋ ๋์๋ณด๋๋ฅผ ๋ง๋๋ ๊ฒ์ ํ์ฌ๊ฐ ๋ ์๋ ์์ต๋๋ค. ์ข์, ์ฌ๋ฌ๋ถ, ์ด๊ฒ์ ๋ค๋ฅธ ๊ฒ์๋ฌผ์ ์ฃผ์ ์ ๋๋ค. ์ฝ์ด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค. ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๊ณ ์ถ์ ๋ถ๋ค์ ์ํด ์๋์ ๋ด GitHub ๋งํฌ๊ฐ ์์ต๋๋ค.
๊ทธ๊ฒ ๋ค์ผ.
์ถ์ฒ : habr.com