서버리스 함수: AWS 람다로 코드 한 조각 실행하기! λ
안녕, 친구들! 오늘은 정말 흥미진진한 주제로 여러분과 함께할 거야. 바로 서버리스 함수와 AWS 람다(Lambda)에 대해 깊이 파헤쳐볼 거거든. 😎 이 주제가 왜 중요하냐고? 현대 웹 개발의 트렌드이자, 효율적인 리소스 관리의 핵심이기 때문이지! 자, 그럼 우리 함께 서버리스의 세계로 뛰어들어볼까? 🏊♂️
🚀 잠깐! 알고 가자!
서버리스(Serverless)라고 해서 서버가 아예 없는 게 아니야. 단지 우리가 서버 관리에 신경 쓰지 않아도 된다는 뜻이지. 마치 재능넷에서 다양한 재능을 거래할 때, 플랫폼 관리는 신경 쓰지 않고 오로지 재능 교환에만 집중할 수 있는 것처럼 말이야!
1. 서버리스 아키텍처란 뭐야? 🤔
서버리스 아키텍처는 말 그대로 '서버 없는' 구조를 의미해. 하지만 실제로는 서버가 없는 게 아니라, 개발자가 서버 관리에 신경 쓰지 않아도 되는 구조를 말하는 거야. 즉, 서버 인프라를 클라우드 제공업체가 관리하고, 개발자는 순수하게 코드 작성에만 집중할 수 있는 환경이지.
서버리스의 핵심은 '함수'야. 전통적인 서버 기반 아키텍처에서는 애플리케이션 전체를 하나의 큰 덩어리로 배포하고 관리했다면, 서버리스에서는 애플리케이션을 작은 함수 단위로 쪼개서 필요할 때만 실행하는 방식을 사용해.
위 그림을 보면 차이가 확 와닿지? 전통적인 방식은 하나의 큰 애플리케이션을 통째로 관리해야 했어. 반면 서버리스는 작은 함수들의 집합으로 이루어져 있지. 이렇게 하면 각 기능을 독립적으로 개발하고 배포할 수 있어서 유연성이 크게 향상돼.
서버리스의 장점 🌟
- 비용 효율성: 사용한 만큼만 지불하면 돼. 함수가 실행되지 않을 때는 비용이 들지 않아.
- 확장성: 트래픽이 증가해도 자동으로 확장되니까 걱정 없어!
- 개발 속도 향상: 서버 관리에 시간을 쓰지 않아도 되니까, 순수하게 비즈니스 로직 개발에만 집중할 수 있어.
- 유지보수 간소화: 작은 함수 단위로 관리하니까, 문제가 생겨도 빠르게 해결할 수 있지.
💡 재능넷 팁!
서버리스 아키텍처는 재능넷 같은 플랫폼에서도 활용할 수 있어. 예를 들어, 사용자 인증이나 결제 처리 같은 기능을 서버리스 함수로 구현하면 더 효율적인 리소스 관리가 가능해질 거야.
2. AWS Lambda: 서버리스의 강력한 도구 🛠️
자, 이제 AWS Lambda에 대해 자세히 알아볼 차례야. AWS Lambda는 아마존 웹 서비스(AWS)에서 제공하는 서버리스 컴퓨팅 서비스야. Lambda를 사용하면 서버를 프로비저닝하거나 관리하지 않고도 코드를 실행할 수 있어. 정말 편리하지?
AWS Lambda의 작동 원리 🔍
Lambda의 작동 원리는 생각보다 단순해. 다음과 같은 순서로 진행돼:
- 함수 작성: 원하는 프로그래밍 언어로 함수를 작성해.
- 함수 업로드: 작성한 함수를 AWS Lambda에 업로드해.
- 트리거 설정: 함수를 실행할 조건(트리거)을 설정해.
- 함수 실행: 설정한 트리거 조건이 충족되면 함수가 자동으로 실행돼.
- 결과 반환: 함수 실행 결과가 필요한 곳으로 전달돼.
이 과정이 자동으로 이뤄지기 때문에, 개발자는 함수 로직에만 집중할 수 있어. 서버 관리나 스케일링에 대해서는 전혀 신경 쓸 필요가 없지. 👍
Lambda 함수의 특징 🌈
- 이벤트 기반 실행: HTTP 요청, 데이터베이스 변경, 파일 업로드 등 다양한 이벤트에 반응해 실행돼.
- 자동 스케일링: 동시에 여러 요청이 들어와도 자동으로 확장되어 처리해.
- 다양한 언어 지원: Node.js, Python, Java, C#, Go 등 다양한 프로그래밍 언어를 지원해.
- 타임아웃 제한: 기본적으로 함수 실행 시간은 최대 15분으로 제한돼. 긴 작업은 다른 방식으로 처리해야 해.
- 상태 비저장(Stateless): 함수는 상태를 저장하지 않아. 필요한 경우 외부 저장소를 사용해야 해.
🔔 알림!
Lambda 함수는 재능넷 같은 플랫폼에서 다양하게 활용될 수 있어. 예를 들어, 사용자가 새로운 재능을 등록할 때마다 자동으로 검증하는 함수를 만들 수 있지. 이렇게 하면 관리자의 수동 작업을 줄이고 효율성을 높일 수 있어!
3. Lambda 함수 만들기: 실전 예제 👨💻
이제 실제로 Lambda 함수를 만들어볼 거야. 간단한 예제로 시작해서, 점점 복잡한 함수로 발전시켜 나가볼게. 준비됐니? 그럼 시작해볼까! 🚀
3.1 Hello, Lambda! 👋
가장 기본적인 Lambda 함수부터 시작해보자. 이 함수는 단순히 "Hello, Lambda!"라는 메시지를 반환할 거야.
exports.handler = async (event) => {
const response = {
statusCode: 200,
body: JSON.stringify('Hello, Lambda!'),
};
return response;
};
이 코드를 설명해줄게:
exports.handler
: 이것이 Lambda 함수의 진입점이야. AWS가 이 함수를 호출할 거야.async (event) => { ... }
: 비동기 함수로,event
파라미터를 받아. 이event
에는 함수 호출 시 전달된 데이터가 들어있어.response
객체: HTTP 응답을 모방한 구조야.statusCode
는 HTTP 상태 코드,body
는 응답 본문이야.JSON.stringify()
: 문자열을 JSON 형식으로 변환해. API Gateway와 함께 사용할 때 필요해.
이 함수를 Lambda에 업로드하고 테스트해보면, "Hello, Lambda!"라는 메시지를 받을 수 있을 거야.
3.2 이벤트 데이터 활용하기 🎭
이번에는 이벤트 데이터를 활용해서 조금 더 동적인 함수를 만들어볼게. 사용자의 이름을 받아서 개인화된 인사를 반환하는 함수를 만들어보자.
exports.handler = async (event) => {
let name = "Guest";
if (event.queryStringParameters && event.queryStringParameters.name) {
name = event.queryStringParameters.name;
}
const response = {
statusCode: 200,
body: JSON.stringify(`Hello, ${name}! Welcome to Lambda.`),
};
return response;
};
이 함수는 조금 더 복잡해 보이지? 하나씩 설명해줄게:
event.queryStringParameters
: API Gateway를 통해 전달된 쿼리 문자열 파라미터를 포함해.if (event.queryStringParameters && event.queryStringParameters.name) { ... }
: 쿼리 문자열에 'name' 파라미터가 있는지 확인해.name = event.queryStringParameters.name;
: 'name' 파라미터가 있으면, 그 값을 사용해.`Hello, ${name}! Welcome to Lambda.`
: 템플릿 리터럴을 사용해 동적 메시지를 생성해.
이 함수를 API Gateway와 연결하면, https://your-api-endpoint.com/path?name=John
같은 URL로 요청을 보냈을 때 "Hello, John! Welcome to Lambda."라는 응답을 받을 수 있어.
💡 Pro Tip:
실제 프로덕션 환경에서는 사용자 입력을 항상 검증하고 살균(sanitize)해야 해. 악의적인 입력으로부터 시스템을 보호하는 것이 중요해!
3.3 외부 서비스와 통합하기: 날씨 정보 가져오기 🌤️
이번에는 좀 더 실용적인 예제를 만들어볼게. 외부 API를 호출해서 날씨 정보를 가져오는 Lambda 함수를 만들어보자. 이를 위해 axios
라이브러리를 사용할 거야.
먼저, Lambda 함수에 axios
를 설치해야 해. Lambda 콘솔에서 직접 할 수도 있지만, 로컬에서 개발하고 업로드하는 것이 더 편리할 거야.
const axios = require('axios');
exports.handler = async (event) => {
let city = "Seoul";
if (event.queryStringParameters && event.queryStringParameters.city) {
city = event.queryStringParameters.city;
}
try {
const apiKey = 'your_openweathermap_api_key';
const url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric`;
const response = await axios.get(url);
const weatherData = response.data;
return {
statusCode: 200,
body: JSON.stringify({
city: weatherData.name,
temperature: weatherData.main.temp,
description: weatherData.weather[0].description
}),
};
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify({ error: 'Failed to fetch weather data' }),
};
}
};
와! 이 함수는 꽤 많은 일을 하고 있어. 하나씩 살펴보자:
- 도시 이름을 쿼리 파라미터로 받아와. 기본값은 "Seoul"이야.
- OpenWeatherMap API를 사용해 해당 도시의 날씨 정보를 가져와.
axios.get()
을 사용해 HTTP GET 요청을 보내.- 받아온 데이터에서 필요한 정보(도시 이름, 온도, 날씨 설명)만 추출해 반환해.
- 에러 처리도 해. API 호출이 실패하면 500 에러를 반환해.
이 함수를 사용하면, https://your-api-endpoint.com/path?city=London
같은 URL로 요청을 보내 런던의 현재 날씨 정보를 받아올 수 있어!
⚠️ 주의사항:
실제 프로덕션 환경에서는 API 키를 코드에 직접 넣지 마! AWS Secrets Manager나 환경 변수를 사용해 안전하게 관리해야 해.
3.4 데이터베이스와 연동하기: DynamoDB 사용 예제 📊
서버리스 아키텍처에서 데이터를 영구적으로 저장하려면 외부 데이터베이스를 사용해야 해. AWS에서는 DynamoDB라는 NoSQL 데이터베이스를 제공하는데, 이것과 Lambda를 연동해보자.
이 예제에서는 간단한 방명록 시스템을 만들어볼 거야. 사용자가 메시지를 남기면 DynamoDB에 저장하고, 모든 메시지를 조회할 수 있는 기능을 구현할 거야.
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event) => {
const { httpMethod, body } = event;
const TABLE_NAME = 'Guestbook';
switch (httpMethod) {
case 'POST':
const { message, author } = JSON.parse(body);
const timestamp = new Date().toISOString();
const params = {
TableName: TABLE_NAME,
Item: {
id: timestamp,
message,
author,
createdAt: timestamp
}
};
try {
await dynamodb.put(params).promise();
return {
statusCode: 200,
body: JSON.stringify({ message: 'Message added successfully' })
};
} catch (error) {
console.error('Error adding message:', error);
return {
statusCode: 500,
body: JSON.stringify({ error: 'Failed to add message' })
};
}
case 'GET':
try {
const result = await dynamodb.scan({ TableName: TABLE_NAME }).promise();
return {
statusCode: 200,
body: JSON.stringify(result.Items)
};
} catch (error) {
console.error('Error fetching messages:', error);
return {
statusCode: 500,
body: JSON.stringify({ error: 'Failed to fetch messages' })
};
}
default:
return {
statusCode: 400,
body: JSON.stringify({ error: 'Unsupported HTTP method' })
};
}
};
우와, 이 함수는 정말 많은 일을 하고 있어! 하나씩 뜯어보자:
AWS.DynamoDB.DocumentClient()
: DynamoDB와 상호작용하기 위한 클라이언트를 생성해.switch (httpMethod)
: HTTP 메서드에 따라 다른 동작을 수행해. POST는 메시지 추가, GET은 메시지 조회야.- POST 요청 처리:
- 요청 본문에서 메시지와 작성자 정보를 추출해.
- 현재 시간을 ID로 사용해 고유성을 보장해.
dynamodb.put()
을 사용해 새 항목을 DynamoDB에 추가해.
- GET 요청 처리:
dynamodb.scan()
을 사용해 테이블의 모든 항목을 조회해.- 조회된 항목들을 JSON 형태로 반환해.
- 에러 처리: 데이터베이스 작업 중 발생할 수 있는 에러를 잡아서 적절한 응답을 반환해.
이 함수를 사용하면, POST 요청으로 새 메시지를 추가하고 GET 요청으로 모든 메시지를 조회할 수 있어. 재능넷 같은 플랫폼에서 사용자 리뷰 시스템을 구현할 때 이런 방식을 활용할 수 있을 거야!
🔧 개선 포인트:
실제 애플리케이션에서는 페이지네이션, 정렬, 필터링 등의 기능을 추가하는 것이 좋아. 또한, 입력 값 검증과 보안 처리도 꼭 해야 해!
4. Lambda 함수의 고급 기능 🚀
지금까지 기본적인 Lambda 함수 작성법을 배웠어. 이제 좀 더 고급 기능들을 살펴볼 차례야. 이 기능들을 활용하면 더욱 강력하고 효율적인 서버리스 애플리케이션을 만들 수 있을 거야!
4.1 환경 변수 사용하기 🌿
API 키나 데이터베이스 연결 문자열 같은 민감한 정보는 코드에 직접 넣지 않는 것이 좋아. 대신 Lambda 함수의 환경 변수를 사용할 수 있어.
const API_KEY = process.env.API_KEY;
const DATABASE_URL = process.env.DATABASE_URL;
exports.handler = async (event) => {
// API_KEY와 DATABASE_URL을 사용하는 코드
...
};
Lambda 콘솔에서 이러한 환경 변수를 설정할 수 있어. 이렇게 하면 코드를 변경하지 않고도 다양한 환경(개발, 테스트, 프로덕션 등)에서 서로 다른 설정을 사용할 수 있지.
4.2 Lambda 레이어 활용하기 🧅
Lambda 레이어를 사용하면 함수 코드와 종속성을 분리할 수 있어. 이는 코드 크기를 줄이고 배포 속도를 높이는 데 도움이 돼.
예를 들어, axios
같은 라이브러리를 레이어로 만들어 여러 함수에서 공유할 수 있어:
// Lambda 함수 코드
const axios = require('axios'); // 이 라이브러리는 레이어에서 제공됨
exports.handler = async (event) => {
const response = await axios.get('https://api.example.com/data');
// 응답 처리
...
};
레이어를 사용하면 함수 코드가 더 간결해지고, 라이 브러리 업데이트도 더 쉬워져. 한 번 레이어를 업데이트하면 모든 연결된 함수에 변경사항이 적용되니까.
4.3 VPC 내에서 Lambda 실행하기 🔒
보안이 중요한 리소스(예: 프라이빗 데이터베이스)에 접근해야 할 때는 Lambda 함수를 VPC(Virtual Private Cloud) 내에서 실행할 수 있어. 이렇게 하면 함수가 VPC 내의 리소스에 안전하게 접근할 수 있지.
const mysql = require('mysql');
exports.handler = async (event) => {
const connection = mysql.createConnection({
host: 'your-private-db-host',
user: 'username',
password: 'password',
database: 'your_database'
});
// 데이터베이스 쿼리 실행
...
};
이 함수를 VPC 내에서 실행하도록 설정하면, 프라이빗 서브넷에 있는 데이터베이스에 안전하게 접근할 수 있어.
4.4 Step Functions로 워크플로우 만들기 🔗
AWS Step Functions를 사용하면 여러 Lambda 함수를 조합해 복잡한 워크플로우를 만들 수 있어. 예를 들어, 재능넷에서 새로운 재능이 등록되면 다음과 같은 과정을 자동화할 수 있지:
- 재능 정보 검증
- 이미지 처리 (리사이징, 워터마크 추가 등)
- 관련 태그 자동 생성
- 검색 인덱스 업데이트
- 알림 발송
각 단계를 별도의 Lambda 함수로 구현하고, Step Functions로 이들을 연결하면 돼.
// 재능 정보 검증 Lambda 함수
exports.validateTalent = async (event) => {
// 검증 로직
...
return { isValid: true, talentData: event };
};
// 이미지 처리 Lambda 함수
exports.processImage = async (event) => {
// 이미지 처리 로직
...
return { ...event, processedImageUrl: 'https://example.com/processed-image.jpg' };
};
// 태그 생성 Lambda 함수
exports.generateTags = async (event) => {
// 태그 생성 로직
...
return { ...event, tags: ['creative', 'design', 'illustration'] };
};
// 이런 식으로 각 단계를 별도의 함수로 구현
Step Functions의 상태 머신 정의에서 이 함수들을 순서대로 연결하면 전체 워크플로우가 완성돼.
4.5 EventBridge로 이벤트 기반 아키텍처 구현하기 🌉
AWS EventBridge를 사용하면 다양한 AWS 서비스와 외부 애플리케이션 간의 이벤트 기반 아키텍처를 쉽게 구현할 수 있어. 예를 들어, 재능넷에서 새로운 거래가 성사될 때마다 여러 작업을 자동으로 트리거할 수 있지: