1. langchain이 무엇일까?

- llm을 직접 호출하고 다양한 방식으로 사용하는 파이프라인을 만들려면 어떻게 해야할까?

- llm으로 특정 애플리케이션과 파이프하인을 만들때 사용하는 프레임워크 중에 하나가 langchain이다.

- 우리가 복잡한 머신러닝 기법을 직접 구현하지 않고 라이브러리를 사용하는 것과 같은 것이라고 생각하면 된다.

 

2. langchain으로 gemini 모델을 사용한 llm 응답 함수를 만들어보자

- 직접 gemini의 sdk를 사용하는 것이 아니라 langchain으로 기능을 만들어보자.

- 시스템 프롬프트는 이전 글에서 사용한 것을 그대로 사용한다.

from langchain_google_genai import GoogleGenerativeAI
from langchain_core.messages import HumanMessage, SystemMessage

GEMINI_API_KEY = '발급받은 gemini api key'

system_prompt = \
"""
1. 답변에는 다른 예시를 추가해서 알려줘야해
수학 연산에 답변을 줬다면 예시처럼 다른 경우도 알려줘
예시1 : 1+4=5야
예시2 : 100+123=223이야
예시3 : 3-1=2야
예시4 : 15/3=5야

2. 너는 학교선생님처럼 친절하게 설명해줘야해.
짧은 답변이 아니라 자세히 친절하게 설명해줘야해.
질문자에게 공부를 잘 할 수 있다는 격려도 해줘야해.

예시1 : 3+3에서 +은 더하기로 앞의 숫자와 뒤의 숫자를 합치는 거야. 다른 케이스도 더 잘 할 수 있을거니 열심히 공부하길 바라
예시2 : 4-3에서 -은 빼기로 앞의 숫자에서 뒤의 숫자 만큼을 줄이는 거야. 다른 연산법도 잘 이해할 수 있도록 내가 잘 알려줄게
"""

model = GoogleGenerativeAI(model="gemini-1.5-flash", google_api_key=GEMINI_API_KEY)

messages = [
    SystemMessage(
        content=system_prompt
    ),
    HumanMessage(
        content="10-3은?"
    )
]

print(model.invoke(messages))

 

- 결과는 이전 글과 동일하게 나온다.

- 이걸 함수로 만든다면 아래와 같이 단순하게 만들 수 있을 것이다.

from langchain_google_genai import GoogleGenerativeAI
from langchain_core.messages import HumanMessage, SystemMessage

system_prompt = \
"""
1. 답변에는 다른 예시를 추가해서 알려줘야해
수학 연산에 답변을 줬다면 예시처럼 다른 경우도 알려줘
예시1 : 1+4=5야
예시2 : 100+123=223이야
예시3 : 3-1=2야
예시4 : 15/3=5야

2. 너는 학교선생님처럼 친절하게 설명해줘야해.
짧은 답변이 아니라 자세히 친절하게 설명해줘야해.
질문자에게 공부를 잘 할 수 있다는 격려도 해줘야해.

예시1 : 3+3에서 +은 더하기로 앞의 숫자와 뒤의 숫자를 합치는 거야. 다른 케이스도 더 잘 할 수 있을거니 열심히 공부하길 바라
예시2 : 4-3에서 -은 빼기로 앞의 숫자에서 뒤의 숫자 만큼을 줄이는 거야. 다른 연산법도 잘 이해할 수 있도록 내가 잘 알려줄게
"""

def inference_message(model=None, human_message=None):
    messages = [
    SystemMessage(
        content=system_prompt
    ),
    HumanMessage(
        content=human_message
    )
    ]
    result = model.invoke(messages)
    return result

 

- 그리고 이 함수를 통해 llm으로 결과를 받으려면 아래와 같이 사용하면 된다.

model = GoogleGenerativeAI(model="gemini-1.5-flash", google_api_key="발급받은 gemini api 키")

result = inference_message(
    model=model,
    human_message="112+34는?"
)

print(result)

 

3. langchain 프레임워크로 간단히 기능을 만들어보자.

- 이미 추상화된 기능을 사용해 llm 기능을 구현하면 편리하게 애플리케이션을 구현할 수 있다.

- 특히 최신 llm 기술에서 사용하는 것도 langchain에서 사용할 수 있기 때문에 langchain을 활용한 개발에 익숙해지자.

1. 시스템 프롬프트란?

- 쉽게 말해서 llm이 특정 명령을 수행할 수 있는 역할을 주는 것이라고 할 수 있다.

- 주로 기본적인 동작방식과 대화의 방식 등을 설정하는데 사용한다.

- api로 결과를 호출할 때 어떤 시스템 프롬프트를 거칠지 설정할 수 있다.

- 이를 파이썬으로 사용하려면 일부 패키지 설치를 통해 쉽게 사용할 수 있다.

- gemini에서는 공식 문서에서 기본적으로 필요한 패키지를 설치하는 과정을 설명해주고 있으니 참고해서 설치해보자.

- https://ai.google.dev/gemini-api/docs/get-started/tutorial?lang=python&hl=ko#install_the_python_sdk

 

튜토리얼: Gemini API 시작하기  |  Google AI for Developers

텍스트 생성 및 채팅 기능을 포함하여 Gemini API 및 Gemini 1.5 Flash를 시작합니다.

ai.google.dev

 

 

2. 라이브러리 설치와 단순한 사용 방법

- 아래의 패키지를 설치한다.

- 주피터 노트북을 사용한다면 설치 후 커널을 재실행하자

pip install -q -U google-generativeai

 

- GEMINI_API_KEY에 발급받은 api key를 할당하고, genai.configure에 등록하면 llm에 호출 할 수 있다.

import google.generativeai as genai

GEMINI_API_KEY = "발급받은 gemini api key"
# api key를 설정
genai.configure(api_key=GEMINI_API_KEY)
# 모델 설정
model = genai.GenerativeModel('gemini-1.5-flash')
# 결과 요청
response = model.generate_content("3+3은 뭐야?")
# 결과 확인
print(response.text)

# 결과 : 3 + 3 = 6 입니다.

 

3. 시스템 프롬프트를 설정해서 내가 원하는 방식의 결과를 받아보자.

- 단순히 결과만 나오는 것이 아니라 내가 원하는 추가 설명이 있는 결과를 받도록 설정해보자.

- 아래와 같이 다른 예시를 하나 추가해주고, 학교 선생님처럼 친절하게 설명해달라는 예시를 붙여보자.

system_prompt = \
"""
1. 답변에는 다른 예시를 추가해서 알려줘야해
수학 연산에 답변을 줬다면 예시처럼 다른 경우도 알려줘
예시1 : 1+4=5야
예시2 : 100+123=223이야
예시3 : 3-1=2야
예시4 : 15/3=5야

2. 너는 학교선생님처럼 친절하게 설명해줘야해.
짧은 답변이 아니라 자세히 친절하게 설명해줘야해.
질문자에게 공부를 잘 할 수 있다는 격려도 해줘야해.

예시1 : 3+3에서 +은 더하기로 앞의 숫자와 뒤의 숫자를 합치는 거야. 다른 케이스도 더 잘 할 수 있을거니 열심히 공부하길 바라
예시2 : 4-3에서 -은 빼기로 앞의 숫자에서 뒤의 숫자 만큼을 줄이는 거야. 다른 연산법도 잘 이해할 수 있도록 내가 잘 알려줄게
"""
# 시스템 프롬프트를 모델 설정에 추가
model=genai.GenerativeModel(
  model_name="gemini-1.5-flash",
  system_instruction=system_prompt)

# 결과 요청
response = model.generate_content("100-73은 뭐야?")
# 결과 확인
print(response.text)

 

- 위와 같은 세팅을 통해 아래와 같은 친절하고 예시가 있는 답변을 얻을 수 있다.

안녕하세요! 100 - 73을 계산하는 방법을 알려드릴게요.  '-' 기호는 빼기를 의미하며, 앞의 수에서 뒤의 수를 빼는 연산입니다.

100에서 73을 빼려면,  우리는 자릿수(일의 자리, 십의 자리, 백의 자리)별로 빼기를 해야 합니다.

* **일의 자리:** 0에서 3을 뺄 수 없으므로, 십의 자리에서 10을 빌려와야 합니다.  십의 자리는 0이므로, 백의 자리에서 1을 빌려와 십의 자리를 10으로 만들고, 다시 십의 자리에서 1을 빌려 일의 자리를 10으로 만듭니다. 이제 일의 자리는 10 - 3 = 7이 됩니다.

* **십의 자리:** 십의 자리는 10에서 1을 빌려줬으므로 9가 됩니다.  9에서 7을 빼면 2가 됩니다.

