API GW 상용화 서비스 개발 (API GW편)
개요
어느날 개발 요청이 들어왔다
- API GW
- Agent
Agent가 DB Data를 읽어 API GW로 발송 하는 구조로 구조 자체는 단순 하지만 구현해야 하는 기능이 많았다.</br>
방향성
개발에 방향성을 아래와 같이 잡았다.
- 확장이 가능한 구조
- 기능 추가가 자유로운 구조
- 장애 최소화
- 레거시를 만들지 말자
- 인프라 관리가 쉬운 구조
관련하여 개발을 리소스를 줄이기 위하여 AWS 기능을 최대한 사용 하기로 하였다.
구성도
개발을 진행 하면서 구성도는 계속 바뀔꺼 같다.
기능
GW
- API 사용자 인증
- Basic 인증
- HMac
- JWT Token
- Agent Request 제한
- API를 호출 할때마다 실제로 데이터가 발송 되므로 고객별 호출 횟수 제한
- Redis 사용 예정
- 라우팅 기능
- 고객별 호출되는 백앤드를 다르게 하기 위하여 라우팅 도입
- Redis 사용 예정
- 기능 추가가 쉬워야 한다
- API URL 버저닝을 통하여 분리
- api.test.com/v1.0/test
- 연동 테스트 API 지원
- 고객이 연동 개발을 할때 운영용이 아닌 테스트용으로 사용 가능 할 수 있도록 분리
- URL 분리와 라우팅 기능 활용
- 로드벨런싱
- AWS ELB 이용
- 메시지 큐 도입
- Lamabda가 DB 연결을 하게 하지 못하게 하기위해 큐 도입
- 잔여 Request 확인 기능
- 고객이 발송 가능한 Request 잔여량이 얼마나 남았는지 확인 가능
Infra
- IAM 정책 및 계정 정리
- CloudTrail + CloudWatch + SNS + Lambda + Slack을 이용한 사용자 로깅
AWS 사용 서비스
1개의 서비스를 만드는데 사용하는 서비스가 이렇게 많다... 돈이 최고다..
- ELB
- WAF
- Route53
- API Gateway
- Lambda
- SQS
- RDS
- S3
- ElastiCache
- ECS
- Simple Notification Service
- CloudTrail
- CloudWatch
- IAM
일기
API 사용자 인증
처음은 JWT Token만 구현 할려고 하였지만 다양한 인증 방식 지원을 위하여
ID:PW:API_KEY를 단순히 Base64로 인코딩 하고 인증 요청하는 Basic 방식 먼저 구현 하였다.
라우팅 기능
라우팅 기능을 구현하고 있으며 AWS ElasticCache Redis를 이용하기로 하였다.
Lambda가 Auth인증을 정상적으로 끝난 Request를 Redis에 key 검색하여 어디로 발송이 가능 한지 확인 후
해당 메시지 큐로 보낸다.
보안
요즘 AWS 세미나를 신청하여 듣고 있다.
내용은 Devops + Security = Devsecops 에 관한 내용이다.
들으면서 역시 AWS... 진짜 없는게 없다.
보면서 보안에 신경을 써야되겠다고 많이 느꼇다.
소스 코드단에 보안 + CI/CD단에 보안 + 배포 후 인프라단에 보안
하지만 혼자 하다보니 개발할 시간도 촉박하기에 제일 쉽고 성능이 좋은
인프라단에 보안을 먼저 진행 하기로 하였다.
WAF, VPC, NACL, IAM, GuardDuty 할께 많다...
중복 제거
Agent를 나중에 설계할때 오동작하여 Request를 여러번 보내는 경우 GW는 따로 중복 검사를 하지 않아 여러건의 문자가 발송 될 수 있다.
해당 상황을 막기위해 기능을 추가 해야되는데 Redis에 Key timeout 걸고 할까 생각중이다.
AWS 요금
요금 청구서를 보니 SQS와 VPC 요금이 많이 나왔다.
- SQS
SQS Request를 4,583,293건이나 했다고 하는데 나는 그런적이 없는데...
추측으로는 SQS Send 자체는 얼마 안했는데 reciver쪽에서 pull을 하는 것도 Request에 포함되는거 같다.
아니 그러면 메시지가 들어왔는지 어떻게 확인 하지 메시지가 없어도 계속 켜놓기만 하면 요금폭탄 당하는게 아닌가...
세가지 방법을 생각했다.
1. 메시지가 들어온게 없을 경우 일정 시간 sleep
- sleep 동안 메시지가 들어오면 그만큼 지연인데..
- 하루(86,400초) 한달(2,592,000) 한달에 최소 이만큼 Request를 한다.
2. SNS를 이용한 pub/sub 구조로 변경??
3. SQS Lambda 트리거???? 이걸 사용할까...
아니 이런 기능이 있었다니... 처음부터 공부좀 하고 할껄..
개발을 다시 해야되지만 Agent를 ECS에 돌리는 것보다 비용도 절감되고 리소스 낭비도 줄어든다..
서버리스 하게 사용하기 좋은거 같다.
생각해 보니 lambda에서 바로 RDS로 연결하면 요청 수 마다 커넥션 수가 늘어나서 문제가 될꺼 같아서 Lambda를 안썼는데...
해결방법
메시지 수신 대기 시간를 설정하여 해결 하였다.
추가적으로 메시지가 들어온게 없다면 sleep을 주어 폴링을 늦춤
- VPC
endpoint 비용 Lambda에서 -> Redis, DynamoDB, RDS, SQS
위와 같이 접근을 하니 Lambda를 VPC에 넣어줘야 했다.
그러니까 DynamoDB, SQS에 접근을 할려면 endpoint를 사용해야 하는데...
다른 구조를 생각해 봐야겠다..
endpoint가 제일 효율적인거 같긴하다.
비용도 보니 네트워크 비용보다는 running 비용이 많이 나온거라 네트워크 사용량이 많아져도
괜찮을꺼 같긴 하다.
VPC -> SQS, DynamoDB (Internet)
1. VPC endpoint
2. NAT gateway
3. Lambda target
- SQS를 고정으로 사용하는게 아닌 랜덤이라 패스
while 1:
messages = queue.receive_messages()
- DynamoDB
처음 설계한 PK랑 정렬키 때문에 Query를 사용하는게 아니라 Scan을 사용해야 했다.
https://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/bp-query-scan.html
"Scan 작업은 요청한 값을 찾기 위해 전체 항목을 검사하기 때문에 대용량 테이블이나 인덱스일 경우에는 단 한 번의 작업으로 프로비저닝된 처리량을 모두 사용할 수 있습니다."
해당 가이드에 이 문구를 보고 수정 하기로함 요금 폭탄 맞기 싫어...
BatchGetItem
파이썬
- Runtime
확실히 데이터량이 많아지는 연산속도가 문제가 있었다 해결 하기 위하여 Runtime pypy로 변경 엄청 빠르다...
- SQLAlchemy
Select를 계속 하는데 실제로 데이터가 있지만 0건을 가져온다...
MariaDB 자체 Select cache 옵션인가 하고 기능을 껐지만 그대로 이다...
프로그램을 껐다 키니까 읽어 오는데 과연 어디 문제 일까 하다가 설마 SQLAlchemy에 Cache가 있나 했는데
아래 처럼 트랙잭션 관리에 대한 글이 있다.
rollback이나 commit을 넣으니까 정상 동작 한다 (덕북에 삽질..)
https://stackoverflow.com/questions/10210080/how-to-disable-sqlalchemy-caching