좀 더 적은 비용으로 GeoIP API 서버 만들기
Maxmind GeoIP 서비스를 사용하고 있다
GeoIP Web Services 를 이용하면 사실 모든 것이 해결되지만, 비용 Per Query 로 이루어져 있기 때문에 = 종량제 라고 봐야 한다.
사실 트래픽이 어느 정도 예상 되고, 특정 할 수 있는 내용으로 증가하는 서비스에서는 이런 종량제는 좋은 선택일 수 있다. 사실 개발자가 신경 쓰지 않는게 가장 비용 절감이 아닐까 생각한다.
각설하고, 회사에서는 여러 곳의 웹 서비스를 배포 하고 있기 때문에, Query 로 따지면 비용이 생각 보다 많이 나올 것 같아서, GeoIP Database 를 구매하고 있다. 이 또한 구독제(Subscription)로 약 $130/monthly 로 비용을 내고 있다.
한 달에 약 $130 내고, 전체 서비스에서 Database 파일을 받아서 업데이트 해가면서 사용하고 있는데, 이게 여간 불편함이 말도 못 한다.
GeoIP Database 파일은 정말 잦은 주기 (최소 3일)로 업데이트가 이루어지고 있기 때문이기에, 파일 업데이트는 아무리 부지런한 개발자 (그건 바로 나?) 라도 1~2개월에 한 번 정도 업데이트 하면 다행인 것 같다.
그래서 자체 API 서비스를 만들기로 결정 했다
우리는 이것을 자체 API 서비스를 하기로 결정 했다. API 서비스를 하려면 여러 불편함이 존재하지만, 많은 서비스가 배포 된 상황에서 GEOIP WebServices 같은 WebService 를 하나 개발 하기로 한 내용이다.
- 관리 포인트 최소로 낮추는게 목적
- 비용 최소로 낮추는게 목적
- 업데이트 자동으로 되도록 하는게 목적
이 조건을 만족하도록 하는 설계와 개발 내용은 다음과 같다.
- AWS Serverless 를 최대로 이용하기로 했다
- ECS Fargate - 서버 관리 필요 없음
- Elastic File System (EFS) - Shared File Storage 사용
- EventBridge Scheduler - Updator 에 사용
- docker image 2개 Task Definition
geoip-updator
- GEOIP Database File 을 Update 하기 위해 Maxmind 의 GeoipUpdate 를 사용한다
geoip-api
- Database file load 해서 결과 내려주는 API Server
[ 여기에 인프라 레이아웃 다이어그램 필요 ]
먼저 API 서버를 만들어보자
먼저 GeoIP 서비스를 위한 Nuget Package 를 받아야 한다.
install-package MaxMind.Db
MaxMind.GeoIP2
[Link] 라는 package 가 Maxmind.Db
를 포함하고 있고, 지원되는 함수들이 좀 더 쓰기 편할 수 있지만, 여기에서는 Country DB 만 사용할 것이기 때문에 크게 상관 없고, 최소의 패키지만 관리하고 싶어서 MaxMind.Db
만 다운로드 받았다.
API 서버는 여러 가지 필수 기능들이 있으나, 여기에서는 딱 GeoIP 에 대한 부분만을 다루도록 한다.
위의 코드가 구현된 내용이고, 해당 구현에 대한 부가 설명을 한다면, PublicIP 로 Country DB 를 읽어서 나온 CountryCode 는 MemoryCache 에 저장해서 (12시간)은 캐시된 내용을 그대로 전달하는 식으로 구현이 되어져 있다.
Database File 은 직접 넣어도 되고, appsettings.json
에 넣어서 관리 하도록 한다. Program.cs
에는 아래의 DI 코드가 들어가야 제대로 작동을 할 수 있다.
builder.Services.AddTransient<IGeoIpService, GeoIpService>(); // DI
builder.Services.AddDistributedMemoryCache(options =>
{
options.SizeLimit = 200 * 1024 * 1024; // Default size limit of 200 MB
});
Controller 는 아래와 같이 간단히(?) 구현하면 된다.
[HttpGet]
[Route("")]
public async Task<IActionResult> Get([FromServices] IGeoIpService service, [FromQuery] string? ip)
{
if (string.IsNullOrWhiteSpace(ip))
return NoContent();
var isoCountryCode = await service.GetCountryCode(ip, databasePath);
return Content(isoCountryCode, "text/plain", Encoding.UTF8);
}
완성된 API Server 를 Docker Image 로 만들고, AWS ECR 에 올려두도록 하자.
AWS EFS Storage 연결
아래 링크는 geoipupdate 라는 단독 프로그램의 docker 사용 메뉴얼이다
docker run --env-file <file> -v <database directory>:/usr/share/GeoIP ghcr.io/maxmind/geoipupdate
처럼 실행 시키면 알아서 실행이 되는 구조로 되어있다.
maxmind 에서 제공하는 ENV 를 제공하고, 중요한 지점은 -v 옵션으로 제공된 <database directory>
라는 곳을 우리는 Shared File System 인 AWS EFS 를 사용하도록 한다.
AWS EFS 설정
아래와 같이 기본 EFS 를 하나 만들고, vpc 및 subnet 을 사용할 곳에 맞춰서 설정 후에 Security Group 에서 NFS 2049 포트를 Inbound 로 설정 하여 하나 추가 해서 해당 EFS 의 Security Group 에 추가 해주자.
AWS ECR Task 만들기
스크린샷을 참조하여 만들고, Environment 항목들은 위의 docker readme 를 보면 된다. Maxmind 의 AccountID 및 LicenseKey 를 넣으면 되고, 여기에서는 Country 서비스만을 사용 하고 72시간 주기로 업데이트 하도록 설정 했다.
geoipupdate
라는 Container 는 EFS 볼륨인 geoipupdate-data
라는 볼륨에 붙어서 ghcr.io/maxmind/geoipupdate
라는 이미지의 /usr/share/GeoIP
경로의 내용을 /
와 공유(Share) 시키라는 형태로 이해하면 된다.
docker run -v /usr/share/GeoIP:/ ghcr.io/maxmind/geoipupdate:v7.0.1
이렇게 되면, 해당 EFS 에 GeoIP-Country.mmdb
가 들어오게 된다.
같은 방법으로 API 서버의 ECR Task 를 만들어야한다.
이미지 이름과 AWS ECR 위치를 입력하고 Volumn 입력 하는 곳에 와서 아래와 같이 맞춰 준다. 보라색의 Container = geoip-API Container 이름이다.
.NET은 linux OS 의 경우 Working Directory /app
에서 시작한다.
docker run -v /app/data:/ xxxxxxx.dkr.ecr.{region}.amazonaws.com/geoip-api
형태의 docker 가 실행이 되게 된다. 이러면 data 폴더 = EFS root directory
를 Share 하게 된다.
또한 1g 짜리 팁으로 Read only 에 체크 해서 EFS 에 Write 를 하지 않는다는 선언을 하게 되면, Read Throughput 만 사용하게 되어서 약간의 비용 절감을 할 수 있다.
이렇게 만든 Task Group 2개를 ECR 에 Fargate 로 올릴껀데, 여기서 GeoIP API 서버는 계속 돌게 만들꺼지만, geoip-update Task Group 은 실행 하고 완료 후에는 삭제 되도록 하는게 유리하다.
AWS EventBridge Scheduler 를 사용 하도록 하자
AWS EventBridge Scheduler 는 서버리스로 만들어진 것들을 쉽게 스케쥴링 할 수 있도록 도와주는 서비스이다.
이미 만든 AWS ECR Fargate Task Group 인 geoip-update 를 3일(72시간) 에 한 번씩만 실행하고, 실행 후에는 삭제 되도록 (Action after completion : DELETE) 설정 한다.
서비스 확인
자 이제 모든 준비는 끝났다.
먼저 geoip-update
를 실행하여 로그가 잘 나오고, EFS 에 파일이 저장 되었는지 확인한다.
GeoIP API 서비스도 Fargate 로 올려서 원하는 주소에서 잘 동작하는지 확인하자.
추가 작업으로 GeoIP API 서비스는 ECR Fargate 의 기능을 이용하여 Scale-out 을 쉽게 적용 가능하다.
그래서 비용은 얼마나 저렴한데?
- Maxmind GeoIP Database subscription
- about $130/monthly
- AWS EFS - country file - under 10mb
- about $7 /monthly
- AWS ECS Fargate
- 0.25 vcpu , 0.5 ram 1개 - 항시
- about $9 /monthly
- 0.25 vcpu, 0.5 ram 1개 - 3일마다 한 번씩 쓰고 15분 후 삭제
- ??? 더 적게 쓰겠죠
- AWS EventBridge Scheduler
- 3일에 한 번씩 쓰는거라 가격은 0원이나 다름 없음
- 0.25 vcpu , 0.5 ram 1개 - 항시
Maxmind Database 를 구독하는 비용을 제외하면 월 약 $20 이내로 충분히 전체 서비스를 커버하는 웹 서비스를 구현 가능 하다.
그리고 모두 서버리스 이기 때문에 딱히 관리할 필요가 없다.
제발 잘 살아 있어 주세요. AWS 님. (기도메타)