* **백의 자리:** 백의 자리는 100에서 1을 빌려줬으므로 9가 됩니다.  9에서 아무것도 빼지 않으므로 9가 그대로 남습니다.

따라서, 100 - 73 = 27 입니다.

다른 예시를 통해 더 연습해 볼까요?

* **예시 1:** 55 - 22 = ?  (십의 자리와 일의 자리 모두 뺄 수 있으므로, 각 자릿수별로 빼면 됩니다.)
* **예시 2:** 80 - 35 = ? (일의 자리에서 뺄 수 없으므로 십의 자리에서 10을 빌려와야 합니다.)
* **예시 3:** 125 - 48 = ? (백의 자리, 십의 자리, 일의 자리 모두 계산해야 합니다.  자릿수를 잘 나눠서 생각하면 쉽게 풀 수 있어요!)

이러한 연습을 통해 빼기 연산에 대한 이해도를 높일 수 있습니다.  수학은 조금씩 연습하면 누구든 잘 할 수 있어요!  열심히 노력하면 분명 실력이 향상될 거예요.  힘내세요!

 

4. 시스템 프롬프트를 사용하면 좋은 점

- 우리가 원하는 방식으로 답변을 얻을 수 있도록 튜닝할 수 있다.

- 서비스를 만들거나 원하는 결과를 도출하기 위해서는 이런 프롬프팅을 사용해야만 좋은 결과를 얻을 수 있다.

- 일반적으로 우리들이 사용하고 있는 chatGPT도 프롬프팅이 되어 있어서 우리가 편리하게 사용하고 있는 것이다.

- llm을 사용한 서비스를 만들기 위해 시스템 프롬프트를 잘 사용해보자.

1. 구글 gemini 무료로 사용하기

- 하루 마다 사용할 수 있는 요청 수에 제한이 있고, 분당 요청 수도 제한이 있다.

- 가격 정책을 보면 어느 정도 하루에 무료로 사용할 수 있는지 알 수 있다.

- 사용하는 방식은 

- 관련 사용 문서를 보면 api에 특정 요청을 보내는 것으로 간단히 사용할 수 있는 것을 알 수 있다.

- https://ai.google.dev/gemini-api/docs/get-started/tutorial?lang=python&hl=ko#install_the_python_sdk

- https://ai.google.dev/pricing?hl=ko#1_5flash

 

Gemini API 가격 책정  |  Google AI for Developers

개발자를 위한 Gemini API는 확장할 때 강력한 무료 등급과 유연한 가격 책정을 제공합니다.

ai.google.dev

 

튜토리얼: Gemini API 시작하기  |  Google AI for Developers

텍스트 생성 및 채팅 기능을 포함하여 Gemini API 및 Gemini 1.5 Flash를 시작합니다.

ai.google.dev

 

2. 간단히 요청 보내고 확인해보기

- api키를 생성하면 간단히 요청을 보내는 예제를 확인할 수 있다.

- 요청 주소에서 GEMINI_API_KEY 부분을 발급받은 키로 바꾸면 LLM으로 부터 보낸 요청에 대한 답을 받을 수 있다.

- 보내는 요청은 아래에서 "Explain how AI works" 부분이다.

curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=GEMINI_API_KEY" \
-H 'Content-Type: application/json' \
-X POST \
-d '{
  "contents": [{
    "parts":[{"text": "Explain how AI works"}]
    }]
   }'

 

- 요청을 보내면 아래와 비슷한 결과를 볼 수 있다.

- text에 llm으로 생성된 response가 나오는 것을 확인할 수 있다.

{
  "candidates": [
    {
      "content": {
        "parts": [
          {
            "text": "AI, or Artificial Intelligence, doesn't work in a single, unified way.  Instead, it encompasses a vast range of techniques and approaches, all aiming to mimic human intel .....

1. 어떤 사용 예시가 있을까?

- 클래스를 만들면 동일하거나 비슷한 속성의 객체를 쉽게 관리할 수 있다.

- 예를 들어 카드의 전투력과 방어력이 변동하고 해당 값으로 승패를 가르는 게임이 있다면 쉽게 사용할 수 있을 것이다.

 

 

2. 카드 게임에 사용할 기본 클래스를 구현해보자

- 아래와 같이 구현해보자

class BattleCard:
    def __init__(self, name, attack, defense):
        self.name = name
        self.attack = attack
        self.defense = defense

    def __repr__(self):
        return f"BattleCard('{self.name}', {self.attack}, {self.defense})"
    
    def __getitem__(self, key):
        if key == 'name':
            return self.name
        elif key == 'attack':
            return self.attack
        elif key == 'defense':
            return self.defense
        else:
            raise KeyError(f"Invalid key: {key}")

# wave_card: BattleCard('훌라댄서 웨이브', 10, 5)
# wave_card['name']: 훌라댄서 웨이브
# wave_card['attack']: 10
# wave_card['defense']: 5
# --------------------------------
# surf_card: BattleCard('먹부림 대장 서프', 4, 9)
# surf_card['name']: 먹부림 대장 서프
# surf_card['attack']: 4
# surf_card['defense']: 9

- 그러면 아래와 같이 데이터를 각 카드의 속성을 확인할 수 있다.

wave_card = BattleCard(name="훌라댄서 웨이브", attack=10, defense=5)
surf_card = BattleCard(name="먹부림 대장 서프", attack=4, defense=9)

print(f"wave_card: {wave_card}")
print(f"wave_card['name']: {wave_card['name']}")
print(f"wave_card['attack']: {wave_card['attack']}")
print(f"wave_card['defense']: {wave_card['defense']}")
print("--------------------------------")
print(f"surf_card: {surf_card}")
print(f"surf_card['name']: {surf_card['name']}")
print(f"surf_card['attack']: {surf_card['attack']}")
print(f"surf_card['defense']: {surf_card['defense']}")

- 그렇다면 카드끼리 싸우는 함수를 통해 한 번의 싸움마다 카드의 승패를 확인할 수 있다.

def battle_result(player1_card, player2_card):
    player1_card_defense_status_after_battle = player1_card['defense'] - player2_card['attack']
    player2_card_defense_status_after_battle = player2_card['defense'] - player1_card['attack']
    
    if player1_card_defense_status_after_battle <= 0 and player2_card_defense_status_after_battle <= 0:
        return "두 카드가 모두 파괴되어 무승부입니다.."
    elif player1_card_defense_status_after_battle <= 0 and player2_card_defense_status_after_battle > 0:
        return f"{player1_card['name']} 패배했습니다."
    elif player1_card_defense_status_after_battle > 0 and player2_card_defense_status_after_battle <= 0:
        return f"{player2_card['name']} 패배했습니다."
    else:
        return "두 카드가 모두 살아있습니다."
        

battle_result(wave_card, surf_card)
# '먹부림 대장 서프 패배했습니다.'

- 하지만 만약 무승부로 끝나서 이어서 대결을 해야한다면??

- 그렇다면 인스턴스의 값을 변경하고 다시 대결을 하는 과정이 필요하다.

- 따라서 인스턴스의 값을 변경시킬 수 있는 특별 메서드를 추가한다.

 

 

3. 값을 변경할 수 있도록 바꾸고 배틀 함수를 변경해보자

- __setitem__을 추가해보자

class BattleCard:
    def __init__(self, name, attack, defense):
        self.name = name
        self.attack = attack
        self.defense = defense

    def __repr__(self):
        return f"BattleCard('{self.name}', {self.attack}, {self.defense})"
    
    def __getitem__(self, key):
        if key == 'name':
            return self.name
        elif key == 'attack':
            return self.attack
        elif key == 'defense':
            return self.defense
        else:
            raise KeyError(f"Invalid key: {key}")
    
    def __setitem__(self, key, value):
        if key == 'name':
            self.name = value
        elif key == 'attack':
            self.attack = value
        elif key == 'defense':
            self.defense = value
        else:
            raise KeyError(f"Invalid key: {key}")

- 그리고 배틀 함수에서 변경된 defence의 값을 적용하고 결과로 출력한다.

- 또한 배틀 후의 결과를 출력하는 함수와 배틀을 하는 함수로 분할해서 함수를 관리한다.

def cards_status_after_battle(player1_card, player2_card):
    player1_card_defense_status_after_battle = player1_card['defense'] - player2_card['attack']
    player2_card_defense_status_after_battle = player2_card['defense'] - player1_card['attack']
    player1_card['defense'] = player1_card_defense_status_after_battle
    player2_card['defense'] = player2_card_defense_status_after_battle
    return player1_card, player2_card
    
def battle_result(player1_card, player2_card):
    player1_card_defense_status_after_battle = player1_card['defense']
    player2_card_defense_status_after_battle = player2_card['defense']
    
    if player1_card_defense_status_after_battle <= 0 and player2_card_defense_status_after_battle <= 0:
        return "두 카드가 모두 파괴되어 무승부입니다.."
    elif player1_card_defense_status_after_battle <= 0 and player2_card_defense_status_after_battle > 0:
        return f"{player1_card['name']} 패배했습니다."
    elif player1_card_defense_status_after_battle > 0 and player2_card_defense_status_after_battle <= 0:
        return f"{player2_card['name']} 패배했습니다."
    else:
        return "두 카드가 모두 살아있습니다."


player1_card, player2_card = cards_status_after_battle(wave_card, surf_card)
print(battle_result(player1_card, player2_card))
print(player1_card)
print(player2_card)

# 먹부림 대장 서프 패배했습니다.
# BattleCard('훌라댄서 웨이브', 10, 1)
# BattleCard('먹부림 대장 서프', 4, -1)

 

'개발 공부 > Python' 카테고리의 다른 글

1. 특별 메서드의 기본적인 사용  (0) 2025.01.09

1. 특별 메서드?

- 클래스에 특정한 동작을 부여하기 위해 사용되는 방법이다.

- 더하기, 빼기, 길이 출력 등 쉽게 코드로 구현할 수 있는 기능을 제공한다.

- 하지만 특별 메서드를 사용하면 추가적인 구현이 없어도 되고, 클래스의 기능 구성이 간결해진다.

 

2. 예시를 통해 알아보자

class NumberList:
    def __init__(self, initial_data=None):
        self.data = initial_data
    
    def __getitem__(self, index):
        return self.data[index]
    
    def __len__(self):
        return len(self.data)
    
    def __repr__(self):
        return f"NumberList({self.data})"


- 위의 클래스를 아래와 같이 실행하면 주석으로 달아둔 결과를 얻을 수 있다.

my_list = NumberList([1, 2, 3, 4, 5])

print(f"3번째 숫자: {my_list[3]}")
print(f"나의 리스트 길이 : {len(my_list)}")
print(f"나의 리스트 문자열: {my_list}")

# 출력 결과
# 3번째 숫자: 4
# 나의 리스트 길이 : 5
# 나의 리스트 문자열: NumberList([1, 2, 3, 4, 5])

1. Dockerfile로 특정 작업을 실행하는 이미지를 만들면 좋은점

- 특정 작업을 실행하는 이미지를 만들어 해당 작업을 어디서든 실행시킬 수 있다.

- 도커컨테이너로 작업하면 실행 환경이 보장되기 때문에 안정적인 배포가 가능하다.

- 이를 통해 CI/CD를 할 수 있다.

 

2. Dockerfile를 만드는 법

- 실습을 위해 폴더를 하나 만들고 아래와 같이 main.py와 Dockerfile이라는 파일을 만들자.

# main.py
# argparse로 특정 인자를 실행할 때 받는 코드

import argparse

parser = argparse.ArgumentParser(description="Process two arguments.")
parser.add_argument("arg1", help="The first argument.")
parser.add_argument("arg2", help="The second argument.")
args = parser.parse_args()

print(f"arg1: {args.arg1}, arg2: {args.arg2}")
# Dockerfile (확장자가 없는 파일입니다.)
FROM python:3.9-slim

# 작업 디렉토리 설정
WORKDIR /app

# main.py 복사
COPY main.py .

# 파이썬 로그가 보이게 버퍼 설정
ENV PYTHONUNBUFFERED=1

# 실행 설정
ENTRYPOINT ["python", "main.py"]

- 평소에 argparse를 사용했다면 main.py에 arg가 2개 들어가야 한다는 것을 알것이다.

- 해당 arguments는 이미지를 실행(run) 할 때 넣으면 된다.

 

3. Dockerfile로 image 만들기

- Dockerfile이 있는 경로에서 아래와 같은 명령어를 실행한다.

# main-with-args라는 이름과 1.0이라는 tag를 가지고 docker image가 생긴다
docker build -t main-with-args:1.0

# build가 성공적으로 완료되면 설정한 이름으로 이미지가 생성됐는지 본다.
docker image list

성공했다면 이렇게 조회된다.

 

4. arguments를 써서 컨테이너를 실행하기

- 단순히 컨텐이너를 실행할 때 arguments를 붙이면 된다.

# test-arguments라는 컨테이너 이름으로 first와 second라는 arguments를 붙여서 실행한다.
docker run --name test-arguments main-with-args:1.0 first second

# 실행이 완료되면 docker logs로 확인하자
docker logs test-arguments

아래와 같은 로그가 나오면 성공이다.

 

5. arguments가 아니라 환경변수 값으로는 안될까?

- arguments가 아니라 환경변수를 인자로 받아서 실행하고 싶은 경우도 있을 것이다.

- 그런경우 아래와 같이 환경 변수를 Dockerfile에서 줄 수 있고 실행해서 확인할 수 있다.

# MY_ARG1, MY_ARG2라는 이름으로 설정된 환경 변수를 가져온다.
import os

print(f"MY_ARG1: {os.environ.get('MY_ARG1')}, MY_ARG2: {os.environ.get('MY_ARG2')}")
# 환경 변수를 설정했으니 main.py에 환경변수를 받는 코드가 있으면 된다.
FROM python:3.9-slim

# 작업 디렉토리 설정
WORKDIR /app

# main.py 복사
COPY main.py .

# 파이썬 로그가 보이게 버퍼 설정
ENV PYTHONUNBUFFERED=1

# 환경 변수 설정
ENV MY_ARG1="first my env"
ENV MY_ARG2="second my env"

# 실행 설정
ENTRYPOINT ["python", "main.py"]

 

6. 위와 동일하게 이미지를 만들고 실행해보자

- 명령어는 동일한 방식으로 사용하면 된다.

- 물론 이번에는 arguments를 받는 경우가 아니므로 컨테이너를 그냥 실행하기만 하면 된다.

# 이미지를 생성한다.
docker build -t main-with-envs:1.0 .

# arguments를 주는 코드가 아니므로 실행만한다.
docker run --name test-envs main-with-envs:1.0

# 로그를 살펴보자!
docker logs test-envs

정상적으로 적용된 것을 알 수 있다.

 

7. 결론

- 상황에 따라 적절하게 이미지를 생성해서 사용하자.

- 주로 환경변수로 작업을 진행할테지만 상황에 따라 arguments를 부여해야하는 경우가 있으니 적절히 사용해보자!

1. 문제상황

  • Dockerfile로 특정 print문이 있는 작업을 실행했다.
  • 이 print문은 while문 내에 있다.
  • 실시간으로는 log가 보이지 않고, 강제 종료하면 log가 생기는데 어떻게 하지??

2. 해결 방법

  • Dockerfile에서 ENV PYTHONUNBUFFERED=1을 작성한다.
  • docker logs에서 파이썬 프로세스가 종료되기 전에 발생하는 로그들도 확인할 수 있다.

1. redshift가 뭔가요?

- postgresql를 기반으로한 AWS의 서비스입니다.

- 실습에서는 데이터웨어하우스로 사용하기 위해 구축합니다.

- 관리형 데이터베이스 서비스인 RDS를 사용하면 Zero-ETL을 구축할 수 있습니다.

https://docs.aws.amazon.com/ko_kr/redshift/latest/dg/c_redshift-and-postgres-sql.html

 

Amazon Redshift 및 PostgreSQL - Amazon Redshift

이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.

docs.aws.amazon.com

https://docs.aws.amazon.com/ko_kr/redshift/latest/mgmt/serverless-whatis.html

 

Amazon Redshift 서버리스란 무엇인가요? - Amazon Redshift

Amazon Redshift 서버리스란 무엇인가요? Amazon Redshift Serverless는 데이터 웨어하우스 용량을 자동으로 프로비저닝하고 기본 리소스를 지능적으로 확장합니다. Amazon Redshift Serverless는 용량을 몇 초 만

docs.aws.amazon.com

 

2. Zero-ETL은 뭔가요?

- ETL 과정에서 복잡한 파이프라인 생성을 생략하는 기능입니다.

- AWS의 관리형 데이터베이스인 RDS를 사용하면 CDC 기능을 사용해서 redshift에 데이터를 바로 쌓을 수 있습니다.

- ETL은 데이터른 추출하고 변환하고 적재하는 과정을 말합니다.

- CDC는 데이터베이스의 변경되는 데이터를 바로 다른 DB나 저장소에 반영하는 것으로 생각하면 됩니다.

https://aws.amazon.com/ko/what-is/zero-etl/

 

제로 ETL이란? - 제로 ETL에 대한 설명 - AWS

제로 ETL은 ETL 데이터 파이프라인을 구축할 필요성을 없애거나 최소화하는 통합 세트입니다. 추출, 전환, 적재(ETL)는 다양한 소스의 데이터를 결합, 정리 및 정규화하여 분석, 인공 지능 (AI) 및 기

aws.amazon.com

 

3. 요금은 어떻게 나올까

- 기본적으로 저장된 데이터의 용량에 따라 월별 요금이 나옵니다.

- 그리고 쿼리 작업을 하는데 사용하는 컴퓨팅 리소스에 따라 요금이 나옵니다.

https://aws.amazon.com/ko/redshift/pricing/

 

클라우드 데이터 웨어하우스 – Amazon Redshift 요금–Amazon Web Services

 

aws.amazon.com

 

4. 너무 복잡해요!

- 용어에 대해서 너무 깊게 이해할 필요는 없습니다.

- 실습을 진행하면서 어떤 기능인지 눈으로 확인하고 이해해도 괜찮아요.

- 생각보다 redshift를 이용한 CDC 방법이 제일 쉬울 수 있습니다.

 

 

4. 다음 글 예고

- AWS에서 redshift를 직접 생성합니다.

1. 데이터 레이크란 무엇인가요?

- 어떤 서비스에서 생성되는 데이터를 모두 적재하는 저장소를 운영하는 것으로 생각하면 됩니다.

- 원천 데이터에서 저장소 까지 데이터를 적재하는 작업과 적재한 데이터를 잘 사용할 수 있도록 하는 작업이 주를 이룹니다.

 

2. AWS는 어렵지 않나요?

- 익히기는 어렵지만 로컬 컴퓨터에 실제 구축을 하는 것 보다 훨씬 적은 노력이 들어갑니다.

- 현재는 대부분의 기능은 자동으로 관리되는 관리형 기능이 많기 때문에 인프라 지식도 생각보다 많이 필요 없습니다.

 

3. 시작하며

- 대략적인 구조는 원천 데이터 베이스와 동일한 데이터를 가지는 데이터 웨어하우스를 만들고 파일로 적재합니다.

- 사용되는 기능은 s3, redshift, RDS, DMS, Athena 등이 있습니다.

- 당연히 AWS에 가입해서 리소스를 생성하는 작업이 있으니 AWS 계정을 생성하고 시작하세요!

- 사용에 따라 금액이 나올 수 있으나, 공부를 위해 조금은 투자를 한다고 생각하면 안 아까울지도??

1. airflow 테스트 환경 구축

- 간단한 테스트 환경 구축을 위해 airflow에서 제공하는 docker compose yaml파일을 사용한다.

- 아래의 스크린샷과 같은 부분에서 다운받을 수 있다.

- 링크 : https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html

curl로 다운하는 것도 가능하다

2. airflow에서 사용할 파이썬 라이브러리 추가 방법

- docker compose 파일에 간단하게 라이브러리를 추가하는 방법이 있다.

- airflow에서 pymysql이 기본으로 제공되지 않는데, pymysql을 설치하려면 아래와 같이 내용을 수정하고 저장하자.

## docker compose 파일에서 추가로 설치할 python module을 등록하는 경우
## 아래와 같은 environment 찾아서 수정 후 docker compose up -d
_PIP_ADDITIONAL_REQUIREMENTS: ${_PIP_ADDITIONAL_REQUIREMENTS:- pymysql}

## module을 여러개 설치해야하는 경우는 아래와 같이 공백으로 구분하여 추가한다
_PIP_ADDITIONAL_REQUIREMENTS: ${_PIP_ADDITIONAL_REQUIREMENTS:- pymysql pandas numpy}

3. airflow를 실행하자

- docker compose 파일이 있는 폴더에서 docker compose up -d으로 airflow 환경을 구축한다.

- airflow에서 사용하려는 port를 이미 사용하고 있는 경우 yaml에서 port 번호를 바꿔주도록 하자.

- 공식적으로 제공하는 파일에서는 id와 password는 모두 airflow이므로 변경이 필요하면 yaml에서 바꿔주자.

- localhost:8080 으로 접속해서 아래와 같은 창이 뜨면 테스트 환경 구축에 성공한 것이다.

 

'데이터 시스템 구축 정보 공유 > airflow' 카테고리의 다른 글

1. Airflow란?  (0) 2022.07.31

+ Recent posts